diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 9f63688e..c5c61772 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: 10cc3bd835df5bf3fce4fe2563a34256
+ docChecksum: e032e86ef04bdf8f15a28ac612f6d594
docVersion: 1.0.0
speakeasyVersion: 1.787.0
generationVersion: 2.914.0
- releaseVersion: 1.2.8
- configChecksum: 5aa38056cf49b40445697d3786c6310a
+ releaseVersion: 1.2.9
+ configChecksum: 841528c31258661e3e68f30fe63a47be
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: dce5049f-6fa8-49be-a5f5-bc657ee76aa9
- pristine_commit_hash: 7f8731cb0345e17e75f6ee2102f01698513004ce
- pristine_tree_hash: b9165056d686a979117bcf0e228ee3567ce2ffc4
+ generation_id: 7451add0-ef9a-4d11-9867-a9c87ba6c3f9
+ pristine_commit_hash: 291e61baec96227b527eaa4ac2e6d70beaa1f1ba
+ pristine_tree_hash: 6b28d150bd4c63b55c892b5e375607167a7b1a48
features:
python:
acceptHeaders: 3.0.0
@@ -2967,8 +2967,8 @@ trackedFiles:
pristine_git_object: 78a4f7f400f84c2e1f494530afa2066633443b9f
docs/components/internchatcompletionchunk.mdx:
id: 4f5dc2924625
- last_write_checksum: sha1:0f4f38f8d2f6b648929a1a4899aa14dcc397aac8
- pristine_git_object: 647b2b27bcb2772220838000da30d4adb8f0a1cd
+ last_write_checksum: sha1:7576fe0d255e706ec04cbfa93ad21536adc5dc4a
+ pristine_git_object: 9f35a80a9f2e3fc4d2d352e9d27ec973bf476f58
docs/components/internchatcompletionchunkobject.mdx:
id: 3a1962ac4886
last_write_checksum: sha1:9602771c3a5fc48b22adf67daeaf1387bbdfb501
@@ -3003,12 +3003,12 @@ trackedFiles:
pristine_git_object: 7b057bd6aebd0261f7f15ac2e6189414001d0d09
docs/components/internchaterror.mdx:
id: 64defb4bf787
- last_write_checksum: sha1:a6d4fb39f4cf2880b4eda8e6fa60bb6496b988f5
- pristine_git_object: ccdf070f589cf27dad47e6cd64e39d1e5729df51
+ last_write_checksum: sha1:c75fae440575a3f8a3c3846f291a7ecaa21cb693
+ pristine_git_object: 84af96295ce8f7b446014c6648618346a16687ee
docs/components/internchaterrormetadata.mdx:
id: e5a6cafc8cf1
- last_write_checksum: sha1:307a2328b3d1f48f939b2e0bf2d903680aa81ab3
- pristine_git_object: c9de8ffb2200f8283e669fcfe8b03d20cf6a2b44
+ last_write_checksum: sha1:54ea3296b6988d804548d70c9ce6cb32a617a4a2
+ pristine_git_object: 0e5c6b605420f764fdcabafde013eb56c5a5527a
docs/components/internchaterrormetadatareason.mdx:
id: e912c85957cc
last_write_checksum: sha1:f5c63a578391ef058999767b2fe00ac26861c8d8
@@ -3027,8 +3027,8 @@ trackedFiles:
pristine_git_object: 77b2e34176730645168f5953bca6c98134dc37e8
docs/components/internchatstreamerror.mdx:
id: d960f7518865
- last_write_checksum: sha1:2a6201fe3472169e67b734eeb7aa6dc7f887e603
- pristine_git_object: 48f3773bca2854d5657e918fdefb5e12d8ca4b53
+ last_write_checksum: sha1:93c6917119e7a9b36c8736c614a505ea86c8f7de
+ pristine_git_object: b19200571a678d1d83e140f5bd753930450b4a0c
docs/components/internchatstreamingresponse.mdx:
id: 5bcf4a593132
last_write_checksum: sha1:8c36128d1cdac2822bbb2c223dabd6b63f508a5c
@@ -3087,8 +3087,12 @@ trackedFiles:
pristine_git_object: 4a98d72416014765c3e6b38b7b5eae9cbc8e2f34
docs/components/internlifecycleerrorerror.mdx:
id: 501146f0d87d
- last_write_checksum: sha1:1b49f19b35c20245a088fc58825a9ee97d27c300
- pristine_git_object: c9eacd7d34fe43fbad032729e0dc9d130684ed72
+ last_write_checksum: sha1:044b3295aa55836ed6b018679d1e8d6558bd33ec
+ pristine_git_object: dc3a8f402833fa05fab1c530c48a149aa4b45114
+ docs/components/internlifecycleerrormetadata.mdx:
+ id: 86fa451a31a7
+ last_write_checksum: sha1:3176bc02e88e75c81a0be655309bad2d43b49661
+ pristine_git_object: f0f45816263733aa1b00c5eb21f8e6c951853102
docs/components/internlistresponse.mdx:
id: 4c41e6189730
last_write_checksum: sha1:8253a947e183a40e10e54a21a5daecff3c1ca969
@@ -6427,8 +6431,8 @@ trackedFiles:
pristine_git_object: 2a892b08d47733e805a94c47c7f87252f262f753
docs/errors/internchaterrorresponse.mdx:
id: 68f63d6ed931
- last_write_checksum: sha1:887bc2e4b9e53a33836eb4a7bd01392638498b49
- pristine_git_object: c8312437d9da083b4bf320af415a357b5471dee0
+ last_write_checksum: sha1:a657b9024d5365dfc17727a35efeca2d56485ca9
+ pristine_git_object: ec1c162ec35061c1e1b1d2015e2ce3b079032997
docs/errors/internlifecycleerror.mdx:
id: 628a6023e104
last_write_checksum: sha1:bf1a5dd26e7c994c2bef5eef51e3a70dbccd2ceb
@@ -6711,16 +6715,20 @@ trackedFiles:
pristine_git_object: a4bd48afd3faf36fa76a2d37561c5582af141ca0
docs/operations/createinternchatcompletionresponse.mdx:
id: a5139c86a594
- last_write_checksum: sha1:dc7481067fc785d7db1163fe12b694a303a2df1a
- pristine_git_object: 2e1d5764aa37e363aed5760421c9f6b8681f460c
+ last_write_checksum: sha1:9f6f43db4ee4f560100c712deea289da32a5bedd
+ pristine_git_object: 6c0f59590a3d8a4377b7be09672cfca88605359e
+ docs/operations/createinternchatcompletionresponseresult.mdx:
+ id: 266a0e6c2271
+ last_write_checksum: sha1:dbd3b8c92f4b7d2ec1cd9c6af6730b82bf9d3cd5
+ pristine_git_object: df62ccd54237a8c5dd59e31bf51a5b789a540d72
docs/operations/createinternglobals.mdx:
id: 45b4d0de1076
last_write_checksum: sha1:d9bae324793bf0ceed41e23e92bf267574cd7834
pristine_git_object: 8eb5e1fc3969fddf5f3706423354192dcaa725e6
docs/operations/createinternrequest.mdx:
id: 775d728f4c95
- last_write_checksum: sha1:071295f8ffaee68807950f2fc1554c9c288509ec
- pristine_git_object: 0806040f7e5aebcded7d4309baa80a0e6a0d3ffb
+ last_write_checksum: sha1:4e1bf8e46cf4535f491f18119c13c60316618d70
+ pristine_git_object: b3a22348904b9b6e07314e82f77b08763524eb1b
docs/operations/createkeysdata.mdx:
id: bf8133a06827
last_write_checksum: sha1:315420c8bb79b06c579bf9473d1f94a26b2aa626
@@ -7495,8 +7503,8 @@ trackedFiles:
pristine_git_object: 3a55ed59f02347866993fd5891898cec46a62c28
docs/operations/listinternsrequest.mdx:
id: e6de03b26b5e
- last_write_checksum: sha1:21e87a5a17a54322e2ce07eb1a334bfbc9fa3d38
- pristine_git_object: 31c29ce6d21afd0e97d25329d704ad9e6f470f0b
+ last_write_checksum: sha1:1a3875f6b6a9674b0640038e11bc0daba6b882fd
+ pristine_git_object: c595b861d0fae9a14542d150c17acd38c700babf
docs/operations/listinternvaultsecretsglobals.mdx:
id: 83e0c9cb95c6
last_write_checksum: sha1:4def94f91a2e27836d1e4d8d313ad5bc31154d01
@@ -8107,8 +8115,8 @@ trackedFiles:
pristine_git_object: 08c687694efbecf50406ae7929029d39fb121295
docs/sdks/interns/README.mdx:
id: 2f8a053ffe78
- last_write_checksum: sha1:a1a2bf31ac879e14767dddc88fa87e98046ef925
- pristine_git_object: 8fc5e6b9bb5d4626033ffd3f745f9fe49bd106fd
+ last_write_checksum: sha1:5bb4be91b9cb5513e1a80bb4dd289fb58b2ceb55
+ pristine_git_object: c45371fd13d43dd0c4883df28d3e8653fd3298a3
docs/sdks/models/README.mdx:
id: 58f1ca464e0b
last_write_checksum: sha1:093dd30ebdd18b9763a6956915e0dcae4ae7d5e5
@@ -8175,8 +8183,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:9c9aac4feea5df58390f40a1d212f251d3b80123
- pristine_git_object: 2fa4c827c0a455783b23e7183a3076a34e06723b
+ last_write_checksum: sha1:439ead1db332b473d81a6ac9a013a2e172f51dc1
+ pristine_git_object: 6e8aa3bc92d909047e178eb66829664ce4232e5b
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -8203,8 +8211,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:bf31610e41c64a659df291327e64114d28656f4f
- pristine_git_object: 2a441139a5a23bb3841818e1e027427935a32494
+ last_write_checksum: sha1:ecc9ae4a1a405cde2bcb40c98a297fd0de4d7235
+ pristine_git_object: ba0c777e2908fb473dd2e881a773524ab1c674db
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:0c25a52ed5fb688ec1e923e4e82bcfc9cae49465
@@ -8247,8 +8255,8 @@ trackedFiles:
pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:b15aafa75b2ffb302936401d2bf05fc68be4ab3e
- pristine_git_object: 31ae0510c41c6b0e0194189ea0ed4b4f1c5f8d89
+ last_write_checksum: sha1:363e12b7b42a054a22088edd196351bfa728455e
+ pristine_git_object: 331cc51584bf4ae089e18d26629538b9260a3102
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c
@@ -9567,8 +9575,8 @@ trackedFiles:
pristine_git_object: 6ddb8c0cb704f5d042e89077fdf487614ab92939
src/openrouter/components/internchaterrormetadata.py:
id: 6285b9634aae
- last_write_checksum: sha1:13100ae9f103fb6b5cfb130eeef37c36f7a77224
- pristine_git_object: ef32d56c946d1378f096cb81241dfa0b5c1b75c0
+ last_write_checksum: sha1:01dbf6ba388feaf4b4cb146b8ac27f4f7298ef69
+ pristine_git_object: 78eb3a03224a49f5399f276166fda60a16ff40e3
src/openrouter/components/internchatmessage.py:
id: a1261b993693
last_write_checksum: sha1:94fa02daf0022b3867764cb6de75587ee0b7b104
@@ -9619,8 +9627,8 @@ trackedFiles:
pristine_git_object: a87aacc5a001412a5789caace557974ccf931928
src/openrouter/components/internlifecycleerror.py:
id: 2b89c094850e
- last_write_checksum: sha1:952dc08e0ed7a08c0ca8cde1798916305f16edba
- pristine_git_object: 589fcd031d428922ff76b506ea068fc746425a1c
+ last_write_checksum: sha1:5cd04c20e433588e3ecbc026af90cf3508ecbc7c
+ pristine_git_object: cde6b4d1fdd5eaaef513b8f289f0da6ebcb7174b
src/openrouter/components/internlistresponse.py:
id: 1d6ce743dbed
last_write_checksum: sha1:ffb97c9bdd1ccca6cfe9951cd0ae0297e4525765
@@ -11147,8 +11155,8 @@ trackedFiles:
pristine_git_object: 50643a126668498dd668c7cceb9f78c03d413d32
src/openrouter/interns.py:
id: d18df05c5c6d
- last_write_checksum: sha1:cad4e1386e159c796d926eeacc0f658208e9c102
- pristine_git_object: 705236ee7435e3cd591571b81cf5f67ed9cbebd7
+ last_write_checksum: sha1:2842133a9360e0c3f26c20dbf93b87a6d180c395
+ pristine_git_object: 087c09b4896bd56a5cc4e2d86f9686a1e747f86e
src/openrouter/models/__init__.py:
id: ed73b93abb3f
last_write_checksum: sha1:932a790ae66ccd7d7022b39c659bcf72a664ebea
@@ -11175,8 +11183,8 @@ trackedFiles:
pristine_git_object: 8680343bbc90107ae6413bd5686012b1fd75d665
src/openrouter/operations/__init__.py:
id: 9afcea1e7161
- last_write_checksum: sha1:0c2f16d015e25e4cb302ba60d5aa8cf0e4d29f9f
- pristine_git_object: f11532262b28c15b5a367afdeff9dd415e78f53e
+ last_write_checksum: sha1:65bf7e8c4463ba62e1a3547b98ddb9936b810480
+ pristine_git_object: dad6359d2132c7fb98338cf94a2c1ae04572e9d4
src/openrouter/operations/bulkaddworkspacemembers.py:
id: e0ed56117619
last_write_checksum: sha1:5c44eb0d40fdece3ac084615f6c6082be4cf1d5a
@@ -11243,12 +11251,12 @@ trackedFiles:
pristine_git_object: 8216a656ec1412a034878e257bd9de9e94fa8da1
src/openrouter/operations/createintern.py:
id: b5cd9ac981a1
- last_write_checksum: sha1:5bdd5fb6257c05a65d0855d7bfb7e3235602ba90
- pristine_git_object: 2efb94a2e159ac4c6bd32fdf6e80877b9e209d81
+ last_write_checksum: sha1:ddd5255797b56717dbc1a9a9eae62ca74fc6c760
+ pristine_git_object: 4443b789b7d9f68a1d25d085da8aeb80cadd2f8f
src/openrouter/operations/createinternchatcompletion.py:
id: 3d0567b5533b
- last_write_checksum: sha1:e9efb3542c13d8b5f450117be623ecb509440849
- pristine_git_object: 67d40aee49e2ed9c4ceb7017e0986a00edc5f18e
+ last_write_checksum: sha1:45a571239c1fbe5030712cfa0eb4594a0d2e366e
+ pristine_git_object: de66beac18f237ad536b93094a36352366788f6e
src/openrouter/operations/createkeys.py:
id: 64ad31fdaa6c
last_write_checksum: sha1:92e122bf7ca252e6cc1f4200cbcd6ded9a0d35a7
@@ -11515,8 +11523,8 @@ trackedFiles:
pristine_git_object: 01655ae02036acf433ec5f54fd1d9323a55f0684
src/openrouter/operations/listinterns.py:
id: 89bc4fa38c9f
- last_write_checksum: sha1:a73fccd1268f4586f5adc3477ed21011a914eb9a
- pristine_git_object: f782b7b4230850b68af902f813083140ab28fb82
+ last_write_checksum: sha1:8b938ac53c5ff37cc670b49c605fd7cf513be8be
+ pristine_git_object: 305b5b570d1bac7698a8fb7ce809e68de9e0bfa4
src/openrouter/operations/listinternvaultsecrets.py:
id: d9f9db46871d
last_write_checksum: sha1:31bd0f67cb4e7dffe16c4a4af5d27a08920d355c
@@ -14849,9 +14857,9 @@ examples:
"200":
application/json: {"data": [{"attached_vault_id": null, "created_at": "2026-09-16T08:30:00.000Z", "description": "Researches customer questions", "hostname": "research-assistant.openrouter.ai", "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "instructions": null, "last_failure_message": null, "model": "openai/gpt-5.4", "name": "research-assistant", "progress": null, "status": "running", "updated_at": "2026-09-16T08:45:00.000Z", "vault_id": "b431c59d-6eed-41ac-bc89-9a89be79a121", "workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"}], "has_more": false}
"400":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
createIntern:
speakeasy-default-create-intern:
requestBody:
@@ -14860,9 +14868,9 @@ examples:
"200":
application/json: {"attached_vault_id": null, "created_at": "2026-09-16T08:30:00.000Z", "description": "Researches customer questions", "hostname": "research-assistant.openrouter.ai", "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "instructions": null, "last_failure_message": null, "model": "openai/gpt-5.4", "name": "research-assistant", "progress": null, "status": "running", "updated_at": "2026-09-16T08:45:00.000Z", "vault_id": "b431c59d-6eed-41ac-bc89-9a89be79a121", "workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"}
"400":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
deleteIntern:
speakeasy-default-delete-intern:
parameters:
@@ -14876,9 +14884,9 @@ examples:
"401":
application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
"400":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
getIntern:
speakeasy-default-get-intern:
parameters:
@@ -14888,9 +14896,9 @@ examples:
"200":
application/json: {"attached_vault_id": null, "created_at": "2026-09-16T08:30:00.000Z", "description": "Researches customer questions", "hostname": "research-assistant.openrouter.ai", "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "instructions": null, "last_failure_message": null, "model": "openai/gpt-5.4", "name": "research-assistant", "progress": null, "status": "running", "updated_at": "2026-09-16T08:45:00.000Z", "vault_id": "b431c59d-6eed-41ac-bc89-9a89be79a121", "workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"}
"401":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
updateIntern:
speakeasy-default-update-intern:
parameters:
@@ -14902,9 +14910,9 @@ examples:
"200":
application/json: {"attached_vault_id": null, "created_at": "2026-09-16T08:30:00.000Z", "description": "Researches customer questions", "hostname": "research-assistant.openrouter.ai", "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "instructions": null, "last_failure_message": null, "model": "openai/gpt-5.4", "name": "research-assistant", "progress": null, "status": "running", "updated_at": "2026-09-16T08:45:00.000Z", "vault_id": "b431c59d-6eed-41ac-bc89-9a89be79a121", "workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"}
"400":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
provisionIntern:
speakeasy-default-provision-intern:
parameters:
@@ -14916,7 +14924,9 @@ examples:
"401":
application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "400":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
suspendIntern:
speakeasy-default-suspend-intern:
parameters:
@@ -14928,7 +14938,9 @@ examples:
"401":
application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
"500":
- application/json: {"error": {"code": "not_found", "message": "Intern not found"}}
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "400":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
createApiAlphaDecisions:
speakeasy-default-create-api-alpha-decisions:
requestBody:
@@ -14974,6 +14986,10 @@ examples:
application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}}
"502":
application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}}
+ "409":
+ application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}}
+ "503":
+ application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}}
createSystemone:
speakeasy-default-create-systemone:
requestBody:
@@ -15006,6 +15022,4 @@ examples:
"529":
application/json: {"error": {"code": 529, "message": "Provider returned error"}}
examplesVersion: 1.0.2
-releaseNotes: |
- ## Python SDK Changes:
- * `open_router.system_one.create()`: **Added**
+releaseNotes: "## Python SDK Changes:\n* `open_router.interns.list_interns()`: `error.metadata` **Added**\n* `open_router.interns.create_intern()`: `error.metadata` **Added**\n* `open_router.interns.delete_intern()`: `error.metadata` **Added**\n* `open_router.interns.get_intern()`: `error.metadata` **Added**\n* `open_router.interns.update_intern()`: `error` **Changed**\n* `open_router.interns.provision_intern()`: `error` **Changed**\n* `open_router.interns.suspend_intern()`: `error` **Changed**\n* `open_router.interns.chat()`: \n * `response` **Changed**\n * `error` **Changed**\n"
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 4aa000a9..a295d2b9 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -36,7 +36,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.2.8
+ version: 1.2.9
additionalDependencies:
dev: {}
main: {}
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index c2508a42..41604b91 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -12756,6 +12756,7 @@ components:
message: 'That question is no longer waiting for an answer.'
metadata:
reason: 'interaction_not_pending'
+ retryable: false
properties:
code:
description: 'The HTTP status of the response.'
@@ -12772,6 +12773,7 @@ components:
description: 'Machine-readable detail for the failure.'
example:
reason: 'interaction_not_pending'
+ retryable: false
properties:
reason:
description: 'A stable reason a client can branch on.'
@@ -12794,8 +12796,12 @@ components:
- 'turn_failed'
type: 'string'
x-speakeasy-unknown-values: allow
+ retryable:
+ description: 'Whether the same request may be sent again unchanged. Always `true` for the transient refusals — `busy`, `intern_not_ready`, `intern_unreachable`, `rate_limited`, `stream_severed` and `timeout` — and always `false` for the ones a retry cannot fix. For `turn_failed` it varies by failure and is the intern''s own classification of what went wrong: `true` for an upstream overload, rate limit, timeout or transport fault, `false` for an authentication or bad-request failure that would be rejected the same way again. Branch on this field rather than on `reason` when deciding whether to retry. A `429`, and a `409` or `503` with reason `busy`, also carry a `Retry-After` header saying how long to wait.'
+ type: 'boolean'
required:
- 'reason'
+ - 'retryable'
type: 'object'
InternChatErrorResponse:
description: 'A refusal before the stream opens. Once the response is `200` and streaming, failures arrive as a chunk with `finish_reason: "error"` instead.'
@@ -12805,6 +12811,7 @@ components:
message: 'That question is no longer waiting for an answer.'
metadata:
reason: 'interaction_not_pending'
+ retryable: false
properties:
error:
$ref: '#/components/schemas/InternChatError'
@@ -12856,6 +12863,7 @@ components:
message: 'The intern could not continue this run.'
metadata:
reason: 'attachment_failed'
+ retryable: false
properties:
code:
description: 'The HTTP status this failure would have had before the stream opened.'
@@ -13041,8 +13049,11 @@ components:
description: 'Intern lifecycle request failure.'
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
properties:
error:
additionalProperties: false
@@ -13053,6 +13064,17 @@ components:
- type: 'integer'
message:
type: 'string'
+ metadata:
+ additionalProperties: false
+ properties:
+ reason:
+ type: 'string'
+ retryable:
+ type: 'boolean'
+ required:
+ - 'reason'
+ - 'retryable'
+ type: 'object'
required:
- 'code'
- 'message'
@@ -36355,13 +36377,13 @@ paths:
maximum: 500
minimum: 1
type: 'integer'
- - description: 'Comma-separated lifecycle statuses to include.'
+ - description: 'Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed.'
explode: false
in: 'query'
name: 'status'
required: false
schema:
- description: 'Comma-separated lifecycle statuses to include.'
+ description: 'Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed.'
example:
- 'queued'
- 'running'
@@ -36377,6 +36399,7 @@ paths:
- 'destroy_failed'
type: 'string'
x-speakeasy-unknown-values: allow
+ maxItems: 8
type: 'array'
style: 'form'
- description: 'The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.'
@@ -36425,8 +36448,11 @@ paths:
application/json:
example:
error:
- code: 'invalid_body'
+ code: 400
message: 'Invalid list query'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The list filters are invalid.'
@@ -36455,8 +36481,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -36466,20 +36495,26 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'500':
content:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
security:
- apiKey: []
summary: 'List interns'
@@ -36489,13 +36524,14 @@ paths:
description: 'Creates an intern in an explicit workspace. The operation also creates its private vault. It can start provisioning immediately or wait for a later provision call. A retry with the same idempotency key and body resumes unfinished work. The request body is capped at 1048576 bytes and a larger body is refused with 413. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.'
operationId: 'createIntern'
parameters:
- - description: 'Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body.'
+ - description: 'Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body.'
in: 'header'
name: 'Idempotency-Key'
required: false
schema:
- description: 'Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body.'
+ description: 'Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body.'
example: 'create-research-assistant-2026-09-16'
+ maxLength: 255
minLength: 1
type: 'string'
requestBody:
@@ -36556,8 +36592,11 @@ paths:
application/json:
example:
error:
- code: 'invalid_body'
+ code: 400
message: 'Invalid request body'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is invalid.'
@@ -36576,8 +36615,11 @@ paths:
application/json:
example:
error:
- code: 'no_acting_user'
+ code: 403
message: 'This key acts as the organization and has no member to own a new intern'
+ metadata:
+ reason: 'no_acting_user'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The key acts as an organization and has no member who can own the intern, or regional access is refused.'
@@ -36586,8 +36628,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -36597,10 +36642,13 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'409':
content:
application/json:
@@ -36608,13 +36656,19 @@ paths:
idempotency_key_reused:
value:
error:
- code: 'idempotency_key_reused'
+ code: 409
message: 'This Idempotency-Key was already used with a different request'
+ metadata:
+ reason: 'idempotency_key_reused'
+ retryable: false
name_taken:
value:
error:
- code: 'name_taken'
+ code: 409
message: 'An intern named "research-assistant" already exists in this workspace'
+ metadata:
+ reason: 'name_taken'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The idempotency key was reused, the intern name is already taken in the workspace, the member reached the intern limit, or the requested vault cannot be attached.'
@@ -36623,8 +36677,11 @@ paths:
application/json:
example:
error:
- code: 'payload_too_large'
+ code: 413
message: 'Request body exceeds 1048576 bytes'
+ metadata:
+ reason: 'payload_too_large'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is larger than 1048576 bytes.'
@@ -36633,18 +36690,24 @@ paths:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
'502':
content:
application/json:
example:
error:
- code: 'upstream_unavailable'
+ code: 502
message: 'The intern was created but setup is not ready yet, retry the request'
+ metadata:
+ reason: 'upstream_unavailable'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The vault or provisioner did not complete a recoverable create step. Retry the same request.'
@@ -36693,8 +36756,11 @@ paths:
application/json:
example:
error:
- code: 'invalid_body'
+ code: 400
message: 'Invalid request body'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is invalid.'
@@ -36723,8 +36789,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -36734,17 +36803,23 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'409':
content:
application/json:
example:
error:
- code: 'intern_busy'
+ code: 409
message: 'The intern is not in a state that allows this operation'
+ metadata:
+ reason: 'intern_busy'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern is not in a state that allows this operation.'
@@ -36753,8 +36828,11 @@ paths:
application/json:
example:
error:
- code: 'payload_too_large'
+ code: 413
message: 'Request body exceeds 1048576 bytes'
+ metadata:
+ reason: 'payload_too_large'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is larger than 1048576 bytes.'
@@ -36763,18 +36841,24 @@ paths:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
'502':
content:
application/json:
example:
error:
- code: 'upstream_unavailable'
+ code: 502
message: 'The intern service could not be reached, retry the request'
+ metadata:
+ reason: 'upstream_unavailable'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern service could not accept the operation.'
@@ -36843,8 +36927,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -36854,20 +36941,26 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'500':
content:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
security:
- apiKey: []
summary: 'Get an intern'
@@ -36922,8 +37015,11 @@ paths:
application/json:
example:
error:
- code: 'invalid_body'
+ code: 400
message: 'Invalid request body'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is invalid.'
@@ -36952,8 +37048,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -36963,17 +37062,36 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
+ '409':
+ content:
+ application/json:
+ example:
+ error:
+ code: 409
+ message: 'An intern named "research-assistant" already exists in this workspace'
+ metadata:
+ reason: 'name_taken'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The new name is already taken by an intern in this workspace.'
'413':
content:
application/json:
example:
error:
- code: 'payload_too_large'
+ code: 413
message: 'Request body exceeds 1048576 bytes'
+ metadata:
+ reason: 'payload_too_large'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The request body is larger than 1048576 bytes.'
@@ -36982,11 +37100,14 @@ paths:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
security:
- apiKey: []
summary: 'Update an intern'
@@ -37058,6 +37179,7 @@ paths:
message: 'The intern did not accept that answer for this tool_call_id.'
metadata:
reason: 'bad_request'
+ retryable: false
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
description: 'The body is not a valid request (`bad_request`), or the intern did not accept the answer for the pending question, such as a permission option it did not offer.'
@@ -37090,9 +37212,23 @@ paths:
message: 'No pending question has this tool_call_id.'
metadata:
reason: 'interaction_unknown'
+ retryable: false
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
description: 'The caller is outside the interns programme, the intern does not exist for this key (`not_found`), or no pending question has this `tool_call_id` in this session (`interaction_unknown`).'
+ '408':
+ content:
+ application/json:
+ example:
+ error:
+ code: 408
+ message: 'Operation timed out after 300s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
+ schema:
+ $ref: '#/components/schemas/InternChatErrorResponse'
+ description: 'The request exceeded the route''s own deadline before the handler answered (`timeout`). Distinct from the 504, which is the intern failing to answer within the turn budget.'
'409':
content:
application/json:
@@ -37102,9 +37238,18 @@ paths:
message: 'The run that asked this question has already ended.'
metadata:
reason: 'interaction_not_pending'
+ retryable: false
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
- description: 'The intern is not running (`intern_not_ready`), another turn is running in this session (`busy`), the question is no longer waiting (`interaction_not_pending`), or another request is already attached to the run (`attachment_failed`).'
+ description: 'The intern is not running (`intern_not_ready`), another turn is already running on this intern (`busy`), the question is no longer waiting (`interaction_not_pending`), or another request is already attached to the run (`attachment_failed`). The turn lock is per intern, not per session. `intern_not_ready` and `busy` report `retryable: true`, and a `busy` refusal carries `Retry-After`.'
+ headers:
+ Retry-After:
+ description: 'Seconds to wait before retrying this request. Present only on a `busy` refusal.'
+ required: false
+ schema:
+ description: 'Seconds to wait before retrying this request. Present only on a `busy` refusal.'
+ example: '5'
+ type: 'string'
'410':
content:
application/json:
@@ -37114,6 +37259,7 @@ paths:
message: 'The run produced more output than the intern retains for replay.'
metadata:
reason: 'attachment_failed'
+ retryable: false
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
description: 'The run produced more output than the intern retains, so the paused stream cannot be resumed (`attachment_failed`).'
@@ -37126,6 +37272,7 @@ paths:
message: 'Request body exceeds 1048576 bytes'
metadata:
reason: 'payload_too_large'
+ retryable: false
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
description: 'The body exceeds 1 MiB (`payload_too_large`).'
@@ -37138,9 +37285,18 @@ paths:
message: 'Too many intern turns. Please wait a moment.'
metadata:
reason: 'rate_limited'
+ retryable: true
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
- description: 'Too many turns for the user or organization this key acts as (`rate_limited`).'
+ description: 'Too many turns for the user or organization this key acts as (`rate_limited`). It reports `retryable: true` and carries `Retry-After`.'
+ headers:
+ Retry-After:
+ description: 'Seconds to wait before retrying this request.'
+ required: true
+ schema:
+ description: 'Seconds to wait before retrying this request.'
+ example: '60'
+ type: 'string'
'502':
content:
application/json:
@@ -37150,9 +37306,10 @@ paths:
message: 'The intern could not be reached.'
metadata:
reason: 'intern_unreachable'
+ retryable: true
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
- description: 'The intern could not be reached or rejected the request (`intern_unreachable`, `intern_rejected`), the intern refused the turn before any output (`turn_failed`), or its stream ended before the turn started (`stream_severed`).'
+ description: 'The intern could not be reached or rejected the request (`intern_unreachable`, `intern_rejected`), the intern refused the turn before any output (`turn_failed`), or its stream ended before the turn started (`stream_severed`). `intern_unreachable` and `stream_severed` are transient and report `retryable: true`; `intern_rejected` reports `false`. A `turn_failed` varies by failure and carries the intern''s own classification of what went wrong, so read `metadata.retryable` rather than assuming from the reason.'
'503':
content:
application/json:
@@ -37162,9 +37319,18 @@ paths:
message: 'The intern cannot hold another run open across a question right now. Retry later.'
metadata:
reason: 'busy'
+ retryable: true
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
- description: 'The intern cannot hold another run open across a question right now (`busy`). Retry later.'
+ description: 'The intern cannot hold another run open across a question right now (`busy`). It reports `retryable: true` and carries `Retry-After`.'
+ headers:
+ Retry-After:
+ description: 'Seconds to wait before retrying this request.'
+ required: true
+ schema:
+ description: 'Seconds to wait before retrying this request.'
+ example: '5'
+ type: 'string'
'504':
content:
application/json:
@@ -37174,6 +37340,7 @@ paths:
message: 'The intern did not answer in time.'
metadata:
reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternChatErrorResponse'
description: 'The intern did not answer within the request budget (`timeout`).'
@@ -37190,7 +37357,7 @@ paths:
- $ref: "#/components/parameters/AppCategories"
/interns/{internId}/provision:
post:
- description: 'Starts the first boot, or resumes an intern after suspension. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.'
+ description: 'Starts the first boot, or resumes an intern after suspension. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.'
operationId: 'provisionIntern'
parameters:
- description: 'ID of an intern visible to the authenticated API key.'
@@ -37211,6 +37378,19 @@ paths:
schema:
$ref: '#/components/schemas/ProvisionInternResponse'
description: 'The operation was accepted.'
+ '400':
+ content:
+ application/json:
+ example:
+ error:
+ code: 400
+ message: 'Invalid request body'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is invalid.'
'401':
content:
application/json:
@@ -37236,8 +37416,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -37247,37 +37430,62 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'409':
content:
application/json:
example:
error:
- code: 'intern_busy'
+ code: 409
message: 'The intern is not in a state that allows this operation'
+ metadata:
+ reason: 'intern_busy'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern is not in a state that allows this operation.'
+ '413':
+ content:
+ application/json:
+ example:
+ error:
+ code: 413
+ message: 'Request body exceeds 1048576 bytes'
+ metadata:
+ reason: 'payload_too_large'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is larger than 1048576 bytes.'
'500':
content:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
'502':
content:
application/json:
example:
error:
- code: 'upstream_unavailable'
+ code: 502
message: 'The intern service could not be reached, retry the request'
+ metadata:
+ reason: 'upstream_unavailable'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern service could not accept the operation.'
@@ -37292,7 +37500,7 @@ paths:
- $ref: "#/components/parameters/AppCategories"
/interns/{internId}/suspend:
post:
- description: 'Stops the intern runtime while keeping its disk and configuration for a later provision call. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.'
+ description: 'Stops the intern runtime while keeping its disk and configuration for a later provision call. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.'
operationId: 'suspendIntern'
parameters:
- description: 'ID of an intern visible to the authenticated API key.'
@@ -37313,6 +37521,19 @@ paths:
schema:
$ref: '#/components/schemas/SuspendInternResponse'
description: 'Intern suspended.'
+ '400':
+ content:
+ application/json:
+ example:
+ error:
+ code: 400
+ message: 'Invalid request body'
+ metadata:
+ reason: 'invalid_body'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is invalid.'
'401':
content:
application/json:
@@ -37338,8 +37559,11 @@ paths:
application/json:
example:
error:
- code: 'not_found'
+ code: 404
message: 'Intern not found'
+ metadata:
+ reason: 'not_found'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled.'
@@ -37349,37 +37573,62 @@ paths:
example:
error:
code: 408
- message: 'Request timed out'
+ message: 'Operation timed out after 10s. Please try again later.'
+ metadata:
+ reason: 'timeout'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request exceeded its route deadline.'
+ description: 'The request exceeded its route deadline. The deadline quoted in the message is the route''s own, so it differs between operations.'
'409':
content:
application/json:
example:
error:
- code: 'intern_busy'
+ code: 409
message: 'The intern is not in a state that allows this operation'
+ metadata:
+ reason: 'intern_busy'
+ retryable: false
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern is not in a state that allows this operation.'
+ '413':
+ content:
+ application/json:
+ example:
+ error:
+ code: 413
+ message: 'Request body exceeds 1048576 bytes'
+ metadata:
+ reason: 'payload_too_large'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is larger than 1048576 bytes.'
'500':
content:
application/json:
example:
error:
- code: 'internal_error'
+ code: 500
message: 'The request could not be completed'
+ metadata:
+ reason: 'internal_error'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
- description: 'The request could not be completed.'
+ description: 'The request could not be completed. `metadata.reason` says whether to try again: `internal_error` is a transient failure and carries `metadata.retryable: true`, so the same request may be sent again, while `configuration_error` carries `retryable: false` because the next attempt reads the same missing binding or unusable stored credential.'
'502':
content:
application/json:
example:
error:
- code: 'upstream_unavailable'
+ code: 502
message: 'The intern service could not be reached, retry the request'
+ metadata:
+ reason: 'upstream_unavailable'
+ retryable: true
schema:
$ref: '#/components/schemas/InternLifecycleError'
description: 'The intern service could not accept the operation.'
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 3932be46..c7191321 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,8 +2,8 @@ speakeasyVersion: 1.787.0
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:afa706f4e8224e896a845cf5ab0b73d8e7f98460c6cd9644071c183083268eda
- sourceBlobDigest: sha256:52077f88403046264219927d45e06d3e45a47bcfcc5aceaeb5c494ec1144ae9a
+ sourceRevisionDigest: sha256:2fcbda5454aa05a488ea1f73dcda2afb05c66b64b11951bbde80083779ff3d34
+ sourceBlobDigest: sha256:4ba1433df1ac27ba9bb38a386be7ce40974196905546fc0469e37d47409fba65
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:afa706f4e8224e896a845cf5ab0b73d8e7f98460c6cd9644071c183083268eda
- sourceBlobDigest: sha256:52077f88403046264219927d45e06d3e45a47bcfcc5aceaeb5c494ec1144ae9a
+ sourceRevisionDigest: sha256:2fcbda5454aa05a488ea1f73dcda2afb05c66b64b11951bbde80083779ff3d34
+ sourceBlobDigest: sha256:4ba1433df1ac27ba9bb38a386be7ce40974196905546fc0469e37d47409fba65
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:b2cd8196b0557606a3c03dd8dfed3be0e421e0c278c63058cb0f8b947b49f6f6
+ codeSamplesRevisionDigest: sha256:23877904ef6eab8294181987f8799443237e442a74316dbd55728cc3c11f7849
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.787.0
diff --git a/RELEASES.md b/RELEASES.md
index 982cd92e..f1c6ab69 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -2489,4 +2489,14 @@ Based on:
### Generated
- [python v1.2.8] .
### Releases
-- [PyPI v1.2.8] https://pypi.org/project/openrouter/1.2.8 - .
\ No newline at end of file
+- [PyPI v1.2.8] https://pypi.org/project/openrouter/1.2.8 - .
+
+## 2026-09-21 01:07:37
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.2.9] .
+### Releases
+- [PyPI v1.2.9] https://pypi.org/project/openrouter/1.2.9 - .
\ No newline at end of file
diff --git a/docs/components/internchatcompletionchunk.mdx b/docs/components/internchatcompletionchunk.mdx
index 647b2b27..9f35a80a 100644
--- a/docs/components/internchatcompletionchunk.mdx
+++ b/docs/components/internchatcompletionchunk.mdx
@@ -11,7 +11,7 @@ One `data:` line of the stream. A run streams a role chunk, content and reasonin
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `choices` | List[[components.InternChatChoice](../components/internchatchoice.mdx)] | :heavy_check_mark: | One choice on content, tool-call and error chunks. Empty on the final chunk that carries `session_id`. | |
| `created` | *int* | :heavy_check_mark: | N/A | |
-| `error` | [Optional[components.InternChatStreamError]](../components/internchatstreamerror.mdx) | :heavy_minus_sign: | A failure after the response headers were sent. The chunk that carries it has `finish_reason: "error"`, then the final empty-`choices` chunk and `[DONE]` follow. Reasons here are `attachment_failed`, `busy`, `client_closed_request`, `interaction_not_pending`, `interaction_unknown`, `intern_unreachable`, `run_ended`, `stream_severed`, `timeout` or `turn_failed`. `run_ended` reports an ending the intern confirmed, such as a cancellation or a deadline, while `stream_severed` reports a connection lost without that confirmation. | \{
"code": 502,
"message": "The intern could not continue this run.",
"metadata": \{
"reason": "attachment_failed"
}
} |
+| `error` | [Optional[components.InternChatStreamError]](../components/internchatstreamerror.mdx) | :heavy_minus_sign: | A failure after the response headers were sent. The chunk that carries it has `finish_reason: "error"`, then the final empty-`choices` chunk and `[DONE]` follow. Reasons here are `attachment_failed`, `busy`, `client_closed_request`, `interaction_not_pending`, `interaction_unknown`, `intern_unreachable`, `run_ended`, `stream_severed`, `timeout` or `turn_failed`. `run_ended` reports an ending the intern confirmed, such as a cancellation or a deadline, while `stream_severed` reports a connection lost without that confirmation. | \{
"code": 502,
"message": "The intern could not continue this run.",
"metadata": \{
"reason": "attachment_failed",
"retryable": false
}
} |
| `id` | *str* | :heavy_check_mark: | The completion id, constant for the whole response. | chatcmpl-f727571a-3bad-4e0d-8a9e-f18f8cda9750 |
| `model` | *str* | :heavy_check_mark: | The runtime's identifier for the model the intern is running, as the intern reports it. Each chunk carries the model from the event behind it: `openrouter/intern` on chunks emitted before the intern has reported one and on chunks the API emits itself (timeout, run-ended and severed-stream errors and their final usage chunk), even after an earlier chunk named a model. It can change within a stream. It is not an OpenRouter model slug, and the request `model` is never used. | |
| `object` | [components.InternChatCompletionChunkObject](../components/internchatcompletionchunkobject.mdx) | :heavy_check_mark: | N/A | |
diff --git a/docs/components/internchaterror.mdx b/docs/components/internchaterror.mdx
index ccdf070f..84af9629 100644
--- a/docs/components/internchaterror.mdx
+++ b/docs/components/internchaterror.mdx
@@ -11,4 +11,4 @@ The OpenAI-compatible error object. `metadata` is present on refusals from the c
| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `code` | *int* | :heavy_check_mark: | The HTTP status of the response. | |
| `message` | *str* | :heavy_check_mark: | N/A | |
-| `metadata` | [Optional[components.InternChatErrorMetadata]](../components/internchaterrormetadata.mdx) | :heavy_minus_sign: | Machine-readable detail for the failure. | \{
"reason": "interaction_not_pending"
} |
\ No newline at end of file
+| `metadata` | [Optional[components.InternChatErrorMetadata]](../components/internchaterrormetadata.mdx) | :heavy_minus_sign: | Machine-readable detail for the failure. | \{
"reason": "interaction_not_pending",
"retryable": false
} |
\ No newline at end of file
diff --git a/docs/components/internchaterrormetadata.mdx b/docs/components/internchaterrormetadata.mdx
index c9de8ffb..0e5c6b60 100644
--- a/docs/components/internchaterrormetadata.mdx
+++ b/docs/components/internchaterrormetadata.mdx
@@ -7,6 +7,7 @@ Machine-readable detail for the failure.
## Fields
-| Field | Type | Required | Description |
-| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------ |
-| `reason` | [components.InternChatErrorMetadataReason](../components/internchaterrormetadatareason.mdx) | :heavy_check_mark: | A stable reason a client can branch on. |
\ No newline at end of file
+| Field | Type | Required | Description |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `reason` | [components.InternChatErrorMetadataReason](../components/internchaterrormetadatareason.mdx) | :heavy_check_mark: | A stable reason a client can branch on. |
+| `retryable` | *bool* | :heavy_check_mark: | Whether the same request may be sent again unchanged. Always `true` for the transient refusals — `busy`, `intern_not_ready`, `intern_unreachable`, `rate_limited`, `stream_severed` and `timeout` — and always `false` for the ones a retry cannot fix. For `turn_failed` it varies by failure and is the intern's own classification of what went wrong: `true` for an upstream overload, rate limit, timeout or transport fault, `false` for an authentication or bad-request failure that would be rejected the same way again. Branch on this field rather than on `reason` when deciding whether to retry. A `429`, and a `409` or `503` with reason `busy`, also carry a `Retry-After` header saying how long to wait. |
\ No newline at end of file
diff --git a/docs/components/internchatstreamerror.mdx b/docs/components/internchatstreamerror.mdx
index 48f3773b..b1920057 100644
--- a/docs/components/internchatstreamerror.mdx
+++ b/docs/components/internchatstreamerror.mdx
@@ -11,4 +11,4 @@ A failure after the response headers were sent. The chunk that carries it has `f
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ |
| `code` | *int* | :heavy_check_mark: | The HTTP status this failure would have had before the stream opened. | |
| `message` | *str* | :heavy_check_mark: | N/A | |
-| `metadata` | [components.InternChatErrorMetadata](../components/internchaterrormetadata.mdx) | :heavy_check_mark: | Machine-readable detail for the failure. | \{
"reason": "interaction_not_pending"
} |
\ No newline at end of file
+| `metadata` | [components.InternChatErrorMetadata](../components/internchaterrormetadata.mdx) | :heavy_check_mark: | Machine-readable detail for the failure. | \{
"reason": "interaction_not_pending",
"retryable": false
} |
\ No newline at end of file
diff --git a/docs/components/internlifecycleerrorerror.mdx b/docs/components/internlifecycleerrorerror.mdx
index c9eacd7d..dc3a8f40 100644
--- a/docs/components/internlifecycleerrorerror.mdx
+++ b/docs/components/internlifecycleerrorerror.mdx
@@ -4,7 +4,8 @@ title: "InternLifecycleErrorError"
## Fields
-| Field | Type | Required | Description |
-| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- |
-| `code` | [components.Code](../components/code.mdx) | :heavy_check_mark: | N/A |
-| `message` | *str* | :heavy_check_mark: | N/A |
\ No newline at end of file
+| Field | Type | Required | Description |
+| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
+| `code` | [components.Code](../components/code.mdx) | :heavy_check_mark: | N/A |
+| `message` | *str* | :heavy_check_mark: | N/A |
+| `metadata` | [Optional[components.InternLifecycleErrorMetadata]](../components/internlifecycleerrormetadata.mdx) | :heavy_minus_sign: | N/A |
\ No newline at end of file
diff --git a/docs/components/internlifecycleerrormetadata.mdx b/docs/components/internlifecycleerrormetadata.mdx
new file mode 100644
index 00000000..f0f45816
--- /dev/null
+++ b/docs/components/internlifecycleerrormetadata.mdx
@@ -0,0 +1,10 @@
+---
+title: "InternLifecycleErrorMetadata"
+---
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------ | ------------------ | ------------------ | ------------------ |
+| `reason` | *str* | :heavy_check_mark: | N/A |
+| `retryable` | *bool* | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/errors/internchaterrorresponse.mdx b/docs/errors/internchaterrorresponse.mdx
index c8312437..ec1c162e 100644
--- a/docs/errors/internchaterrorresponse.mdx
+++ b/docs/errors/internchaterrorresponse.mdx
@@ -9,4 +9,4 @@ A refusal before the stream opens. Once the response is `200` and streaming, fai
| Field | Type | Required | Description | Example |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `error` | [components.InternChatError](../components/internchaterror.mdx) | :heavy_check_mark: | The OpenAI-compatible error object. `metadata` is present on refusals from the chat route. Authentication refusals (`401`), the departed-creator `403` and the programme `404` carry only `code` and `message`. | \{
"code": 409,
"message": "That question is no longer waiting for an answer.",
"metadata": \{
"reason": "interaction_not_pending"
}
} |
\ No newline at end of file
+| `error` | [components.InternChatError](../components/internchaterror.mdx) | :heavy_check_mark: | The OpenAI-compatible error object. `metadata` is present on refusals from the chat route. Authentication refusals (`401`), the departed-creator `403` and the programme `404` carry only `code` and `message`. | \{
"code": 409,
"message": "That question is no longer waiting for an answer.",
"metadata": \{
"reason": "interaction_not_pending",
"retryable": false
}
} |
\ No newline at end of file
diff --git a/docs/operations/createinternchatcompletionresponse.mdx b/docs/operations/createinternchatcompletionresponse.mdx
index 2e1d5764..6c0f5959 100644
--- a/docs/operations/createinternchatcompletionresponse.mdx
+++ b/docs/operations/createinternchatcompletionresponse.mdx
@@ -2,17 +2,9 @@
title: "CreateInternChatCompletionResponse"
---
-## Supported Types
-
-### `Union[eventstreaming.EventStream[components.InternChatCompletionChunk], eventstreaming.EventStreamAsync[components.InternChatCompletionChunk]]`
-
-```python
-value: Union[eventstreaming.EventStream[components.InternChatCompletionChunk], eventstreaming.EventStreamAsync[components.InternChatCompletionChunk]] = /* values here */
-```
-
-### `components.InternChatCompletionChunk`
-
-```python
-value: components.InternChatCompletionChunk = /* values here */
-```
+## Fields
+| Field | Type | Required | Description |
+| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
+| `headers` | Dict[str, List[*str*]] | :heavy_check_mark: | N/A |
+| `result` | [operations.CreateInternChatCompletionResponseResult](../operations/createinternchatcompletionresponseresult.mdx) | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/operations/createinternchatcompletionresponseresult.mdx b/docs/operations/createinternchatcompletionresponseresult.mdx
new file mode 100644
index 00000000..df62ccd5
--- /dev/null
+++ b/docs/operations/createinternchatcompletionresponseresult.mdx
@@ -0,0 +1,18 @@
+---
+title: "CreateInternChatCompletionResponseResult"
+---
+
+## Supported Types
+
+### `Union[eventstreaming.EventStream[components.InternChatCompletionChunk], eventstreaming.EventStreamAsync[components.InternChatCompletionChunk]]`
+
+```python
+value: Union[eventstreaming.EventStream[components.InternChatCompletionChunk], eventstreaming.EventStreamAsync[components.InternChatCompletionChunk]] = /* values here */
+```
+
+### `components.InternChatCompletionChunk`
+
+```python
+value: components.InternChatCompletionChunk = /* values here */
+```
+
diff --git a/docs/operations/createinternrequest.mdx b/docs/operations/createinternrequest.mdx
index 0806040f..b3a22348 100644
--- a/docs/operations/createinternrequest.mdx
+++ b/docs/operations/createinternrequest.mdx
@@ -4,10 +4,10 @@ title: "CreateInternRequest"
## Fields
-| Field | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
-| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
-| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
-| `idempotency_key` | *Optional[str]* | :heavy_minus_sign: | Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body. | create-research-assistant-2026-09-16 |
-| `create_intern_request` | [components.CreateInternRequest](../components/createinternrequest.mdx) | :heavy_check_mark: | N/A | \{
"name": "research-assistant",
"provision": true,
"workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"
} |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `idempotency_key` | *Optional[str]* | :heavy_minus_sign: | Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body. | create-research-assistant-2026-09-16 |
+| `create_intern_request` | [components.CreateInternRequest](../components/createinternrequest.mdx) | :heavy_check_mark: | N/A | \{
"name": "research-assistant",
"provision": true,
"workspace_id": "89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb"
} |
\ No newline at end of file
diff --git a/docs/operations/listinternsrequest.mdx b/docs/operations/listinternsrequest.mdx
index 31c29ce6..c595b861 100644
--- a/docs/operations/listinternsrequest.mdx
+++ b/docs/operations/listinternsrequest.mdx
@@ -10,6 +10,6 @@ title: "ListInternsRequest"
| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
| `limit` | *Optional[int]* | :heavy_minus_sign: | Maximum number of interns to return, from 1 through 500. | 50 |
-| `status` | List[[operations.Status](../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include. | [
"queued",
"running"
] |
+| `status` | List[[operations.Status](../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed. | [
"queued",
"running"
] |
| `starting_after` | *Optional[str]* | :heavy_minus_sign: | The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400. | MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw |
| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Only return interns in this workspace. It must match the API key workspace. | 89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb |
\ No newline at end of file
diff --git a/docs/sdks/interns/README.mdx b/docs/sdks/interns/README.mdx
index 8fc5e6b9..c45371fd 100644
--- a/docs/sdks/interns/README.mdx
+++ b/docs/sdks/interns/README.mdx
@@ -51,7 +51,7 @@ with OpenRouter(
| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
| `limit` | *Optional[int]* | :heavy_minus_sign: | Maximum number of interns to return, from 1 through 500. | 50 |
-| `status` | List[[operations.Status](../../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include. | [
"queued",
"running"
] |
+| `status` | List[[operations.Status](../../operations/status.mdx)] | :heavy_minus_sign: | Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed. | [
"queued",
"running"
] |
| `starting_after` | *Optional[str]* | :heavy_minus_sign: | The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400. | MjAyNi0wOS0xNlQwODozMDowMC4wMDAwMDBafDdjOWU2Njc5LTc0MjUtNDBkZS05NDRiLWUwN2ZjMWY5MGFlNw |
| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Only return interns in this workspace. It must match the API key workspace. | 89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb |
| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
@@ -95,19 +95,19 @@ with OpenRouter(
### Parameters
-| Parameter | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | *str* | :heavy_check_mark: | Intern name, unique per creator within the workspace. | |
-| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
-| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
-| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
-| `idempotency_key` | *Optional[str]* | :heavy_minus_sign: | Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body. | create-research-assistant-2026-09-16 |
-| `description` | *OptionalNullable[str]* | :heavy_minus_sign: | Free-form description, or null. | |
-| `instructions` | *OptionalNullable[str]* | :heavy_minus_sign: | Standing instructions the intern boots with, or null. | |
-| `provision` | *Optional[bool]* | :heavy_minus_sign: | Start provisioning during this create operation. Defaults to false. | |
-| `vault_id` | *Optional[str]* | :heavy_minus_sign: | Vault owned by another intern in this workspace to attach as a borrowed vault. | |
-| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Workspace that will own the intern. Defaults to the workspace the API key resolves to. When given, it must match the API key workspace. | |
-| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
+| Parameter | Type | Required | Description | Example |
+| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `name` | *str* | :heavy_check_mark: | Intern name, unique per creator within the workspace. | |
+| `http_referer` | *Optional[str]* | :heavy_minus_sign: | The app identifier should be your app's URL and is used as the primary identifier for rankings.
This is used to track API usage per application.
| |
+| `x_open_router_title` | *Optional[str]* | :heavy_minus_sign: | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | :heavy_minus_sign: | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `idempotency_key` | *Optional[str]* | :heavy_minus_sign: | Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body. | create-research-assistant-2026-09-16 |
+| `description` | *OptionalNullable[str]* | :heavy_minus_sign: | Free-form description, or null. | |
+| `instructions` | *OptionalNullable[str]* | :heavy_minus_sign: | Standing instructions the intern boots with, or null. | |
+| `provision` | *Optional[bool]* | :heavy_minus_sign: | Start provisioning during this create operation. Defaults to false. | |
+| `vault_id` | *Optional[str]* | :heavy_minus_sign: | Vault owned by another intern in this workspace to attach as a borrowed vault. | |
+| `workspace_id` | *Optional[str]* | :heavy_minus_sign: | Workspace that will own the intern. Defaults to the workspace the API key resolves to. When given, it must match the API key workspace. | |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
### Response
@@ -261,15 +261,15 @@ with OpenRouter(
### Errors
-| Error Type | Status Code | Content Type |
-| ----------------------------- | ----------------------------- | ----------------------------- |
-| errors.InternLifecycleError | 400, 401, 403, 404, 408, 413 | application/json |
-| errors.InternLifecycleError | 500 | application/json |
-| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternLifecycleError | 400, 401, 403, 404, 408, 409, 413 | application/json |
+| errors.InternLifecycleError | 500 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
## provision_intern
-Starts the first boot, or resumes an intern after suspension. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+Starts the first boot, or resumes an intern after suspension. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
### Example Usage
@@ -308,15 +308,15 @@ with OpenRouter(
### Errors
-| Error Type | Status Code | Content Type |
-| ----------------------------- | ----------------------------- | ----------------------------- |
-| errors.InternLifecycleError | 401, 403, 404, 408, 409 | application/json |
-| errors.InternLifecycleError | 500, 502 | application/json |
-| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternLifecycleError | 400, 401, 403, 404, 408, 409, 413 | application/json |
+| errors.InternLifecycleError | 500, 502 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
## suspend_intern
-Stops the intern runtime while keeping its disk and configuration for a later provision call. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+Stops the intern runtime while keeping its disk and configuration for a later provision call. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
### Example Usage
@@ -355,11 +355,11 @@ with OpenRouter(
### Errors
-| Error Type | Status Code | Content Type |
-| ----------------------------- | ----------------------------- | ----------------------------- |
-| errors.InternLifecycleError | 401, 403, 404, 408, 409 | application/json |
-| errors.InternLifecycleError | 500, 502 | application/json |
-| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternLifecycleError | 400, 401, 403, 404, 408, 409, 413 | application/json |
+| errors.InternLifecycleError | 500, 502 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
## chat
@@ -425,8 +425,10 @@ with OpenRouter(
### Errors
-| Error Type | Status Code | Content Type |
-| -------------------------------------- | -------------------------------------- | -------------------------------------- |
-| errors.InternChatErrorResponse | 400, 401, 403, 404, 409, 410, 413, 429 | application/json |
-| errors.InternChatErrorResponse | 502, 503, 504 | application/json |
-| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
\ No newline at end of file
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternChatErrorResponse | 400, 401, 403, 404, 408, 410, 413 | application/json |
+| errors.InternChatErrorResponse | 409, 429 | application/json |
+| errors.InternChatErrorResponse | 503 | application/json |
+| errors.InternChatErrorResponse | 502, 504 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index 2fa4c827..6e8aa3bc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.2.8"
+version = "1.2.9"
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 2a441139..ba0c777e 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "1.2.8"
+__version__: str = "1.2.9"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.914.0"
-__user_agent__: str = "speakeasy-sdk/python 1.2.8 2.914.0 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.2.9 2.914.0 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 31ae0510..331cc515 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -1704,6 +1704,8 @@
CodeTypedDict,
InternLifecycleErrorError,
InternLifecycleErrorErrorTypedDict,
+ InternLifecycleErrorMetadata,
+ InternLifecycleErrorMetadataTypedDict,
)
from .internlistresponse import InternListResponse, InternListResponseTypedDict
from .itemreferenceitem import (
@@ -4696,6 +4698,8 @@
"InternChatUserMessageTypedDict",
"InternLifecycleErrorError",
"InternLifecycleErrorErrorTypedDict",
+ "InternLifecycleErrorMetadata",
+ "InternLifecycleErrorMetadataTypedDict",
"InternListResponse",
"InternListResponseTypedDict",
"InternStatus",
@@ -7230,6 +7234,8 @@
"CodeTypedDict": ".internlifecycleerror",
"InternLifecycleErrorError": ".internlifecycleerror",
"InternLifecycleErrorErrorTypedDict": ".internlifecycleerror",
+ "InternLifecycleErrorMetadata": ".internlifecycleerror",
+ "InternLifecycleErrorMetadataTypedDict": ".internlifecycleerror",
"InternListResponse": ".internlistresponse",
"InternListResponseTypedDict": ".internlistresponse",
"ItemReferenceItem": ".itemreferenceitem",
diff --git a/src/openrouter/components/internchaterrormetadata.py b/src/openrouter/components/internchaterrormetadata.py
index ef32d56c..78eb3a03 100644
--- a/src/openrouter/components/internchaterrormetadata.py
+++ b/src/openrouter/components/internchaterrormetadata.py
@@ -35,6 +35,8 @@ class InternChatErrorMetadataTypedDict(TypedDict):
reason: InternChatErrorMetadataReason
r"""A stable reason a client can branch on."""
+ retryable: bool
+ r"""Whether the same request may be sent again unchanged. Always `true` for the transient refusals — `busy`, `intern_not_ready`, `intern_unreachable`, `rate_limited`, `stream_severed` and `timeout` — and always `false` for the ones a retry cannot fix. For `turn_failed` it varies by failure and is the intern's own classification of what went wrong: `true` for an upstream overload, rate limit, timeout or transport fault, `false` for an authentication or bad-request failure that would be rejected the same way again. Branch on this field rather than on `reason` when deciding whether to retry. A `429`, and a `409` or `503` with reason `busy`, also carry a `Retry-After` header saying how long to wait."""
class InternChatErrorMetadata(BaseModel):
@@ -42,3 +44,6 @@ class InternChatErrorMetadata(BaseModel):
reason: InternChatErrorMetadataReason
r"""A stable reason a client can branch on."""
+
+ retryable: bool
+ r"""Whether the same request may be sent again unchanged. Always `true` for the transient refusals — `busy`, `intern_not_ready`, `intern_unreachable`, `rate_limited`, `stream_severed` and `timeout` — and always `false` for the ones a retry cannot fix. For `turn_failed` it varies by failure and is the intern's own classification of what went wrong: `true` for an upstream overload, rate limit, timeout or transport fault, `false` for an authentication or bad-request failure that would be rejected the same way again. Branch on this field rather than on `reason` when deciding whether to retry. A `429`, and a `409` or `503` with reason `busy`, also carry a `Retry-After` header saying how long to wait."""
diff --git a/src/openrouter/components/internlifecycleerror.py b/src/openrouter/components/internlifecycleerror.py
index 589fcd03..cde6b4d1 100644
--- a/src/openrouter/components/internlifecycleerror.py
+++ b/src/openrouter/components/internlifecycleerror.py
@@ -1,9 +1,10 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
-from openrouter.types import BaseModel
-from typing import Union
-from typing_extensions import TypeAliasType, TypedDict
+from openrouter.types import BaseModel, UNSET_SENTINEL
+from pydantic import model_serializer
+from typing import Optional, Union
+from typing_extensions import NotRequired, TypeAliasType, TypedDict
CodeTypedDict = TypeAliasType("CodeTypedDict", Union[str, int])
@@ -12,12 +13,42 @@
Code = TypeAliasType("Code", Union[str, int])
+class InternLifecycleErrorMetadataTypedDict(TypedDict):
+ reason: str
+ retryable: bool
+
+
+class InternLifecycleErrorMetadata(BaseModel):
+ reason: str
+
+ retryable: bool
+
+
class InternLifecycleErrorErrorTypedDict(TypedDict):
code: CodeTypedDict
message: str
+ metadata: NotRequired[InternLifecycleErrorMetadataTypedDict]
class InternLifecycleErrorError(BaseModel):
code: Code
message: str
+
+ metadata: Optional[InternLifecycleErrorMetadata] = None
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(["metadata"])
+ serialized = handler(self)
+ m = {}
+
+ for n, f in type(self).model_fields.items():
+ k = f.alias or n
+ val = serialized.get(k, serialized.get(n))
+
+ if val != UNSET_SENTINEL:
+ if val is not None or k not in optional_fields:
+ m[k] = val
+
+ return m
diff --git a/src/openrouter/interns.py b/src/openrouter/interns.py
index 705236ee..087c09b4 100644
--- a/src/openrouter/interns.py
+++ b/src/openrouter/interns.py
@@ -41,7 +41,7 @@ def list_interns(
:param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
:param limit: Maximum number of interns to return, from 1 through 500.
- :param status: Comma-separated lifecycle statuses to include.
+ :param status: Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed.
:param starting_after: The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.
:param workspace_id: Only return interns in this workspace. It must match the API key workspace.
:param retries: Override the default retry configuration for this method
@@ -178,7 +178,7 @@ async def list_interns_async(
:param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
:param limit: Maximum number of interns to return, from 1 through 500.
- :param status: Comma-separated lifecycle statuses to include.
+ :param status: Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed.
:param starting_after: The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400.
:param workspace_id: Only return interns in this workspace. It must match the API key workspace.
:param retries: Override the default retry configuration for this method
@@ -318,7 +318,7 @@ def create_intern(
:param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
- :param idempotency_key: Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body.
+ :param idempotency_key: Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body.
:param description: Free-form description, or null.
:param instructions: Standing instructions the intern boots with, or null.
:param provision: Start provisioning during this create operation. Defaults to false.
@@ -475,7 +475,7 @@ async def create_intern_async(
:param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
- :param idempotency_key: Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body.
+ :param idempotency_key: Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body.
:param description: Free-form description, or null.
:param instructions: Standing instructions the intern boots with, or null.
:param provision: Start provisioning during this create operation. Defaults to false.
@@ -1265,7 +1265,9 @@ def update_intern(
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.Intern, http_res)
if utils.match_response(
- http_res, ["400", "401", "403", "404", "408", "413"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1414,7 +1416,9 @@ async def update_intern_async(
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.Intern, http_res)
if utils.match_response(
- http_res, ["400", "401", "403", "404", "408", "413"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1452,7 +1456,7 @@ def provision_intern(
) -> components.ProvisionInternResponse:
r"""Provision an intern
- Starts the first boot, or resumes an intern after suspension. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+ Starts the first boot, or resumes an intern after suspension. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
If set, this operation will use `api_key` from the global security.
@@ -1542,7 +1546,9 @@ def provision_intern(
if utils.match_response(http_res, "202", "application/json"):
return unmarshal_json_response(components.ProvisionInternResponse, http_res)
if utils.match_response(
- http_res, ["401", "403", "404", "408", "409"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1580,7 +1586,7 @@ async def provision_intern_async(
) -> components.ProvisionInternResponse:
r"""Provision an intern
- Starts the first boot, or resumes an intern after suspension. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+ Starts the first boot, or resumes an intern after suspension. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
If set, this operation will use `api_key` from the global security.
@@ -1670,7 +1676,9 @@ async def provision_intern_async(
if utils.match_response(http_res, "202", "application/json"):
return unmarshal_json_response(components.ProvisionInternResponse, http_res)
if utils.match_response(
- http_res, ["401", "403", "404", "408", "409"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1708,7 +1716,7 @@ def suspend_intern(
) -> components.SuspendInternResponse:
r"""Suspend an intern
- Stops the intern runtime while keeping its disk and configuration for a later provision call. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+ Stops the intern runtime while keeping its disk and configuration for a later provision call. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
If set, this operation will use `api_key` from the global security.
@@ -1798,7 +1806,9 @@ def suspend_intern(
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.SuspendInternResponse, http_res)
if utils.match_response(
- http_res, ["401", "403", "404", "408", "409"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1836,7 +1846,7 @@ async def suspend_intern_async(
) -> components.SuspendInternResponse:
r"""Suspend an intern
- Stops the intern runtime while keeping its disk and configuration for a later provision call. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+ Stops the intern runtime while keeping its disk and configuration for a later provision call. This operation takes no request body. A body carrying any field is refused with 400 rather than ignored. The API key selects the caller, workspace and visible interns. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
If set, this operation will use `api_key` from the global security.
@@ -1926,7 +1936,9 @@ async def suspend_intern_async(
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.SuspendInternResponse, http_res)
if utils.match_response(
- http_res, ["401", "403", "404", "408", "409"], "application/json"
+ http_res,
+ ["400", "401", "403", "404", "408", "409", "413"],
+ "application/json",
):
response_data = unmarshal_json_response(
errors.InternLifecycleErrorData, http_res
@@ -1969,8 +1981,8 @@ def chat(
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> Union[
- components.InternChatCompletionChunk,
- eventstreaming.EventStream[components.InternChatCompletionChunk],
+ operations.CreateInternChatCompletionResponse,
+ operations.CreateInternChatCompletionResponse,
]:
r"""Stream a chat completion with an intern
@@ -2096,22 +2108,28 @@ def chat(
response_data: Any = None
if utils.match_response(http_res, "200", "text/event-stream"):
- return eventstreaming.EventStream(
- http_res,
- lambda raw: unmarshal_json_response(
- components.InternChatStreamingResponse, http_res, raw
- ).data,
- sentinel="[DONE]",
- client_ref=self,
+ return operations.CreateInternChatCompletionResponse(
+ result=eventstreaming.EventStream(
+ http_res,
+ lambda raw: unmarshal_json_response(
+ components.InternChatStreamingResponse, http_res, raw
+ ).data,
+ sentinel="[DONE]",
+ client_ref=self,
+ ),
+ headers={},
)
if utils.match_response(http_res, "200", "application/json"):
http_res_text = utils.stream_to_text(http_res)
- return unmarshal_json_response(
- components.InternChatCompletionChunk, http_res, http_res_text
+ return operations.CreateInternChatCompletionResponse(
+ result=unmarshal_json_response(
+ components.InternChatCompletionChunk, http_res, http_res_text
+ ),
+ headers={},
)
if utils.match_response(
http_res,
- ["400", "401", "403", "404", "409", "410", "413", "429"],
+ ["400", "401", "403", "404", "408", "410", "413"],
"application/json",
):
http_res_text = utils.stream_to_text(http_res)
@@ -2119,7 +2137,19 @@ def chat(
errors.InternChatErrorResponseData, http_res, http_res_text
)
raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
- if utils.match_response(http_res, ["502", "503", "504"], "application/json"):
+ if utils.match_response(http_res, ["409", "429"], "application/json"):
+ http_res_text = utils.stream_to_text(http_res)
+ response_data = unmarshal_json_response(
+ errors.InternChatErrorResponseData, http_res, http_res_text
+ )
+ raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
+ if utils.match_response(http_res, "503", "application/json"):
+ http_res_text = utils.stream_to_text(http_res)
+ response_data = unmarshal_json_response(
+ errors.InternChatErrorResponseData, http_res, http_res_text
+ )
+ raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
+ if utils.match_response(http_res, ["502", "504"], "application/json"):
http_res_text = utils.stream_to_text(http_res)
response_data = unmarshal_json_response(
errors.InternChatErrorResponseData, http_res, http_res_text
@@ -2160,8 +2190,8 @@ async def chat_async(
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> Union[
- components.InternChatCompletionChunk,
- eventstreaming.EventStreamAsync[components.InternChatCompletionChunk],
+ operations.CreateInternChatCompletionResponse,
+ operations.CreateInternChatCompletionResponse,
]:
r"""Stream a chat completion with an intern
@@ -2287,22 +2317,28 @@ async def chat_async(
response_data: Any = None
if utils.match_response(http_res, "200", "text/event-stream"):
- return eventstreaming.EventStreamAsync(
- http_res,
- lambda raw: unmarshal_json_response(
- components.InternChatStreamingResponse, http_res, raw
- ).data,
- sentinel="[DONE]",
- client_ref=self,
+ return operations.CreateInternChatCompletionResponse(
+ result=eventstreaming.EventStreamAsync(
+ http_res,
+ lambda raw: unmarshal_json_response(
+ components.InternChatStreamingResponse, http_res, raw
+ ).data,
+ sentinel="[DONE]",
+ client_ref=self,
+ ),
+ headers={},
)
if utils.match_response(http_res, "200", "application/json"):
http_res_text = await utils.stream_to_text_async(http_res)
- return unmarshal_json_response(
- components.InternChatCompletionChunk, http_res, http_res_text
+ return operations.CreateInternChatCompletionResponse(
+ result=unmarshal_json_response(
+ components.InternChatCompletionChunk, http_res, http_res_text
+ ),
+ headers={},
)
if utils.match_response(
http_res,
- ["400", "401", "403", "404", "409", "410", "413", "429"],
+ ["400", "401", "403", "404", "408", "410", "413"],
"application/json",
):
http_res_text = await utils.stream_to_text_async(http_res)
@@ -2310,7 +2346,19 @@ async def chat_async(
errors.InternChatErrorResponseData, http_res, http_res_text
)
raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
- if utils.match_response(http_res, ["502", "503", "504"], "application/json"):
+ if utils.match_response(http_res, ["409", "429"], "application/json"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ response_data = unmarshal_json_response(
+ errors.InternChatErrorResponseData, http_res, http_res_text
+ )
+ raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
+ if utils.match_response(http_res, "503", "application/json"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ response_data = unmarshal_json_response(
+ errors.InternChatErrorResponseData, http_res, http_res_text
+ )
+ raise errors.InternChatErrorResponse(response_data, http_res, http_res_text)
+ if utils.match_response(http_res, ["502", "504"], "application/json"):
http_res_text = await utils.stream_to_text_async(http_res)
response_data = unmarshal_json_response(
errors.InternChatErrorResponseData, http_res, http_res_text
diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py
index f1153226..dad6359d 100644
--- a/src/openrouter/operations/__init__.py
+++ b/src/openrouter/operations/__init__.py
@@ -161,6 +161,8 @@
CreateInternChatCompletionRequest,
CreateInternChatCompletionRequestTypedDict,
CreateInternChatCompletionResponse,
+ CreateInternChatCompletionResponseResult,
+ CreateInternChatCompletionResponseResultTypedDict,
CreateInternChatCompletionResponseTypedDict,
)
from .createkeys import (
@@ -1093,6 +1095,8 @@
"CreateInternChatCompletionRequest",
"CreateInternChatCompletionRequestTypedDict",
"CreateInternChatCompletionResponse",
+ "CreateInternChatCompletionResponseResult",
+ "CreateInternChatCompletionResponseResultTypedDict",
"CreateInternChatCompletionResponseTypedDict",
"CreateInternGlobals",
"CreateInternGlobalsTypedDict",
@@ -1839,6 +1843,8 @@
"CreateInternChatCompletionRequest": ".createinternchatcompletion",
"CreateInternChatCompletionRequestTypedDict": ".createinternchatcompletion",
"CreateInternChatCompletionResponse": ".createinternchatcompletion",
+ "CreateInternChatCompletionResponseResult": ".createinternchatcompletion",
+ "CreateInternChatCompletionResponseResultTypedDict": ".createinternchatcompletion",
"CreateInternChatCompletionResponseTypedDict": ".createinternchatcompletion",
"CreateKeysData": ".createkeys",
"CreateKeysDataTypedDict": ".createkeys",
diff --git a/src/openrouter/operations/createintern.py b/src/openrouter/operations/createintern.py
index 2efb94a2..4443b789 100644
--- a/src/openrouter/operations/createintern.py
+++ b/src/openrouter/operations/createintern.py
@@ -90,7 +90,7 @@ class CreateInternRequestTypedDict(TypedDict):
"""
idempotency_key: NotRequired[str]
- r"""Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body."""
+ r"""Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body."""
class CreateInternRequest(BaseModel):
@@ -132,7 +132,7 @@ class CreateInternRequest(BaseModel):
pydantic.Field(alias="Idempotency-Key"),
FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
] = None
- r"""Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body."""
+ r"""Key that makes retries resume the same create operation, from 1 through 255 characters. An empty or longer key is refused with 400. Without the header, the server derives a stable key from the request body."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
diff --git a/src/openrouter/operations/createinternchatcompletion.py b/src/openrouter/operations/createinternchatcompletion.py
index 67d40aee..de66beac 100644
--- a/src/openrouter/operations/createinternchatcompletion.py
+++ b/src/openrouter/operations/createinternchatcompletion.py
@@ -15,7 +15,7 @@
)
import pydantic
from pydantic import model_serializer
-from typing import Optional, Union
+from typing import Dict, List, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict
@@ -164,8 +164,8 @@ def serialize_model(self, handler):
return m
-CreateInternChatCompletionResponseTypedDict = TypeAliasType(
- "CreateInternChatCompletionResponseTypedDict",
+CreateInternChatCompletionResponseResultTypedDict = TypeAliasType(
+ "CreateInternChatCompletionResponseResultTypedDict",
Union[
components_internchatcompletionchunk.InternChatCompletionChunkTypedDict,
Union[
@@ -180,8 +180,8 @@ def serialize_model(self, handler):
)
-CreateInternChatCompletionResponse = TypeAliasType(
- "CreateInternChatCompletionResponse",
+CreateInternChatCompletionResponseResult = TypeAliasType(
+ "CreateInternChatCompletionResponseResult",
Union[
components_internchatcompletionchunk.InternChatCompletionChunk,
Union[
@@ -194,3 +194,14 @@ def serialize_model(self, handler):
],
],
)
+
+
+class CreateInternChatCompletionResponseTypedDict(TypedDict):
+ headers: Dict[str, List[str]]
+ result: CreateInternChatCompletionResponseResultTypedDict
+
+
+class CreateInternChatCompletionResponse(BaseModel):
+ headers: Dict[str, List[str]]
+
+ result: CreateInternChatCompletionResponseResult
diff --git a/src/openrouter/operations/listinterns.py b/src/openrouter/operations/listinterns.py
index f782b7b4..305b5b57 100644
--- a/src/openrouter/operations/listinterns.py
+++ b/src/openrouter/operations/listinterns.py
@@ -105,7 +105,7 @@ class ListInternsRequestTypedDict(TypedDict):
limit: NotRequired[int]
r"""Maximum number of interns to return, from 1 through 500."""
status: NotRequired[List[Status]]
- r"""Comma-separated lifecycle statuses to include."""
+ r"""Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed."""
starting_after: NotRequired[str]
r"""The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400."""
workspace_id: NotRequired[str]
@@ -151,7 +151,7 @@ class ListInternsRequest(BaseModel):
Optional[List[Status]],
FieldMetadata(query=QueryParamMetadata(style="form", explode=False)),
] = None
- r"""Comma-separated lifecycle statuses to include."""
+ r"""Comma-separated lifecycle statuses to include, at most 8. Repeats are collapsed."""
starting_after: Annotated[
Optional[str],
diff --git a/uv.lock b/uv.lock
index 46c838ee..0c43653e 100644
--- a/uv.lock
+++ b/uv.lock
@@ -213,7 +213,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.2.8"
+version = "1.2.9"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },