diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 6236c3fc..3eeac571 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: dfe297f1e160a1084303efb6211f4058
+ docChecksum: 2fe567942733dd3f020b7f1ff0fd02d8
docVersion: 1.0.0
speakeasyVersion: 1.803.2
generationVersion: 2.950.13
- releaseVersion: 1.3.123
- configChecksum: c674eddd41c9bef60461d13a78688109
+ releaseVersion: 1.3.124
+ configChecksum: 4c8fc1e57b2cdff5192d1b5b7e2fb166
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: e42d1548-440e-42f8-9b16-95e929203bf8
- pristine_commit_hash: e4c78f0be023cd6a88bf208f4bdc975ec659747d
- pristine_tree_hash: be0568a86fcd500bef84b71d88d6a2d1c4086eec
+ generation_id: 14a992de-7a74-4727-80d9-47c17f828af9
+ pristine_commit_hash: d5164283e00654cebdf94937e24b9726333a4e28
+ pristine_tree_hash: 1685aba1ff2cab7e07a13a12174161c55a6008db
features:
python:
acceptHeaders: 3.0.0
@@ -2180,8 +2180,8 @@ trackedFiles:
pristine_git_object: 48386287b072381a9b59de6ae804b0ffbbab221a
docs/components/chatusage.mdx:
id: d7c2bc8b3eb2
- last_write_checksum: sha1:d6d9961d68cec736cd081c151b299b4748e5b87f
- pristine_git_object: 2bb1e32441b71d5616dda7134fa115f0a02d423e
+ last_write_checksum: sha1:7e88196fd7a48982974db6f0fa3d6f6da816fe47
+ pristine_git_object: 2f9b81331967705b2abc349c838c760c273ee8be
docs/components/chatusagecompletiontokensdetails.mdx:
id: 0274e721a9d9
last_write_checksum: sha1:c6111d83cf3b08f228fc92197ce89aba5cba6faf
@@ -3052,8 +3052,12 @@ trackedFiles:
pristine_git_object: a226240fb3b94358d33acc91761a8bba03309b63
docs/components/deferredtoolscontrol.mdx:
id: 13db9fb1f102
- last_write_checksum: sha1:fd854b3d96e1fd9f3223b3603f4c3b80f2612290
- pristine_git_object: ebb8bfa594095e21b1c84eab5a0e3ad3ed16720c
+ last_write_checksum: sha1:92e20daf24c49c040d40dcba0d6b5f4ec46900f6
+ pristine_git_object: c226e1a86b4a6b12668e11e4033c0568a8d4c52d
+ docs/components/deferredtoolsdetails.mdx:
+ id: 18832b6c60aa
+ last_write_checksum: sha1:15b5cc53097084283f00f04ce8b0f4016a0abb5c
+ pristine_git_object: 2a290bbd3177b4e748807e26d6ac921ff5c091ee
docs/components/deferredtoolssearchstrategy.mdx:
id: 6152b1ee19ef
last_write_checksum: sha1:bbd8c8508c11d8b065cc8a0caed09ef92b820738
@@ -6428,8 +6432,12 @@ trackedFiles:
pristine_git_object: d68bd61421859df1e00c0ec15f5a6946ed52dfd1
docs/components/outputtoolsearchservertoolitem.mdx:
id: 7106fbb89729
- last_write_checksum: sha1:6158bcc60cd42ce08009cb486e930404245cb21a
- pristine_git_object: 29b9d6202d9f4f82768ee0f501f0896752e5c5ac
+ last_write_checksum: sha1:624ad5b5ea8b46034cde801d3322141411bbda4c
+ pristine_git_object: c49ae6e87990a02aa270c6d26b98669fd6af4760
+ docs/components/outputtoolsearchservertoolitemformat.mdx:
+ id: 717072e9e3e8
+ last_write_checksum: sha1:04cf65dbe63614cfee6df054640472e679b4faac
+ pristine_git_object: 7d64dcb2814cc71db092a40b0dc45305680f924a
docs/components/outputtoolsearchservertoolitemtype.mdx:
id: 2b67e805a2ae
last_write_checksum: sha1:7d4b330d471721610a9ac7d9f44684fd1a099f7b
@@ -6780,8 +6788,8 @@ trackedFiles:
pristine_git_object: 6c3e7e5d4da71c9aa3052bf628a98a37de57a648
docs/components/profile.mdx:
id: cb682ce5da89
- last_write_checksum: sha1:4cf126470a616a8097d53d721fbc5b50ca2a5495
- pristine_git_object: b59688b7be0ae1054801e22f84a62252d5692821
+ last_write_checksum: sha1:85fc558652373eaf48459a2c14c15da8cd7c990e
+ pristine_git_object: f9eb1da620f71c083b8db1563c4b424f3ece8bcf
docs/components/promptcachebreakpoint.mdx:
id: c135956dc623
last_write_checksum: sha1:581974fd4042ee26dd8a88d28a084c28b3ccdef9
@@ -8476,8 +8484,8 @@ trackedFiles:
pristine_git_object: c5fe94ebc3791026c16a9636c7d6077773297e19
docs/components/usage.mdx:
id: d84b29a6ea8c
- last_write_checksum: sha1:6fa13809fd51308a2fc96110ff42fe7dc306f867
- pristine_git_object: 10680b424111c6f82d49dc9b2bbe15a6449c802f
+ last_write_checksum: sha1:a893189873208f1eccc91563aa4e24f2dcc8dc2e
+ pristine_git_object: f70fe4842e667898a9fbd16eebcbd55c80694f59
docs/components/usagecostdetails.mdx:
id: 95d8a52fead9
last_write_checksum: sha1:d3cb96ee83e39f1c736a63f6577d0c0e509a058a
@@ -10168,8 +10176,8 @@ trackedFiles:
pristine_git_object: f7ab206b5ca32f5af427138d0a9156f66e92211c
docs/operations/listorganizationmembersdata.mdx:
id: d96ba08cbfe4
- last_write_checksum: sha1:f7e3ae704edba14da53afbc3cde58ceeec1b54e0
- pristine_git_object: fc485e857933e51b9d190534b5f262d2799e315d
+ last_write_checksum: sha1:e8d8484bd155fd79905699db6ae993d76c1cf74a
+ pristine_git_object: f65b92ed5b0400090645b019e89358a83484617e
docs/operations/listorganizationmembersglobals.mdx:
id: 421fd4978d8f
last_write_checksum: sha1:b4aec9055bf7a1f276ebdc4b270e09aee733e3fd
@@ -10440,8 +10448,8 @@ trackedFiles:
pristine_git_object: 24b7423443ac3523f8625a5e517bfc7028bb9481
docs/operations/role.mdx:
id: ee0d3c3547d7
- last_write_checksum: sha1:11ebdfcfbf9a1197a42516d3daa0eaa3e2955f81
- pristine_git_object: 9e1219b8c4da58c9ee1d0707aa809d3d3b54f372
+ last_write_checksum: sha1:c2c27a0591e9de3995858a6e91f0e6358036f0ed
+ pristine_git_object: 533bb7464eb384876aba0a0f3c19bcd5382e1cb9
docs/operations/searchsurface.mdx:
id: 2d463024ea29
last_write_checksum: sha1:f612f65bd78b46bd424a0bbbbfb6260331738acc
@@ -10820,8 +10828,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:5329d9a8a9a1686c5eb37209f0582690781c0c22
- pristine_git_object: a66006a71e2412308f21e53e34b58acafd109be6
+ last_write_checksum: sha1:c5e1924981838851b3d839d32f63ec62d8996265
+ pristine_git_object: a33e8a445cb823382ff26f6e7ab63382970abdf6
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -10848,8 +10856,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:eff4f3a9bc877a572a413e3fa0384027fe0a034a
- pristine_git_object: 7250656ffea1731e53d7a49f5f153b4728c199ca
+ last_write_checksum: sha1:83dce9640df4a5aa9d044290ff5f65c7a0ff1e50
+ pristine_git_object: b01419c49ec9beca4349bc329325b37cd378374c
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:80cc0f39649445431cc2247ed0e0765438467766
@@ -10896,8 +10904,8 @@ trackedFiles:
pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:4515fb513d201ae92f0e96aad89bef200973aa80
- pristine_git_object: 212a3d7b1f97f526a713bb58742ac339e0eca83d
+ last_write_checksum: sha1:77d26d645188b87e6bca9deb1e375de58c598160
+ pristine_git_object: 94487b2834d8a4eb212455fec5b618042e9a1677
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c
@@ -11804,8 +11812,8 @@ trackedFiles:
pristine_git_object: 2ccba8386486b7a730816a9829b01754935a2e96
src/openrouter/components/chatusage.py:
id: f224a054bf45
- last_write_checksum: sha1:ea708aa417bad1c480ef113ec9c4491f1cdfcf44
- pristine_git_object: 4fd2be35dd11a5c81fcc575f766ae23cbdc4e78e
+ last_write_checksum: sha1:a16d2ff72e087e940ca5eeef75844baa7e9ca1a1
+ pristine_git_object: 9df54c7862f45164e9093affcd8af5a2850cf7aa
src/openrouter/components/chatusermessage.py:
id: 7777191e729a
last_write_checksum: sha1:6e9d3d1a827832b947bbb688a8f78f43aaaa9f81
@@ -12180,8 +12188,12 @@ trackedFiles:
pristine_git_object: 8a4e94425724c374a040ea028d0933db39ec1451
src/openrouter/components/deferredtoolscontrol.py:
id: b8b6ceef6f86
- last_write_checksum: sha1:a0037788a6737210bec53e6f67046d5eb8ce72f2
- pristine_git_object: 53c2c277462ed9b10ff68432790f1e654b47599b
+ last_write_checksum: sha1:5e39422e677b596848df4fadf4b32f80d554cab7
+ pristine_git_object: cef37bad7a45c3731eeca91832fa4f867c885825
+ src/openrouter/components/deferredtoolsdetails.py:
+ id: 044f0e33803d
+ last_write_checksum: sha1:2f8fcc43fc779a0cb9621149875a5e7bbfa5e6dc
+ pristine_git_object: 1cc2be0d154e3487e2f7b33b6cf3baa652f21e5b
src/openrouter/components/deferredtoolssearchstrategy.py:
id: 6bd66af4513f
last_write_checksum: sha1:fa3e06da0ca4390085a58f5ded26a64ebe157fff
@@ -12724,8 +12736,8 @@ trackedFiles:
pristine_git_object: f499cbbb546232f5cfbfe2c44fb41aefb306c87f
src/openrouter/components/inputs_union.py:
id: 17d6239cb6a7
- last_write_checksum: sha1:a5065a0dbdecb23a269ca4e60ca0ce0b0a210b18
- pristine_git_object: a2efac9eee07c47fd1d7db56dd24b27c62b816d4
+ last_write_checksum: sha1:dfe49f1e6c19162682f6fa841ff6d26081a13a21
+ pristine_git_object: bea147ee65f20c44bae5de0c758e7f2959ac8b49
src/openrouter/components/inputtext.py:
id: a995ae96be99
last_write_checksum: sha1:94c720a449e0d5a3f23ee7195f648422f61ac114
@@ -13168,8 +13180,8 @@ trackedFiles:
pristine_git_object: 08d990d8cc07b7928158fc55784cd9d613f4c58b
src/openrouter/components/openresponsesresult.py:
id: 78f7e33b19e6
- last_write_checksum: sha1:efefeab1914ae1f1d978084bbd1f01f6844dc463
- pristine_git_object: 703b72543c0783ae1d97a7fab4a7fc45474509ce
+ last_write_checksum: sha1:4b96f26ba96c33ae35aaa48a0c74616d93dd8d1f
+ pristine_git_object: d5ffb60091faae032e6d20c5696c4f57314590e0
src/openrouter/components/openrouterfile.py:
id: df1961bcb130
last_write_checksum: sha1:1a9a1b1e640f4d0ef78ce0caa160b5ab342f02cc
@@ -13340,8 +13352,8 @@ trackedFiles:
pristine_git_object: 616b0f5112e106777b4c096aeea6fef58ff32020
src/openrouter/components/outputitems.py:
id: 90f107de3116
- last_write_checksum: sha1:b5b931651d18454e9eddc807f9226debf70befdb
- pristine_git_object: 53f3d7f01df67fe89520ccae6e5e232a35ff338c
+ last_write_checksum: sha1:8e0e487161f75e4d205f490f28520fa2f9a16867
+ pristine_git_object: c4933ca3bf16935f1defe8ab2ac29cd5e4448310
src/openrouter/components/outputitemwebsearchcall.py:
id: bac8732aecb9
last_write_checksum: sha1:00d5b67226d6ff2c6a5497e6e01c764aeede496e
@@ -13404,8 +13416,8 @@ trackedFiles:
pristine_git_object: d5a5c820aff0971a68a725af296d68d8d3891992
src/openrouter/components/outputtoolsearchservertoolitem.py:
id: fb4ec737039d
- last_write_checksum: sha1:18ad18555adb74558726426d34dfa28f3c01769a
- pristine_git_object: 69f1f522ddee5316f9540e77ec36a1cd7340ab54
+ last_write_checksum: sha1:26f3a6e53d940ea78b3317e86a1e4da6eb1a63e0
+ pristine_git_object: b1cd35a559ceebe4b5b6d9f85915bb311fca343c
src/openrouter/components/outputwebfetchservertoolitem.py:
id: 2b12eb287cdf
last_write_checksum: sha1:60ec6ef59d691699c092120ea7dffed824197872
@@ -15100,8 +15112,8 @@ trackedFiles:
pristine_git_object: 6912194b6639fd1fbcd56b359c52f78857955954
src/openrouter/operations/listorganizationmembers.py:
id: d40a3e0e2b38
- last_write_checksum: sha1:95091a5194c0df932a15898831dea3738973ab2b
- pristine_git_object: f8ab3cfb4b38110dd4c64da3595e9e1f8d367f2f
+ last_write_checksum: sha1:f00056f68a32cdd602e362e4180c8344daa4bb41
+ pristine_git_object: bab4420d737b66ae01eb72c70892ec4b2b4cfea8
src/openrouter/operations/listpresets.py:
id: ecdc7097aab7
last_write_checksum: sha1:4b209724a3bf1627ca12250d165806bed44fb8ac
@@ -19960,4 +19972,4 @@ examples:
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
examplesVersion: 1.0.2
-releaseNotes: "## Python SDK Changes:\n* `open_router.batch.create_batches()`: `response.results[].response.body.union(OpenResponsesResult)` **Changed**\n* `open_router.batch.get_batches()`: `response.results[].response.body.union(OpenResponsesResult)` **Changed**\n* `open_router.presets.create_presets_responses()`: \n * `request.input.union(Array<>)[].union(CompactionTriggerItem)` **Added**\n"
+releaseNotes: "## Python SDK Changes:\n* `open_router.batch.create_batches()`: `response.results[].response.body.union(OpenResponsesResult)` **Changed**\n* `open_router.batch.get_batches()`: `response.results[].response.body.union(OpenResponsesResult)` **Changed**\n* `open_router.organization.list_members()`: `response.data[].role.enum(org:viewer)` **Added**\n* `open_router.presets.create_presets_chat_completions()`: \n * `request.deferred_tools.profile.enum(universal)` **Added**\n* `open_router.presets.create_presets_messages()`: \n * `request.deferred_tools.profile.enum(universal)` **Added**\n* `open_router.presets.create_presets_responses()`: `request` **Changed**\n"
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 3dbe76e1..fc03d110 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -37,7 +37,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.3.123
+ version: 1.3.124
additionalDependencies:
dev:
pytest: '>=8.3'
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 7a15488c..700ccf02 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -8743,6 +8743,8 @@ components:
- 'null'
cost_details:
$ref: '#/components/schemas/CostDetails'
+ deferred_tools_details:
+ $ref: '#/components/schemas/DeferredToolsDetails'
is_byok:
description: 'Whether a request was made using a Bring Your Own Key configuration'
type: 'boolean'
@@ -11530,10 +11532,12 @@ components:
validation: 'runtime'
properties:
profile:
- description: 'Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model.'
+ description: 'Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation.'
enum:
- 'portable'
+ - 'universal'
type: 'string'
+ x-speakeasy-unknown-values: allow
protocol:
enum:
- 'v1'
@@ -11551,6 +11555,34 @@ components:
- 'validation'
- 'search'
type: 'object'
+ DeferredToolsDetails:
+ description: 'Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call.'
+ example:
+ completion_tokens: 180
+ prompt_tokens: 2400
+ total_tokens: 2580
+ turns: 2
+ properties:
+ completion_tokens:
+ description: 'Completion tokens summed over every upstream call'
+ type: 'integer'
+ prompt_tokens:
+ description: 'Prompt tokens summed over every upstream call'
+ type: 'integer'
+ total_tokens:
+ description: 'Sum of the above two fields'
+ type: 'integer'
+ turns:
+ description: 'Upstream model calls the run made'
+ exclusiveMinimum: true
+ minimum: 0
+ type: 'integer'
+ required:
+ - 'turns'
+ - 'prompt_tokens'
+ - 'completion_tokens'
+ - 'total_tokens'
+ type: 'object'
DeferredToolsSearchStrategy:
description: 'Router-local regex/BM25 or caller-owned custom search.'
discriminator:
@@ -18994,6 +19026,28 @@ components:
- 'null'
cost_details:
$ref: '#/components/schemas/CostDetails'
+ deferred_tools_details:
+ properties:
+ completion_tokens:
+ description: 'Completion tokens summed over every upstream call'
+ type: 'integer'
+ prompt_tokens:
+ description: 'Prompt tokens summed over every upstream call'
+ type: 'integer'
+ total_tokens:
+ description: 'Sum of the above two fields'
+ type: 'integer'
+ turns:
+ description: 'Upstream model calls the run made'
+ exclusiveMinimum: true
+ minimum: 0
+ type: 'integer'
+ required:
+ - 'turns'
+ - 'prompt_tokens'
+ - 'completion_tokens'
+ - 'total_tokens'
+ type: 'object'
is_byok:
type: 'boolean'
iterations:
@@ -26178,10 +26232,32 @@ components:
status: 'completed'
type: 'openrouter:tool_search'
properties:
+ arguments:
+ description: 'The JSON arguments of the model call, verbatim. Replaying the item reuses them.'
+ example: '{"query":"weather tools"}'
+ type: 'string'
+ call_id:
+ description: 'The ID of the model call that ran the search. Replaying the item reuses it.'
+ example: 'call_search_1'
+ type: 'string'
+ catalog_index:
+ description: 'The deferred-tool index the router showed the model with a pre-search, listing tool sources and names. Replaying the item shows the same index.'
+ example: "Deferred tools, found with tool_search and called with tool_exec:\nSources: mcp__sentry (12)."
+ type: 'string'
error:
description: 'The error message when the tool call failed before producing a result. Set together with `status: ''failed''`; absent on a successful call.'
example: 'Tool execution failed'
type: 'string'
+ format:
+ description: 'How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result.'
+ enum:
+ - 'compact'
+ example: 'compact'
+ type: 'string'
+ hint:
+ description: 'The guidance the model got when the search matched no tools.'
+ example: 'No tools matched. Search again with other keywords, or load tools by exact name with "select:Name1,Name2".'
+ type: 'string'
id:
type: 'string'
matches:
@@ -26204,6 +26280,14 @@ components:
type: 'string'
status:
$ref: '#/components/schemas/FailableToolCallStatus'
+ turn_call_ids:
+ description: 'The IDs of every tool call in the model response that ran the search, in order. Replaying the item keeps those calls in one turn.'
+ example:
+ - 'call_search_1'
+ - 'call_exec_1'
+ items:
+ type: 'string'
+ type: 'array'
type:
enum:
- 'openrouter:tool_search'
@@ -34603,6 +34687,8 @@ components:
- 'upstream_inference_input_cost'
- 'upstream_inference_output_cost'
type: 'object'
+ deferred_tools_details:
+ $ref: '#/components/schemas/DeferredToolsDetails'
is_byok:
description: 'Whether a request was made using a Bring Your Own Key configuration'
type: 'boolean'
@@ -48349,10 +48435,11 @@ paths:
- 'string'
- 'null'
role:
- description: 'Role of the member in the organization'
+ description: 'Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces.'
enum:
- 'org:admin'
- 'org:member'
+ - 'org:viewer'
example: 'org:member'
type: 'string'
x-speakeasy-unknown-values: allow
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 048c6480..90f9915e 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,8 +2,8 @@ speakeasyVersion: 1.803.2
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:48d683ebca808ecf2a33d82e720da6a0e4c4c8bd9f403e4ae7218eb52a5cc4a5
- sourceBlobDigest: sha256:52a6bbab3c7b34eed54c1028f4467443bc9f24b24181ee7d0ac542caca5ca126
+ sourceRevisionDigest: sha256:b0702bea14c14c62d23f2a99482e4f39b9934e5091fe1ad463128671abfb08e1
+ sourceBlobDigest: sha256:1497f72360880691a966e318272e68b27d573cc4ed89f0a4a2b1ed692dcf6e25
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:48d683ebca808ecf2a33d82e720da6a0e4c4c8bd9f403e4ae7218eb52a5cc4a5
- sourceBlobDigest: sha256:52a6bbab3c7b34eed54c1028f4467443bc9f24b24181ee7d0ac542caca5ca126
+ sourceRevisionDigest: sha256:b0702bea14c14c62d23f2a99482e4f39b9934e5091fe1ad463128671abfb08e1
+ sourceBlobDigest: sha256:1497f72360880691a966e318272e68b27d573cc4ed89f0a4a2b1ed692dcf6e25
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:cd248b5bf76d621f943dd3de7dbd3cefab3ad776e174585b02b40bcb222cd89d
+ codeSamplesRevisionDigest: sha256:1b2625a1c2ec06a271fa89696cd45cbd537cddb04f2d5ccce4a6ab3ac6d24418
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.803.2
diff --git a/RELEASES.md b/RELEASES.md
index 0d41b58c..0baae360 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3999,4 +3999,14 @@ Based on:
### Generated
- [python v1.3.123] .
### Releases
-- [PyPI v1.3.123] https://pypi.org/project/openrouter/1.3.123 - .
\ No newline at end of file
+- [PyPI v1.3.123] https://pypi.org/project/openrouter/1.3.123 - .
+
+## 2026-11-05 01:49:48
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.803.2 (2.950.13) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.3.124] .
+### Releases
+- [PyPI v1.3.124] https://pypi.org/project/openrouter/1.3.124 - .
\ No newline at end of file
diff --git a/docs/components/chatusage.mdx b/docs/components/chatusage.mdx
index 2bb1e324..2f9b8133 100644
--- a/docs/components/chatusage.mdx
+++ b/docs/components/chatusage.mdx
@@ -7,14 +7,15 @@ Token usage statistics
## Fields
-| Field | Type | Required | Description | Example |
-| ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
-| `completion_tokens` | *int* | ✔️ | Number of tokens in the completion | |
-| `completion_tokens_details` | [OptionalNullable[components.ChatUsageCompletionTokensDetails]](../components/chatusagecompletiontokensdetails.mdx) | ➖ | Detailed completion token usage | |
-| `cost` | *OptionalNullable[float]* | ➖ | Cost of the completion | |
-| `cost_details` | [OptionalNullable[components.CostDetails]](../components/costdetails.mdx) | ➖ | Breakdown of upstream inference costs | \{
"upstream_inference_completions_cost": 0.0004,
"upstream_inference_cost": null,
"upstream_inference_prompt_cost": 0.0008
} |
-| `is_byok` | *Optional[bool]* | ➖ | Whether a request was made using a Bring Your Own Key configuration | |
-| `prompt_tokens` | *int* | ✔️ | Number of tokens in the prompt | |
-| `prompt_tokens_details` | [OptionalNullable[components.ChatUsagePromptTokensDetails]](../components/chatusageprompttokensdetails.mdx) | ➖ | Detailed prompt token usage | |
-| `server_tool_use_details` | [OptionalNullable[components.ServerToolUseDetails]](../components/servertoolusedetails.mdx) | ➖ | Usage for server-side tool execution (e.g., web search) | \{
"tool_calls_executed": 2,
"tool_calls_requested": 2,
"web_search_requests": 2
} |
-| `total_tokens` | *int* | ✔️ | Total number of tokens | |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
+| `completion_tokens` | *int* | ✔️ | Number of tokens in the completion | |
+| `completion_tokens_details` | [OptionalNullable[components.ChatUsageCompletionTokensDetails]](../components/chatusagecompletiontokensdetails.mdx) | ➖ | Detailed completion token usage | |
+| `cost` | *OptionalNullable[float]* | ➖ | Cost of the completion | |
+| `cost_details` | [OptionalNullable[components.CostDetails]](../components/costdetails.mdx) | ➖ | Breakdown of upstream inference costs | \{
"upstream_inference_completions_cost": 0.0004,
"upstream_inference_cost": null,
"upstream_inference_prompt_cost": 0.0008
} |
+| `deferred_tools_details` | [Optional[components.DeferredToolsDetails]](../components/deferredtoolsdetails.mdx) | ➖ | Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call. | \{
"completion_tokens": 180,
"prompt_tokens": 2400,
"total_tokens": 2580,
"turns": 2
} |
+| `is_byok` | *Optional[bool]* | ➖ | Whether a request was made using a Bring Your Own Key configuration | |
+| `prompt_tokens` | *int* | ✔️ | Number of tokens in the prompt | |
+| `prompt_tokens_details` | [OptionalNullable[components.ChatUsagePromptTokensDetails]](../components/chatusageprompttokensdetails.mdx) | ➖ | Detailed prompt token usage | |
+| `server_tool_use_details` | [OptionalNullable[components.ServerToolUseDetails]](../components/servertoolusedetails.mdx) | ➖ | Usage for server-side tool execution (e.g., web search) | \{
"tool_calls_executed": 2,
"tool_calls_requested": 2,
"web_search_requests": 2
} |
+| `total_tokens` | *int* | ✔️ | Total number of tokens | |
\ No newline at end of file
diff --git a/docs/components/deferredtoolscontrol.mdx b/docs/components/deferredtoolscontrol.mdx
index ebb8bfa5..c226e1a8 100644
--- a/docs/components/deferredtoolscontrol.mdx
+++ b/docs/components/deferredtoolscontrol.mdx
@@ -7,9 +7,9 @@ Opt-in versioned router-level deferred-tool protocol. Replay assistant reasoning
## Fields
-| Field | Type | Required | Description | Example |
-| -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `profile` | [components.Profile](../components/profile.mdx) | ✔️ | Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model. | |
-| `protocol` | [components.Protocol](../components/protocol.mdx) | ✔️ | N/A | |
-| `search` | [components.DeferredToolsSearchStrategy](../components/deferredtoolssearchstrategy.mdx) | ✔️ | Router-local regex/BM25 or caller-owned custom search. | \{
"max_results": 5,
"type": "bm25"
} |
-| `validation` | [components.Validation](../components/validation.mdx) | ✔️ | Where tool-call arguments are checked against the original schema. Only `runtime` (in OpenRouter) is available in this release. | |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `profile` | [components.Profile](../components/profile.mdx) | ✔️ | Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation. | |
+| `protocol` | [components.Protocol](../components/protocol.mdx) | ✔️ | N/A | |
+| `search` | [components.DeferredToolsSearchStrategy](../components/deferredtoolssearchstrategy.mdx) | ✔️ | Router-local regex/BM25 or caller-owned custom search. | \{
"max_results": 5,
"type": "bm25"
} |
+| `validation` | [components.Validation](../components/validation.mdx) | ✔️ | Where tool-call arguments are checked against the original schema. Only `runtime` (in OpenRouter) is available in this release. | |
\ No newline at end of file
diff --git a/docs/components/deferredtoolsdetails.mdx b/docs/components/deferredtoolsdetails.mdx
new file mode 100644
index 00000000..2a290bbd
--- /dev/null
+++ b/docs/components/deferredtoolsdetails.mdx
@@ -0,0 +1,15 @@
+---
+title: "DeferredToolsDetails"
+---
+
+Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call.
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------- |
+| `completion_tokens` | *int* | ✔️ | Completion tokens summed over every upstream call |
+| `prompt_tokens` | *int* | ✔️ | Prompt tokens summed over every upstream call |
+| `total_tokens` | *int* | ✔️ | Sum of the above two fields |
+| `turns` | *int* | ✔️ | Upstream model calls the run made |
\ No newline at end of file
diff --git a/docs/components/outputtoolsearchservertoolitem.mdx b/docs/components/outputtoolsearchservertoolitem.mdx
index 29b9d620..c49ae6e8 100644
--- a/docs/components/outputtoolsearchservertoolitem.mdx
+++ b/docs/components/outputtoolsearchservertoolitem.mdx
@@ -7,11 +7,17 @@ An openrouter:tool_search server tool output item
## Fields
-| Field | Type | Required | Description | Example |
-| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
-| `error` | *Optional[str]* | ➖ | The error message when the tool call failed before producing a result. Set together with `status: 'failed'`; absent on a successful call. | Tool execution failed |
-| `id` | *Optional[str]* | ➖ | N/A | |
-| `matches` | List[[components.Match](../components/match.mdx)] | ➖ | N/A | |
-| `query` | *Optional[str]* | ➖ | N/A | |
-| `status` | [components.FailableToolCallStatus](../components/failabletoolcallstatus.mdx) | ✔️ | N/A | completed |
-| `type` | [components.OutputToolSearchServerToolItemType](../components/outputtoolsearchservertoolitemtype.mdx) | ✔️ | N/A | |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `arguments` | *Optional[str]* | ➖ | The JSON arguments of the model call, verbatim. Replaying the item reuses them. | \{"query":"weather tools"} |
+| `call_id` | *Optional[str]* | ➖ | The ID of the model call that ran the search. Replaying the item reuses it. | call_search_1 |
+| `catalog_index` | *Optional[str]* | ➖ | The deferred-tool index the router showed the model with a pre-search, listing tool sources and names. Replaying the item shows the same index. | Deferred tools, found with tool_search and called with tool_exec:
Sources: mcp__sentry (12). |
+| `error` | *Optional[str]* | ➖ | The error message when the tool call failed before producing a result. Set together with `status: 'failed'`; absent on a successful call. | Tool execution failed |
+| `format_` | [Optional[components.OutputToolSearchServerToolItemFormat]](../components/outputtoolsearchservertoolitemformat.mdx) | ➖ | How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result. | compact |
+| `hint` | *Optional[str]* | ➖ | The guidance the model got when the search matched no tools. | No tools matched. Search again with other keywords, or load tools by exact name with "select:Name1,Name2". |
+| `id` | *Optional[str]* | ➖ | N/A | |
+| `matches` | List[[components.Match](../components/match.mdx)] | ➖ | N/A | |
+| `query` | *Optional[str]* | ➖ | N/A | |
+| `status` | [components.FailableToolCallStatus](../components/failabletoolcallstatus.mdx) | ✔️ | N/A | completed |
+| `turn_call_ids` | List[*str*] | ➖ | The IDs of every tool call in the model response that ran the search, in order. Replaying the item keeps those calls in one turn. | [
"call_search_1",
"call_exec_1"
] |
+| `type` | [components.OutputToolSearchServerToolItemType](../components/outputtoolsearchservertoolitemtype.mdx) | ✔️ | N/A | |
\ No newline at end of file
diff --git a/docs/components/outputtoolsearchservertoolitemformat.mdx b/docs/components/outputtoolsearchservertoolitemformat.mdx
new file mode 100644
index 00000000..7d64dcb2
--- /dev/null
+++ b/docs/components/outputtoolsearchservertoolitemformat.mdx
@@ -0,0 +1,17 @@
+---
+title: "OutputToolSearchServerToolItemFormat"
+---
+
+How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result.
+
+## Example Usage
+
+```python
+from openrouter.components import OutputToolSearchServerToolItemFormat
+value: OutputToolSearchServerToolItemFormat = "compact"
+```
+
+
+## Values
+
+- `"compact"`
diff --git a/docs/components/profile.mdx b/docs/components/profile.mdx
index b59688b7..f9eb1da6 100644
--- a/docs/components/profile.mdx
+++ b/docs/components/profile.mdx
@@ -2,16 +2,21 @@
title: "Profile"
---
-Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model.
+Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation.
## Example Usage
```python
from openrouter.components import Profile
+
+# Open enum: unrecognized values are captured as UnrecognizedStr
value: Profile = "portable"
```
## Values
+This is an open enum. Unrecognized values will not fail type checks.
+
- `"portable"`
+- `"universal"`
diff --git a/docs/components/usage.mdx b/docs/components/usage.mdx
index 10680b42..f70fe484 100644
--- a/docs/components/usage.mdx
+++ b/docs/components/usage.mdx
@@ -4,14 +4,15 @@ title: "Usage"
## Fields
-| Field | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
-| `input_tokens` | *int* | ✔️ | N/A | |
-| `input_tokens_details` | [components.InputTokensDetails](../components/inputtokensdetails.mdx) | ✔️ | N/A | |
-| `output_tokens` | *int* | ✔️ | N/A | |
-| `output_tokens_details` | [components.OutputTokensDetails](../components/outputtokensdetails.mdx) | ✔️ | N/A | |
-| `total_tokens` | *int* | ✔️ | N/A | |
-| `cost` | *OptionalNullable[float]* | ➖ | Cost of the completion | |
-| `cost_details` | [Optional[components.UsageCostDetails]](../components/usagecostdetails.mdx) | ➖ | N/A | |
-| `is_byok` | *Optional[bool]* | ➖ | Whether a request was made using a Bring Your Own Key configuration | |
-| `server_tool_use_details` | [OptionalNullable[components.ServerToolUseDetails]](../components/servertoolusedetails.mdx) | ➖ | Usage for server-side tool execution (e.g., web search) | \{
"tool_calls_executed": 2,
"tool_calls_requested": 2,
"web_search_requests": 2
} |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
+| `input_tokens` | *int* | ✔️ | N/A | |
+| `input_tokens_details` | [components.InputTokensDetails](../components/inputtokensdetails.mdx) | ✔️ | N/A | |
+| `output_tokens` | *int* | ✔️ | N/A | |
+| `output_tokens_details` | [components.OutputTokensDetails](../components/outputtokensdetails.mdx) | ✔️ | N/A | |
+| `total_tokens` | *int* | ✔️ | N/A | |
+| `cost` | *OptionalNullable[float]* | ➖ | Cost of the completion | |
+| `cost_details` | [Optional[components.UsageCostDetails]](../components/usagecostdetails.mdx) | ➖ | N/A | |
+| `deferred_tools_details` | [Optional[components.DeferredToolsDetails]](../components/deferredtoolsdetails.mdx) | ➖ | Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call. | \{
"completion_tokens": 180,
"prompt_tokens": 2400,
"total_tokens": 2580,
"turns": 2
} |
+| `is_byok` | *Optional[bool]* | ➖ | Whether a request was made using a Bring Your Own Key configuration | |
+| `server_tool_use_details` | [OptionalNullable[components.ServerToolUseDetails]](../components/servertoolusedetails.mdx) | ➖ | Usage for server-side tool execution (e.g., web search) | \{
"tool_calls_executed": 2,
"tool_calls_requested": 2,
"web_search_requests": 2
} |
\ No newline at end of file
diff --git a/docs/operations/listorganizationmembersdata.mdx b/docs/operations/listorganizationmembersdata.mdx
index fc485e85..f65b92ed 100644
--- a/docs/operations/listorganizationmembersdata.mdx
+++ b/docs/operations/listorganizationmembersdata.mdx
@@ -4,10 +4,10 @@ title: "ListOrganizationMembersData"
## Fields
-| Field | Type | Required | Description | Example |
-| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
-| `email` | *str* | ✔️ | Email address of the member | jane.doe@example.com |
-| `first_name` | *Nullable[str]* | ✔️ | First name of the member | Jane |
-| `id` | *str* | ✔️ | User ID of the organization member | user_2dHFtVWx2n56w6HkM0000000000 |
-| `last_name` | *Nullable[str]* | ✔️ | Last name of the member | Doe |
-| `role` | [operations.Role](../operations/role.mdx) | ✔️ | Role of the member in the organization | org:member |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `email` | *str* | ✔️ | Email address of the member | jane.doe@example.com |
+| `first_name` | *Nullable[str]* | ✔️ | First name of the member | Jane |
+| `id` | *str* | ✔️ | User ID of the organization member | user_2dHFtVWx2n56w6HkM0000000000 |
+| `last_name` | *Nullable[str]* | ✔️ | Last name of the member | Doe |
+| `role` | [operations.Role](../operations/role.mdx) | ✔️ | Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces. | org:member |
\ No newline at end of file
diff --git a/docs/operations/role.mdx b/docs/operations/role.mdx
index 9e1219b8..533bb746 100644
--- a/docs/operations/role.mdx
+++ b/docs/operations/role.mdx
@@ -2,7 +2,7 @@
title: "Role"
---
-Role of the member in the organization
+Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces.
## Example Usage
@@ -20,3 +20,4 @@ This is an open enum. Unrecognized values will not fail type checks.
- `"org:admin"`
- `"org:member"`
+- `"org:viewer"`
diff --git a/pyproject.toml b/pyproject.toml
index a66006a7..a33e8a44 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.3.123"
+version = "1.3.124"
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 7250656f..b01419c4 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "1.3.123"
+__version__: str = "1.3.124"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.950.13"
-__user_agent__: str = "speakeasy-sdk/python 1.3.123 2.950.13 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.3.124 2.950.13 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 212a3d7b..94487b28 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -1755,6 +1755,10 @@
Protocol,
Validation,
)
+ from .deferredtoolsdetails import (
+ DeferredToolsDetails,
+ DeferredToolsDetailsTypedDict,
+ )
from .deferredtoolssearchstrategy import (
DeferredToolsSearchStrategy,
DeferredToolsSearchStrategyTypedDict,
@@ -3613,6 +3617,7 @@
Match,
MatchTypedDict,
OutputToolSearchServerToolItem,
+ OutputToolSearchServerToolItemFormat,
OutputToolSearchServerToolItemType,
OutputToolSearchServerToolItemTypedDict,
)
@@ -5927,6 +5932,8 @@
"DeferredRegexSearchTypedDict",
"DeferredToolsControl",
"DeferredToolsControlTypedDict",
+ "DeferredToolsDetails",
+ "DeferredToolsDetailsTypedDict",
"DeferredToolsSearchStrategy",
"DeferredToolsSearchStrategyTypedDict",
"DeleteBYOKKeyResponse",
@@ -7254,6 +7261,7 @@
"OutputToolSearchCallItemType",
"OutputToolSearchCallItemTypedDict",
"OutputToolSearchServerToolItem",
+ "OutputToolSearchServerToolItemFormat",
"OutputToolSearchServerToolItemType",
"OutputToolSearchServerToolItemTypedDict",
"OutputWebFetchServerToolItem",
@@ -9486,6 +9494,8 @@
"Profile": ".deferredtoolscontrol",
"Protocol": ".deferredtoolscontrol",
"Validation": ".deferredtoolscontrol",
+ "DeferredToolsDetails": ".deferredtoolsdetails",
+ "DeferredToolsDetailsTypedDict": ".deferredtoolsdetails",
"DeferredToolsSearchStrategy": ".deferredtoolssearchstrategy",
"DeferredToolsSearchStrategyTypedDict": ".deferredtoolssearchstrategy",
"DeleteBYOKKeyResponse": ".deletebyokkeyresponse",
@@ -10914,6 +10924,7 @@
"Match": ".outputtoolsearchservertoolitem",
"MatchTypedDict": ".outputtoolsearchservertoolitem",
"OutputToolSearchServerToolItem": ".outputtoolsearchservertoolitem",
+ "OutputToolSearchServerToolItemFormat": ".outputtoolsearchservertoolitem",
"OutputToolSearchServerToolItemType": ".outputtoolsearchservertoolitem",
"OutputToolSearchServerToolItemTypedDict": ".outputtoolsearchservertoolitem",
"OutputWebFetchServerToolItem": ".outputwebfetchservertoolitem",
diff --git a/src/openrouter/components/chatusage.py b/src/openrouter/components/chatusage.py
index 4fd2be35..9df54c78 100644
--- a/src/openrouter/components/chatusage.py
+++ b/src/openrouter/components/chatusage.py
@@ -2,6 +2,7 @@
from __future__ import annotations
from .costdetails import CostDetails, CostDetailsTypedDict
+from .deferredtoolsdetails import DeferredToolsDetails, DeferredToolsDetailsTypedDict
from .servertoolusedetails import ServerToolUseDetails, ServerToolUseDetailsTypedDict
from openrouter.types import (
BaseModel,
@@ -147,6 +148,8 @@ class ChatUsageTypedDict(TypedDict):
r"""Cost of the completion"""
cost_details: NotRequired[Nullable[CostDetailsTypedDict]]
r"""Breakdown of upstream inference costs"""
+ deferred_tools_details: NotRequired[DeferredToolsDetailsTypedDict]
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
is_byok: NotRequired[bool]
r"""Whether a request was made using a Bring Your Own Key configuration"""
prompt_tokens_details: NotRequired[Nullable[ChatUsagePromptTokensDetailsTypedDict]]
@@ -178,6 +181,9 @@ class ChatUsage(BaseModel):
cost_details: OptionalNullable[CostDetails] = UNSET
r"""Breakdown of upstream inference costs"""
+ deferred_tools_details: Optional[DeferredToolsDetails] = None
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
+
is_byok: Optional[bool] = None
r"""Whether a request was made using a Bring Your Own Key configuration"""
@@ -194,6 +200,7 @@ def serialize_model(self, handler):
"completion_tokens_details",
"cost",
"cost_details",
+ "deferred_tools_details",
"is_byok",
"prompt_tokens_details",
"server_tool_use_details",
diff --git a/src/openrouter/components/deferredtoolscontrol.py b/src/openrouter/components/deferredtoolscontrol.py
index 53c2c277..cef37bad 100644
--- a/src/openrouter/components/deferredtoolscontrol.py
+++ b/src/openrouter/components/deferredtoolscontrol.py
@@ -5,13 +5,19 @@
DeferredToolsSearchStrategy,
DeferredToolsSearchStrategyTypedDict,
)
-from openrouter.types import BaseModel
-from typing import Literal
+from openrouter.types import BaseModel, UnrecognizedStr
+from typing import Literal, Union
from typing_extensions import TypedDict
-Profile = Literal["portable",]
-r"""Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model."""
+Profile = Union[
+ Literal[
+ "portable",
+ "universal",
+ ],
+ UnrecognizedStr,
+]
+r"""Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation."""
Protocol = Literal["v1",]
@@ -25,7 +31,7 @@ class DeferredToolsControlTypedDict(TypedDict):
r"""Opt-in versioned router-level deferred-tool protocol. Replay assistant reasoning unchanged on continuation; keep the catalog unchanged."""
profile: Profile
- r"""Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model."""
+ r"""Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation."""
protocol: Protocol
search: DeferredToolsSearchStrategyTypedDict
r"""Router-local regex/BM25 or caller-owned custom search."""
@@ -37,7 +43,7 @@ class DeferredToolsControl(BaseModel):
r"""Opt-in versioned router-level deferred-tool protocol. Replay assistant reasoning unchanged on continuation; keep the catalog unchanged."""
profile: Profile
- r"""Loading profile. Only `portable` is available in this release: OpenRouter serves deferral with router-built search and call wrappers on any model."""
+ r"""Loading profile. `portable` serves the `defer_loading` tools with router-built search and call wrappers on any model and keeps the catalog fixed. `universal` defers every wrappable tool behind the same wrappers so the provider-facing tool list never changes, and rebuilds the catalog from each request so tools can be added or removed mid-conversation."""
protocol: Protocol
diff --git a/src/openrouter/components/deferredtoolsdetails.py b/src/openrouter/components/deferredtoolsdetails.py
new file mode 100644
index 00000000..1cc2be0d
--- /dev/null
+++ b/src/openrouter/components/deferredtoolsdetails.py
@@ -0,0 +1,34 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.types import BaseModel
+from typing_extensions import TypedDict
+
+
+class DeferredToolsDetailsTypedDict(TypedDict):
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
+
+ completion_tokens: int
+ r"""Completion tokens summed over every upstream call"""
+ prompt_tokens: int
+ r"""Prompt tokens summed over every upstream call"""
+ total_tokens: int
+ r"""Sum of the above two fields"""
+ turns: int
+ r"""Upstream model calls the run made"""
+
+
+class DeferredToolsDetails(BaseModel):
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
+
+ completion_tokens: int
+ r"""Completion tokens summed over every upstream call"""
+
+ prompt_tokens: int
+ r"""Prompt tokens summed over every upstream call"""
+
+ total_tokens: int
+ r"""Sum of the above two fields"""
+
+ turns: int
+ r"""Upstream model calls the run made"""
diff --git a/src/openrouter/components/inputs_union.py b/src/openrouter/components/inputs_union.py
index a2efac9e..bea147ee 100644
--- a/src/openrouter/components/inputs_union.py
+++ b/src/openrouter/components/inputs_union.py
@@ -414,26 +414,26 @@ def serialize_model(self, handler):
ToolSearchOutputItemTypedDict,
ToolSearchCallItemTypedDict,
InputsMessageTypedDict,
- OutputToolSearchServerToolItemTypedDict,
OutputComputerCallItemTypedDict,
AgentMessageItemTypedDict,
OutputCodeInterpreterCallItemTypedDict,
- ShellCallItemTypedDict,
McpCallItemTypedDict,
+ ShellCallItemTypedDict,
ReasoningItemTypedDict,
- OutputWebFetchServerToolItemTypedDict,
- OutputAdvisorServerToolItemTypedDict,
InputsReasoningTypedDict,
- CustomToolCallItemTypedDict,
+ OutputAdvisorServerToolItemTypedDict,
OutputCodeInterpreterServerToolItemTypedDict,
+ OutputWebFetchServerToolItemTypedDict,
+ CustomToolCallItemTypedDict,
+ OutputImageGenerationServerToolItemTypedDict,
OutputArmorBlockedItemTypedDict,
ShellCallOutputItemTypedDict,
- OutputImageGenerationServerToolItemTypedDict,
OutputFusionServerToolItemTypedDict,
OutputShellServerToolItemTypedDict,
OutputFilesServerToolItemTypedDict,
FunctionCallItemTypedDict,
OutputSubagentServerToolItemTypedDict,
+ OutputToolSearchServerToolItemTypedDict,
OutputBashServerToolItemTypedDict,
],
)
@@ -474,26 +474,26 @@ def serialize_model(self, handler):
ToolSearchOutputItem,
ToolSearchCallItem,
InputsMessage,
- OutputToolSearchServerToolItem,
OutputComputerCallItem,
AgentMessageItem,
OutputCodeInterpreterCallItem,
- ShellCallItem,
McpCallItem,
+ ShellCallItem,
ReasoningItem,
- OutputWebFetchServerToolItem,
- OutputAdvisorServerToolItem,
InputsReasoning,
- CustomToolCallItem,
+ OutputAdvisorServerToolItem,
OutputCodeInterpreterServerToolItem,
+ OutputWebFetchServerToolItem,
+ CustomToolCallItem,
+ OutputImageGenerationServerToolItem,
OutputArmorBlockedItem,
ShellCallOutputItem,
- OutputImageGenerationServerToolItem,
OutputFusionServerToolItem,
OutputShellServerToolItem,
OutputFilesServerToolItem,
FunctionCallItem,
OutputSubagentServerToolItem,
+ OutputToolSearchServerToolItem,
OutputBashServerToolItem,
],
)
diff --git a/src/openrouter/components/openresponsesresult.py b/src/openrouter/components/openresponsesresult.py
index 703b7254..d5ffb600 100644
--- a/src/openrouter/components/openresponsesresult.py
+++ b/src/openrouter/components/openresponsesresult.py
@@ -14,6 +14,7 @@
from .codexlocalshelltool import CodexLocalShellTool, CodexLocalShellToolTypedDict
from .computeruseservertool import ComputerUseServerTool, ComputerUseServerToolTypedDict
from .customtool import CustomTool, CustomToolTypedDict
+from .deferredtoolsdetails import DeferredToolsDetails, DeferredToolsDetailsTypedDict
from .filesearchservertool import FileSearchServerTool, FileSearchServerToolTypedDict
from .imagegenerationservertool import (
ImageGenerationServerTool,
@@ -339,6 +340,8 @@ class UsageTypedDict(TypedDict):
cost: NotRequired[Nullable[float]]
r"""Cost of the completion"""
cost_details: NotRequired[UsageCostDetailsTypedDict]
+ deferred_tools_details: NotRequired[DeferredToolsDetailsTypedDict]
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
is_byok: NotRequired[bool]
r"""Whether a request was made using a Bring Your Own Key configuration"""
server_tool_use_details: NotRequired[Nullable[ServerToolUseDetailsTypedDict]]
@@ -361,6 +364,9 @@ class Usage(BaseModel):
cost_details: Optional[UsageCostDetails] = None
+ deferred_tools_details: Optional[DeferredToolsDetails] = None
+ r"""Totals across every upstream model call of a deferred-tools run. The native usage fields report only the final call; cost covers every call."""
+
is_byok: Optional[bool] = None
r"""Whether a request was made using a Bring Your Own Key configuration"""
@@ -370,7 +376,13 @@ class Usage(BaseModel):
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(
- ["cost", "cost_details", "is_byok", "server_tool_use_details"]
+ [
+ "cost",
+ "cost_details",
+ "deferred_tools_details",
+ "is_byok",
+ "server_tool_use_details",
+ ]
)
nullable_fields = set(["cost", "server_tool_use_details"])
serialized = handler(self)
diff --git a/src/openrouter/components/outputitems.py b/src/openrouter/components/outputitems.py
index 53f3d7f0..c4933ca3 100644
--- a/src/openrouter/components/outputitems.py
+++ b/src/openrouter/components/outputitems.py
@@ -151,23 +151,23 @@
OutputMemoryServerToolItemTypedDict,
OutputComputerCallItemTypedDict,
OutputMessageItemTypedDict,
- OutputToolSearchServerToolItemTypedDict,
OutputShellCallItemTypedDict,
OutputCodeInterpreterCallItemTypedDict,
- OutputReasoningItemTypedDict,
+ OutputCodeInterpreterServerToolItemTypedDict,
OutputCustomToolCallItemTypedDict,
OutputWebFetchServerToolItemTypedDict,
- OutputCodeInterpreterServerToolItemTypedDict,
+ OutputReasoningItemTypedDict,
OutputAdvisorServerToolItemTypedDict,
- OutputShellCallOutputItemTypedDict,
OutputArmorBlockedItemTypedDict,
OutputImageGenerationServerToolItemTypedDict,
+ OutputShellCallOutputItemTypedDict,
OutputFusionServerToolItemTypedDict,
- OutputFilesServerToolItemTypedDict,
OutputShellServerToolItemTypedDict,
OutputFunctionCallItemTypedDict,
+ OutputFilesServerToolItemTypedDict,
OutputSubagentServerToolItemTypedDict,
OutputBashServerToolItemTypedDict,
+ OutputToolSearchServerToolItemTypedDict,
],
)
r"""An output item from the response"""
diff --git a/src/openrouter/components/outputtoolsearchservertoolitem.py b/src/openrouter/components/outputtoolsearchservertoolitem.py
index 69f1f522..b1cd35a5 100644
--- a/src/openrouter/components/outputtoolsearchservertoolitem.py
+++ b/src/openrouter/components/outputtoolsearchservertoolitem.py
@@ -3,9 +3,14 @@
from __future__ import annotations
from .failabletoolcallstatus import FailableToolCallStatus
from openrouter.types import BaseModel, UNSET_SENTINEL
+import pydantic
from pydantic import model_serializer
from typing import Any, Dict, List, Literal, Optional
-from typing_extensions import NotRequired, TypedDict
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+OutputToolSearchServerToolItemFormat = Literal["compact",]
+r"""How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result."""
class MatchTypedDict(TypedDict):
@@ -30,11 +35,23 @@ class OutputToolSearchServerToolItemTypedDict(TypedDict):
status: FailableToolCallStatus
type: OutputToolSearchServerToolItemType
+ arguments: NotRequired[str]
+ r"""The JSON arguments of the model call, verbatim. Replaying the item reuses them."""
+ call_id: NotRequired[str]
+ r"""The ID of the model call that ran the search. Replaying the item reuses it."""
+ catalog_index: NotRequired[str]
+ r"""The deferred-tool index the router showed the model with a pre-search, listing tool sources and names. Replaying the item shows the same index."""
error: NotRequired[str]
r"""The error message when the tool call failed before producing a result. Set together with `status: 'failed'`; absent on a successful call."""
+ format_: NotRequired[OutputToolSearchServerToolItemFormat]
+ r"""How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result."""
+ hint: NotRequired[str]
+ r"""The guidance the model got when the search matched no tools."""
id: NotRequired[str]
matches: NotRequired[List[MatchTypedDict]]
query: NotRequired[str]
+ turn_call_ids: NotRequired[List[str]]
+ r"""The IDs of every tool call in the model response that ran the search, in order. Replaying the item keeps those calls in one turn."""
class OutputToolSearchServerToolItem(BaseModel):
@@ -44,18 +61,51 @@ class OutputToolSearchServerToolItem(BaseModel):
type: OutputToolSearchServerToolItemType
+ arguments: Optional[str] = None
+ r"""The JSON arguments of the model call, verbatim. Replaying the item reuses them."""
+
+ call_id: Optional[str] = None
+ r"""The ID of the model call that ran the search. Replaying the item reuses it."""
+
+ catalog_index: Optional[str] = None
+ r"""The deferred-tool index the router showed the model with a pre-search, listing tool sources and names. Replaying the item shows the same index."""
+
error: Optional[str] = None
r"""The error message when the tool call failed before producing a result. Set together with `status: 'failed'`; absent on a successful call."""
+ format_: Annotated[
+ Optional[OutputToolSearchServerToolItemFormat], pydantic.Field(alias="format")
+ ] = None
+ r"""How the model saw the matches. `compact` means each tool by name, description, and input shape, plus a call example. Replaying the item renders the same result."""
+
+ hint: Optional[str] = None
+ r"""The guidance the model got when the search matched no tools."""
+
id: Optional[str] = None
matches: Optional[List[Match]] = None
query: Optional[str] = None
+ turn_call_ids: Optional[List[str]] = None
+ r"""The IDs of every tool call in the model response that ran the search, in order. Replaying the item keeps those calls in one turn."""
+
@model_serializer(mode="wrap")
def serialize_model(self, handler):
- optional_fields = set(["error", "id", "matches", "query"])
+ optional_fields = set(
+ [
+ "arguments",
+ "call_id",
+ "catalog_index",
+ "error",
+ "format",
+ "hint",
+ "id",
+ "matches",
+ "query",
+ "turn_call_ids",
+ ]
+ )
serialized = handler(self)
m = {}
@@ -68,3 +118,9 @@ def serialize_model(self, handler):
m[k] = val
return m
+
+
+try:
+ OutputToolSearchServerToolItem.model_rebuild()
+except NameError:
+ pass
diff --git a/src/openrouter/operations/listorganizationmembers.py b/src/openrouter/operations/listorganizationmembers.py
index f8ab3cfb..bab4420d 100644
--- a/src/openrouter/operations/listorganizationmembers.py
+++ b/src/openrouter/operations/listorganizationmembers.py
@@ -178,10 +178,11 @@ def serialize_model(self, handler):
Literal[
"org:admin",
"org:member",
+ "org:viewer",
],
UnrecognizedStr,
]
-r"""Role of the member in the organization"""
+r"""Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces."""
class ListOrganizationMembersDataTypedDict(TypedDict):
@@ -194,7 +195,7 @@ class ListOrganizationMembersDataTypedDict(TypedDict):
last_name: Nullable[str]
r"""Last name of the member"""
role: Role
- r"""Role of the member in the organization"""
+ r"""Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces."""
class ListOrganizationMembersData(BaseModel):
@@ -211,7 +212,7 @@ class ListOrganizationMembersData(BaseModel):
r"""Last name of the member"""
role: Role
- r"""Role of the member in the organization"""
+ r"""Role of the member in the organization. `org:viewer` is coming soon and not yet available. Once launched, it has read-only organization access: it can view organization settings, billing and workspaces but not change them. Workspace roles can still grant write access in specific workspaces."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
diff --git a/uv.lock b/uv.lock
index 1d11bc98..7c142354 100644
--- a/uv.lock
+++ b/uv.lock
@@ -231,7 +231,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.3.123"
+version = "1.3.124"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },