diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 4249b4b..d69c794 100644
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -1,19 +1,19 @@
lockVersion: 2.0.0
id: c48cf606-fb42-4a45-9c23-8f0555307828
management:
- docChecksum: 8dd32184dc771115ba5e79b3c70e7f6f
+ docChecksum: cc6966b5800766370c195f5c42b10761
docVersion: 1.0.0
speakeasyVersion: 1.680.0
generationVersion: 2.788.4
- releaseVersion: 0.10.0
- configChecksum: 00a97c5bcdbddf7e591c0a1d7a45e98e
+ releaseVersion: 0.10.1
+ configChecksum: b1687c127d87a1ac114b35dd9b492f3c
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: b6cb6701-b1ae-453f-beb8-2064f09433f4
- pristine_commit_hash: ed0a00c99b7b3b76ed1de023bc8174696435c2cd
- pristine_tree_hash: a5b3d8dc9253bb236d709d9f365f5766595d820b
+ generation_id: 8123354f-2376-451c-8dbd-6e7ed6d6980c
+ pristine_commit_hash: 48c154f879472adb6f282e81083593c020808530
+ pristine_tree_hash: 3e5484ebb7e5c6660a037fb427b4aa9edd240571
features:
python:
acceptHeaders: 3.0.0
@@ -1448,6 +1448,10 @@ trackedFiles:
id: 8d84fb41685d
last_write_checksum: sha1:fcfbe6740c505b263b90f7de5281d4f506922b05
pristine_git_object: 870296bd3335da46ecdf4ec1722a3d47037a09c9
+ docs/components/defaulteffort.md:
+ id: 08dabde07c1d
+ last_write_checksum: sha1:96f06eb8b68e44984b691338b99e746fef1253ac
+ pristine_git_object: f3f07f26e47692dd4e6a728e45f32cfe5795082e
docs/components/defaultparameters.md:
id: a84477afcaec
last_write_checksum: sha1:a20e8b576e341dbcdb91884b8fc83cf4316ab106
@@ -2522,8 +2526,8 @@ trackedFiles:
pristine_git_object: d5bbdc95f658be46eebf13f0ba8b9ae3716f72e2
docs/components/model.md:
id: 673ad57400cd
- last_write_checksum: sha1:517cbce221606bacb2cab7b97e53d316d09a5f17
- pristine_git_object: 8ce3d9d7c9ddc7c270da3a39df079148aa7ff207
+ last_write_checksum: sha1:ea20bf9ca8f49a181142f516f1b36758cf5ceac6
+ pristine_git_object: edb000fc276b3eec0dbe0bb1e82c4f5d7a72e8c9
docs/components/modelarchitecture.md:
id: 79816051e6e8
last_write_checksum: sha1:158b04c79b7a32a2d95e3d3fda8fa6da0ab91cd9
@@ -2548,10 +2552,14 @@ trackedFiles:
id: 74607e6a173d
last_write_checksum: sha1:445ec227b130763e2509d1a181dd5e3e6d71420a
pristine_git_object: 317190772f743d2aba63c4dad770827b46688f6a
+ docs/components/modelreasoning.md:
+ id: 47976b46e5b9
+ last_write_checksum: sha1:07deec55fe155257ef07086b6dc2fbc7e012e031
+ pristine_git_object: 306c0aeb39047768e6c79975996240584a97525b
docs/components/modelresponse.md:
id: 9d48c3f335b1
- last_write_checksum: sha1:5d8890c41a9f448341037e9915dd6e93df9140cb
- pristine_git_object: 2a7433dc87413943d14220ffdfda8b25e59bc9c0
+ last_write_checksum: sha1:442bb6c4d21debbceb5a48a9563b07704983123f
+ pristine_git_object: 2ad6e9dc16fa06d03318e98bc540c7aca0d497ed
docs/components/modelscountresponse.md:
id: abdad0c1a02a
last_write_checksum: sha1:50ae205604eddcbdced268b8cd3e1ac06f0dd7c0
@@ -6042,8 +6050,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:ccf5925a473a1eb527cec02639f862b79b601251
- pristine_git_object: 396bd51f9c1428f03560f3e7988edc99edc698e8
+ last_write_checksum: sha1:8223abd8e7463dfa2b2c1097670bb28b2ec73e68
+ pristine_git_object: b98c0280ffbb42638747b1064375fa36f467223c
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -6070,8 +6078,8 @@ trackedFiles:
pristine_git_object: 07ace03229fd3267623c8f48665d2c3a67c3565d
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:017dc1ec43588b31eee23532d74d4421993dd874
- pristine_git_object: be619e3be1aa8d27deef5752ecc9ff09ccd4cd9f
+ last_write_checksum: sha1:856bdf17b7de36f6e1abd0b56f55bbc6093e4c68
+ pristine_git_object: ade61995259031f3789ff71f0cfd1d6ae4b39395
src/openrouter/analytics.py:
id: cb406b5aaabb
last_write_checksum: sha1:6d47d1ab3da9cb4ac9f0a2bfe442f1a82a614f35
@@ -6102,8 +6110,8 @@ trackedFiles:
pristine_git_object: a1894915bd32aee65f019885634eb7908970a046
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:56e0c315ac8fe611bf70b465a91341acbbe34534
- pristine_git_object: 2c07302c12f51cdf053e306906ac30862e925246
+ last_write_checksum: sha1:a136f824b02becfa0584a28474bb5f308a6861dc
+ pristine_git_object: 9df66e9e82ebd373652cc654f23b104ef315f3c5
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:1b6b66672fb80dccdc39843a98bdef6d7d804364
@@ -7178,8 +7186,8 @@ trackedFiles:
pristine_git_object: 1257b38d2001f34078cd1b052c20264e81a95e57
src/openrouter/components/model.py:
id: cef3adaa772b
- last_write_checksum: sha1:53eb4a044a7bf546225416bb08597df46a3b60a2
- pristine_git_object: 637b3fbe54ddcc454750d8de702045ee690c3333
+ last_write_checksum: sha1:53f544fe39ae08cde33f99c5d0bb4b6cc1555301
+ pristine_git_object: c0345109fb1717ea27010605984c27e1137426fd
src/openrouter/components/modelarchitecture.py:
id: b37ac27e512b
last_write_checksum: sha1:e1dd41aa140b2ca2c3bbf15abf74e034d42b0166
@@ -7196,6 +7204,10 @@ trackedFiles:
id: b8759a1a4787
last_write_checksum: sha1:69b2c991666848f4790e5136c67553733cc68a54
pristine_git_object: c197cb2c527296adff2c3cfd9e49bcbc48087ce7
+ src/openrouter/components/modelreasoning.py:
+ id: 58bb3f2d75e0
+ last_write_checksum: sha1:3da126ae596520b6d4f0edcc7fb8e4f786f686c7
+ pristine_git_object: b71947b65e2054b23ff2094a270763720e740d96
src/openrouter/components/modelresponse.py:
id: 023136e6dedf
last_write_checksum: sha1:af84587984cbe6341f59f176b08df43096ac48c6
@@ -10043,4 +10055,9 @@ examples:
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
examplesVersion: 1.0.2
-releaseNotes: "## Python SDK Changes:\n* `open_router.beta.responses.send()`: \n * `request` **Changed** **Breaking** :warning:\n * `response` **Changed** **Breaking** :warning:\n* `open_router.presets.create_presets_responses()`: `request` **Changed** **Breaking** :warning:\n* `open_router.presets.create_presets_chat_completions()`: `request` **Changed** **Breaking** :warning:\n* `open_router.chat.send()`: `request` **Changed** **Breaking** :warning:\n* `open_router.workspaces.set_budget()`: **Added**\n* `open_router.o_auth.create_auth_code()`: \n * `request.workspace_id` **Added**\n * `error.status[403]` **Added**\n* `open_router.files.download()`: **Added**\n* `open_router.models.get()`: **Added**\n* `open_router.workspaces.list_budgets()`: **Added**\n* `open_router.workspaces.delete_budget()`: **Added**\n* `open_router.datasets.get_benchmarks_artificial_analysis()`: **Added**\n* `open_router.beta.analytics.query_analytics()`: `response.data.warnings` **Added**\n* `open_router.files.delete()`: **Added**\n* `open_router.files.retrieve()`: **Added**\n* `open_router.files.upload()`: **Added**\n* `open_router.embeddings.list_models()`: `response.data.[].benchmarks` **Added**\n* `open_router.models.list()`: \n * `request` **Changed**\n * `response.data.[].benchmarks` **Added**\n* `open_router.models.list_for_user()`: `response.data.[].benchmarks` **Added**\n* `open_router.files.list()`: **Added**\n* `open_router.presets.create_presets_messages()`: `request` **Changed**\n* `open_router.datasets.get_benchmarks_design_arena()`: **Added**\n"
+releaseNotes: |
+ ## Python SDK Changes:
+ * `open_router.embeddings.list_models()`: `response.data.[].reasoning` **Added**
+ * `open_router.models.get()`: `response.data.reasoning` **Added**
+ * `open_router.models.list()`: `response.data.[].reasoning` **Added**
+ * `open_router.models.list_for_user()`: `response.data.[].reasoning` **Added**
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 652ef6c..dec9772 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -32,7 +32,7 @@ generation:
skipResponseBodyAssertions: false
preApplyUnionDiscriminators: true
python:
- version: 0.10.0
+ version: 0.10.1
additionalDependencies:
dev: {}
main: {}
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 0efe6ba..35fa2a0 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -12151,6 +12151,15 @@ components:
image: '0'
prompt: '0.00003'
request: '0'
+ reasoning:
+ default_effort: medium
+ default_enabled: true
+ mandatory: false
+ supported_efforts:
+ - high
+ - medium
+ - low
+ - minimal
supported_parameters:
- temperature
- top_p
@@ -12213,6 +12222,8 @@ components:
$ref: '#/components/schemas/PerRequestLimits'
pricing:
$ref: '#/components/schemas/PublicPricing'
+ reasoning:
+ $ref: '#/components/schemas/ModelReasoning'
supported_parameters:
description: List of supported parameters for this model
items:
@@ -12377,6 +12388,43 @@ components:
description: Model to use for completion
example: openai/gpt-4
type: string
+ ModelReasoning:
+ description: Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models.
+ example:
+ default_effort: medium
+ default_enabled: true
+ mandatory: false
+ supported_efforts:
+ - high
+ - medium
+ - low
+ - minimal
+ properties:
+ default_effort:
+ allOf:
+ - $ref: '#/components/schemas/ReasoningEffort'
+ - description: >-
+ Default reasoning effort when the client enables reasoning without specifying effort. Maps to `reasoning.effort` in chat requests. When `"none"`, prefer omitting effort unless the user explicitly disables reasoning.
+ default_enabled:
+ description: Default reasoning enabled state when the client does not set `reasoning.enabled`.
+ type: boolean
+ mandatory:
+ description: When true, reasoning cannot be disabled and effort "none" is rejected.
+ type: boolean
+ supported_efforts:
+ description: >-
+ Allowed reasoning effort values for this model, in descending effort order (highest first). Null means no allowlist — all gateway effort values are accepted.
+ items:
+ $ref: '#/components/schemas/ReasoningEffort'
+ nullable: true
+ type: array
+ supports_max_tokens:
+ description: >-
+ Present and `true` when the model accepts `reasoning.max_tokens` in requests (Anthropic-style) instead of or in addition to `reasoning.effort`. Omitted otherwise.
+ type: boolean
+ required:
+ - mandatory
+ type: object
ModelResponse:
description: Single model response
example:
@@ -28725,7 +28773,7 @@ paths:
id: openai/gpt-4
knowledge_cutoff: null
links:
- details: /api/v1/models/openai/gpt-5.4/endpoints
+ details: /api/v1/models/openai/gpt-4/endpoints
name: GPT-4
per_request_limits: null
pricing:
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 8c16144..8e8a7d4 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,20 +2,20 @@ speakeasyVersion: 1.680.0
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:716ece4a1211eac2ee0e7e5836c7b484cff9bb002bd4e676d9ecad8317ee7941
- sourceBlobDigest: sha256:12d3dc8e7150ab2c4c5e3d613b01cb5e4dcce52b329eea89ca1fdc656d6fe045
+ sourceRevisionDigest: sha256:b28471bf9c3ac9b7d9b816a09bfb5b5c58d98db2d82dbc971d64f5aa980f4e10
+ sourceBlobDigest: sha256:8d445ea792f56fb2ebeb3f418757e6404802be1c21ab50520c66d10871bb960a
tags:
- latest
- - speakeasy-sdk-regen-1781312282
+ - speakeasy-sdk-regen-1781726096
- 1.0.0
targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:716ece4a1211eac2ee0e7e5836c7b484cff9bb002bd4e676d9ecad8317ee7941
- sourceBlobDigest: sha256:12d3dc8e7150ab2c4c5e3d613b01cb5e4dcce52b329eea89ca1fdc656d6fe045
+ sourceRevisionDigest: sha256:b28471bf9c3ac9b7d9b816a09bfb5b5c58d98db2d82dbc971d64f5aa980f4e10
+ sourceBlobDigest: sha256:8d445ea792f56fb2ebeb3f418757e6404802be1c21ab50520c66d10871bb960a
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:e7d6f4de48a7c63cf15f3a8378f952277cd4c59373c28c61909497853fa769e2
+ codeSamplesRevisionDigest: sha256:0bb2447eb2e776cdc9347c290ddcde4be0b9f9ded69c93e5b29231e2c54c3e5f
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.680.0
diff --git a/RELEASES.md b/RELEASES.md
index 3c7e1bf..cd89fff 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -28,4 +28,14 @@ Based on:
### Generated
- [python v0.10.0] .
### Releases
-- [PyPI v0.10.0] https://pypi.org/project/openrouter/0.10.0 - .
\ No newline at end of file
+- [PyPI v0.10.0] https://pypi.org/project/openrouter/0.10.0 - .
+
+## 2026-06-18 00:58:22
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.680.0 (2.788.4) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v0.10.1] .
+### Releases
+- [PyPI v0.10.1] https://pypi.org/project/openrouter/0.10.1 - .
\ No newline at end of file
diff --git a/docs/components/model.md b/docs/components/model.md
index 8ce3d9d..edb000f 100644
--- a/docs/components/model.md
+++ b/docs/components/model.md
@@ -22,6 +22,7 @@ Information about an AI model available on OpenRouter
| `name` | *str* | :heavy_check_mark: | Display name of the model | GPT-4 |
| `per_request_limits` | [Nullable[components.PerRequestLimits]](../components/perrequestlimits.md) | :heavy_check_mark: | Per-request token limits | {
"completion_tokens": 1000,
"prompt_tokens": 1000
} |
| `pricing` | [components.PublicPricing](../components/publicpricing.md) | :heavy_check_mark: | Pricing information for the model | {
"completion": "0.00006",
"image": "0",
"prompt": "0.00003",
"request": "0"
} |
+| `reasoning` | [Optional[components.ModelReasoning]](../components/modelreasoning.md) | :heavy_minus_sign: | Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models. | {
"default_effort": "medium",
"default_enabled": true,
"mandatory": false,
"supported_efforts": [
"high",
"medium",
"low",
"minimal"
]
} |
| `supported_parameters` | List[[components.Parameter](../components/parameter.md)] | :heavy_check_mark: | List of supported parameters for this model | |
| `supported_voices` | List[*str*] | :heavy_check_mark: | List of supported voice identifiers for TTS models. Null for non-TTS models. | |
| `top_provider` | [components.TopProviderInfo](../components/topproviderinfo.md) | :heavy_check_mark: | Information about the top provider for this model | {
"context_length": 8192,
"is_moderated": true,
"max_completion_tokens": 4096
} |
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 396bd51..b98c028 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "0.10.0"
+version = "0.10.1"
description = "Official Python Client SDK for OpenRouter."
authors = [{ name = "OpenRouter" },]
readme = "README-PYPI.md"
diff --git a/src/openrouter/_version.py b/src/openrouter/_version.py
index be619e3..ade6199 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "0.10.0"
+__version__: str = "0.10.1"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.788.4"
-__user_agent__: str = "speakeasy-sdk/python 0.10.0 2.788.4 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 0.10.1 2.788.4 1.0.0 openrouter"
try:
if __package__ is not None:
diff --git a/src/openrouter/components/__init__.py b/src/openrouter/components/__init__.py
index 2c07302..9df66e9 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -1436,6 +1436,7 @@ if TYPE_CHECKING:
from .modelbenchmarks import ModelBenchmarks, ModelBenchmarksTypedDict
from .modelgroup import ModelGroup
from .modellinks import ModelLinks, ModelLinksTypedDict
+ from .modelreasoning import DefaultEffort, ModelReasoning, ModelReasoningTypedDict
from .modelresponse import ModelResponse, ModelResponseTypedDict
from .modelscountresponse import (
ModelsCountResponse,
@@ -3076,6 +3077,7 @@ __all__ = [
"DatetimeServerToolConfigTypedDict",
"DatetimeServerToolType",
"DatetimeServerToolTypedDict",
+ "DefaultEffort",
"DefaultParameters",
"DefaultParametersTypedDict",
"DeleteBYOKKeyResponse",
@@ -3518,6 +3520,8 @@ __all__ = [
"ModelGroup",
"ModelLinks",
"ModelLinksTypedDict",
+ "ModelReasoning",
+ "ModelReasoningTypedDict",
"ModelResponse",
"ModelResponseTypedDict",
"ModelTypedDict",
@@ -5459,6 +5463,9 @@ _dynamic_imports: dict[str, str] = {
"ModelGroup": ".modelgroup",
"ModelLinks": ".modellinks",
"ModelLinksTypedDict": ".modellinks",
+ "DefaultEffort": ".modelreasoning",
+ "ModelReasoning": ".modelreasoning",
+ "ModelReasoningTypedDict": ".modelreasoning",
"ModelResponse": ".modelresponse",
"ModelResponseTypedDict": ".modelresponse",
"ModelsCountResponse": ".modelscountresponse",
diff --git a/src/openrouter/components/model.py b/src/openrouter/components/model.py
index 637b3fb..c034510 100644
--- a/src/openrouter/components/model.py
+++ b/src/openrouter/components/model.py
@@ -5,6 +5,7 @@ from .defaultparameters import DefaultParameters, DefaultParametersTypedDict
from .modelarchitecture import ModelArchitecture, ModelArchitectureTypedDict
from .modelbenchmarks import ModelBenchmarks, ModelBenchmarksTypedDict
from .modellinks import ModelLinks, ModelLinksTypedDict
+from .modelreasoning import ModelReasoning, ModelReasoningTypedDict
from .parameter import Parameter
from .perrequestlimits import PerRequestLimits, PerRequestLimitsTypedDict
from .publicpricing import PublicPricing, PublicPricingTypedDict
@@ -62,6 +63,8 @@ class ModelTypedDict(TypedDict):
r"""Hugging Face model identifier, if applicable"""
knowledge_cutoff: NotRequired[Nullable[str]]
r"""The date up to which the model was trained on data. ISO 8601 date string (YYYY-MM-DD) or null if unknown."""
+ reasoning: NotRequired[ModelReasoningTypedDict]
+ r"""Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models."""
class Model(BaseModel):
@@ -123,6 +126,9 @@ class Model(BaseModel):
knowledge_cutoff: OptionalNullable[str] = UNSET
r"""The date up to which the model was trained on data. ISO 8601 date string (YYYY-MM-DD) or null if unknown."""
+ reasoning: Optional[ModelReasoning] = None
+ r"""Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models."""
+
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = [
@@ -131,6 +137,7 @@ class Model(BaseModel):
"expiration_date",
"hugging_face_id",
"knowledge_cutoff",
+ "reasoning",
]
nullable_fields = [
"context_length",
diff --git a/src/openrouter/components/modelreasoning.py b/src/openrouter/components/modelreasoning.py
new file mode 100644
index 0000000..b71947b
--- /dev/null
+++ b/src/openrouter/components/modelreasoning.py
@@ -0,0 +1,106 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from .reasoningeffort import ReasoningEffort
+from openrouter.types import (
+ BaseModel,
+ Nullable,
+ OptionalNullable,
+ UNSET,
+ UNSET_SENTINEL,
+ UnrecognizedStr,
+)
+from openrouter.utils import validate_open_enum
+from pydantic import model_serializer
+from pydantic.functional_validators import PlainValidator
+from typing import List, Literal, Optional, Union
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+DefaultEffort = Union[
+ Literal[
+ "xhigh",
+ "high",
+ "medium",
+ "low",
+ "minimal",
+ "none",
+ ],
+ UnrecognizedStr,
+]
+r"""Default reasoning effort when the client enables reasoning without specifying effort. Maps to `reasoning.effort` in chat requests. When `\"none\"`, prefer omitting effort unless the user explicitly disables reasoning."""
+
+
+class ModelReasoningTypedDict(TypedDict):
+ r"""Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models."""
+
+ mandatory: bool
+ r"""When true, reasoning cannot be disabled and effort \"none\" is rejected."""
+ default_effort: NotRequired[Nullable[DefaultEffort]]
+ default_enabled: NotRequired[bool]
+ r"""Default reasoning enabled state when the client does not set `reasoning.enabled`."""
+ supported_efforts: NotRequired[Nullable[List[Nullable[ReasoningEffort]]]]
+ r"""Allowed reasoning effort values for this model, in descending effort order (highest first). Null means no allowlist — all gateway effort values are accepted."""
+ supports_max_tokens: NotRequired[bool]
+ r"""Present and `true` when the model accepts `reasoning.max_tokens` in requests (Anthropic-style) instead of or in addition to `reasoning.effort`. Omitted otherwise."""
+
+
+class ModelReasoning(BaseModel):
+ r"""Reasoning effort configuration. Omitted for non-reasoning models and dynamic router models."""
+
+ mandatory: bool
+ r"""When true, reasoning cannot be disabled and effort \"none\" is rejected."""
+
+ default_effort: Annotated[
+ OptionalNullable[DefaultEffort], PlainValidator(validate_open_enum(False))
+ ] = UNSET
+
+ default_enabled: Optional[bool] = None
+ r"""Default reasoning enabled state when the client does not set `reasoning.enabled`."""
+
+ supported_efforts: OptionalNullable[
+ List[
+ Annotated[
+ Nullable[ReasoningEffort], PlainValidator(validate_open_enum(False))
+ ]
+ ]
+ ] = UNSET
+ r"""Allowed reasoning effort values for this model, in descending effort order (highest first). Null means no allowlist — all gateway effort values are accepted."""
+
+ supports_max_tokens: Optional[bool] = None
+ r"""Present and `true` when the model accepts `reasoning.max_tokens` in requests (Anthropic-style) instead of or in addition to `reasoning.effort`. Omitted otherwise."""
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = [
+ "default_effort",
+ "default_enabled",
+ "supported_efforts",
+ "supports_max_tokens",
+ ]
+ nullable_fields = ["default_effort", "supported_efforts"]
+ null_default_fields = []
+
+ serialized = handler(self)
+
+ m = {}
+
+ for n, f in type(self).model_fields.items():
+ k = f.alias or n
+ val = serialized.get(k)
+ serialized.pop(k, None)
+
+ optional_nullable = k in optional_fields and k in nullable_fields
+ is_set = (
+ self.__pydantic_fields_set__.intersection({n})
+ or k in null_default_fields
+ ) # pylint: disable=no-member
+
+ if val is not None and val != UNSET_SENTINEL:
+ m[k] = val
+ elif val != UNSET_SENTINEL and (
+ not k in optional_fields or (optional_nullable and is_set)
+ ):
+ m[k] = val
+
+ return m
diff --git a/uv.lock b/uv.lock
index ac18dd7..0bfff32 100644
--- a/uv.lock
+++ b/uv.lock
@@ -220,7 +220,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "0.10.0"
+version = "0.10.1"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },