diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 29e9740a..bc1ffc5b 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: 8468014ae21c6d6b2cfe530ed4223f06 + docChecksum: 1c6c707c5466d1fb0e85c3fcc78925f8 docVersion: 1.0.0 speakeasyVersion: 1.787.0 generationVersion: 2.914.0 - releaseVersion: 1.3.82 - configChecksum: 0fd9dd77f08c999b63282b5c5177726c + releaseVersion: 1.3.83 + configChecksum: 045ab02bef0b678da1d8aa8a2a5e3004 repoURL: https://github.com/OpenRouterTeam/python-sdk.git installationURL: https://github.com/OpenRouterTeam/python-sdk.git published: true persistentEdits: - generation_id: a2a88003-7157-430f-b02e-6387210a5301 - pristine_commit_hash: 98a14e7115503da2434094192c1a041349db476b - pristine_tree_hash: 8d08efaebbc18f992f0faa62293f44f91b302d85 + generation_id: bd3d8c62-ebd6-431d-998a-b0fd3968fc8a + pristine_commit_hash: 67c259ba248abe8fe6937b9f3be694f01f927a35 + pristine_tree_hash: 4ace05f29115f4cbe42d145c2b7270d022ad58ec features: python: acceptHeaders: 3.0.0 @@ -1322,6 +1322,10 @@ trackedFiles: id: c457db82a4ac last_write_checksum: sha1:eda63702a1bab370efe326a661950ea0b864169e pristine_git_object: ef98b1de499df79940ccacaf5da0be2d635b104e + docs/components/authmode.mdx: + id: 7af44811cd7d + last_write_checksum: sha1:58ff1c8059d69e927c42e2c2fc3305c70a046c50 + pristine_git_object: da46605300064ce28cf815b6a2841a5e22c2e82e docs/components/autobetarouterplugin.mdx: id: 036f0e51d7c9 last_write_checksum: sha1:eb214c8c4642dbacc5d5ddfda593b0c87bb4e976 @@ -4876,8 +4880,8 @@ trackedFiles: pristine_git_object: 2de0187cd759280f723333c6e6ba95ad4d2ae2bd docs/components/observabilitys3destinationconfig.mdx: id: 040367f19dfe - last_write_checksum: sha1:063638b494568601ae5043fa24f40cbac6a1b641 - pristine_git_object: 3974209559c2b3f15d0a3108b9849815a3dd97bb + last_write_checksum: sha1:6f577fd48644c931713c67fd5f07e0569114be88 + pristine_git_object: ffd7785c00a3a93f29f7150a699061c124931575 docs/components/observabilitys3destinationtype.mdx: id: 8279c13af28f last_write_checksum: sha1:10cea4da23cb74039112d0a531eee503e1a760df @@ -6226,6 +6230,10 @@ trackedFiles: id: 75786e3aa079 last_write_checksum: sha1:9af190f60239a910768092d5ed8342ed7aed4ebd pristine_git_object: e4103b29b85cafaf653bf8f71bd8e12278a16fa8 + docs/components/providerenum.mdx: + id: 3065d8db71f9 + last_write_checksum: sha1:8adf2339eb304261db4be5001a8e3cf7ea449e2f + pristine_git_object: 70dcf1b583a3d202157814d8bd4f3c8f7811d0d9 docs/components/providername.mdx: id: aa3a4904b228 last_write_checksum: sha1:e2a84dbc4284448764b55b2ed907ea0a48a09bd5 @@ -10052,8 +10060,8 @@ trackedFiles: pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544 pyproject.toml: id: 5d07e7d72637 - last_write_checksum: sha1:30f518c065a2035ceb1922db0ed2d4c721e5ae9e - pristine_git_object: e055e6ffdb236bd945862219a1496ff051c9565e + last_write_checksum: sha1:7bf735478be2806297e53ef9fe5ed6b51b87d4da + pristine_git_object: 15399be72216a8119c6356435edb4c36408e7f62 scripts/prepare_readme.py: id: e0c5957a6035 last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54 @@ -10080,8 +10088,8 @@ trackedFiles: pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137 src/openrouter/_version.py: id: d8d15ad6c586 - last_write_checksum: sha1:87b47c2646ed28bff3c322234619bad2e187dbb3 - pristine_git_object: 0c690e1a9771bdfd13c2432ae60c83b287c06729 + last_write_checksum: sha1:d712bd32457db4c579ae6c85c5b9570e8b8137cb + pristine_git_object: 82ca016553de358467d5d6a26497049f6d33ad76 src/openrouter/alpha.py: id: 306c4d93308d last_write_checksum: sha1:30f55a360f41376ab194b9ea725fe4e001a5ae1a @@ -10128,8 +10136,8 @@ trackedFiles: pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1 src/openrouter/components/__init__.py: id: 81754e97b3f4 - last_write_checksum: sha1:7e3f1389dc13717a35ed760c9186fc7819a8242b - pristine_git_object: 27a498a5fc24d45b93b7c86171d4b0707fa6ce1d + last_write_checksum: sha1:0adc9b2e076c2f45193cfadb4b7f6923a54178e4 + pristine_git_object: 66f727d993f7230d54452ba0bc46b15bd2d8f514 src/openrouter/components/aabenchmarkentry.py: id: e2e0f0b48c82 last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c @@ -12152,8 +12160,8 @@ trackedFiles: pristine_git_object: 96356019658ed556dcb141ba8fffeea595687aac src/openrouter/components/observabilitys3destination.py: id: 2022d25fe7d6 - last_write_checksum: sha1:2750f3cbf434831a16002b0b449a22d3bf14c920 - pristine_git_object: 1c1ede2857cdfa9c4193d8b19d9a0f90aaff4d1b + last_write_checksum: sha1:2d4dad841e9df73fcec61bfc673fe158a2a24643 + pristine_git_object: 1364fb168a10dc8f936470194732cdfe10ae969b src/openrouter/components/observabilitysentrydestination.py: id: d27b8b37d1f8 last_write_checksum: sha1:02be4646d9f95b8e97417722157ff9f6e55fca0a @@ -18673,4 +18681,9 @@ examples: "500": application/json: {"error": {"code": 404, "message": "Intern not found"}} examplesVersion: 1.0.2 -releaseNotes: "## Python SDK Changes:\n* `open_router.presets.create_presets_messages()`: \n * `request.messages[].content.union(Array<>)[].union(tool_addition).tool.union(tool_definition)` **Added**\n" +releaseNotes: | + ## Python SDK Changes: + * `open_router.observability.list()`: `response.data[].union(s3).config` **Changed** + * `open_router.observability.create()`: `response.data.union(s3).config` **Changed** + * `open_router.observability.get()`: `response.data.union(s3).config` **Changed** + * `open_router.observability.update()`: `response.data.union(s3).config` **Changed** diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 02b32443..8fbf477e 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -36,7 +36,7 @@ generation: documentation: mintlify preApplyUnionDiscriminators: true python: - version: 1.3.82 + version: 1.3.83 additionalDependencies: dev: pytest: '>=8.3' diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml index 8548581a..5a4def1a 100644 --- a/.speakeasy/out.openapi.yaml +++ b/.speakeasy/out.openapi.yaml @@ -20842,6 +20842,26 @@ components: accessKeyId: minLength: 1 type: 'string' + visibleWhen: + - field: 'authMode' + in: + - 'access_keys' + - '' + authMode: + default: 'access_keys' + description: 'IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don''t share long-lived keys.' + enum: + - 'access_keys' + - 'iam_role' + optionLabels: + access_keys: 'Access keys' + iam_role: 'IAM role' + type: 'string' + visibleWhen: + - field: 'provider' + in: + - 'aws' + x-speakeasy-unknown-values: allow bucketName: minLength: 1 type: 'string' @@ -20849,6 +20869,24 @@ components: description: 'Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3.' format: 'uri' type: 'string' + visibleWhen: + - field: 'provider' + in: + - 'cloudflare_r2' + - 'gcs' + - 'other' + - '' + externalId: + description: 'Generated by OpenRouter when you save. Require it as sts:ExternalId in your role''s trust policy.' + readOnly: true + type: 'string' + visibleWhen: + - field: 'provider' + in: + - 'aws' + - field: 'authMode' + in: + - 'iam_role' headers: additionalProperties: type: 'string' @@ -20861,17 +20899,51 @@ components: prefix: default: 'openrouter-traces' type: 'string' + provider: + description: 'The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys.' + enum: + - 'aws' + - 'cloudflare_r2' + - 'gcs' + - 'other' + optionLabels: + aws: 'AWS S3' + cloudflare_r2: 'Cloudflare R2' + gcs: 'Google Cloud Storage' + other: 'Other S3-compatible' + type: 'string' + x-speakeasy-unknown-values: allow region: + description: 'Required for IAM role authentication. With access keys, AWS S3 detects the bucket region when you leave this blank.' + type: 'string' + roleArn: + description: 'The IAM role in your account that OpenRouter assumes. Its trust policy must allow sts:AssumeRole from arn:aws:iam::536697249728:role/openrouter-broadcast-exporter and require the external ID below, and its permissions must allow s3:PutObject on the bucket and prefix (plus kms:GenerateDataKey for SSE-KMS buckets).' + pattern: '^arn:aws(?:-[a-z]+)*:iam::\d{12}:role\/[\w+=,.@/-]{1,512}$' type: 'string' + visibleWhen: + - field: 'provider' + in: + - 'aws' + - field: 'authMode' + in: + - 'iam_role' secretAccessKey: minLength: 1 type: 'string' + visibleWhen: + - field: 'authMode' + in: + - 'access_keys' + - '' sessionToken: type: 'string' + visibleWhen: + - field: 'authMode' + in: + - 'access_keys' + - '' required: - 'bucketName' - - 'accessKeyId' - - 'secretAccessKey' type: 'object' created_at: description: 'ISO timestamp of when the destination was created.' diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 8058e43d..3dce701a 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:038e56b2c3b2cf3c81df89a8a2313957f3613b5e3b0094187e084dc2e8e7e27a - sourceBlobDigest: sha256:60ac6a4d7eaa2d67c97a0a2ebe4b776a40ebf0674fa3e717fa9a67f8920fbd45 + sourceRevisionDigest: sha256:ae57d6e79c415b3724a00d445a652cdf81bf8dcc80e35cdf17abf28c3256c47e + sourceBlobDigest: sha256:640f9897e616ccbb3990bd0b3af52557683829d0a7dd20f1497a477bcec7d9df tags: - latest - 1.0.0 @@ -11,10 +11,10 @@ targets: open-router: source: OpenRouter API sourceNamespace: open-router-chat-completions-api - sourceRevisionDigest: sha256:038e56b2c3b2cf3c81df89a8a2313957f3613b5e3b0094187e084dc2e8e7e27a - sourceBlobDigest: sha256:60ac6a4d7eaa2d67c97a0a2ebe4b776a40ebf0674fa3e717fa9a67f8920fbd45 + sourceRevisionDigest: sha256:ae57d6e79c415b3724a00d445a652cdf81bf8dcc80e35cdf17abf28c3256c47e + sourceBlobDigest: sha256:640f9897e616ccbb3990bd0b3af52557683829d0a7dd20f1497a477bcec7d9df codeSamplesNamespace: open-router-python-code-samples - codeSamplesRevisionDigest: sha256:d96edd7519c09a0538c39859014b269f5c03fbab1e4ac43c85342e72a7656b7d + codeSamplesRevisionDigest: sha256:2570859003af791de7fd54409f3da367025c94b61e056a5ecf3a01d8ad324e17 workflow: workflowVersion: 1.0.0 speakeasyVersion: 1.787.0 diff --git a/RELEASES.md b/RELEASES.md index 350b5541..dd2d9ede 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3589,4 +3589,14 @@ Based on: ### Generated - [python v1.3.82] . ### Releases -- [PyPI v1.3.82] https://pypi.org/project/openrouter/1.3.82 - . \ No newline at end of file +- [PyPI v1.3.82] https://pypi.org/project/openrouter/1.3.82 - . + +## 2026-10-27 00:13:32 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.787.0 (2.914.0) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v1.3.83] . +### Releases +- [PyPI v1.3.83] https://pypi.org/project/openrouter/1.3.83 - . \ No newline at end of file diff --git a/docs/components/authmode.mdx b/docs/components/authmode.mdx new file mode 100644 index 00000000..da466053 --- /dev/null +++ b/docs/components/authmode.mdx @@ -0,0 +1,22 @@ +--- +title: "AuthMode" +--- + +IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don't share long-lived keys. + +## Example Usage + +```python +from openrouter.components import AuthMode + +# Open enum: unrecognized values are captured as UnrecognizedStr +value: AuthMode = "access_keys" +``` + + +## Values + +This is an open enum. Unrecognized values will not fail type checks. + +- `"access_keys"` +- `"iam_role"` diff --git a/docs/components/observabilitys3destinationconfig.mdx b/docs/components/observabilitys3destinationconfig.mdx index e6dfccca..98fb88f2 100644 --- a/docs/components/observabilitys3destinationconfig.mdx +++ b/docs/components/observabilitys3destinationconfig.mdx @@ -4,14 +4,18 @@ title: "ObservabilityS3DestinationConfig" ## Fields -| Field | Type | Required | Description | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `access_key_id` | *str* | ✅ | N/A | -| `bucket_name` | *str* | ✅ | N/A | -| `endpoint` | *Optional[str]* | ➖ | Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3. | -| `headers` | Dict[str, *str*] | ➖ | Custom HTTP headers to include in requests to this destination. | -| `path_template` | *Optional[str]* | ➖ | Template for S3 object path. The filename (\{traceId}-\{timestamp}.json) is automatically appended. Available variables: \{prefix}, \{date}, \{year}, \{month}, \{day}, \{apiKeyName} | -| `prefix` | *Optional[str]* | ➖ | N/A | -| `region` | *Optional[str]* | ➖ | N/A | -| `secret_access_key` | *str* | ✅ | N/A | -| `session_token` | *Optional[str]* | ➖ | N/A | \ No newline at end of file +| Field | Type | Required | Description | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `access_key_id` | *Optional[str]* | ➖ | N/A | +| `auth_mode` | [Optional[components.AuthMode]](../components/authmode.mdx) | ➖ | IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don't share long-lived keys. | +| `bucket_name` | *str* | ✅ | N/A | +| `endpoint` | *Optional[str]* | ➖ | Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3. | +| `external_id` | *Optional[str]* | ➖ | Generated by OpenRouter when you save. Require it as sts:ExternalId in your role's trust policy. | +| `headers` | Dict[str, *str*] | ➖ | Custom HTTP headers to include in requests to this destination. | +| `path_template` | *Optional[str]* | ➖ | Template for S3 object path. The filename (\{traceId}-\{timestamp}.json) is automatically appended. Available variables: \{prefix}, \{date}, \{year}, \{month}, \{day}, \{apiKeyName} | +| `prefix` | *Optional[str]* | ➖ | N/A | +| `provider` | [Optional[components.ProviderEnum]](../components/providerenum.mdx) | ➖ | The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys. | +| `region` | *Optional[str]* | ➖ | Required for IAM role authentication. With access keys, AWS S3 detects the bucket region when you leave this blank. | +| `role_arn` | *Optional[str]* | ➖ | The IAM role in your account that OpenRouter assumes. Its trust policy must allow sts:AssumeRole from arn:aws:iam::536697249728:role/openrouter-broadcast-exporter and require the external ID below, and its permissions must allow s3:PutObject on the bucket and prefix (plus kms:GenerateDataKey for SSE-KMS buckets). | +| `secret_access_key` | *Optional[str]* | ➖ | N/A | +| `session_token` | *Optional[str]* | ➖ | N/A | \ No newline at end of file diff --git a/docs/components/providerenum.mdx b/docs/components/providerenum.mdx new file mode 100644 index 00000000..70dcf1b5 --- /dev/null +++ b/docs/components/providerenum.mdx @@ -0,0 +1,24 @@ +--- +title: "ProviderEnum" +--- + +The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys. + +## Example Usage + +```python +from openrouter.components import ProviderEnum + +# Open enum: unrecognized values are captured as UnrecognizedStr +value: ProviderEnum = "aws" +``` + + +## Values + +This is an open enum. Unrecognized values will not fail type checks. + +- `"aws"` +- `"cloudflare_r2"` +- `"gcs"` +- `"other"` diff --git a/pyproject.toml b/pyproject.toml index e055e6ff..15399be7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openrouter" -version = "1.3.82" +version = "1.3.83" 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 0c690e1a..82ca0165 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.82" +__version__: str = "1.3.83" __openapi_doc_version__: str = "1.0.0" __gen_version__: str = "2.914.0" -__user_agent__: str = "speakeasy-sdk/python 1.3.82 2.914.0 1.0.0 openrouter" +__user_agent__: str = "speakeasy-sdk/python 1.3.83 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 27a498a5..66f727d9 100644 --- a/src/openrouter/components/__init__.py +++ b/src/openrouter/components/__init__.py @@ -2822,11 +2822,13 @@ ObservabilityRampDestinationTypedDict, ) from .observabilitys3destination import ( + AuthMode, ObservabilityS3Destination, ObservabilityS3DestinationConfig, ObservabilityS3DestinationConfigTypedDict, ObservabilityS3DestinationType, ObservabilityS3DestinationTypedDict, + ProviderEnum, ) from .observabilitysentrydestination import ( ObservabilitySentryDestination, @@ -4860,6 +4862,7 @@ "ArmorSafeguardResultTypedDict", "AudioURL", "AudioURLTypedDict", + "AuthMode", "AutoBetaRouterPlugin", "AutoBetaRouterPluginCostTier", "AutoBetaRouterPluginID", @@ -6817,6 +6820,7 @@ "PromptCacheOptionsTypedDict", "PromptInjectionScanScope", "Protocol", + "ProviderEnum", "ProviderName", "ProviderOptions", "ProviderOptionsTypedDict", @@ -9666,11 +9670,13 @@ "ObservabilityRampDestinationConfigTypedDict": ".observabilityrampdestination", "ObservabilityRampDestinationType": ".observabilityrampdestination", "ObservabilityRampDestinationTypedDict": ".observabilityrampdestination", + "AuthMode": ".observabilitys3destination", "ObservabilityS3Destination": ".observabilitys3destination", "ObservabilityS3DestinationConfig": ".observabilitys3destination", "ObservabilityS3DestinationConfigTypedDict": ".observabilitys3destination", "ObservabilityS3DestinationType": ".observabilitys3destination", "ObservabilityS3DestinationTypedDict": ".observabilitys3destination", + "ProviderEnum": ".observabilitys3destination", "ObservabilitySentryDestination": ".observabilitysentrydestination", "ObservabilitySentryDestinationConfig": ".observabilitysentrydestination", "ObservabilitySentryDestinationConfigTypedDict": ".observabilitysentrydestination", diff --git a/src/openrouter/components/observabilitys3destination.py b/src/openrouter/components/observabilitys3destination.py index 1c1ede28..1364fb16 100644 --- a/src/openrouter/components/observabilitys3destination.py +++ b/src/openrouter/components/observabilitys3destination.py @@ -6,38 +6,75 @@ ObservabilityFilterRulesConfig, ObservabilityFilterRulesConfigTypedDict, ) -from openrouter.types import BaseModel, Nullable, UNSET_SENTINEL +from openrouter.types import BaseModel, Nullable, UNSET_SENTINEL, UnrecognizedStr import pydantic from pydantic import model_serializer -from typing import Dict, List, Literal, Optional +from typing import Dict, List, Literal, Optional, Union from typing_extensions import Annotated, NotRequired, TypedDict +AuthMode = Union[ + Literal[ + "access_keys", + "iam_role", + ], + UnrecognizedStr, +] +r"""IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don't share long-lived keys.""" + + +ProviderEnum = Union[ + Literal[ + "aws", + "cloudflare_r2", + "gcs", + "other", + ], + UnrecognizedStr, +] +r"""The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys.""" + + class ObservabilityS3DestinationConfigTypedDict(TypedDict): - access_key_id: str bucket_name: str - secret_access_key: str + access_key_id: NotRequired[str] + auth_mode: NotRequired[AuthMode] + r"""IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don't share long-lived keys.""" endpoint: NotRequired[str] r"""Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3.""" + external_id: NotRequired[str] + r"""Generated by OpenRouter when you save. Require it as sts:ExternalId in your role's trust policy.""" headers: NotRequired[Dict[str, str]] r"""Custom HTTP headers to include in requests to this destination.""" path_template: NotRequired[str] r"""Template for S3 object path. The filename ({traceId}-{timestamp}.json) is automatically appended. Available variables: {prefix}, {date}, {year}, {month}, {day}, {apiKeyName}""" prefix: NotRequired[str] + provider: NotRequired[ProviderEnum] + r"""The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys.""" region: NotRequired[str] + r"""Required for IAM role authentication. With access keys, AWS S3 detects the bucket region when you leave this blank.""" + role_arn: NotRequired[str] + r"""The IAM role in your account that OpenRouter assumes. Its trust policy must allow sts:AssumeRole from arn:aws:iam::536697249728:role/openrouter-broadcast-exporter and require the external ID below, and its permissions must allow s3:PutObject on the bucket and prefix (plus kms:GenerateDataKey for SSE-KMS buckets).""" + secret_access_key: NotRequired[str] session_token: NotRequired[str] class ObservabilityS3DestinationConfig(BaseModel): - access_key_id: Annotated[str, pydantic.Field(alias="accessKeyId")] - bucket_name: Annotated[str, pydantic.Field(alias="bucketName")] - secret_access_key: Annotated[str, pydantic.Field(alias="secretAccessKey")] + access_key_id: Annotated[Optional[str], pydantic.Field(alias="accessKeyId")] = None + + auth_mode: Annotated[Optional[AuthMode], pydantic.Field(alias="authMode")] = ( + "access_keys" + ) + r"""IAM role: OpenRouter assumes a role in your AWS account with short-lived STS credentials, so you don't share long-lived keys.""" endpoint: Optional[str] = None r"""Only for S3-compatible services like Cloudflare R2 (https://account-id.r2.cloudflarestorage.com) or MinIO. Leave blank for standard AWS S3.""" + external_id: Annotated[Optional[str], pydantic.Field(alias="externalId")] = None + r"""Generated by OpenRouter when you save. Require it as sts:ExternalId in your role's trust policy.""" + headers: Optional[Dict[str, str]] = None r"""Custom HTTP headers to include in requests to this destination.""" @@ -48,14 +85,38 @@ class ObservabilityS3DestinationConfig(BaseModel): prefix: Optional[str] = "openrouter-traces" + provider: Optional[ProviderEnum] = None + r"""The object storage service that hosts the bucket. AWS S3 supports IAM role authentication; the other providers use access keys.""" + region: Optional[str] = None + r"""Required for IAM role authentication. With access keys, AWS S3 detects the bucket region when you leave this blank.""" + + role_arn: Annotated[Optional[str], pydantic.Field(alias="roleArn")] = None + r"""The IAM role in your account that OpenRouter assumes. Its trust policy must allow sts:AssumeRole from arn:aws:iam::536697249728:role/openrouter-broadcast-exporter and require the external ID below, and its permissions must allow s3:PutObject on the bucket and prefix (plus kms:GenerateDataKey for SSE-KMS buckets).""" + + secret_access_key: Annotated[ + Optional[str], pydantic.Field(alias="secretAccessKey") + ] = None session_token: Annotated[Optional[str], pydantic.Field(alias="sessionToken")] = None @model_serializer(mode="wrap") def serialize_model(self, handler): optional_fields = set( - ["endpoint", "headers", "pathTemplate", "prefix", "region", "sessionToken"] + [ + "accessKeyId", + "authMode", + "endpoint", + "externalId", + "headers", + "pathTemplate", + "prefix", + "provider", + "region", + "roleArn", + "secretAccessKey", + "sessionToken", + ] ) serialized = handler(self) m = {} diff --git a/uv.lock b/uv.lock index 7e0ec7f6..b31bd2a5 100644 --- a/uv.lock +++ b/uv.lock @@ -231,7 +231,7 @@ wheels = [ [[package]] name = "openrouter" -version = "1.3.82" +version = "1.3.83" source = { editable = "." } dependencies = [ { name = "httpcore" },