From 6d345808ea5ed4bafc556687486d8dfc41c15d2b Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Wed, 23 Sep 2026 17:26:28 +0000 Subject: [PATCH 1/2] ## Python SDK Changes: * `open_router.interns.invoke()`: **Added** --- .speakeasy/gen.lock | 94 ++++- .speakeasy/gen.yaml | 2 +- .speakeasy/out.openapi.yaml | 253 ++++++++++++++ .speakeasy/workflow.lock | 10 +- RELEASES.md | 12 +- .../interninvokeacceptedresponse.mdx | 13 + .../interninvokeacceptedresponsestatus.mdx | 22 ++ docs/components/interninvokerequest.mdx | 13 + docs/operations/invokeinternglobals.mdx | 11 + docs/operations/invokeinternrequest.mdx | 13 + docs/operations/invokeinternresponse.mdx | 10 + docs/sdks/interns/README.mdx | 60 +++- pyproject.toml | 2 +- src/openrouter/_version.py | 4 +- src/openrouter/components/__init__.py | 16 + .../interninvokeacceptedresponse.py | 35 ++ .../components/interninvokerequest.py | 42 +++ src/openrouter/interns.py | 328 ++++++++++++++++++ src/openrouter/operations/__init__.py | 20 ++ src/openrouter/operations/invokeintern.py | 174 ++++++++++ uv.lock | 2 +- 21 files changed, 1105 insertions(+), 31 deletions(-) create mode 100644 docs/components/interninvokeacceptedresponse.mdx create mode 100644 docs/components/interninvokeacceptedresponsestatus.mdx create mode 100644 docs/components/interninvokerequest.mdx create mode 100644 docs/operations/invokeinternglobals.mdx create mode 100644 docs/operations/invokeinternrequest.mdx create mode 100644 docs/operations/invokeinternresponse.mdx create mode 100644 src/openrouter/components/interninvokeacceptedresponse.py create mode 100644 src/openrouter/components/interninvokerequest.py create mode 100644 src/openrouter/operations/invokeintern.py diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index d7f6ed32..e2d7a0dc 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: 468cf191c8bcc65f5a8ce3e0018e2823 + docChecksum: 6e123cb0ea767ec1dfe22b6d5a22eb03 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.2.20 - configChecksum: 86ac2705440475f5369e51fcfea3b0e5 + releaseVersion: 1.2.21 + configChecksum: a5d71454cf56db3056ccd04663866372 repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: a5787b67-da19-4251-bef1-23ae549f5bd3 - pristine_commit_hash: 89e300f89f43145c9c2987065e24dac97a46e476 - pristine_tree_hash: b00ab492d6721240922d381ea1d29ff19a68a3ca + generation_id: 58d82779-89cb-4b09-bf67-c46027d7304d + pristine_commit_hash: ea160db099b23c803386dce65f0700209fa185e7 + pristine_tree_hash: cf523b00e4d3d9d56f5e8d59507ec599ed3eb8fa features: python: acceptHeaders: 3.0.0 @@ -3105,6 +3105,18 @@ trackedFiles: id: b314b250af70 last_write_checksum: sha1:22c9aaa210f59e0d4845a03a268b6ba879fb4132 pristine_git_object: 4a98d72416014765c3e6b38b7b5eae9cbc8e2f34 + docs/components/interninvokeacceptedresponse.mdx: + id: fabf6978427d + last_write_checksum: sha1:2a29dff72ed9ef5438d4269be8b2c0ad2cb21569 + pristine_git_object: bcec63f8d6fc92f2230d08620555507ecbc60fd4 + docs/components/interninvokeacceptedresponsestatus.mdx: + id: 15a13a755d2e + last_write_checksum: sha1:1380143cde9259d756032888c9c8d50de0c97b1b + pristine_git_object: ac3cd774ee80c6b2e84441a7f51bf02e4ab68139 + docs/components/interninvokerequest.mdx: + id: f6cb5da6d6df + last_write_checksum: sha1:700c5215fb1d51ef1a9dd540ff59277b441d10b4 + pristine_git_object: 01ec56d1b224be02f4569c6035ed1d90c5c1f726 docs/components/internlifecycleerrorerror.mdx: id: 501146f0d87d last_write_checksum: sha1:044b3295aa55836ed6b018679d1e8d6558bd33ec @@ -7385,6 +7397,18 @@ trackedFiles: id: fa09ca81a05c last_write_checksum: sha1:6126fc355e98574f157b9b485ac850a0ec6f2a5e pristine_git_object: 2394952123e253a775bb81426d6ee2d49911e97b + docs/operations/invokeinternglobals.mdx: + id: 9095c942b3a0 + last_write_checksum: sha1:3566995d255c6e0b2bf54aaf406b7288fc27a02c + pristine_git_object: fc2a01268a4789e307b4b2d200c493b1b6337036 + docs/operations/invokeinternrequest.mdx: + id: 14842247e729 + last_write_checksum: sha1:fd1cf98386aa1fbc6f35d87ce76cd27c4897dddb + pristine_git_object: 999ed9735479abd59406706ab1f6e6360fa54f2e + docs/operations/invokeinternresponse.mdx: + id: b75de5a70242 + last_write_checksum: sha1:0ab4b732cb71abfe36c826673b0d70ede866d1e3 + pristine_git_object: bf7427ee3e3ea97873d9510e2e0d9f8505d8a54c docs/operations/keepmembers.mdx: id: 2794baf69c28 last_write_checksum: sha1:aaeb714170a62787f1821383b6136d1753f14722 @@ -8151,8 +8175,8 @@ trackedFiles: pristine_git_object: 08c687694efbecf50406ae7929029d39fb121295 docs/sdks/interns/README.mdx: id: 2f8a053ffe78 - last_write_checksum: sha1:cbebf5bbae2c15f93be5c5407b0f8927167abd90 - pristine_git_object: 995fcb35decbd89a885a25568270d4e6044dea13 + last_write_checksum: sha1:fd91c1ccaefb504e09d5f4d808a147715ecefb68 + pristine_git_object: d1c3962d632fb36093e0128ccf9216b82e366c2d docs/sdks/models/README.mdx: id: 58f1ca464e0b last_write_checksum: sha1:093dd30ebdd18b9763a6956915e0dcae4ae7d5e5 @@ -8219,8 +8243,8 @@ trackedFiles: pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:d840d09771e9321a247c7798346f48f4c79f82d2 - pristine_git_object: cdec75962905ef0fde47759c28b7b74e62744f5a + last_write_checksum: sha1:aab9ea784cd1775a5ff0bf967745d37b9e981bf1 + pristine_git_object: 09333c0bfdbd5e89764847d2f9fc65fbbf1a4eff scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -8247,8 +8271,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:4bede80cef633b1474c61639cde1ddfcd62ddce9 - pristine_git_object: 414f7141481e8394c8e826a4ae4fd1acbdd88228 + last_write_checksum: sha1:bb9f5e866713c9ef6501e791a28656687a36aaf5 + pristine_git_object: b0f7b459f819b45c0a54c82340c2b9b069cede6c src/openrouter/alpha.py: id: 306c4d93308d last_write_checksum: sha1:30f55a360f41376ab194b9ea725fe4e001a5ae1a @@ -8291,8 +8315,8 @@ trackedFiles: pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1 src/openrouter/components/__init__.py: id: 81754e97b3f4 - last_write_checksum: sha1:2f032f581d34607e7925f24b87b0114941704d9b - pristine_git_object: 5ca91a9e6179542cd43c397492b173cc360bd85a + last_write_checksum: sha1:289921f26fee4755c45b555fe37997efe0bd8337 + pristine_git_object: 3e788f40a00a2aaa8d49c0121034565046799ac8 src/openrouter/components/aabenchmarkentry.py: id: e2e0f0b48c82 last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c @@ -9669,6 +9693,14 @@ trackedFiles: id: 97fab5db9a7e last_write_checksum: sha1:d7d2493ea2f82a9c1fa1f90fae5c5365e589345f pristine_git_object: a87aacc5a001412a5789caace557974ccf931928 + src/openrouter/components/interninvokeacceptedresponse.py: + id: b33d41d36bed + last_write_checksum: sha1:0237a0fa91192a250e4162f4d6c0a764a87a9fbe + pristine_git_object: 9f2d10b9b07bfd6f1003533c4302c5dfd69c9699 + src/openrouter/components/interninvokerequest.py: + id: 3c9ecc132cba + last_write_checksum: sha1:20dec52635e43847411caa0c78771b955be3f176 + pristine_git_object: f781e6fa44e17f06fe177f0106ee7317683d9362 src/openrouter/components/internlifecycleerror.py: id: 2b89c094850e last_write_checksum: sha1:5cd04c20e433588e3ecbc026af90cf3508ecbc7c @@ -11207,8 +11239,8 @@ trackedFiles: pristine_git_object: 50643a126668498dd668c7cceb9f78c03d413d32 src/openrouter/interns.py: id: d18df05c5c6d - last_write_checksum: sha1:cdc6b94fced75725f6e09279f4562acdc180b7fb - pristine_git_object: 7171db09163adcbdb2588f98aec36b2806e58263 + last_write_checksum: sha1:db884b41dd732eaccaf0d979fc7a0fbb68afd115 + pristine_git_object: 2cad9a030e7346e787a30d2dd1a49290f052a0f2 src/openrouter/models/__init__.py: id: ed73b93abb3f last_write_checksum: sha1:932a790ae66ccd7d7022b39c659bcf72a664ebea @@ -11235,8 +11267,8 @@ trackedFiles: pristine_git_object: 8680343bbc90107ae6413bd5686012b1fd75d665 src/openrouter/operations/__init__.py: id: 9afcea1e7161 - last_write_checksum: sha1:65bf7e8c4463ba62e1a3547b98ddb9936b810480 - pristine_git_object: dad6359d2132c7fb98338cf94a2c1ae04572e9d4 + last_write_checksum: sha1:f27e9cc96299cea25ce64c878423d7f809c66e6a + pristine_git_object: 4aad70a40deb2081b4877d222c7ba32cf650f24a src/openrouter/operations/bulkaddworkspacemembers.py: id: e0ed56117619 last_write_checksum: sha1:5c44eb0d40fdece3ac084615f6c6082be4cf1d5a @@ -11521,6 +11553,10 @@ trackedFiles: id: 1873b593f56e last_write_checksum: sha1:a7f6b390da2472f04cef719e30d998e08b24acd3 pristine_git_object: 0365c6edd5a01c4086dfcf75d326fb48a67ad9d6 + src/openrouter/operations/invokeintern.py: + id: 554091fee715 + last_write_checksum: sha1:31b3686adff4428ebc5c1a9a58190c7475df0d9a + pristine_git_object: e2024274ca5a6aedb60eb9d9dfdc741e04b26c03 src/openrouter/operations/list.py: id: 3ced31e3804e last_write_checksum: sha1:bfad6d8e4c453367e509f063825899ce72b33449 @@ -15075,5 +15111,25 @@ examples: application/json: {"error": {"code": 524, "message": "Request timed out. Please try again later."}} "529": application/json: {"error": {"code": 529, "message": "Provider returned error"}} + invokeIntern: + speakeasy-default-invoke-intern: + parameters: + path: + internId: "a11e0000-0000-4000-8000-000000000005" + requestBody: + application/json: {"input": "New support ticket 48213. Case token: ct_9f2c. Investigate and reply."} + responses: + "202": + application/json: {"session_id": "b51a0e21-368b-4780-a220-14655bf28c55", "status": "started"} + "400": + 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."}} + "500": + application/json: {"error": {"code": 409, "message": "That question is no longer waiting for an answer."}} examplesVersion: 1.0.2 -releaseNotes: "## Python SDK Changes:\n* `open_router.presets.create_presets_messages()`: \n * `request.tools[].union(class (0)).strict` **Added**\n" +releaseNotes: | + ## Python SDK Changes: + * `open_router.interns.invoke()`: **Added** diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 5faffed3..1809f729 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.2.20 + version: 1.2.21 additionalDependencies: dev: {} main: {} diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index e2942625..fc398145 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -13152,6 +13152,48 @@ components: - 'content' - 'role' type: 'object' + InternInvokeAcceptedResponse: + description: 'The intern admitted the prompt. The run continues on the intern.' + example: + session_id: 'b51a0e21-368b-4780-a220-14655bf28c55' + status: 'started' + properties: + session_id: + description: 'The session the run belongs to. Send it back to continue the conversation.' + example: 'b51a0e21-368b-4780-a220-14655bf28c55' + type: 'string' + status: + description: '`started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead.' + enum: + - 'started' + - 'steered' + example: 'started' + type: 'string' + x-speakeasy-unknown-values: allow + required: + - 'session_id' + - 'status' + type: 'object' + InternInvokeRequest: + description: 'A prompt to run on the intern without holding a connection open.' + example: + input: 'New support ticket 48213. Case token: ct_9f2c. Investigate and reply.' + properties: + input: + description: 'The prompt for the run, at most 32000 characters.' + example: 'New support ticket 48213. Case token: ct_9f2c. Investigate and reply.' + maxLength: 32000 + minLength: 1 + type: 'string' + session_id: + description: 'The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`.' + example: 'b51a0e21-368b-4780-a220-14655bf28c55' + maxLength: 256 + minLength: 1 + type: 'string' + required: + - 'input' + type: 'object' InternLifecycleError: additionalProperties: false description: 'Intern lifecycle request failure.' @@ -37668,6 +37710,217 @@ paths: - $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`." + operationId: 'invokeIntern' + parameters: + - description: 'The intern to run.' + in: 'path' + name: 'internId' + required: true + schema: + description: 'The intern to run.' + example: 'a11e0000-0000-4000-8000-000000000005' + type: 'string' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/InternInvokeRequest' + required: true + responses: + '202': + content: + application/json: + schema: + $ref: '#/components/schemas/InternInvokeAcceptedResponse' + description: 'The intern accepted the prompt. The run continues on the intern.' + '400': + content: + application/json: + example: + error: + code: 400 + message: 'Invalid invoke request (input: Too small: expected string to have >=1 characters).' + metadata: + reason: 'bad_request' + retryable: false + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The body is not a valid request (`bad_request`).' + '401': + content: + application/json: + example: + error: + code: 401 + message: 'Invalid or missing API key' + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'No valid API key.' + '403': + content: + application/json: + example: + error: + code: 403 + message: 'This API key''s creator is no longer a member of the organization. Ask an organization admin to reassign the key to an active member.' + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The key belongs to a member who has left the organization and holds no grant.' + '404': + content: + application/json: + example: + error: + code: 404 + message: 'Intern not found' + metadata: + reason: 'not_found' + retryable: false + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The caller is outside the interns programme, the intern does not exist for this key, or the `session_id` was not issued to this caller on this intern (`not_found`).' + '408': + content: + application/json: + example: + error: + code: 408 + message: 'Operation timed out after 60s. 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`).' + '409': + content: + application/json: + example: + error: + code: 409 + message: 'This intern is not running.' + metadata: + reason: 'intern_not_ready' + retryable: true + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The intern is not running or its runtime is too old to keep a run going without a connection (`intern_not_ready`), or the session already has a run that did not take the prompt (`busy`). 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' + '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/InternChatErrorResponse' + description: 'The body exceeds 1 MiB (`payload_too_large`).' + '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/InternChatErrorResponse' + description: 'Too many turns for the user or organization this key acts as (`rate_limited`). It 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: 'Could not look up the intern' + metadata: + reason: 'intern_unreachable' + retryable: true + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The intern could not be looked up, or authenticating the key failed.' + '502': + content: + application/json: + example: + error: + code: 502 + 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, rejected the request, or refused the turn before it started.' + '503': + content: + application/json: + example: + error: + code: 503 + 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 take another run 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: + example: + error: + code: 504 + message: 'The intern did not answer in time.' + metadata: + reason: 'timeout' + retryable: true + schema: + $ref: '#/components/schemas/InternChatErrorResponse' + description: 'The intern did not accept the turn in time (`timeout`).' + security: + - apiKey: [] + summary: 'Start an intern run without waiting for it' + tags: + - 'Interns' + x-speakeasy-group: 'interns' + x-speakeasy-name-override: 'invoke' + parameters: + - $ref: "#/components/parameters/AppIdentifier" + - $ref: "#/components/parameters/AppDisplayName" + - $ref: "#/components/parameters/AppCategories" /interns/{internId}/provision: post: 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.' diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index bee9c0af..19428b1d 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:9096e3c973fe03b2d2e126bc0b659394df4714d4f5986c8b092ff2e7e76a1307 - sourceBlobDigest: sha256:b8d713fe553a23ae7ac006f621b79a0a0f4831e7da12d114623f15e168407379 + sourceRevisionDigest: sha256:735f8cdc3a309a74edd33480c4c47de14d32303562cb526eb39a59bc70e35598 + sourceBlobDigest: sha256:55427771e384f01b34046cd72b6c55606a9e94895f6774a99936ebbf6cbc40c5 tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:9096e3c973fe03b2d2e126bc0b659394df4714d4f5986c8b092ff2e7e76a1307 - sourceBlobDigest: sha256:b8d713fe553a23ae7ac006f621b79a0a0f4831e7da12d114623f15e168407379 + sourceRevisionDigest: sha256:735f8cdc3a309a74edd33480c4c47de14d32303562cb526eb39a59bc70e35598 + sourceBlobDigest: sha256:55427771e384f01b34046cd72b6c55606a9e94895f6774a99936ebbf6cbc40c5 codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:3d584eb544edd3781554d297a528027bee5c37b707cbe53974ab972a33fb4f6e + codeSamplesRevisionDigest: sha256:3a17822156ea0541216cff2b222d58e321e916e588857ac5c48cb65083feddaf workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index 30c28553..c9ff193c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2609,4 +2609,14 @@ Based on: ### Generated - [python v1.2.20] . ### Releases -- [PyPI v1.2.20] https://pypi.org/project/openrouter/1.2.20 - . \ No newline at end of file +- [PyPI v1.2.20] https://pypi.org/project/openrouter/1.2.20 - . + +## 2026-09-23 17:24:01 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.2.21] . +### Releases +- [PyPI v1.2.21] https://pypi.org/project/openrouter/1.2.21 - . \ No newline at end of file diff --git a/docs/components/interninvokeacceptedresponse.mdx b/docs/components/interninvokeacceptedresponse.mdx new file mode 100644 index 00000000..bcec63f8 --- /dev/null +++ b/docs/components/interninvokeacceptedresponse.mdx @@ -0,0 +1,13 @@ +--- +title: "InternInvokeAcceptedResponse" +--- + +The intern admitted the prompt. The run continues on the intern. + + +## Fields + +| Field | Type | Required | Description | Example | +| -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `session_id` | *str* | :heavy_check_mark: | The session the run belongs to. Send it back to continue the conversation. | b51a0e21-368b-4780-a220-14655bf28c55 | +| `status` | [components.InternInvokeAcceptedResponseStatus](../components/interninvokeacceptedresponsestatus.mdx) | :heavy_check_mark: | `started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead. | started | \ No newline at end of file diff --git a/docs/components/interninvokeacceptedresponsestatus.mdx b/docs/components/interninvokeacceptedresponsestatus.mdx new file mode 100644 index 00000000..ac3cd774 --- /dev/null +++ b/docs/components/interninvokeacceptedresponsestatus.mdx @@ -0,0 +1,22 @@ +--- +title: "InternInvokeAcceptedResponseStatus" +--- + +`started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead. + +## Example Usage + +```python +from openrouter.components import InternInvokeAcceptedResponseStatus + +# Open enum: unrecognized values are captured as UnrecognizedStr +value: InternInvokeAcceptedResponseStatus = "started" +``` + + +## Values + +This is an open enum. Unrecognized values will not fail type checks. + +- `"started"` +- `"steered"` diff --git a/docs/components/interninvokerequest.mdx b/docs/components/interninvokerequest.mdx new file mode 100644 index 00000000..01ec56d1 --- /dev/null +++ b/docs/components/interninvokerequest.mdx @@ -0,0 +1,13 @@ +--- +title: "InternInvokeRequest" +--- + +A prompt to run on the intern without holding a connection open. + + +## Fields + +| Field | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `input` | *str* | :heavy_check_mark: | The prompt for the run, at most 32000 characters. | New support ticket 48213. Case token: ct_9f2c. Investigate and reply. | +| `session_id` | *Optional[str]* | :heavy_minus_sign: | The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`. | b51a0e21-368b-4780-a220-14655bf28c55 | \ No newline at end of file diff --git a/docs/operations/invokeinternglobals.mdx b/docs/operations/invokeinternglobals.mdx new file mode 100644 index 00000000..fc2a0126 --- /dev/null +++ b/docs/operations/invokeinternglobals.mdx @@ -0,0 +1,11 @@ +--- +title: "InvokeInternGlobals" +--- + +## Fields + +| Field | Type | Required | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `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.
| \ No newline at end of file diff --git a/docs/operations/invokeinternrequest.mdx b/docs/operations/invokeinternrequest.mdx new file mode 100644 index 00000000..999ed973 --- /dev/null +++ b/docs/operations/invokeinternrequest.mdx @@ -0,0 +1,13 @@ +--- +title: "InvokeInternRequest" +--- + +## 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.
| | +| `intern_id` | *str* | :heavy_check_mark: | The intern to run. | a11e0000-0000-4000-8000-000000000005 | +| `intern_invoke_request` | [components.InternInvokeRequest](../components/interninvokerequest.mdx) | :heavy_check_mark: | N/A | \{
"input": "New support ticket 48213. Case token: ct_9f2c. Investigate and reply."
} | \ No newline at end of file diff --git a/docs/operations/invokeinternresponse.mdx b/docs/operations/invokeinternresponse.mdx new file mode 100644 index 00000000..bf7427ee --- /dev/null +++ b/docs/operations/invokeinternresponse.mdx @@ -0,0 +1,10 @@ +--- +title: "InvokeInternResponse" +--- + +## Fields + +| Field | Type | Required | Description | Example | +| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| `headers` | Dict[str, List[*str*]] | :heavy_check_mark: | N/A | | +| `result` | [components.InternInvokeAcceptedResponse](../components/interninvokeacceptedresponse.mdx) | :heavy_check_mark: | N/A | \{
"session_id": "b51a0e21-368b-4780-a220-14655bf28c55",
"status": "started"
} | \ No newline at end of file diff --git a/docs/sdks/interns/README.mdx b/docs/sdks/interns/README.mdx index 995fcb35..d1c3962d 100644 --- a/docs/sdks/interns/README.mdx +++ b/docs/sdks/interns/README.mdx @@ -17,6 +17,7 @@ Create, inspect, update, provision, suspend and delete OpenRouter interns throug * [provision_intern](#provision_intern) - Provision an intern * [suspend_intern](#suspend_intern) - Suspend an intern * [chat](#chat) - Stream a chat completion with an intern +* [invoke](#invoke) - Start an intern run without waiting for it ## list_interns @@ -431,4 +432,61 @@ with OpenRouter( | 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 +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | + +## invoke + +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. + +Send 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`. + +Runs 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). + +Available to interns programme members. Callers outside the programme receive `404` for every path under `/api/v1/interns`. + +### 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.invoke(intern_id="a11e0000-0000-4000-8000-000000000005", input="New support ticket 48213. Case token: ct_9f2c. Investigate and reply.") + + # Handle response + print(res) + +``` + +### Parameters + +| Parameter | Type | Required | Description | Example | +| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `intern_id` | *str* | :heavy_check_mark: | The intern to run. | a11e0000-0000-4000-8000-000000000005 | +| `input` | *str* | :heavy_check_mark: | The prompt for the run, at most 32000 characters. | New support ticket 48213. Case token: ct_9f2c. Investigate and reply. | +| `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.
| | +| `session_id` | *Optional[str]* | :heavy_minus_sign: | The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`. | b51a0e21-368b-4780-a220-14655bf28c55 | +| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.mdx) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | | + +### Response + +**[operations.InvokeInternResponse](../../operations/invokeinternresponse.mdx)** + +### Errors + +| Error Type | Status Code | Content Type | +| ------------------------------ | ------------------------------ | ------------------------------ | +| errors.InternChatErrorResponse | 400, 401, 403, 404, 408, 413 | application/json | +| errors.InternChatErrorResponse | 409, 429 | application/json | +| errors.InternChatErrorResponse | 503 | application/json | +| errors.InternChatErrorResponse | 500, 502, 504 | application/json | +| errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index cdec7596..09333c0b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.2.20" +version = "1.2.21" 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 414f7141..b0f7b459 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.20" +__version__: str = "1.2.21" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.2.20 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.2.21 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 5ca91a9e..3e788f40 100644 --- a/src/openrouter/components/__init__.py +++ b/src/openrouter/components/__init__.py @@ -1706,6 +1706,12 @@ InternChatUserMessageRole, InternChatUserMessageTypedDict, ) + from .interninvokeacceptedresponse import ( + InternInvokeAcceptedResponse, + InternInvokeAcceptedResponseStatus, + InternInvokeAcceptedResponseTypedDict, + ) + from .interninvokerequest import InternInvokeRequest, InternInvokeRequestTypedDict from .internlifecycleerror import ( Code, CodeTypedDict, @@ -4718,6 +4724,11 @@ "InternChatUserMessage", "InternChatUserMessageRole", "InternChatUserMessageTypedDict", + "InternInvokeAcceptedResponse", + "InternInvokeAcceptedResponseStatus", + "InternInvokeAcceptedResponseTypedDict", + "InternInvokeRequest", + "InternInvokeRequestTypedDict", "InternLifecycleErrorError", "InternLifecycleErrorErrorTypedDict", "InternLifecycleErrorMetadata", @@ -7264,6 +7275,11 @@ "InternChatUserMessage": ".internchatusermessage", "InternChatUserMessageRole": ".internchatusermessage", "InternChatUserMessageTypedDict": ".internchatusermessage", + "InternInvokeAcceptedResponse": ".interninvokeacceptedresponse", + "InternInvokeAcceptedResponseStatus": ".interninvokeacceptedresponse", + "InternInvokeAcceptedResponseTypedDict": ".interninvokeacceptedresponse", + "InternInvokeRequest": ".interninvokerequest", + "InternInvokeRequestTypedDict": ".interninvokerequest", "Code": ".internlifecycleerror", "CodeTypedDict": ".internlifecycleerror", "InternLifecycleErrorError": ".internlifecycleerror", diff --git a/src/openrouter/components/interninvokeacceptedresponse.py b/src/openrouter/components/interninvokeacceptedresponse.py new file mode 100644 index 00000000..9f2d10b9 --- /dev/null +++ b/src/openrouter/components/interninvokeacceptedresponse.py @@ -0,0 +1,35 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel, UnrecognizedStr +from typing import Literal, Union +from typing_extensions import TypedDict + + +InternInvokeAcceptedResponseStatus = Union[ + Literal[ + "started", + "steered", + ], + UnrecognizedStr, +] +r"""`started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead.""" + + +class InternInvokeAcceptedResponseTypedDict(TypedDict): + r"""The intern admitted the prompt. The run continues on the intern.""" + + session_id: str + r"""The session the run belongs to. Send it back to continue the conversation.""" + status: InternInvokeAcceptedResponseStatus + r"""`started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead.""" + + +class InternInvokeAcceptedResponse(BaseModel): + r"""The intern admitted the prompt. The run continues on the intern.""" + + session_id: str + r"""The session the run belongs to. Send it back to continue the conversation.""" + + status: InternInvokeAcceptedResponseStatus + r"""`started` when a new run began. `steered` when the session already had a run going and the prompt was delivered into it instead.""" diff --git a/src/openrouter/components/interninvokerequest.py b/src/openrouter/components/interninvokerequest.py new file mode 100644 index 00000000..f781e6fa --- /dev/null +++ b/src/openrouter/components/interninvokerequest.py @@ -0,0 +1,42 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.types import BaseModel, UNSET_SENTINEL +from pydantic import model_serializer +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class InternInvokeRequestTypedDict(TypedDict): + r"""A prompt to run on the intern without holding a connection open.""" + + input: str + r"""The prompt for the run, at most 32000 characters.""" + session_id: NotRequired[str] + r"""The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`.""" + + +class InternInvokeRequest(BaseModel): + r"""A prompt to run on the intern without holding a connection open.""" + + input: str + r"""The prompt for the run, at most 32000 characters.""" + + session_id: Optional[str] = None + r"""The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`.""" + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = set(["session_id"]) + 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 7171db09..2cad9a03 100644 --- a/src/openrouter/interns.py +++ b/src/openrouter/interns.py @@ -2399,3 +2399,331 @@ async def chat_async( raise errors.OpenRouterDefaultError( "Unexpected response received", http_res, http_res_text ) + + def invoke( + self, + *, + intern_id: str, + input: str, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + session_id: 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.InvokeInternResponse: + r"""Start an intern run without waiting for it + + 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. + + Send 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`. + + Runs 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). + + Available to interns programme members. Callers outside the programme receive `404` for every path under `/api/v1/interns`. + + If set, this operation will use `api_key` from the global security. + + :param intern_id: The intern to run. + :param input: The prompt for the run, at most 32000 characters. + :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 session_id: The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`. + :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.InvokeInternRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + intern_id=intern_id, + intern_invoke_request=components.InternInvokeRequest( + input=input, + session_id=session_id, + ), + ) + + req = self._build_request( + method="POST", + path="/interns/{internId}/invoke", + 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.InvokeInternGlobals( + 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.intern_invoke_request, + False, + False, + "json", + components.InternInvokeRequest, + ), + 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="invokeIntern", + 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, "202", "application/json"): + return operations.InvokeInternResponse( + result=unmarshal_json_response( + components.InternInvokeAcceptedResponse, http_res + ), + headers={}, + ) + if utils.match_response( + http_res, ["400", "401", "403", "404", "408", "413"], "application/json" + ): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["409", "429"], "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, "503", "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["500", "502", "504"], "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(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 invoke_async( + self, + *, + intern_id: str, + input: str, + http_referer: Optional[str] = None, + x_open_router_title: Optional[str] = None, + x_open_router_categories: Optional[str] = None, + session_id: 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.InvokeInternResponse: + r"""Start an intern run without waiting for it + + 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. + + Send 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`. + + Runs 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). + + Available to interns programme members. Callers outside the programme receive `404` for every path under `/api/v1/interns`. + + If set, this operation will use `api_key` from the global security. + + :param intern_id: The intern to run. + :param input: The prompt for the run, at most 32000 characters. + :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 session_id: The session to run in. Send the `session_id` from an earlier `202` to continue that conversation, for example to hand the intern a decision on a case it is working. Omit it to start a new session. Only a `session_id` this endpoint issued to the same caller on the same intern is accepted; any other is refused with `404`. + :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.InvokeInternRequest( + http_referer=http_referer, + x_open_router_title=x_open_router_title, + x_open_router_categories=x_open_router_categories, + intern_id=intern_id, + intern_invoke_request=components.InternInvokeRequest( + input=input, + session_id=session_id, + ), + ) + + req = self._build_request_async( + method="POST", + path="/interns/{internId}/invoke", + 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.InvokeInternGlobals( + 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.intern_invoke_request, + False, + False, + "json", + components.InternInvokeRequest, + ), + 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="invokeIntern", + 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, "202", "application/json"): + return operations.InvokeInternResponse( + result=unmarshal_json_response( + components.InternInvokeAcceptedResponse, http_res + ), + headers={}, + ) + if utils.match_response( + http_res, ["400", "401", "403", "404", "408", "413"], "application/json" + ): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["409", "429"], "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, "503", "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(response_data, http_res) + if utils.match_response(http_res, ["500", "502", "504"], "application/json"): + response_data = unmarshal_json_response( + errors.InternChatErrorResponseData, http_res + ) + raise errors.InternChatErrorResponse(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) diff --git a/src/openrouter/operations/__init__.py b/src/openrouter/operations/__init__.py index dad6359d..4aad70a4 100644 --- a/src/openrouter/operations/__init__.py +++ b/src/openrouter/operations/__init__.py @@ -580,6 +580,14 @@ GetWorkspaceBudgetRequest, GetWorkspaceBudgetRequestTypedDict, ) + from .invokeintern import ( + InvokeInternGlobals, + InvokeInternGlobalsTypedDict, + InvokeInternRequest, + InvokeInternRequestTypedDict, + InvokeInternResponse, + InvokeInternResponseTypedDict, + ) from .list import ( ListData, ListDataTypedDict, @@ -1397,6 +1405,12 @@ "InputTypedDict", "InputUnion", "InputUnionTypedDict", + "InvokeInternGlobals", + "InvokeInternGlobalsTypedDict", + "InvokeInternRequest", + "InvokeInternRequestTypedDict", + "InvokeInternResponse", + "InvokeInternResponseTypedDict", "KeepMembers", "KeepMembersEnum", "KeepMembersTypedDict", @@ -2155,6 +2169,12 @@ "GetWorkspaceBudgetGlobalsTypedDict": ".getworkspacebudget", "GetWorkspaceBudgetRequest": ".getworkspacebudget", "GetWorkspaceBudgetRequestTypedDict": ".getworkspacebudget", + "InvokeInternGlobals": ".invokeintern", + "InvokeInternGlobalsTypedDict": ".invokeintern", + "InvokeInternRequest": ".invokeintern", + "InvokeInternRequestTypedDict": ".invokeintern", + "InvokeInternResponse": ".invokeintern", + "InvokeInternResponseTypedDict": ".invokeintern", "ListData": ".list", "ListDataTypedDict": ".list", "ListGlobals": ".list", diff --git a/src/openrouter/operations/invokeintern.py b/src/openrouter/operations/invokeintern.py new file mode 100644 index 00000000..e2024274 --- /dev/null +++ b/src/openrouter/operations/invokeintern.py @@ -0,0 +1,174 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from openrouter.components import ( + interninvokeacceptedresponse as components_interninvokeacceptedresponse, + interninvokerequest as components_interninvokerequest, +) +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 InvokeInternGlobalsTypedDict(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 InvokeInternGlobals(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 InvokeInternRequestTypedDict(TypedDict): + intern_id: str + r"""The intern to run.""" + intern_invoke_request: components_interninvokerequest.InternInvokeRequestTypedDict + 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 InvokeInternRequest(BaseModel): + intern_id: Annotated[ + str, + pydantic.Field(alias="internId"), + FieldMetadata(path=PathParamMetadata(style="simple", explode=False)), + ] + r"""The intern to run.""" + + intern_invoke_request: Annotated[ + components_interninvokerequest.InternInvokeRequest, + 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 InvokeInternResponseTypedDict(TypedDict): + headers: Dict[str, List[str]] + result: ( + components_interninvokeacceptedresponse.InternInvokeAcceptedResponseTypedDict + ) + + +class InvokeInternResponse(BaseModel): + headers: Dict[str, List[str]] + + result: components_interninvokeacceptedresponse.InternInvokeAcceptedResponse diff --git a/uv.lock b/uv.lock index 413f86d9..8992e576 100644 --- a/uv.lock +++ b/uv.lock @@ -213,7 +213,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.2.20" +version = "1.2.21" source = { editable = "." } dependencies = [ { name = "httpcore" }, From 73eeffb003c26e5de638c0bf1b9093692e140cdd Mon Sep 17 00:00:00 2001 From: "speakeasy-github[bot]" <128539517+speakeasy-github[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 17:26:35 +0000 Subject: [PATCH 2/2] empty commit to trigger [run-tests] workflow