diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 4fb69ee4..eda56587 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: 30567c425d240802631762506228f8ef
+ docChecksum: 0b6a4f9f718f46a6b9f1c42f66c7c30d
docVersion: 1.0.0
speakeasyVersion: 1.803.2
generationVersion: 2.950.13
- releaseVersion: 1.3.171
- configChecksum: ddb32bd4e2b8a710a5724c95f74c9178
+ releaseVersion: 1.3.172
+ configChecksum: 96e13e4cf0f1fa887bacdd39a5d0d076
repoURL: https://github.com/OpenRouterTeam/python-sdk.git
installationURL: https://github.com/OpenRouterTeam/python-sdk.git
published: true
persistentEdits:
- generation_id: 8f603718-2d74-46a4-8de3-253f2cbea57d
- pristine_commit_hash: eb79adce5125c82f470d162346517bb4969878a2
- pristine_tree_hash: 414af1b5eb147165659d5fe3d63d08256f91be78
+ generation_id: 44a2bbd7-6f29-454d-bccc-fedc6448e62e
+ pristine_commit_hash: 630e03187bf7df7f5e8d5d6160ec96523df8ccf0
+ pristine_tree_hash: b0db7e32f346d6660cf37c9ce78472d7711f6af8
features:
python:
acceptHeaders: 3.0.0
@@ -2618,6 +2618,10 @@ trackedFiles:
id: e5d65035c6cb
last_write_checksum: sha1:ea5a9c809cbb6200745c7cfb66c90cfbb08cece1
pristine_git_object: 3c403ebfaf37d008ac6ea149c251b7290ff42301
+ docs/components/contentfilterreadentry.mdx:
+ id: 5a8e6c4e402e
+ last_write_checksum: sha1:cb4e732270307966fc119d309372c04c85d16453
+ pristine_git_object: e76e781ebe9c10107d7981baa5ba49cbdc815421
docs/components/contentimageurl.mdx:
id: 4092a59d86b4
last_write_checksum: sha1:41a45a0483695585f05fbe1a4c7819ae8eba928f
@@ -4212,8 +4216,8 @@ trackedFiles:
pristine_git_object: 6e17644dffb3aef799758f46d5ac781114b58c1f
docs/components/guardrail.mdx:
id: 91791d4c83b6
- last_write_checksum: sha1:d1adf8ad6b61dbed5a1114202791c934a3db6632
- pristine_git_object: 9095f97d749034bcce9ba14d22122a727e7db21b
+ last_write_checksum: sha1:0d3052ca5606284b1b009b793e0c6c29caa0725b
+ pristine_git_object: 16a5de46fe7d071a2cd7ee2914a6e6a9ee9967ae
docs/components/guardrailbudgetpolicyauthoringconfig.mdx:
id: 9e5753c7f2e8
last_write_checksum: sha1:c1527680bab858136a3ceb69966af7aab285636b
@@ -11632,8 +11636,8 @@ trackedFiles:
pristine_git_object: 3e38f1a929f7d6b1d6de74604aa87e3d8f010544
pyproject.toml:
id: 5d07e7d72637
- last_write_checksum: sha1:1fedb72c7a7746bc6820bfc15d27da4668a25d38
- pristine_git_object: d5e097456fcbe579ec290d83033603e77b733dd9
+ last_write_checksum: sha1:bae5be3f485ba7126e93649fc8ca83d9c76b96a8
+ pristine_git_object: 10294129d7ad0e29ff4ec5c11700dd0b91104ece
scripts/prepare_readme.py:
id: e0c5957a6035
last_write_checksum: sha1:77f44b60b98bc126557ec27391f91dfba764bb54
@@ -11660,8 +11664,8 @@ trackedFiles:
pristine_git_object: 86713cfea633e09d33b3d4e65281071fe20e6137
src/openrouter/_version.py:
id: d8d15ad6c586
- last_write_checksum: sha1:54a93a3b40a308a571cbb926dd7a4340c573ded4
- pristine_git_object: 015b9fc84d77cd77a66356cfe7b8fb05de0931a3
+ last_write_checksum: sha1:cc55eb6ad7c80e6c3d3a905686f96ad39415d077
+ pristine_git_object: 3a4ea3ee2c7b9e6290ea23ddfd3a3e51dfcc3d24
src/openrouter/alpha.py:
id: 306c4d93308d
last_write_checksum: sha1:80cc0f39649445431cc2247ed0e0765438467766
@@ -11708,8 +11712,8 @@ trackedFiles:
pristine_git_object: ad3d247954547814054c01989a2dff3d12b3e4e1
src/openrouter/components/__init__.py:
id: 81754e97b3f4
- last_write_checksum: sha1:1e5e989da812bce6bb2832f209b3dd4072ca253b
- pristine_git_object: 0f5c732d00c70b143a6ddf64bd045eceb9546cff
+ last_write_checksum: sha1:43b8464cd93aff7843b793ccdc334cdeda04755a
+ pristine_git_object: cfdfb3cf4efc0e170e3a60b747656228ea906135
src/openrouter/components/aabenchmarkentry.py:
id: e2e0f0b48c82
last_write_checksum: sha1:fab4d9a24d2cea937bb749d46c5f83941e99d65c
@@ -12814,6 +12818,10 @@ trackedFiles:
id: 149ebe184f88
last_write_checksum: sha1:63dcb28479bc328253a4d102a6c191fa0e515394
pristine_git_object: 882178bfe6217c6cf9947ca1ce9fe67d07830262
+ src/openrouter/components/contentfilterreadentry.py:
+ id: 9fb39b4a7350
+ last_write_checksum: sha1:9e169db041e977fe6b42c313991d3fecfd488fac
+ pristine_git_object: 3a227dba2a7c5c7fd802bf354977f8c9aeb7b544
src/openrouter/components/contentpartaddedevent.py:
id: a074d4f3e193
last_write_checksum: sha1:ce0fc4800d5dae3328f0185add65758d149c5d4a
@@ -13452,8 +13460,8 @@ trackedFiles:
pristine_git_object: 1268e32c9058ed4feb7482458a64366c56201676
src/openrouter/components/guardrail.py:
id: 67ee78dd06e6
- last_write_checksum: sha1:246d44cd9b211dcd23614df71505b79b2677125a
- pristine_git_object: 252b329019216d0cc8d4c7568edfc0d9c91968fe
+ last_write_checksum: sha1:71dd7b2bc5afd3708209661a3dbd936db4840251
+ pristine_git_object: 1d5e7be619427a95bc598364fed9810cf8e17596
src/openrouter/components/guardrailbudgetpolicyauthoringconfig.py:
id: 3011896fdeb5
last_write_checksum: sha1:604d6ec6906a391e0ce81e315ec077ab17e081a9
@@ -21641,3 +21649,9 @@ examples:
"500":
application/json: {"error": {"code": 500, "message": "Internal Server Error"}}
examplesVersion: 1.0.2
+releaseNotes: |
+ ## Python SDK Changes:
+ * `open_router.guardrails.list()`: `response.data[].content_filters[].is_enforced` **Added**
+ * `open_router.guardrails.create()`: `response.data.content_filters[].is_enforced` **Added**
+ * `open_router.guardrails.get()`: `response.data.content_filters[].is_enforced` **Added**
+ * `open_router.guardrails.update()`: `response.data.content_filters[].is_enforced` **Added**
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index 682f7c89..bc373b83 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -37,7 +37,7 @@ generation:
documentation: mintlify
preApplyUnionDiscriminators: true
python:
- version: 1.3.171
+ version: 1.3.172
additionalDependencies:
dev:
pytest: '>=8.3'
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index 3e8387c4..2160b4f7 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -10200,6 +10200,23 @@ components:
- 'pattern'
- 'action'
type: 'object'
+ ContentFilterReadEntry:
+ allOf:
+ - $ref: '#/components/schemas/ContentFilterEntry'
+ - properties:
+ is_enforced:
+ description: 'Whether inference applies this pattern. False for a pattern saved before pattern validation that is too complex to run safely; it is kept but skipped until replaced.'
+ example: true
+ type: 'boolean'
+ required:
+ - 'is_enforced'
+ type: 'object'
+ description: 'A custom regex content filter, with whether inference enforces it.'
+ example:
+ action: 'redact'
+ is_enforced: true
+ label: '[API_KEY]'
+ pattern: '\b(sk-[a-zA-Z0-9]{48})\b'
ContentPartAddedEvent:
allOf:
- $ref: '#/components/schemas/BaseContentPartAddedEvent'
@@ -15962,10 +15979,11 @@ components:
description: 'Custom regex content filters applied to request messages'
example:
- action: 'redact'
+ is_enforced: true
label: '[API_KEY]'
pattern: '\b(sk-[a-zA-Z0-9]{48})\b'
items:
- $ref: '#/components/schemas/ContentFilterEntry'
+ $ref: '#/components/schemas/ContentFilterReadEntry'
type:
- 'array'
- 'null'
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 4027b906..4741b64d 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -2,8 +2,8 @@ speakeasyVersion: 1.803.2
sources:
OpenRouter API:
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:2da9790d04eb9873088b59c89e7456494fc51041d339e057428ccf326dabe8e5
- sourceBlobDigest: sha256:fe041198672377cdbae02cfb2a1342e1d96dc5de89fb2338946809ade321fea6
+ sourceRevisionDigest: sha256:aaea7962bb250e48c30aef0665e01972f79cf4b7b5f808aafca88ea64dae0b64
+ sourceBlobDigest: sha256:22a0a735520200446a3deb7951eedee023d6bf24365011fd80670fa3b6cad6bb
tags:
- latest
- 1.0.0
@@ -11,10 +11,10 @@ targets:
open-router:
source: OpenRouter API
sourceNamespace: open-router-chat-completions-api
- sourceRevisionDigest: sha256:2da9790d04eb9873088b59c89e7456494fc51041d339e057428ccf326dabe8e5
- sourceBlobDigest: sha256:fe041198672377cdbae02cfb2a1342e1d96dc5de89fb2338946809ade321fea6
+ sourceRevisionDigest: sha256:aaea7962bb250e48c30aef0665e01972f79cf4b7b5f808aafca88ea64dae0b64
+ sourceBlobDigest: sha256:22a0a735520200446a3deb7951eedee023d6bf24365011fd80670fa3b6cad6bb
codeSamplesNamespace: open-router-python-code-samples
- codeSamplesRevisionDigest: sha256:b23baa9166ec8ee272754fd101966676f619c29ab42423aafeae165f44f8f35e
+ codeSamplesRevisionDigest: sha256:302a2a067b3442735f68158a236dc28ac6b70785bb6560e902e620641c91eeb1
workflow:
workflowVersion: 1.0.0
speakeasyVersion: 1.803.2
diff --git a/RELEASES.md b/RELEASES.md
index c0a08182..5074b4c3 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -4479,4 +4479,14 @@ Based on:
### Generated
- [python v1.3.171] .
### Releases
-- [PyPI v1.3.171] https://pypi.org/project/openrouter/1.3.171 - .
\ No newline at end of file
+- [PyPI v1.3.171] https://pypi.org/project/openrouter/1.3.171 - .
+
+## 2026-11-12 19:40:35
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.803.2 (2.950.13) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v1.3.172] .
+### Releases
+- [PyPI v1.3.172] https://pypi.org/project/openrouter/1.3.172 - .
\ No newline at end of file
diff --git a/docs/components/contentfilterreadentry.mdx b/docs/components/contentfilterreadentry.mdx
new file mode 100644
index 00000000..e76e781e
--- /dev/null
+++ b/docs/components/contentfilterreadentry.mdx
@@ -0,0 +1,15 @@
+---
+title: "ContentFilterReadEntry"
+---
+
+A custom regex content filter, with whether inference enforces it.
+
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `action` | [components.ContentFilterAction](../components/contentfilteraction.mdx) | ✔️ | Action taken when the pattern matches | block |
+| `label` | *OptionalNullable[str]* | ➖ | Optional label used in redaction placeholders or error messages | [API_KEY] |
+| `pattern` | *str* | ✔️ | A regex pattern to match against request content | \b(sk-[a-zA-Z0-9]\{48})\b |
+| `is_enforced` | *bool* | ✔️ | Whether inference applies this pattern. False for a pattern saved before pattern validation that is too complex to run safely; it is kept but skipped until replaced. | true |
\ No newline at end of file
diff --git a/docs/components/guardrail.mdx b/docs/components/guardrail.mdx
index 9095f97d..16a5de46 100644
--- a/docs/components/guardrail.mdx
+++ b/docs/components/guardrail.mdx
@@ -12,7 +12,7 @@ title: "Guardrail"
| `allowed_models` | List[*str*] | ➖ | Array of model canonical_slugs (immutable identifiers) | [
"openai/gpt-5.2-20251211",
"anthropic/claude-4.5-opus-20251124",
"deepseek/deepseek-r1-0528:free"
] |
| `allowed_providers` | List[*str*] | ➖ | List of allowed provider IDs | [
"openai",
"anthropic",
"google"
] |
| `content_filter_builtins` | List[[components.ContentFilterBuiltinEntry](../components/contentfilterbuiltinentry.mdx)] | ➖ | Builtin content filters applied to requests. Includes PII detectors and the regex-based prompt injection detector. | [
\{
"action": "redact",
"label": "[EMAIL]",
"slug": "email"
}
] |
-| `content_filters` | List[[components.ContentFilterEntry](../components/contentfilterentry.mdx)] | ➖ | Custom regex content filters applied to request messages | [
\{
"action": "redact",
"label": "[API_KEY]",
"pattern": "\\b(sk-[a-zA-Z0-9]\{48})\\b"
}
] |
+| `content_filters` | List[[components.ContentFilterReadEntry](../components/contentfilterreadentry.mdx)] | ➖ | Custom regex content filters applied to request messages | [
\{
"action": "redact",
"is_enforced": true,
"label": "[API_KEY]",
"pattern": "\\b(sk-[a-zA-Z0-9]\{48})\\b"
}
] |
| `created_at` | *str* | ✔️ | ISO 8601 timestamp of when the guardrail was created | 2025-08-24T10:30:00Z |
| `description` | *OptionalNullable[str]* | ➖ | Description of the guardrail | Guardrail for production environment |
| `enable_free_model_publication` | *OptionalNullable[bool]* | ➖ | Whether this guardrail allows free endpoints that publish prompts. | false |
diff --git a/pyproject.toml b/pyproject.toml
index d5e09745..10294129 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "openrouter"
-version = "1.3.171"
+version = "1.3.172"
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 015b9fc8..3a4ea3ee 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.171"
+__version__: str = "1.3.172"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.950.13"
-__user_agent__: str = "speakeasy-sdk/python 1.3.171 2.950.13 1.0.0 openrouter"
+__user_agent__: str = "speakeasy-sdk/python 1.3.172 2.950.13 1.0.0 openrouter"
try:
if __package__ is not None:
diff --git a/src/openrouter/components/__init__.py b/src/openrouter/components/__init__.py
index 0f5c732d..cfdfb3cf 100644
--- a/src/openrouter/components/__init__.py
+++ b/src/openrouter/components/__init__.py
@@ -1503,6 +1503,10 @@
)
from .contentfilterbuiltinslug import ContentFilterBuiltinSlug
from .contentfilterentry import ContentFilterEntry, ContentFilterEntryTypedDict
+ from .contentfilterreadentry import (
+ ContentFilterReadEntry,
+ ContentFilterReadEntryTypedDict,
+ )
from .contentpartaddedevent import (
ContentPartAddedEvent,
ContentPartAddedEventPart,
@@ -6092,6 +6096,8 @@
"ContentFilterBuiltinTypedDict",
"ContentFilterEntry",
"ContentFilterEntryTypedDict",
+ "ContentFilterReadEntry",
+ "ContentFilterReadEntryTypedDict",
"ContentFilterTypedDict",
"ContentImageURL",
"ContentImageURLImageURL",
@@ -9888,6 +9894,8 @@
"ContentFilterBuiltinSlug": ".contentfilterbuiltinslug",
"ContentFilterEntry": ".contentfilterentry",
"ContentFilterEntryTypedDict": ".contentfilterentry",
+ "ContentFilterReadEntry": ".contentfilterreadentry",
+ "ContentFilterReadEntryTypedDict": ".contentfilterreadentry",
"ContentPartAddedEvent": ".contentpartaddedevent",
"ContentPartAddedEventPart": ".contentpartaddedevent",
"ContentPartAddedEventPartTypedDict": ".contentpartaddedevent",
diff --git a/src/openrouter/components/contentfilterreadentry.py b/src/openrouter/components/contentfilterreadentry.py
new file mode 100644
index 00000000..3a227dba
--- /dev/null
+++ b/src/openrouter/components/contentfilterreadentry.py
@@ -0,0 +1,67 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from .contentfilteraction import ContentFilterAction
+from openrouter.types import (
+ BaseModel,
+ Nullable,
+ OptionalNullable,
+ UNSET,
+ UNSET_SENTINEL,
+)
+from pydantic import model_serializer
+from typing_extensions import NotRequired, TypedDict
+
+
+class ContentFilterReadEntryTypedDict(TypedDict):
+ r"""A custom regex content filter, with whether inference enforces it."""
+
+ action: ContentFilterAction
+ r"""Action taken when the pattern matches"""
+ pattern: str
+ r"""A regex pattern to match against request content"""
+ is_enforced: bool
+ r"""Whether inference applies this pattern. False for a pattern saved before pattern validation that is too complex to run safely; it is kept but skipped until replaced."""
+ label: NotRequired[Nullable[str]]
+ r"""Optional label used in redaction placeholders or error messages"""
+
+
+class ContentFilterReadEntry(BaseModel):
+ r"""A custom regex content filter, with whether inference enforces it."""
+
+ action: ContentFilterAction
+ r"""Action taken when the pattern matches"""
+
+ pattern: str
+ r"""A regex pattern to match against request content"""
+
+ is_enforced: bool
+ r"""Whether inference applies this pattern. False for a pattern saved before pattern validation that is too complex to run safely; it is kept but skipped until replaced."""
+
+ label: OptionalNullable[str] = UNSET
+ r"""Optional label used in redaction placeholders or error messages"""
+
+ @model_serializer(mode="wrap")
+ def serialize_model(self, handler):
+ optional_fields = set(["label"])
+ nullable_fields = set(["label"])
+ 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))
+ is_nullable_and_explicitly_set = (
+ k in nullable_fields
+ and (self.__pydantic_fields_set__.intersection({n})) # pylint: disable=no-member
+ )
+
+ if val != UNSET_SENTINEL:
+ if (
+ val is not None
+ or k not in optional_fields
+ or is_nullable_and_explicitly_set
+ ):
+ m[k] = val
+
+ return m
diff --git a/src/openrouter/components/guardrail.py b/src/openrouter/components/guardrail.py
index 252b3290..1d5e7be6 100644
--- a/src/openrouter/components/guardrail.py
+++ b/src/openrouter/components/guardrail.py
@@ -5,7 +5,10 @@
ContentFilterBuiltinEntry,
ContentFilterBuiltinEntryTypedDict,
)
-from .contentfilterentry import ContentFilterEntry, ContentFilterEntryTypedDict
+from .contentfilterreadentry import (
+ ContentFilterReadEntry,
+ ContentFilterReadEntryTypedDict,
+)
from .guardraildataregion import GuardrailDataRegion
from .guardrailinterval import GuardrailInterval
from openrouter.types import (
@@ -46,7 +49,7 @@ class GuardrailTypedDict(TypedDict):
Nullable[List[ContentFilterBuiltinEntryTypedDict]]
]
r"""Builtin content filters applied to requests. Includes PII detectors and the regex-based prompt injection detector."""
- content_filters: NotRequired[Nullable[List[ContentFilterEntryTypedDict]]]
+ content_filters: NotRequired[Nullable[List[ContentFilterReadEntryTypedDict]]]
r"""Custom regex content filters applied to request messages"""
description: NotRequired[Nullable[str]]
r"""Description of the guardrail"""
@@ -116,7 +119,7 @@ class Guardrail(BaseModel):
content_filter_builtins: OptionalNullable[List[ContentFilterBuiltinEntry]] = UNSET
r"""Builtin content filters applied to requests. Includes PII detectors and the regex-based prompt injection detector."""
- content_filters: OptionalNullable[List[ContentFilterEntry]] = UNSET
+ content_filters: OptionalNullable[List[ContentFilterReadEntry]] = UNSET
r"""Custom regex content filters applied to request messages"""
description: OptionalNullable[str] = UNSET
diff --git a/uv.lock b/uv.lock
index 72c34a41..ffd45e16 100644
--- a/uv.lock
+++ b/uv.lock
@@ -231,7 +231,7 @@ wheels = [
[[package]]
name = "openrouter"
-version = "1.3.171"
+version = "1.3.172"
source = { editable = "." }
dependencies = [
{ name = "httpcore" },