Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [Unreleased]
### Added
- **`xhigh` Reasoning Effort**: Added `"xhigh"` as an accepted `reasoning_effort` value (maps to `EFFORT_XHIGH`; supported by models such as `grok-4.6`)
- Added `grok-4.6` to the `ChatModel` known-model type literal
- **Imagine File Storage**: Image and video generation (sync and async) now accept a `storage_options` parameter to persist generated assets to the Files API. It takes a dict with a required `filename` and optional `expires_after` (an `int` in seconds or a `datetime.timedelta`) and `public_url` (`True` to create a public URL with default expiry, or `{"expires_after": <seconds>}` for an independent URL expiry). Image and video responses expose new `file_output`, `storage_error`, `public_url`, and `public_url_error` properties.
- **File-ID Inputs for Generation**: Image and video generation now accept Files API `file_id` references as inputs alongside URLs/base64 — `image_file_id` / `image_file_ids` for `image.sample()` / `image.sample_batch()`, and `image_file_id` / `video_file_id` / `reference_image_file_ids` for `video.generate()` / `video.extend()` (and the batch `prepare` helpers). URL and file-ID lists may be mixed in the same multi-image request (file IDs are sent first).
- **Public File URLs**: Added `client.files.create_public_url()` and `client.files.revoke_public_url()` (sync and async) to create and revoke publicly shareable, unauthenticated URLs for stored files. `create_public_url()` accepts an optional `expires_after` (an `int` in seconds or a `datetime.timedelta`).
Expand Down
8 changes: 6 additions & 2 deletions src/xai_sdk/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ def create(
presence_penalty: Positive values penalize new tokens based on whether they appear in the text so far,
increasing the model's likelihood to talk about new topics.
reasoning_effort: Constrains how hard a reasoning model thinks before responding. Possible values are
`none` (no reasoning), `low` (uses fewer reasoning tokens), `medium` (default), and `high`
(uses more reasoning tokens). Defaults to `medium`.
`none` (no reasoning), `low` (uses fewer reasoning tokens), `medium`, `high`
(uses more reasoning tokens), and `xhigh` (maximum reasoning depth; only supported by some
models, e.g. `grok-4.6`). The default varies by model (e.g. `grok-4.5` and `grok-4.6`
default to `high`).
search_parameters: The parameters that control search behavior.
This includes settings like search mode, date range, sources (e.g., web, news, or X), and whether
to return citations. See `SearchParameters` for detailed configuration options.
Expand Down Expand Up @@ -921,6 +923,8 @@ def _reasoning_effort_to_proto(effort: ReasoningEffort) -> chat_pb2.ReasoningEff
return chat_pb2.ReasoningEffort.EFFORT_MEDIUM
case "high":
return chat_pb2.ReasoningEffort.EFFORT_HIGH
case "xhigh":
return chat_pb2.ReasoningEffort.EFFORT_XHIGH
case _:
raise ValueError(f"Invalid reasoning effort: {effort}. Must be one of: {ReasoningEffort.__args__}")

Expand Down
32 changes: 16 additions & 16 deletions src/xai_sdk/proto/v5/chat_pb2.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/xai_sdk/proto/v5/chat_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ReasoningEffort(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
EFFORT_MEDIUM: _ClassVar[ReasoningEffort]
EFFORT_HIGH: _ClassVar[ReasoningEffort]
EFFORT_NONE: _ClassVar[ReasoningEffort]
EFFORT_XHIGH: _ClassVar[ReasoningEffort]

class AgentCount(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
Expand Down Expand Up @@ -109,6 +110,7 @@ EFFORT_LOW: ReasoningEffort
EFFORT_MEDIUM: ReasoningEffort
EFFORT_HIGH: ReasoningEffort
EFFORT_NONE: ReasoningEffort
EFFORT_XHIGH: ReasoningEffort
AGENT_COUNT_UNSPECIFIED: AgentCount
AGENT_COUNT_4: AgentCount
AGENT_COUNT_16: AgentCount
Expand Down
32 changes: 16 additions & 16 deletions src/xai_sdk/proto/v6/chat_pb2.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/xai_sdk/proto/v6/chat_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class ReasoningEffort(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
EFFORT_MEDIUM: _ClassVar[ReasoningEffort]
EFFORT_HIGH: _ClassVar[ReasoningEffort]
EFFORT_NONE: _ClassVar[ReasoningEffort]
EFFORT_XHIGH: _ClassVar[ReasoningEffort]

class AgentCount(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
Expand Down Expand Up @@ -110,6 +111,7 @@ EFFORT_LOW: ReasoningEffort
EFFORT_MEDIUM: ReasoningEffort
EFFORT_HIGH: ReasoningEffort
EFFORT_NONE: ReasoningEffort
EFFORT_XHIGH: ReasoningEffort
AGENT_COUNT_UNSPECIFIED: AgentCount
AGENT_COUNT_4: AgentCount
AGENT_COUNT_16: AgentCount
Expand Down
2 changes: 1 addition & 1 deletion src/xai_sdk/types/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]

AgentCount: TypeAlias = Literal[4, 16]
ReasoningEffort: TypeAlias = Literal["none", "low", "medium", "high"]
ReasoningEffort: TypeAlias = Literal["none", "low", "medium", "high", "xhigh"]
ImageDetail: TypeAlias = Literal["auto", "low", "high"]
Content: TypeAlias = Union[str, chat_pb2.Content]
ToolMode: TypeAlias = Literal["auto", "none", "required"]
Expand Down
1 change: 1 addition & 0 deletions src/xai_sdk/types/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"grok-4.3-latest",
"grok-4.5",
"grok-4.5-latest",
"grok-4.6",
"grok-code-fast-1",
"grok-build-0.1",
"grok-3",
Expand Down
8 changes: 7 additions & 1 deletion tests/aio/chat_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1362,10 +1362,12 @@ async def test_multi_turn_conversation_creates_multiple_spans_with_same_conversa
"low",
"medium",
"high",
"xhigh",
chat_pb2.ReasoningEffort.EFFORT_NONE,
chat_pb2.ReasoningEffort.EFFORT_LOW,
chat_pb2.ReasoningEffort.EFFORT_MEDIUM,
chat_pb2.ReasoningEffort.EFFORT_HIGH,
chat_pb2.ReasoningEffort.EFFORT_XHIGH,
],
)
def test_chat_create_with_reasoning(
Expand All @@ -1385,6 +1387,8 @@ def test_chat_create_with_reasoning(
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_MEDIUM
elif reasoning_effort == "high":
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_HIGH
elif reasoning_effort == "xhigh":
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_XHIGH
else:
assert chat_completion_request.reasoning_effort == reasoning_effort

Expand All @@ -1395,7 +1399,9 @@ def test_chat_with_reasoning_invalid_value(client: AsyncClient):
"grok-4.3",
reasoning_effort="invalid", # type: ignore
)
assert str(e.value) == "Invalid reasoning effort: invalid. Must be one of: ('none', 'low', 'medium', 'high')"
assert (
str(e.value) == "Invalid reasoning effort: invalid. Must be one of: ('none', 'low', 'medium', 'high', 'xhigh')"
)


def test_chat_create_with_tools(client: AsyncClient):
Expand Down
8 changes: 7 additions & 1 deletion tests/sync/chat_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1321,10 +1321,12 @@ def test_multi_turn_conversation_creates_multiple_spans_with_same_conversation_i
"low",
"medium",
"high",
"xhigh",
chat_pb2.ReasoningEffort.EFFORT_NONE,
chat_pb2.ReasoningEffort.EFFORT_LOW,
chat_pb2.ReasoningEffort.EFFORT_MEDIUM,
chat_pb2.ReasoningEffort.EFFORT_HIGH,
chat_pb2.ReasoningEffort.EFFORT_XHIGH,
],
)
def test_chat_create_with_reasoning(
Expand All @@ -1344,6 +1346,8 @@ def test_chat_create_with_reasoning(
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_MEDIUM
elif reasoning_effort == "high":
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_HIGH
elif reasoning_effort == "xhigh":
assert chat_completion_request.reasoning_effort == chat_pb2.ReasoningEffort.EFFORT_XHIGH
else:
assert chat_completion_request.reasoning_effort == reasoning_effort

Expand All @@ -1354,7 +1358,9 @@ def test_chat_with_reasoning_invalid_value(client: Client):
"grok-4.3",
reasoning_effort="invalid", # type: ignore
)
assert str(e.value) == "Invalid reasoning effort: invalid. Must be one of: ('none', 'low', 'medium', 'high')"
assert (
str(e.value) == "Invalid reasoning effort: invalid. Must be one of: ('none', 'low', 'medium', 'high', 'xhigh')"
)


def test_chat_create_with_tools(client: Client):
Expand Down
Loading