diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index b11d6e83..1d719f29 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: a1823e398ef1b0d3f2314d16c5fd9b22
+ docChecksum: fed338adcb556fa937435793d80ba94a
docVersion: 1.0.0
speakeasyVersion: 1.787.0
generationVersion: 2.914.0
- releaseVersion: 1.3.30
- configChecksum: 6c32822b074d7404007cd6410371ad92
+ releaseVersion: 1.3.31
+ configChecksum: 738c44a70d4bc0a581eb475d9e00b44a
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: a58a3b0f-3113-4cbb-b0f9-e0d218f1de4e
- pristine_commit_hash: e5712c504d02689c881c73522c62e866301ad5b6
- pristine_tree_hash: 82f92d658696b808589f8a8936e23dffe0dffd6b
+ generation_id: e4486bab-3f14-41b9-950a-4706ee83390e
+ pristine_commit_hash: a257bb9e4d3c0171cd432677627c33a729c341e3
+ pristine_tree_hash: d6c495cff3d2ebdeb6878413200337e07c0758be
features:
python:
acceptHeaders: 3.0.0
@@ -6770,6 +6770,14 @@ trackedFiles:
id: b35cae5eacec
last_write_checksum: sha1:6865169ff4445d70d63c674092812b47236f213f
pristine_git_object: 1c0dd3c44cfce8b531e7d89e3db6b2787f060984
+ docs/components/signinterndaemonrequest.mdx:
+ id: a611533bd5da
+ last_write_checksum: sha1:9b4ac1fc0b10f73949fa916c7a6413f1dd4e31dc
+ pristine_git_object: b4bf06967824c3ac778856a8b32cb08a9dd980d6
+ docs/components/signinterndaemonresponse.mdx:
+ id: e86dd4c94fe2
+ last_write_checksum: sha1:ae1a817ee130d525983e7d42615ac7a64ba4cdff
+ pristine_git_object: d989162b01084a3c272851642eab332009f68512
docs/components/sourcecontent.mdx:
id: d211413b56ad
last_write_checksum: sha1:e9ec235c28760da429e35fea006321e7a697e5c4
@@ -9634,6 +9642,30 @@ trackedFiles:
id: 8cb7359a629c
last_write_checksum: sha1:710032d2b0328c856d9cf6d6eca279e0b960ff6f
pristine_git_object: ed3d7a92aa56dde65beae92df86cf13120828823
+ docs/operations/signinterndaemonaccessrequestglobals.mdx:
+ id: 1a602cb7d11c
+ last_write_checksum: sha1:dafefd3670d65ba25311c15b08bd8fe4e8562347
+ pristine_git_object: 44569250d14f0af8f285b8edfe5fc9e001f1734e
+ docs/operations/signinterndaemonaccessrequestrequest.mdx:
+ id: b63efa5c132a
+ last_write_checksum: sha1:f05a17482ae2e9b30edea70126de56e3df34ab08
+ pristine_git_object: 1816b60921ef83f3207beba0975993150eba03a4
+ docs/operations/signinterndaemonaccessrequestresponse.mdx:
+ id: 376bcab67c47
+ last_write_checksum: sha1:c22e81b089b238af149e20a0390e66864201beee
+ pristine_git_object: 83bc490dc949459b77506634f53641ee5759f299
+ docs/operations/signinterndaemonrequestglobals.mdx:
+ id: 2ac9596ea11e
+ last_write_checksum: sha1:fb71d14710a92f289a68a73ea93c41fd054ae07a
+ pristine_git_object: 488b9b0634191177b8056fb5da2e6fb5157fcde6
+ docs/operations/signinterndaemonrequestrequest.mdx:
+ id: c2a6b27c1efc
+ last_write_checksum: sha1:62426c2aa3396d8bcb9416f96cf04faca0c16bc8
+ pristine_git_object: afc21adef7f04407021d824320cdfe922e5f800b
+ docs/operations/signinterndaemonrequestresponse.mdx:
+ id: 40881c9760b3
+ last_write_checksum: sha1:36a052827336abc6d1d29f49e05845ed70a5cfc2
+ pristine_git_object: 0686965805d5901fff3ddbe4e13dc6ee4204c138
docs/operations/source.mdx:
id: 53486739ebf2
last_write_checksum: sha1:ed574764fc3d9c85d55705aee27616e3de0c8fcc
@@ -9948,8 +9980,8 @@ trackedFiles:
pristine_git_object: 08c687694efbecf50406ae7929029d39fb121295
docs/sdks/interns/README.mdx:
id: 2f8a053ffe78
- last_write_checksum: sha1:756054e3c8016bf0e6297544fbc0e997820108f7
- pristine_git_object: 93cafb95428d42245c9ebdee0e464cc3487a777d
+ last_write_checksum: sha1:8008b93f37978808ea5c850f57a93653fd897da1
+ pristine_git_object: b90fc698bfe2b3fc3fa0b06699a33e4e158aef22
docs/sdks/models/README.mdx:
id: 58f1ca464e0b
last_write_checksum: sha1:093dd30ebdd18b9763a6956915e0dcae4ae7d5e5
@@ -10024,8 +10056,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:191e980556ab005b582724fda8862fa7e9dd2a7f
- pristine_git_object: 00261de997c35f0431250332a436fc423f3fdab7
+ last_write_checksum: sha1:f0cd2fa4f851f4411afb3f6ae9c07ad2b43eae10
+ pristine_git_object: ac6f28ff1f0e6ca9f41f16c1ab3d9557fda88c3a
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -10052,8 +10084,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:85c2e2691703e999424c2d82d6a4f6460da0e37f
- pristine_git_object: 1681aded2d66dca4cbdca580fe23d25a9329128b
+ last_write_checksum: sha1:aec5bd12e62f41511f30881ea1e3297fb992da2a
+ pristine_git_object: 156c6eb6c4130181de9fc4d55df6ba1bcd570fe4
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:30f55a360f41376ab194b9ea725fe4e001a5ae1a
@@ -10100,8 +10132,8 @@ trackedFiles:
pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:cb293302abf5e8150c7354edf5d8e577ac5ef748
- pristine_git_object: 531cae292be19fde0a57120c2dcd106c4c11fad5
+ last_write_checksum: sha1:650a38893185b857e33b7beff6d6aec857b9d56c
+ pristine_git_object: 87358e71caed4071ac708ef914b7c35878f89e75
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c
@@ -12958,6 +12990,14 @@ trackedFiles:
id: 6d6e8d7d80ad
last_write_checksum: sha1:d065afdd505a8303f6ba8e268cef42a3e9ea39fb
pristine_git_object: 418953ba7366a6015934bf8795178d79adb03b89
+ src/openrouter/components/signinterndaemonrequest.py:
+ id: 20aab639ddf2
+ last_write_checksum: sha1:eb60468372e72512d198e78705dbd254dafe56c9
+ pristine_git_object: 4d2f78f63e022201fb7729a1e218a4c02a148ffc
+ src/openrouter/components/signinterndaemonresponse.py:
+ id: 206595537b76
+ last_write_checksum: sha1:1903ab3a67f8695273bed9f3fe7e90b9f1aa83f2
+ pristine_git_object: e44305da959380e177fcc2077d0e80ce4d522a57
src/openrouter/components/speechinput.py:
id: 14e46bea4b32
last_write_checksum: sha1:4f2acbfbb0b8df5d8d2d3916f9a081a6143fdf45
@@ -13640,8 +13680,8 @@ trackedFiles:
pristine_git_object: 50643a126668498dd668c7cceb9f78c03d413d32
src/openrouter/interns.py:
id: d18df05c5c6d
- last_write_checksum: sha1:9d720df76dd6cb9656f2b5d35f32500906927a71
- pristine_git_object: 186fde866ebf6bd323a3368d0925bf9453979782
+ last_write_checksum: sha1:0034247cc9ab55bae388b349c880f550c1c8d584
+ pristine_git_object: cfee3dcdd1af583da4be969e51ee53bd43f60208
src/openrouter/models/__init__.py:
id: ed73b93abb3f
last_write_checksum: sha1:932a790ae66ccd7d7022b39c659bcf72a664ebea
@@ -13668,8 +13708,8 @@ trackedFiles:
pristine_git_object: 8680343bbc90107ae6413bd5686012b1fd75d665
src/openrouter/operations/__init__.py:
id: 9afcea1e7161
- last_write_checksum: sha1:fbaaabfe450b4ea3cb7b49f65330156f294f7e80
- pristine_git_object: 26d0facba62aa9afca7117557e9f45b8221e38e1
+ last_write_checksum: sha1:69f2394d6b0644c50c2f21349f2fd0617622ade0
+ pristine_git_object: f4753e5e03a329e4732821e00a353f60ad03e884
src/openrouter/operations/activateprivateendpoint.py:
id: 3b39eec5d66f
last_write_checksum: sha1:9406e6b3d38c82895fd795f637702ef579cc6d36
@@ -14190,6 +14230,14 @@ trackedFiles:
id: d9fee71bb577
last_write_checksum: sha1:0cba4011b8e305270ac30f88cb7ab59b6aefe619
pristine_git_object: b065e38c8d449348c4d133004653607e4194da6e
+ src/openrouter/operations/signinterndaemonaccessrequest.py:
+ id: 2f8731a56620
+ last_write_checksum: sha1:18b0b35071bad75696c99ec74b9cc5cd665f2299
+ pristine_git_object: 8334ef4145ebd6f7f446b7ea9263b7a893480a6d
+ src/openrouter/operations/signinterndaemonrequest.py:
+ id: 768271b5b2b1
+ last_write_checksum: sha1:9fa390699ade711e992e3c86e77c877c964cc98f
+ pristine_git_object: 45e6c39309940d5c3000570dbfb923a19872f0dc
src/openrouter/operations/storeinternvaultsecret.py:
id: 59c0352c6d20
last_write_checksum: sha1:60af864dcc1d9140f04957a1b5308de2bee9833e
@@ -18335,5 +18383,40 @@ examples:
application/json: {"error": {"code": 404, "message": "Resource not found"}}
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
+ signInternDaemonAccessRequest:
+ speakeasy-default-sign-intern-daemon-access-request:
+ parameters:
+ path:
+ internId: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
+ requestBody:
+ application/json: {"bodySha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
+ responses:
+ "200":
+ application/json: {"x-ori-invoke-signature": "MEUCIQ...", "x-ori-invoke-timestamp": "1789000000", "x-ori-invoke-user": "user_2abc"}
+ "400":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "429":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "500":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ signInternDaemonRequest:
+ speakeasy-default-sign-intern-daemon-request:
+ parameters:
+ path:
+ internId: "7c9e6679-7425-40de-944b-e07fc1f90ae7"
+ requestBody:
+ application/json: {"bodySha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}
+ responses:
+ "200":
+ application/json: {"x-ori-invoke-signature": "MEUCIQ...", "x-ori-invoke-timestamp": "1789000000", "x-ori-invoke-user": "user_2abc"}
+ "400":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "429":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
+ "500":
+ application/json: {"error": {"code": 404, "message": "Intern not found"}}
examplesVersion: 1.0.2
-releaseNotes: "## Python SDK Changes:\n* `open_router.presets.create_presets_responses()`: \n * `request.input.union(Array<>)[]` **Changed**\n* `open_router.responses.send()`: \n * `request.input.union(Array<>)[]` **Changed**\n* `open_router.beta.responses.send()`: \n * `request.input.union(Array<>)[]` **Changed**\n"
+releaseNotes: |
+ ## Python SDK Changes:
+ * `open_router.interns.sign_intern_daemon_access_request()`: **Added**
+ * `open_router.interns.sign_intern_daemon_request()`: **Added**
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 35081ed1..328ecddf 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -36,7 +36,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.3.30
+ version: 1.3.31
additionalDependencies:
dev: {}
main: {}
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 2dfbbb7a..d891e8b1 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -28839,6 +28839,39 @@ components:
oneOf:
- $ref: '#/components/schemas/ContainerAutoEnvironment'
- $ref: '#/components/schemas/ContainerReferenceEnvironment'
+ SignInternDaemonRequest:
+ additionalProperties: false
+ properties:
+ bodySha256:
+ description: 'Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.'
+ example: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
+ pattern: '^[0-9a-f]{64}$'
+ type: 'string'
+ required:
+ - 'bodySha256'
+ type: 'object'
+ SignInternDaemonResponse:
+ additionalProperties: false
+ description: 'Headers the CLI copies onto the daemon request so the sidecar can verify who is asking.'
+ example:
+ x-ori-invoke-signature: 'MEUCIQ...'
+ x-ori-invoke-timestamp: '1789000000'
+ x-ori-invoke-user: 'user_2abc'
+ properties:
+ x-ori-invoke-signature:
+ description: 'Base64 Ed25519 signature over the intern id, timestamp, user and body digest.'
+ type: 'string'
+ x-ori-invoke-timestamp:
+ description: 'Unix seconds at signing; the daemon refuses proofs older than its window.'
+ type: 'string'
+ x-ori-invoke-user:
+ description: 'The verified OAuth subject the proof names. Never taken from the request.'
+ type: 'string'
+ required:
+ - 'x-ori-invoke-signature'
+ - 'x-ori-invoke-timestamp'
+ - 'x-ori-invoke-user'
+ type: 'object'
SpeechInput:
anyOf:
- type: 'string'
@@ -42437,6 +42470,323 @@ paths:
- $ref: "#/components/parameters/AppIdentifier"
- $ref: "#/components/parameters/AppDisplayName"
- $ref: "#/components/parameters/AppCategories"
+ /interns/{internId}/daemon-access/sign:
+ post:
+ deprecated: true
+ description: 'Deprecated alias of `POST /interns/{internId}/daemon/sign` with the same request, response, and errors. The API key selects the caller, workspace and visible interns. An intern''s own API key sees only that intern: the collection and every other intern answer 404 to it. 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: 'signInternDaemonAccessRequest'
+ parameters:
+ - description: 'ID of an intern visible to the authenticated API key.'
+ in: 'path'
+ name: 'internId'
+ required: true
+ schema:
+ description: 'ID of an intern visible to the authenticated API key.'
+ example: '7c9e6679-7425-40de-944b-e07fc1f90ae7'
+ minLength: 1
+ type: 'string'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SignInternDaemonRequest'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SignInternDaemonResponse'
+ description: 'Signature headers for the digest.'
+ '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:
+ example:
+ error:
+ code: 401
+ message: 'Invalid or missing API key'
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'Missing, unknown or provisioning API key.'
+ '403':
+ content:
+ application/json:
+ example:
+ error:
+ code: 403
+ message: 'Personal connections require ori login --oidc.'
+ metadata:
+ reason: 'personal_identity_required'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The caller is an API key, which names no person (`personal_identity_required`), or an OAuth grant without `vault:read` (`insufficient_scope`). Also returned when the key owner no longer has access or the request used a regional hostname.'
+ '404':
+ content:
+ application/json:
+ example:
+ error:
+ 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.'
+ '408':
+ content:
+ application/json:
+ example:
+ error:
+ code: 408
+ 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.'
+ '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.'
+ '415':
+ content:
+ application/json:
+ example:
+ error:
+ code: 415
+ message: 'Request body must be sent as application/json'
+ metadata:
+ reason: 'unsupported_media_type'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is non-empty and its Content-Type is not application/json.'
+ '429':
+ content:
+ application/json:
+ example:
+ error:
+ code: 429
+ message: 'Too many intern turns. Please wait a moment.'
+ metadata:
+ reason: 'rate_limited'
+ retryable: true
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'Too many turns for the user or organization this credential acts as (`rate_limited`). Shares the chat turn limiter, 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'
+ '500':
+ content:
+ application/json:
+ example:
+ 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. `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: 'Sign a daemon request with the caller''s identity (deprecated alias)'
+ tags:
+ - 'Interns'
+ parameters:
+ - $ref: "#/components/parameters/AppIdentifier"
+ - $ref: "#/components/parameters/AppDisplayName"
+ - $ref: "#/components/parameters/AppCategories"
+ /interns/{internId}/daemon/sign:
+ post:
+ description: 'Signs the SHA-256 digest of one request the CLI is about to send to the intern daemon, binding it to the intern and to the signed-in member so personal connections resolve. Only an OAuth session from `ori login --oidc` whose grant carries `vault:read` can sign: an API key is refused with 403 because it names no person, and an `interns`-only grant is refused with 403 because a proof releases that user''s personal connections. The route is behind the same gate as chat and counts against the chat turn limiter. The response is sent with `Cache-Control: no-store`. The API key selects the caller, workspace and visible interns. An intern''s own API key sees only that intern: the collection and every other intern answer 404 to it. 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: 'signInternDaemonRequest'
+ parameters:
+ - description: 'ID of an intern visible to the authenticated API key.'
+ in: 'path'
+ name: 'internId'
+ required: true
+ schema:
+ description: 'ID of an intern visible to the authenticated API key.'
+ example: '7c9e6679-7425-40de-944b-e07fc1f90ae7'
+ minLength: 1
+ type: 'string'
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SignInternDaemonRequest'
+ required: true
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SignInternDaemonResponse'
+ description: 'Signature headers for the digest.'
+ '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:
+ example:
+ error:
+ code: 401
+ message: 'Invalid or missing API key'
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'Missing, unknown or provisioning API key.'
+ '403':
+ content:
+ application/json:
+ example:
+ error:
+ code: 403
+ message: 'Personal connections require ori login --oidc.'
+ metadata:
+ reason: 'personal_identity_required'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The caller is an API key, which names no person (`personal_identity_required`), or an OAuth grant without `vault:read` (`insufficient_scope`). Also returned when the key owner no longer has access or the request used a regional hostname.'
+ '404':
+ content:
+ application/json:
+ example:
+ error:
+ 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.'
+ '408':
+ content:
+ application/json:
+ example:
+ error:
+ code: 408
+ 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.'
+ '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.'
+ '415':
+ content:
+ application/json:
+ example:
+ error:
+ code: 415
+ message: 'Request body must be sent as application/json'
+ metadata:
+ reason: 'unsupported_media_type'
+ retryable: false
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'The request body is non-empty and its Content-Type is not application/json.'
+ '429':
+ content:
+ application/json:
+ example:
+ error:
+ code: 429
+ message: 'Too many intern turns. Please wait a moment.'
+ metadata:
+ reason: 'rate_limited'
+ retryable: true
+ schema:
+ $ref: '#/components/schemas/InternLifecycleError'
+ description: 'Too many turns for the user or organization this credential acts as (`rate_limited`). Shares the chat turn limiter, 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'
+ '500':
+ content:
+ application/json:
+ example:
+ 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. `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: 'Sign a daemon request with the caller''s identity'
+ tags:
+ - 'Interns'
+ parameters:
+ - $ref: "#/components/parameters/AppIdentifier"
+ - $ref: "#/components/parameters/AppDisplayName"
+ - $ref: "#/components/parameters/AppCategories"
/interns/{internId}/invoke:
post:
description: "Starts a run on one of your interns and answers `202` with the `session_id` as soon as the intern accepts it. The run keeps going on the intern after the response. Nothing about its progress comes back on this request; the intern reports through its own tools, such as Slack.\n\nSend the same `session_id` later to continue the conversation, for example to hand the intern a decision on work it started. If that session already has a run going, the prompt is delivered into it and the status is `steered`. A `session_id` is accepted only from the caller it was issued to, on the same intern; any other, including sessions started from Slack or the chat endpoint, is refused with `404`.\n\nRuns started here self-drive: the intern consents to its own tool approvals, and a question it asks is answered by its own fallback. A run ends when the intern finishes it or after its execution deadline (1 hour by default).\n\nAvailable to interns programme members. Callers outside the programme receive `404` for every path under `/api/v1/interns`."
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 9ecbb9a9..9fdbfad1 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:4f7d856e5b6cc802e2402204573da0cf25747750110b71d92b4f6cc6d9a0f1b2
- sourceBlobDigest: sha256:32d1edb3551b9e15b5e46f7a205f92e832f2ed613979eb3475e8d1a35d3c0c9a
+ sourceRevisionDigest: sha256:76890df717c5d864669ff4732632fe4145cabb3ed31617eccaf999341049a3f3
+ sourceBlobDigest: sha256:7577bdc8b53accc00faa0214440c09a0fb4b5b4ba6600380c963a853c700b801
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:4f7d856e5b6cc802e2402204573da0cf25747750110b71d92b4f6cc6d9a0f1b2
- sourceBlobDigest: sha256:32d1edb3551b9e15b5e46f7a205f92e832f2ed613979eb3475e8d1a35d3c0c9a
+ sourceRevisionDigest: sha256:76890df717c5d864669ff4732632fe4145cabb3ed31617eccaf999341049a3f3
+ sourceBlobDigest: sha256:7577bdc8b53accc00faa0214440c09a0fb4b5b4ba6600380c963a853c700b801
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:5f4f4e8d4e0cf27a769328aa97641bf05eda5ee1098329f37a77e4fffd07a8d7
+ codeSamplesRevisionDigest: sha256:f0e4ca5a5b5b0a21317aeb706e04fee0cc360a6ef52eb30b1e8fc81dea1cc3d6
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.787.0
diff --git a/RELEASES.md b/RELEASES.md
index 978b1aca..eb98b31e 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -3069,4 +3069,14 @@ Based on:
### Generated
- [python v1.3.30] .
### Releases
-- [PyPI v1.3.30] https://pypi.org/project/openrouter/1.3.30 - .
\ No newline at end of file
+- [PyPI v1.3.30] https://pypi.org/project/openrouter/1.3.30 - .
+
+## 2026-10-07 14:08:50
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.3.31] .
+### Releases
+- [PyPI v1.3.31] https://pypi.org/project/openrouter/1.3.31 - .
\ No newline at end of file
diff --git a/docs/components/signinterndaemonrequest.mdx b/docs/components/signinterndaemonrequest.mdx
new file mode 100644
index 00000000..5ed4ce9b
--- /dev/null
+++ b/docs/components/signinterndaemonrequest.mdx
@@ -0,0 +1,9 @@
+---
+title: "SignInternDaemonRequest"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
+| `body_sha256` | *str* | ✅ | Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body. | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
\ No newline at end of file
diff --git a/docs/components/signinterndaemonresponse.mdx b/docs/components/signinterndaemonresponse.mdx
new file mode 100644
index 00000000..5da8e2ee
--- /dev/null
+++ b/docs/components/signinterndaemonresponse.mdx
@@ -0,0 +1,14 @@
+---
+title: "SignInternDaemonResponse"
+---
+
+Headers the CLI copies onto the daemon request so the sidecar can verify who is asking.
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
+| `x_ori_invoke_signature` | *str* | ✅ | Base64 Ed25519 signature over the intern id, timestamp, user and body digest. |
+| `x_ori_invoke_timestamp` | *str* | ✅ | Unix seconds at signing; the daemon refuses proofs older than its window. |
+| `x_ori_invoke_user` | *str* | ✅ | The verified OAuth subject the proof names. Never taken from the request. |
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonaccessrequestglobals.mdx b/docs/operations/signinterndaemonaccessrequestglobals.mdx
new file mode 100644
index 00000000..38e57362
--- /dev/null
+++ b/docs/operations/signinterndaemonaccessrequestglobals.mdx
@@ -0,0 +1,11 @@
+---
+title: "SignInternDaemonAccessRequestGlobals"
+---
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
|
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
|
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonaccessrequestrequest.mdx b/docs/operations/signinterndaemonaccessrequestrequest.mdx
new file mode 100644
index 00000000..bad49873
--- /dev/null
+++ b/docs/operations/signinterndaemonaccessrequestrequest.mdx
@@ -0,0 +1,13 @@
+---
+title: "SignInternDaemonAccessRequestRequest"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `intern_id` | *str* | ✅ | ID of an intern visible to the authenticated API key. | 7c9e6679-7425-40de-944b-e07fc1f90ae7 |
+| `sign_intern_daemon_request` | [components.SignInternDaemonRequest](../components/signinterndaemonrequest.mdx) | ✅ | N/A | |
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonaccessrequestresponse.mdx b/docs/operations/signinterndaemonaccessrequestresponse.mdx
new file mode 100644
index 00000000..6e1f966a
--- /dev/null
+++ b/docs/operations/signinterndaemonaccessrequestresponse.mdx
@@ -0,0 +1,10 @@
+---
+title: "SignInternDaemonAccessRequestResponse"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
+| `headers` | Dict[str, List[*str*]] | ✅ | N/A | |
+| `result` | [components.SignInternDaemonResponse](../components/signinterndaemonresponse.mdx) | ✅ | N/A | \{
"x-ori-invoke-signature": "MEUCIQ...",
"x-ori-invoke-timestamp": "1789000000",
"x-ori-invoke-user": "user_2abc"
} |
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonrequestglobals.mdx b/docs/operations/signinterndaemonrequestglobals.mdx
new file mode 100644
index 00000000..4d4018db
--- /dev/null
+++ b/docs/operations/signinterndaemonrequestglobals.mdx
@@ -0,0 +1,11 @@
+---
+title: "SignInternDaemonRequestGlobals"
+---
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
|
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
|
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonrequestrequest.mdx b/docs/operations/signinterndaemonrequestrequest.mdx
new file mode 100644
index 00000000..29a5ad13
--- /dev/null
+++ b/docs/operations/signinterndaemonrequestrequest.mdx
@@ -0,0 +1,13 @@
+---
+title: "SignInternDaemonRequestRequest"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `intern_id` | *str* | ✅ | ID of an intern visible to the authenticated API key. | 7c9e6679-7425-40de-944b-e07fc1f90ae7 |
+| `sign_intern_daemon_request` | [components.SignInternDaemonRequest](../components/signinterndaemonrequest.mdx) | ✅ | N/A | |
\ No newline at end of file
diff --git a/docs/operations/signinterndaemonrequestresponse.mdx b/docs/operations/signinterndaemonrequestresponse.mdx
new file mode 100644
index 00000000..7d427767
--- /dev/null
+++ b/docs/operations/signinterndaemonrequestresponse.mdx
@@ -0,0 +1,10 @@
+---
+title: "SignInternDaemonRequestResponse"
+---
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
+| `headers` | Dict[str, List[*str*]] | ✅ | N/A | |
+| `result` | [components.SignInternDaemonResponse](../components/signinterndaemonresponse.mdx) | ✅ | N/A | \{
"x-ori-invoke-signature": "MEUCIQ...",
"x-ori-invoke-timestamp": "1789000000",
"x-ori-invoke-user": "user_2abc"
} |
\ No newline at end of file
diff --git a/docs/sdks/interns/README.mdx b/docs/sdks/interns/README.mdx
index bc6a3e87..a7bd746b 100644
--- a/docs/sdks/interns/README.mdx
+++ b/docs/sdks/interns/README.mdx
@@ -16,6 +16,8 @@ Create, inspect, update, provision, suspend and delete OpenRouter interns throug
* [update_intern](#update_intern) - Update an intern
* [get_intern_daemon](#get_intern_daemon) - Get an intern's daemon access
* [~~get_intern_daemon_access~~](#get_intern_daemon_access) - Get an intern's daemon access (deprecated alias) ⚠️ **Deprecated**
+* [~~sign_intern_daemon_access_request~~](#sign_intern_daemon_access_request) - Sign a daemon request with the caller's identity (deprecated alias) ⚠️ **Deprecated**
+* [sign_intern_daemon_request](#sign_intern_daemon_request) - Sign a daemon request with the caller's identity
* [provision_intern](#provision_intern) - Provision an intern
* [suspend_intern](#suspend_intern) - Suspend an intern
* [chat](#chat) - Stream a chat completion with an intern
@@ -366,6 +368,106 @@ with OpenRouter(
| errors.InternLifecycleError | 500 | application/json |
| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+## ~~sign_intern_daemon_access_request~~
+
+Deprecated alias of `POST /interns/{internId}/daemon/sign` with the same request, response, and errors. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
+
+> ⚠️ **DEPRECATED**: This will be removed in a future release, please migrate away from it as soon as possible.
+
+### Example Usage
+
+```python
+from openrouter import OpenRouter
+import os
+
+
+with OpenRouter(
+ http_referer="",
+ x_open_router_title="",
+ x_open_router_categories="",
+ api_key=os.getenv("OPENROUTER_API_KEY", ""),
+) as open_router:
+
+ res = open_router.interns.sign_intern_daemon_access_request(intern_id="7c9e6679-7425-40de-944b-e07fc1f90ae7", body_sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
+
+ # Handle response
+ print(res)
+
+```
+
+### Parameters
+
+| Parameter | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `intern_id` | *str* | ✅ | ID of an intern visible to the authenticated API key. | 7c9e6679-7425-40de-944b-e07fc1f90ae7 |
+| `body_sha256` | *str* | ✅ | Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body. | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
+
+### Response
+
+**[operations.SignInternDaemonAccessRequestResponse](../../operations/signinterndaemonaccessrequestresponse.mdx)**
+
+### Errors
+
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternLifecycleError | 400, 401, 403, 404, 408, 413, 415 | application/json |
+| errors.InternLifecycleError | 429 | application/json |
+| errors.InternLifecycleError | 500 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+
+## sign_intern_daemon_request
+
+Signs the SHA-256 digest of one request the CLI is about to send to the intern daemon, binding it to the intern and to the signed-in member so personal connections resolve. Only an OAuth session from `ori login --oidc` whose grant carries `vault:read` can sign: an API key is refused with 403 because it names no person, and an `interns`-only grant is refused with 403 because a proof releases that user's personal connections. The route is behind the same gate as chat and counts against the chat turn limiter. The response is sent with `Cache-Control: no-store`. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. 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
+
+```python
+from openrouter import OpenRouter
+import os
+
+
+with OpenRouter(
+ http_referer="",
+ x_open_router_title="",
+ x_open_router_categories="",
+ api_key=os.getenv("OPENROUTER_API_KEY", ""),
+) as open_router:
+
+ res = open_router.interns.sign_intern_daemon_request(intern_id="7c9e6679-7425-40de-944b-e07fc1f90ae7", body_sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
+
+ # Handle response
+ print(res)
+
+```
+
+### Parameters
+
+| Parameter | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `intern_id` | *str* | ✅ | ID of an intern visible to the authenticated API key. | 7c9e6679-7425-40de-944b-e07fc1f90ae7 |
+| `body_sha256` | *str* | ✅ | Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body. | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
+| `http_referer` | *Optional[str]* | ➖ | 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]* | ➖ | The app display name allows you to customize how your app appears in OpenRouter's dashboard.
| |
+| `x_open_router_categories` | *Optional[str]* | ➖ | Comma-separated list of app categories (e.g. "cli-agent,cloud-agent"). Used for marketplace rankings.
| |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | ➖ | Configuration to override the default retry behavior of the client. | |
+
+### Response
+
+**[operations.SignInternDaemonRequestResponse](../../operations/signinterndaemonrequestresponse.mdx)**
+
+### Errors
+
+| Error Type | Status Code | Content Type |
+| --------------------------------- | --------------------------------- | --------------------------------- |
+| errors.InternLifecycleError | 400, 401, 403, 404, 408, 413, 415 | application/json |
+| errors.InternLifecycleError | 429 | application/json |
+| errors.InternLifecycleError | 500 | application/json |
+| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* |
+
## provision_intern
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. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. There is no default workspace fallback. Requests on regional hostnames such as `eu.openrouter.ai` are refused. [API key](/docs/api-reference/authentication) required.
diff --git a/pyproject.toml b/pyproject.toml
index 00261de9..ac6f28ff 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.3.30"
+version = "1.3.31"
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 1681aded..156c6eb6 100644
--- a/src/openrouter/_version.py
+++ b/src/openrouter/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
-__version__: str = "1.3.30"
+__version__: str = "1.3.31"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.914.0"
-__user_agent__: str = "speakeasy-sdk/python 1.3.30 2.914.0 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.3.31 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 531cae29..87358e71 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -3827,6 +3827,14 @@
ShellServerToolEnvironment,
ShellServerToolEnvironmentTypedDict,
)
+ from .signinterndaemonrequest import (
+ SignInternDaemonRequest,
+ SignInternDaemonRequestTypedDict,
+ )
+ from .signinterndaemonresponse import (
+ SignInternDaemonResponse,
+ SignInternDaemonResponseTypedDict,
+ )
from .speechinput import SpeechInput, SpeechInputTypedDict
from .speechinputreference import (
SpeechInputReference,
@@ -7039,6 +7047,10 @@
"ShellServerToolOpenRouterTypedDict",
"ShellServerToolType",
"ShellServerToolTypedDict",
+ "SignInternDaemonRequest",
+ "SignInternDaemonRequestTypedDict",
+ "SignInternDaemonResponse",
+ "SignInternDaemonResponseTypedDict",
"SourceContent",
"SourceContentTypedDict",
"SourceType",
@@ -10334,6 +10346,10 @@
"ShellServerToolEngine": ".shellservertoolengine",
"ShellServerToolEnvironment": ".shellservertoolenvironment",
"ShellServerToolEnvironmentTypedDict": ".shellservertoolenvironment",
+ "SignInternDaemonRequest": ".signinterndaemonrequest",
+ "SignInternDaemonRequestTypedDict": ".signinterndaemonrequest",
+ "SignInternDaemonResponse": ".signinterndaemonresponse",
+ "SignInternDaemonResponseTypedDict": ".signinterndaemonresponse",
"SpeechInput": ".speechinput",
"SpeechInputTypedDict": ".speechinput",
"SpeechInputReference": ".speechinputreference",
diff --git a/src/openrouter/components/signinterndaemonrequest.py b/src/openrouter/components/signinterndaemonrequest.py
new file mode 100644
index 00000000..4d2f78f6
--- /dev/null
+++ b/src/openrouter/components/signinterndaemonrequest.py
@@ -0,0 +1,22 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.types import BaseModel
+import pydantic
+from typing_extensions import Annotated, TypedDict
+
+
+class SignInternDaemonRequestTypedDict(TypedDict):
+ body_sha256: str
+ r"""Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body."""
+
+
+class SignInternDaemonRequest(BaseModel):
+ body_sha256: Annotated[str, pydantic.Field(alias="bodySha256")]
+ r"""Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body."""
+
+
+try:
+ SignInternDaemonRequest.model_rebuild()
+except NameError:
+ pass
diff --git a/src/openrouter/components/signinterndaemonresponse.py b/src/openrouter/components/signinterndaemonresponse.py
new file mode 100644
index 00000000..e44305da
--- /dev/null
+++ b/src/openrouter/components/signinterndaemonresponse.py
@@ -0,0 +1,40 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.types import BaseModel
+import pydantic
+from typing_extensions import Annotated, TypedDict
+
+
+class SignInternDaemonResponseTypedDict(TypedDict):
+ r"""Headers the CLI copies onto the daemon request so the sidecar can verify who is asking."""
+
+ x_ori_invoke_signature: str
+ r"""Base64 Ed25519 signature over the intern id, timestamp, user and body digest."""
+ x_ori_invoke_timestamp: str
+ r"""Unix seconds at signing; the daemon refuses proofs older than its window."""
+ x_ori_invoke_user: str
+ r"""The verified OAuth subject the proof names. Never taken from the request."""
+
+
+class SignInternDaemonResponse(BaseModel):
+ r"""Headers the CLI copies onto the daemon request so the sidecar can verify who is asking."""
+
+ x_ori_invoke_signature: Annotated[
+ str, pydantic.Field(alias="x-ori-invoke-signature")
+ ]
+ r"""Base64 Ed25519 signature over the intern id, timestamp, user and body digest."""
+
+ x_ori_invoke_timestamp: Annotated[
+ str, pydantic.Field(alias="x-ori-invoke-timestamp")
+ ]
+ r"""Unix seconds at signing; the daemon refuses proofs older than its window."""
+
+ x_ori_invoke_user: Annotated[str, pydantic.Field(alias="x-ori-invoke-user")]
+ r"""The verified OAuth subject the proof names. Never taken from the request."""
+
+
+try:
+ SignInternDaemonResponse.model_rebuild()
+except NameError:
+ pass
diff --git a/src/openrouter/interns.py b/src/openrouter/interns.py
index 186fde86..cfee3dcd 100644
--- a/src/openrouter/interns.py
+++ b/src/openrouter/interns.py
@@ -1967,6 +1967,620 @@ async def get_intern_daemon_access_async(
raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+ @deprecated(
+ "warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
+ )
+ def sign_intern_daemon_access_request(
+ self,
+ *,
+ intern_id: str,
+ body_sha256: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> operations.SignInternDaemonAccessRequestResponse:
+ r"""Sign a daemon request with the caller's identity (deprecated alias)
+
+ Deprecated alias of `POST /interns/{internId}/daemon/sign` with the same request, response, and errors. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. 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.
+
+ :param intern_id: ID of an intern visible to the authenticated API key.
+ :param body_sha256: Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.
+ :param http_referer: 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.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SignInternDaemonAccessRequestRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ intern_id=intern_id,
+ sign_intern_daemon_request=components.SignInternDaemonRequest(
+ body_sha256=body_sha256,
+ ),
+ )
+
+ req = self._build_request(
+ method="POST",
+ path="/interns/{internId}/daemon-access/sign",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=True,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SignInternDaemonAccessRequestGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.sign_intern_daemon_request,
+ False,
+ False,
+ "json",
+ components.SignInternDaemonRequest,
+ ),
+ allow_empty_value=None,
+ allowed_fields=["api_key"],
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = self.do_request(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="signInternDaemonAccessRequest",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Interns"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return operations.SignInternDaemonAccessRequestResponse(
+ result=unmarshal_json_response(
+ components.SignInternDaemonResponse, http_res
+ ),
+ headers={},
+ )
+ if utils.match_response(
+ http_res,
+ ["400", "401", "403", "404", "408", "413", "415"],
+ "application/json",
+ ):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
+ @deprecated(
+ "warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
+ )
+ async def sign_intern_daemon_access_request_async(
+ self,
+ *,
+ intern_id: str,
+ body_sha256: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> operations.SignInternDaemonAccessRequestResponse:
+ r"""Sign a daemon request with the caller's identity (deprecated alias)
+
+ Deprecated alias of `POST /interns/{internId}/daemon/sign` with the same request, response, and errors. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. 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.
+
+ :param intern_id: ID of an intern visible to the authenticated API key.
+ :param body_sha256: Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.
+ :param http_referer: 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.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SignInternDaemonAccessRequestRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ intern_id=intern_id,
+ sign_intern_daemon_request=components.SignInternDaemonRequest(
+ body_sha256=body_sha256,
+ ),
+ )
+
+ req = self._build_request_async(
+ method="POST",
+ path="/interns/{internId}/daemon-access/sign",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=True,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SignInternDaemonAccessRequestGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.sign_intern_daemon_request,
+ False,
+ False,
+ "json",
+ components.SignInternDaemonRequest,
+ ),
+ allow_empty_value=None,
+ allowed_fields=["api_key"],
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = await self.do_request_async(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="signInternDaemonAccessRequest",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Interns"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return operations.SignInternDaemonAccessRequestResponse(
+ result=unmarshal_json_response(
+ components.SignInternDaemonResponse, http_res
+ ),
+ headers={},
+ )
+ if utils.match_response(
+ http_res,
+ ["400", "401", "403", "404", "408", "413", "415"],
+ "application/json",
+ ):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
+ def sign_intern_daemon_request(
+ self,
+ *,
+ intern_id: str,
+ body_sha256: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> operations.SignInternDaemonRequestResponse:
+ r"""Sign a daemon request with the caller's identity
+
+ Signs the SHA-256 digest of one request the CLI is about to send to the intern daemon, binding it to the intern and to the signed-in member so personal connections resolve. Only an OAuth session from `ori login --oidc` whose grant carries `vault:read` can sign: an API key is refused with 403 because it names no person, and an `interns`-only grant is refused with 403 because a proof releases that user's personal connections. The route is behind the same gate as chat and counts against the chat turn limiter. The response is sent with `Cache-Control: no-store`. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. 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.
+
+ :param intern_id: ID of an intern visible to the authenticated API key.
+ :param body_sha256: Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.
+ :param http_referer: 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.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SignInternDaemonRequestRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ intern_id=intern_id,
+ sign_intern_daemon_request=components.SignInternDaemonRequest(
+ body_sha256=body_sha256,
+ ),
+ )
+
+ req = self._build_request(
+ method="POST",
+ path="/interns/{internId}/daemon/sign",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=True,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SignInternDaemonRequestGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.sign_intern_daemon_request,
+ False,
+ False,
+ "json",
+ components.SignInternDaemonRequest,
+ ),
+ allow_empty_value=None,
+ allowed_fields=["api_key"],
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = self.do_request(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="signInternDaemonRequest",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Interns"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return operations.SignInternDaemonRequestResponse(
+ result=unmarshal_json_response(
+ components.SignInternDaemonResponse, http_res
+ ),
+ headers={},
+ )
+ if utils.match_response(
+ http_res,
+ ["400", "401", "403", "404", "408", "413", "415"],
+ "application/json",
+ ):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = utils.stream_to_text(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
+ async def sign_intern_daemon_request_async(
+ self,
+ *,
+ intern_id: str,
+ body_sha256: str,
+ http_referer: Optional[str] = None,
+ x_open_router_title: Optional[str] = None,
+ x_open_router_categories: Optional[str] = None,
+ retries: OptionalNullable[utils.RetryConfig] = UNSET,
+ server_url: Optional[str] = None,
+ timeout_ms: Optional[int] = None,
+ http_headers: Optional[Mapping[str, str]] = None,
+ ) -> operations.SignInternDaemonRequestResponse:
+ r"""Sign a daemon request with the caller's identity
+
+ Signs the SHA-256 digest of one request the CLI is about to send to the intern daemon, binding it to the intern and to the signed-in member so personal connections resolve. Only an OAuth session from `ori login --oidc` whose grant carries `vault:read` can sign: an API key is refused with 403 because it names no person, and an `interns`-only grant is refused with 403 because a proof releases that user's personal connections. The route is behind the same gate as chat and counts against the chat turn limiter. The response is sent with `Cache-Control: no-store`. The API key selects the caller, workspace and visible interns. An intern's own API key sees only that intern: the collection and every other intern answer 404 to it. 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.
+
+ :param intern_id: ID of an intern visible to the authenticated API key.
+ :param body_sha256: Lower-case hex SHA-256 of the exact bytes the CLI will send as the daemon request body.
+ :param http_referer: 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.
+
+ :param x_open_router_title: The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ :param x_open_router_categories: Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ :param retries: Override the default retry configuration for this method
+ :param server_url: Override the default server URL for this method
+ :param timeout_ms: Override the default request timeout configuration for this method in milliseconds
+ :param http_headers: Additional headers to set or replace on requests.
+ """
+ base_url = None
+ url_variables = None
+ if timeout_ms is None:
+ timeout_ms = self.sdk_configuration.timeout_ms
+
+ if server_url is not None:
+ base_url = server_url
+ else:
+ base_url = self._get_url(base_url, url_variables)
+
+ request = operations.SignInternDaemonRequestRequest(
+ http_referer=http_referer,
+ x_open_router_title=x_open_router_title,
+ x_open_router_categories=x_open_router_categories,
+ intern_id=intern_id,
+ sign_intern_daemon_request=components.SignInternDaemonRequest(
+ body_sha256=body_sha256,
+ ),
+ )
+
+ req = self._build_request_async(
+ method="POST",
+ path="/interns/{internId}/daemon/sign",
+ base_url=base_url,
+ url_variables=url_variables,
+ request=request,
+ request_body_required=True,
+ request_has_path_params=True,
+ request_has_query_params=True,
+ user_agent_header="user-agent",
+ accept_header_value="application/json",
+ http_headers=http_headers,
+ _globals=operations.SignInternDaemonRequestGlobals(
+ http_referer=self.sdk_configuration.globals.http_referer,
+ x_open_router_title=self.sdk_configuration.globals.x_open_router_title,
+ x_open_router_categories=self.sdk_configuration.globals.x_open_router_categories,
+ ),
+ security=self.sdk_configuration.security,
+ get_serialized_body=lambda: utils.serialize_request_body(
+ request.sign_intern_daemon_request,
+ False,
+ False,
+ "json",
+ components.SignInternDaemonRequest,
+ ),
+ allow_empty_value=None,
+ allowed_fields=["api_key"],
+ timeout_ms=timeout_ms,
+ )
+
+ if retries == UNSET:
+ if self.sdk_configuration.retry_config is not UNSET:
+ retries = self.sdk_configuration.retry_config
+ else:
+ retries = utils.RetryConfig(
+ "backoff", utils.BackoffStrategy(500, 60000, 1.5, 3600000), True
+ )
+
+ retry_config = None
+ if isinstance(retries, utils.RetryConfig):
+ retry_config = (retries, ["5XX"])
+
+ http_res = await self.do_request_async(
+ hook_ctx=HookContext(
+ config=self.sdk_configuration,
+ base_url=base_url or "",
+ operation_id="signInternDaemonRequest",
+ oauth2_scopes=None,
+ security_source=get_security_from_env(
+ self.sdk_configuration.security, components.Security
+ ),
+ tags=["Interns"],
+ extensions=None,
+ ),
+ request=req,
+ is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
+ retry_config=retry_config,
+ )
+
+ response_data: Any = None
+ if utils.match_response(http_res, "200", "application/json"):
+ return operations.SignInternDaemonRequestResponse(
+ result=unmarshal_json_response(
+ components.SignInternDaemonResponse, http_res
+ ),
+ headers={},
+ )
+ if utils.match_response(
+ http_res,
+ ["400", "401", "403", "404", "408", "413", "415"],
+ "application/json",
+ ):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "429", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "500", "application/json"):
+ response_data = unmarshal_json_response(
+ errors.InternLifecycleErrorData, http_res
+ )
+ raise errors.InternLifecycleError(response_data, http_res)
+ if utils.match_response(http_res, "4XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+ if utils.match_response(http_res, "5XX", "*"):
+ http_res_text = await utils.stream_to_text_async(http_res)
+ raise errors.OpenRouterDefaultError(
+ "API error occurred", http_res, http_res_text
+ )
+
+ raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
+
def provision_intern(
self,
*,
diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py
index 26d0facb..f4753e5e 100644
--- a/src/openrouter/operations/__init__.py
+++ b/src/openrouter/operations/__init__.py
@@ -1041,6 +1041,22 @@
SendChatCompletionRequestResponse,
SendChatCompletionRequestResponseTypedDict,
)
+ from .signinterndaemonaccessrequest import (
+ SignInternDaemonAccessRequestGlobals,
+ SignInternDaemonAccessRequestGlobalsTypedDict,
+ SignInternDaemonAccessRequestRequest,
+ SignInternDaemonAccessRequestRequestTypedDict,
+ SignInternDaemonAccessRequestResponse,
+ SignInternDaemonAccessRequestResponseTypedDict,
+ )
+ from .signinterndaemonrequest import (
+ SignInternDaemonRequestGlobals,
+ SignInternDaemonRequestGlobalsTypedDict,
+ SignInternDaemonRequestRequest,
+ SignInternDaemonRequestRequestTypedDict,
+ SignInternDaemonRequestResponse,
+ SignInternDaemonRequestResponseTypedDict,
+ )
from .storeinternvaultsecret import (
StoreInternVaultSecretGlobals,
StoreInternVaultSecretGlobalsTypedDict,
@@ -1920,6 +1936,18 @@
"SendChatCompletionRequestRequestTypedDict",
"SendChatCompletionRequestResponse",
"SendChatCompletionRequestResponseTypedDict",
+ "SignInternDaemonAccessRequestGlobals",
+ "SignInternDaemonAccessRequestGlobalsTypedDict",
+ "SignInternDaemonAccessRequestRequest",
+ "SignInternDaemonAccessRequestRequestTypedDict",
+ "SignInternDaemonAccessRequestResponse",
+ "SignInternDaemonAccessRequestResponseTypedDict",
+ "SignInternDaemonRequestGlobals",
+ "SignInternDaemonRequestGlobalsTypedDict",
+ "SignInternDaemonRequestRequest",
+ "SignInternDaemonRequestRequestTypedDict",
+ "SignInternDaemonRequestResponse",
+ "SignInternDaemonRequestResponseTypedDict",
"Source",
"Status",
"StoreInternVaultSecretGlobals",
@@ -2804,6 +2832,18 @@
"SendChatCompletionRequestRequestTypedDict": ".sendchatcompletionrequest",
"SendChatCompletionRequestResponse": ".sendchatcompletionrequest",
"SendChatCompletionRequestResponseTypedDict": ".sendchatcompletionrequest",
+ "SignInternDaemonAccessRequestGlobals": ".signinterndaemonaccessrequest",
+ "SignInternDaemonAccessRequestGlobalsTypedDict": ".signinterndaemonaccessrequest",
+ "SignInternDaemonAccessRequestRequest": ".signinterndaemonaccessrequest",
+ "SignInternDaemonAccessRequestRequestTypedDict": ".signinterndaemonaccessrequest",
+ "SignInternDaemonAccessRequestResponse": ".signinterndaemonaccessrequest",
+ "SignInternDaemonAccessRequestResponseTypedDict": ".signinterndaemonaccessrequest",
+ "SignInternDaemonRequestGlobals": ".signinterndaemonrequest",
+ "SignInternDaemonRequestGlobalsTypedDict": ".signinterndaemonrequest",
+ "SignInternDaemonRequestRequest": ".signinterndaemonrequest",
+ "SignInternDaemonRequestRequestTypedDict": ".signinterndaemonrequest",
+ "SignInternDaemonRequestResponse": ".signinterndaemonrequest",
+ "SignInternDaemonRequestResponseTypedDict": ".signinterndaemonrequest",
"StoreInternVaultSecretGlobals": ".storeinternvaultsecret",
"StoreInternVaultSecretGlobalsTypedDict": ".storeinternvaultsecret",
"StoreInternVaultSecretRequest": ".storeinternvaultsecret",
diff --git a/src/openrouter/operations/signinterndaemonaccessrequest.py b/src/openrouter/operations/signinterndaemonaccessrequest.py
new file mode 100644
index 00000000..8334ef41
--- /dev/null
+++ b/src/openrouter/operations/signinterndaemonaccessrequest.py
@@ -0,0 +1,174 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.components import (
+ signinterndaemonrequest as components_signinterndaemonrequest,
+ signinterndaemonresponse as components_signinterndaemonresponse,
+)
+from openrouter.types import BaseModel, UNSET_SENTINEL
+from openrouter.utils import (
+ FieldMetadata,
+ HeaderMetadata,
+ PathParamMetadata,
+ RequestMetadata,
+)
+import pydantic
+from pydantic import model_serializer
+from typing import Dict, List, Optional
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+class SignInternDaemonAccessRequestGlobalsTypedDict(TypedDict):
+ http_referer: NotRequired[str]
+ r"""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: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SignInternDaemonAccessRequestGlobals(BaseModel):
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""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: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ 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
+
+
+class SignInternDaemonAccessRequestRequestTypedDict(TypedDict):
+ intern_id: str
+ r"""ID of an intern visible to the authenticated API key."""
+ sign_intern_daemon_request: (
+ components_signinterndaemonrequest.SignInternDaemonRequestTypedDict
+ )
+ http_referer: NotRequired[str]
+ r"""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: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SignInternDaemonAccessRequestRequest(BaseModel):
+ intern_id: Annotated[
+ str,
+ pydantic.Field(alias="internId"),
+ FieldMetadata(path=PathParamMetadata(style="simple", explode=False)),
+ ]
+ r"""ID of an intern visible to the authenticated API key."""
+
+ sign_intern_daemon_request: Annotated[
+ components_signinterndaemonrequest.SignInternDaemonRequest,
+ FieldMetadata(request=RequestMetadata(media_type="application/json")),
+ ]
+
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""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: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ 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
+
+
+class SignInternDaemonAccessRequestResponseTypedDict(TypedDict):
+ headers: Dict[str, List[str]]
+ result: components_signinterndaemonresponse.SignInternDaemonResponseTypedDict
+
+
+class SignInternDaemonAccessRequestResponse(BaseModel):
+ headers: Dict[str, List[str]]
+
+ result: components_signinterndaemonresponse.SignInternDaemonResponse
diff --git a/src/openrouter/operations/signinterndaemonrequest.py b/src/openrouter/operations/signinterndaemonrequest.py
new file mode 100644
index 00000000..45e6c393
--- /dev/null
+++ b/src/openrouter/operations/signinterndaemonrequest.py
@@ -0,0 +1,174 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from openrouter.components import (
+ signinterndaemonrequest as components_signinterndaemonrequest,
+ signinterndaemonresponse as components_signinterndaemonresponse,
+)
+from openrouter.types import BaseModel, UNSET_SENTINEL
+from openrouter.utils import (
+ FieldMetadata,
+ HeaderMetadata,
+ PathParamMetadata,
+ RequestMetadata,
+)
+import pydantic
+from pydantic import model_serializer
+from typing import Dict, List, Optional
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+class SignInternDaemonRequestGlobalsTypedDict(TypedDict):
+ http_referer: NotRequired[str]
+ r"""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: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SignInternDaemonRequestGlobals(BaseModel):
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""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: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ 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
+
+
+class SignInternDaemonRequestRequestTypedDict(TypedDict):
+ intern_id: str
+ r"""ID of an intern visible to the authenticated API key."""
+ sign_intern_daemon_request: (
+ components_signinterndaemonrequest.SignInternDaemonRequestTypedDict
+ )
+ http_referer: NotRequired[str]
+ r"""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: NotRequired[str]
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+ x_open_router_categories: NotRequired[str]
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+
+class SignInternDaemonRequestRequest(BaseModel):
+ intern_id: Annotated[
+ str,
+ pydantic.Field(alias="internId"),
+ FieldMetadata(path=PathParamMetadata(style="simple", explode=False)),
+ ]
+ r"""ID of an intern visible to the authenticated API key."""
+
+ sign_intern_daemon_request: Annotated[
+ components_signinterndaemonrequest.SignInternDaemonRequest,
+ FieldMetadata(request=RequestMetadata(media_type="application/json")),
+ ]
+
+ http_referer: Annotated[
+ Optional[str],
+ pydantic.Field(alias="HTTP-Referer"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""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: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Title"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""The app display name allows you to customize how your app appears in OpenRouter's dashboard.
+
+ """
+
+ x_open_router_categories: Annotated[
+ Optional[str],
+ pydantic.Field(alias="X-OpenRouter-Categories"),
+ FieldMetadata(header=HeaderMetadata(style="simple", explode=False)),
+ ] = None
+ r"""Comma-separated list of app categories (e.g. \"cli-agent,cloud-agent\"). Used for marketplace rankings.
+
+ """
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(
+ ["HTTP-Referer", "X-OpenRouter-Title", "X-OpenRouter-Categories"]
+ )
+ 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
+
+
+class SignInternDaemonRequestResponseTypedDict(TypedDict):
+ headers: Dict[str, List[str]]
+ result: components_signinterndaemonresponse.SignInternDaemonResponseTypedDict
+
+
+class SignInternDaemonRequestResponse(BaseModel):
+ headers: Dict[str, List[str]]
+
+ result: components_signinterndaemonresponse.SignInternDaemonResponse
diff --git a/uv.lock b/uv.lock
index 0a12b503..83df5cf9 100644
--- a/uv.lock
+++ b/uv.lock
@@ -213,7 +213,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.3.30"
+version = "1.3.31"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },