chore: 🐝 Update SDK - Generate (spec change merged) 0.11.4 (#396)

Co-authored-by: speakeasybot <bot@speakeasyapi.dev>
Co-authored-by: speakeasy-github[bot] <128539517+speakeasy-github[bot]@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2026-07-07 14:35:05 +00:00
committed by GitHub
co-authored by speakeasybot speakeasy-github[bot] <128539517+speakeasy-github[bot]@users.noreply.github.com>
parent 34403bd422
commit 1e88de8988
35 changed files with 1073 additions and 148 deletions
+2 -2
View File
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "openrouter"
__version__: str = "0.11.3"
__version__: str = "0.11.4"
__openapi_doc_version__: str = "1.0.0"
__gen_version__: str = "2.914.0"
__user_agent__: str = "speakeasy-sdk/python 0.11.3 2.914.0 1.0.0 openrouter"
__user_agent__: str = "speakeasy-sdk/python 0.11.4 2.914.0 1.0.0 openrouter"
try:
if __package__ is not None:
+3
View File
@@ -2074,6 +2074,7 @@ if TYPE_CHECKING:
ParetoRouterPlugin,
ParetoRouterPluginID,
ParetoRouterPluginTypedDict,
PriceSource,
)
from .payloadtoolargeresponseerrordata import (
PayloadTooLargeResponseErrorData,
@@ -4192,6 +4193,7 @@ __all__ = [
"PreviewWebSearchUserLocation",
"PreviewWebSearchUserLocationType",
"PreviewWebSearchUserLocationTypedDict",
"PriceSource",
"Pricing",
"PricingTypedDict",
"PromptInjectionScanScope",
@@ -6262,6 +6264,7 @@ _dynamic_imports: dict[str, str] = {
"ParetoRouterPlugin": ".paretorouterplugin",
"ParetoRouterPluginID": ".paretorouterplugin",
"ParetoRouterPluginTypedDict": ".paretorouterplugin",
"PriceSource": ".paretorouterplugin",
"PayloadTooLargeResponseErrorData": ".payloadtoolargeresponseerrordata",
"PayloadTooLargeResponseErrorDataTypedDict": ".payloadtoolargeresponseerrordata",
"PaymentRequiredResponseErrorData": ".paymentrequiredresponseerrordata",
+1 -1
View File
@@ -78,8 +78,8 @@ ChatRequestPluginTypedDict = TypeAliasType(
ResponseHealingPluginTypedDict,
FileParserPluginTypedDict,
ContextCompressionPluginTypedDict,
ParetoRouterPluginTypedDict,
AutoRouterPluginTypedDict,
ParetoRouterPluginTypedDict,
WebFetchPluginTypedDict,
FusionPluginTypedDict,
WebSearchPluginTypedDict,
@@ -698,7 +698,7 @@ class ImageGenerationRequestTypedDict(TypedDict):
seed: NotRequired[int]
r"""If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers."""
size: NotRequired[str]
r"""Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected."""
r"""Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400."""
stream: NotRequired[bool]
r"""If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response."""
@@ -743,7 +743,7 @@ class ImageGenerationRequest(BaseModel):
r"""If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers."""
size: Optional[str] = None
r"""Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected."""
r"""Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400."""
stream: Optional[bool] = None
r"""If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response."""
+1 -1
View File
@@ -355,8 +355,8 @@ MessagesRequestPluginTypedDict = TypeAliasType(
ResponseHealingPluginTypedDict,
FileParserPluginTypedDict,
ContextCompressionPluginTypedDict,
ParetoRouterPluginTypedDict,
AutoRouterPluginTypedDict,
ParetoRouterPluginTypedDict,
WebFetchPluginTypedDict,
FusionPluginTypedDict,
WebSearchPluginTypedDict,
@@ -1,21 +1,33 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
from openrouter.types import BaseModel, UNSET_SENTINEL
from openrouter.types import BaseModel, UNSET_SENTINEL, UnrecognizedStr
from pydantic import model_serializer
from typing import Literal, Optional
from typing import Literal, Optional, Union
from typing_extensions import NotRequired, TypedDict
ParetoRouterPluginID = Literal["pareto-router",]
PriceSource = Union[
Literal[
"prompt",
"weighted_avg",
],
UnrecognizedStr,
]
r"""Price source for the Pareto frontier cost axis. \"prompt\" uses catalog list price (endpoint.pricing.prompt). \"weighted_avg\" uses traffic-weighted effective input price from ClickHouse, falling back to prompt price for models without traffic data. Defaults to \"prompt\"."""
class ParetoRouterPluginTypedDict(TypedDict):
id: ParetoRouterPluginID
enabled: NotRequired[bool]
r"""Set to false to disable the pareto-router plugin for this request. Defaults to true."""
min_coding_score: NotRequired[float]
r"""Minimum desired coding score between 0 and 1, where 1 is best. Higher values select from stronger coding models (sourced from Artificial Analysis coding percentiles). Maps internally to one of three tiers (low, medium, high). Omit to use the router default tier."""
r"""Minimum coding quality score between 0 and 1. Maps to internal quality tiers: >= 0.66 → high (top coding models), >= 0.33 → medium (strong modern flagships), < 0.33 → low (capable coders above the median). Omit to default to the highest tier (equivalent to >= 0.66)."""
price_source: NotRequired[PriceSource]
r"""Price source for the Pareto frontier cost axis. \"prompt\" uses catalog list price (endpoint.pricing.prompt). \"weighted_avg\" uses traffic-weighted effective input price from ClickHouse, falling back to prompt price for models without traffic data. Defaults to \"prompt\"."""
class ParetoRouterPlugin(BaseModel):
@@ -25,11 +37,14 @@ class ParetoRouterPlugin(BaseModel):
r"""Set to false to disable the pareto-router plugin for this request. Defaults to true."""
min_coding_score: Optional[float] = None
r"""Minimum desired coding score between 0 and 1, where 1 is best. Higher values select from stronger coding models (sourced from Artificial Analysis coding percentiles). Maps internally to one of three tiers (low, medium, high). Omit to use the router default tier."""
r"""Minimum coding quality score between 0 and 1. Maps to internal quality tiers: >= 0.66 → high (top coding models), >= 0.33 → medium (strong modern flagships), < 0.33 → low (capable coders above the median). Omit to default to the highest tier (equivalent to >= 0.66)."""
price_source: Optional[PriceSource] = None
r"""Price source for the Pareto frontier cost axis. \"prompt\" uses catalog list price (endpoint.pricing.prompt). \"weighted_avg\" uses traffic-weighted effective input price from ClickHouse, falling back to prompt price for models without traffic data. Defaults to \"prompt\"."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["enabled", "min_coding_score"])
optional_fields = set(["enabled", "min_coding_score", "price_source"])
serialized = handler(self)
m = {}
@@ -123,8 +123,8 @@ ResponsesRequestPluginTypedDict = TypeAliasType(
ResponseHealingPluginTypedDict,
FileParserPluginTypedDict,
ContextCompressionPluginTypedDict,
ParetoRouterPluginTypedDict,
AutoRouterPluginTypedDict,
ParetoRouterPluginTypedDict,
WebFetchPluginTypedDict,
FusionPluginTypedDict,
WebSearchPluginTypedDict,
+4 -4
View File
@@ -360,7 +360,7 @@ class Files(BaseSDK):
def upload(
self,
*,
file: Union[operations.File, operations.FileTypedDict],
file: Union[operations.UploadFileFile, operations.UploadFileFileTypedDict],
http_referer: Optional[str] = None,
x_open_router_title: Optional[str] = None,
x_open_router_categories: Optional[str] = None,
@@ -404,7 +404,7 @@ class Files(BaseSDK):
x_open_router_categories=x_open_router_categories,
workspace_id=workspace_id,
request_body=operations.UploadFileRequestBody(
file=utils.get_pydantic_model(file, operations.File),
file=utils.get_pydantic_model(file, operations.UploadFileFile),
),
)
@@ -515,7 +515,7 @@ class Files(BaseSDK):
async def upload_async(
self,
*,
file: Union[operations.File, operations.FileTypedDict],
file: Union[operations.UploadFileFile, operations.UploadFileFileTypedDict],
http_referer: Optional[str] = None,
x_open_router_title: Optional[str] = None,
x_open_router_categories: Optional[str] = None,
@@ -559,7 +559,7 @@ class Files(BaseSDK):
x_open_router_categories=x_open_router_categories,
workspace_id=workspace_id,
request_body=operations.UploadFileRequestBody(
file=utils.get_pydantic_model(file, operations.File),
file=utils.get_pydantic_model(file, operations.UploadFileFile),
),
)
+8 -8
View File
@@ -71,7 +71,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -138,7 +138,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -208,7 +208,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -277,7 +277,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -543,7 +543,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -610,7 +610,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -680,7 +680,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -749,7 +749,7 @@ class Images(BaseSDK):
:param quality: Rendering quality. Providers without a quality knob ignore this.
:param resolution: Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider.
:param seed: If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. Interchangeable with resolution + aspect_ratio; use those directly for enumerated, per-model discoverable values. Conflicting size + resolution/aspect_ratio is rejected.
:param size: Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.
:param stream: If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
+35 -6
View File
@@ -53,6 +53,17 @@ if TYPE_CHECKING:
CreateAudioTranscriptionsRequest,
CreateAudioTranscriptionsRequestTypedDict,
)
from .createaudiotranscriptions_multipart import (
CreateAudioTranscriptionsMultipartFile,
CreateAudioTranscriptionsMultipartFileTypedDict,
CreateAudioTranscriptionsMultipartGlobals,
CreateAudioTranscriptionsMultipartGlobalsTypedDict,
CreateAudioTranscriptionsMultipartRequest,
CreateAudioTranscriptionsMultipartRequestBody,
CreateAudioTranscriptionsMultipartRequestBodyTypedDict,
CreateAudioTranscriptionsMultipartRequestTypedDict,
ResponseFormat,
)
from .createauthkeyscode import (
CreateAuthKeysCodeCodeChallengeMethod,
CreateAuthKeysCodeData,
@@ -707,8 +718,8 @@ if TYPE_CHECKING:
UpdateWorkspaceRequestTypedDict,
)
from .uploadfile import (
File,
FileTypedDict,
UploadFileFile,
UploadFileFileTypedDict,
UploadFileGlobals,
UploadFileGlobalsTypedDict,
UploadFileRequest,
@@ -763,6 +774,14 @@ __all__ = [
"CreateAudioSpeechRequestTypedDict",
"CreateAudioTranscriptionsGlobals",
"CreateAudioTranscriptionsGlobalsTypedDict",
"CreateAudioTranscriptionsMultipartFile",
"CreateAudioTranscriptionsMultipartFileTypedDict",
"CreateAudioTranscriptionsMultipartGlobals",
"CreateAudioTranscriptionsMultipartGlobalsTypedDict",
"CreateAudioTranscriptionsMultipartRequest",
"CreateAudioTranscriptionsMultipartRequestBody",
"CreateAudioTranscriptionsMultipartRequestBodyTypedDict",
"CreateAudioTranscriptionsMultipartRequestTypedDict",
"CreateAudioTranscriptionsRequest",
"CreateAudioTranscriptionsRequestTypedDict",
"CreateAuthKeysCodeCodeChallengeMethod",
@@ -915,8 +934,6 @@ __all__ = [
"ExchangeAuthCodeForAPIKeyRequestTypedDict",
"ExchangeAuthCodeForAPIKeyResponse",
"ExchangeAuthCodeForAPIKeyResponseTypedDict",
"File",
"FileTypedDict",
"Filter",
"FilterTypedDict",
"GetAnalyticsMetaData",
@@ -1208,6 +1225,7 @@ __all__ = [
"RateLimit",
"RateLimitTypedDict",
"Region",
"ResponseFormat",
"Result",
"ResultTypedDict",
"Role",
@@ -1251,6 +1269,8 @@ __all__ = [
"UpdateWorkspaceGlobalsTypedDict",
"UpdateWorkspaceRequest",
"UpdateWorkspaceRequestTypedDict",
"UploadFileFile",
"UploadFileFileTypedDict",
"UploadFileGlobals",
"UploadFileGlobalsTypedDict",
"UploadFileRequest",
@@ -1304,6 +1324,15 @@ _dynamic_imports: dict[str, str] = {
"CreateAudioTranscriptionsGlobalsTypedDict": ".createaudiotranscriptions",
"CreateAudioTranscriptionsRequest": ".createaudiotranscriptions",
"CreateAudioTranscriptionsRequestTypedDict": ".createaudiotranscriptions",
"CreateAudioTranscriptionsMultipartFile": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartFileTypedDict": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartGlobals": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartGlobalsTypedDict": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartRequest": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartRequestBody": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartRequestBodyTypedDict": ".createaudiotranscriptions_multipart",
"CreateAudioTranscriptionsMultipartRequestTypedDict": ".createaudiotranscriptions_multipart",
"ResponseFormat": ".createaudiotranscriptions_multipart",
"CreateAuthKeysCodeCodeChallengeMethod": ".createauthkeyscode",
"CreateAuthKeysCodeData": ".createauthkeyscode",
"CreateAuthKeysCodeDataTypedDict": ".createauthkeyscode",
@@ -1805,8 +1834,8 @@ _dynamic_imports: dict[str, str] = {
"UpdateWorkspaceGlobalsTypedDict": ".updateworkspace",
"UpdateWorkspaceRequest": ".updateworkspace",
"UpdateWorkspaceRequestTypedDict": ".updateworkspace",
"File": ".uploadfile",
"FileTypedDict": ".uploadfile",
"UploadFileFile": ".uploadfile",
"UploadFileFileTypedDict": ".uploadfile",
"UploadFileGlobals": ".uploadfile",
"UploadFileGlobalsTypedDict": ".uploadfile",
"UploadFileRequest": ".uploadfile",
@@ -0,0 +1,244 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
import io
from openrouter.types import BaseModel, UNSET_SENTINEL
from openrouter.utils import (
FieldMetadata,
HeaderMetadata,
MultipartFormMetadata,
RequestMetadata,
)
import pydantic
from pydantic import model_serializer
from typing import IO, Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypedDict
class CreateAudioTranscriptionsMultipartGlobalsTypedDict(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 CreateAudioTranscriptionsMultipartGlobals(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 CreateAudioTranscriptionsMultipartFileTypedDict(TypedDict):
file_name: str
content: Union[bytes, IO[bytes], io.IOBase]
content_type: NotRequired[str]
class CreateAudioTranscriptionsMultipartFile(BaseModel):
file_name: Annotated[
str, pydantic.Field(alias="fileName"), FieldMetadata(multipart=True)
]
content: Annotated[
Union[bytes, IO[bytes], io.IOBase],
pydantic.Field(alias=""),
FieldMetadata(multipart=MultipartFormMetadata(content=True)),
]
content_type: Annotated[
Optional[str],
pydantic.Field(alias="Content-Type"),
FieldMetadata(multipart=True),
] = None
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["contentType"])
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
ResponseFormat = Literal["json",]
r"""The response format. Only \"json\" is supported."""
class CreateAudioTranscriptionsMultipartRequestBodyTypedDict(TypedDict):
file: CreateAudioTranscriptionsMultipartFileTypedDict
r"""The audio file to transcribe. The format is derived from the filename extension or the file part content type. Max 25 MB; send larger files as base64 JSON via input_audio."""
model: str
r"""The model to use for transcription."""
language: NotRequired[str]
r"""The language of the input audio (ISO-639-1)."""
response_format: NotRequired[ResponseFormat]
r"""The response format. Only \"json\" is supported."""
temperature: NotRequired[float]
r"""The sampling temperature."""
class CreateAudioTranscriptionsMultipartRequestBody(BaseModel):
file: Annotated[
CreateAudioTranscriptionsMultipartFile,
FieldMetadata(multipart=MultipartFormMetadata(file=True)),
]
r"""The audio file to transcribe. The format is derived from the filename extension or the file part content type. Max 25 MB; send larger files as base64 JSON via input_audio."""
model: Annotated[str, FieldMetadata(multipart=True)]
r"""The model to use for transcription."""
language: Annotated[Optional[str], FieldMetadata(multipart=True)] = None
r"""The language of the input audio (ISO-639-1)."""
response_format: Annotated[
Optional[ResponseFormat], FieldMetadata(multipart=True)
] = None
r"""The response format. Only \"json\" is supported."""
temperature: Annotated[Optional[float], FieldMetadata(multipart=True)] = None
r"""The sampling temperature."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
optional_fields = set(["language", "response_format", "temperature"])
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 CreateAudioTranscriptionsMultipartRequestTypedDict(TypedDict):
request_body: CreateAudioTranscriptionsMultipartRequestBodyTypedDict
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 CreateAudioTranscriptionsMultipartRequest(BaseModel):
request_body: Annotated[
CreateAudioTranscriptionsMultipartRequestBody,
FieldMetadata(request=RequestMetadata(media_type="multipart/form-data")),
]
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
+6 -4
View File
@@ -80,13 +80,13 @@ class UploadFileGlobals(BaseModel):
return m
class FileTypedDict(TypedDict):
class UploadFileFileTypedDict(TypedDict):
file_name: str
content: Union[bytes, IO[bytes], io.IOBase]
content_type: NotRequired[str]
class File(BaseModel):
class UploadFileFile(BaseModel):
file_name: Annotated[
str, pydantic.Field(alias="fileName"), FieldMetadata(multipart=True)
]
@@ -121,11 +121,13 @@ class File(BaseModel):
class UploadFileRequestBodyTypedDict(TypedDict):
file: FileTypedDict
file: UploadFileFileTypedDict
class UploadFileRequestBody(BaseModel):
file: Annotated[File, FieldMetadata(multipart=MultipartFormMetadata(file=True))]
file: Annotated[
UploadFileFile, FieldMetadata(multipart=MultipartFormMetadata(file=True))
]
class UploadFileRequestTypedDict(TypedDict):
+380 -2
View File
@@ -32,7 +32,7 @@ class Stt(BaseSDK):
) -> components.STTResponse:
r"""Create transcription
Transcribes audio into text. Accepts base64-encoded audio input and returns the transcribed text.
Transcribes audio into text. Accepts base64-encoded audio input as JSON or an OpenAI-style multipart/form-data file upload, and returns the transcribed text.
:param input_audio: Base64-encoded audio to transcribe
:param model: STT model identifier
@@ -218,7 +218,7 @@ class Stt(BaseSDK):
) -> components.STTResponse:
r"""Create transcription
Transcribes audio into text. Accepts base64-encoded audio input and returns the transcribed text.
Transcribes audio into text. Accepts base64-encoded audio input as JSON or an OpenAI-style multipart/form-data file upload, and returns the transcribed text.
:param input_audio: Base64-encoded audio to transcribe
:param model: STT model identifier
@@ -383,3 +383,381 @@ class Stt(BaseSDK):
)
raise errors.OpenRouterDefaultError("Unexpected response received", http_res)
def create_transcription_multipart(
self,
*,
file: Union[
operations.CreateAudioTranscriptionsMultipartFile,
operations.CreateAudioTranscriptionsMultipartFileTypedDict,
],
model: str,
http_referer: Optional[str] = None,
x_open_router_title: Optional[str] = None,
x_open_router_categories: Optional[str] = None,
language: Optional[str] = None,
response_format: Optional[operations.ResponseFormat] = None,
temperature: Optional[float] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> components.STTResponse:
r"""Create transcription
Transcribes audio into text. Accepts base64-encoded audio input as JSON or an OpenAI-style multipart/form-data file upload, and returns the transcribed text.
:param file: The audio file to transcribe. The format is derived from the filename extension or the file part content type. Max 25 MB; send larger files as base64 JSON via input_audio.
:param model: The model to use for transcription.
: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 language: The language of the input audio (ISO-639-1).
:param response_format: The response format. Only \"json\" is supported.
:param temperature: The sampling temperature.
: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.CreateAudioTranscriptionsMultipartRequest(
http_referer=http_referer,
x_open_router_title=x_open_router_title,
x_open_router_categories=x_open_router_categories,
request_body=operations.CreateAudioTranscriptionsMultipartRequestBody(
file=utils.get_pydantic_model(
file, operations.CreateAudioTranscriptionsMultipartFile
),
language=language,
model=model,
response_format=response_format,
temperature=temperature,
),
)
req = self._build_request(
method="POST",
path="/audio/transcriptions",
base_url=base_url,
url_variables=url_variables,
request=request,
request_body_required=True,
request_has_path_params=False,
request_has_query_params=True,
user_agent_header="user-agent",
accept_header_value="application/json",
http_headers=http_headers,
_globals=operations.CreateAudioTranscriptionsMultipartGlobals(
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.request_body,
False,
False,
"multipart",
operations.CreateAudioTranscriptionsMultipartRequestBody,
),
allow_empty_value=None,
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="createAudioTranscriptions_multipart",
oauth2_scopes=None,
security_source=get_security_from_env(
self.sdk_configuration.security, components.Security
),
tags=["STT"],
extensions=None,
),
request=req,
is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
retry_config=retry_config,
)
response_data: Any = None
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.STTResponse, http_res)
if utils.match_response(http_res, "400", "application/json"):
response_data = unmarshal_json_response(
errors.BadRequestResponseErrorData, http_res
)
raise errors.BadRequestResponseError(response_data, http_res)
if utils.match_response(http_res, "401", "application/json"):
response_data = unmarshal_json_response(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
if utils.match_response(http_res, "402", "application/json"):
response_data = unmarshal_json_response(
errors.PaymentRequiredResponseErrorData, http_res
)
raise errors.PaymentRequiredResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
)
raise errors.NotFoundResponseError(response_data, http_res)
if utils.match_response(http_res, "429", "application/json"):
response_data = unmarshal_json_response(
errors.TooManyRequestsResponseErrorData, http_res
)
raise errors.TooManyRequestsResponseError(response_data, http_res)
if utils.match_response(http_res, "500", "application/json"):
response_data = unmarshal_json_response(
errors.InternalServerResponseErrorData, http_res
)
raise errors.InternalServerResponseError(response_data, http_res)
if utils.match_response(http_res, "502", "application/json"):
response_data = unmarshal_json_response(
errors.BadGatewayResponseErrorData, http_res
)
raise errors.BadGatewayResponseError(response_data, http_res)
if utils.match_response(http_res, "503", "application/json"):
response_data = unmarshal_json_response(
errors.ServiceUnavailableResponseErrorData, http_res
)
raise errors.ServiceUnavailableResponseError(response_data, http_res)
if utils.match_response(http_res, "524", "application/json"):
response_data = unmarshal_json_response(
errors.EdgeNetworkTimeoutResponseErrorData, http_res
)
raise errors.EdgeNetworkTimeoutResponseError(response_data, http_res)
if utils.match_response(http_res, "529", "application/json"):
response_data = unmarshal_json_response(
errors.ProviderOverloadedResponseErrorData, http_res
)
raise errors.ProviderOverloadedResponseError(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 create_transcription_multipart_async(
self,
*,
file: Union[
operations.CreateAudioTranscriptionsMultipartFile,
operations.CreateAudioTranscriptionsMultipartFileTypedDict,
],
model: str,
http_referer: Optional[str] = None,
x_open_router_title: Optional[str] = None,
x_open_router_categories: Optional[str] = None,
language: Optional[str] = None,
response_format: Optional[operations.ResponseFormat] = None,
temperature: Optional[float] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> components.STTResponse:
r"""Create transcription
Transcribes audio into text. Accepts base64-encoded audio input as JSON or an OpenAI-style multipart/form-data file upload, and returns the transcribed text.
:param file: The audio file to transcribe. The format is derived from the filename extension or the file part content type. Max 25 MB; send larger files as base64 JSON via input_audio.
:param model: The model to use for transcription.
: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 language: The language of the input audio (ISO-639-1).
:param response_format: The response format. Only \"json\" is supported.
:param temperature: The sampling temperature.
: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.CreateAudioTranscriptionsMultipartRequest(
http_referer=http_referer,
x_open_router_title=x_open_router_title,
x_open_router_categories=x_open_router_categories,
request_body=operations.CreateAudioTranscriptionsMultipartRequestBody(
file=utils.get_pydantic_model(
file, operations.CreateAudioTranscriptionsMultipartFile
),
language=language,
model=model,
response_format=response_format,
temperature=temperature,
),
)
req = self._build_request_async(
method="POST",
path="/audio/transcriptions",
base_url=base_url,
url_variables=url_variables,
request=request,
request_body_required=True,
request_has_path_params=False,
request_has_query_params=True,
user_agent_header="user-agent",
accept_header_value="application/json",
http_headers=http_headers,
_globals=operations.CreateAudioTranscriptionsMultipartGlobals(
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.request_body,
False,
False,
"multipart",
operations.CreateAudioTranscriptionsMultipartRequestBody,
),
allow_empty_value=None,
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="createAudioTranscriptions_multipart",
oauth2_scopes=None,
security_source=get_security_from_env(
self.sdk_configuration.security, components.Security
),
tags=["STT"],
extensions=None,
),
request=req,
is_error_status_code=lambda c: utils.match_status_codes(["4XX", "5XX"], c),
retry_config=retry_config,
)
response_data: Any = None
if utils.match_response(http_res, "200", "application/json"):
return unmarshal_json_response(components.STTResponse, http_res)
if utils.match_response(http_res, "400", "application/json"):
response_data = unmarshal_json_response(
errors.BadRequestResponseErrorData, http_res
)
raise errors.BadRequestResponseError(response_data, http_res)
if utils.match_response(http_res, "401", "application/json"):
response_data = unmarshal_json_response(
errors.UnauthorizedResponseErrorData, http_res
)
raise errors.UnauthorizedResponseError(response_data, http_res)
if utils.match_response(http_res, "402", "application/json"):
response_data = unmarshal_json_response(
errors.PaymentRequiredResponseErrorData, http_res
)
raise errors.PaymentRequiredResponseError(response_data, http_res)
if utils.match_response(http_res, "404", "application/json"):
response_data = unmarshal_json_response(
errors.NotFoundResponseErrorData, http_res
)
raise errors.NotFoundResponseError(response_data, http_res)
if utils.match_response(http_res, "429", "application/json"):
response_data = unmarshal_json_response(
errors.TooManyRequestsResponseErrorData, http_res
)
raise errors.TooManyRequestsResponseError(response_data, http_res)
if utils.match_response(http_res, "500", "application/json"):
response_data = unmarshal_json_response(
errors.InternalServerResponseErrorData, http_res
)
raise errors.InternalServerResponseError(response_data, http_res)
if utils.match_response(http_res, "502", "application/json"):
response_data = unmarshal_json_response(
errors.BadGatewayResponseErrorData, http_res
)
raise errors.BadGatewayResponseError(response_data, http_res)
if utils.match_response(http_res, "503", "application/json"):
response_data = unmarshal_json_response(
errors.ServiceUnavailableResponseErrorData, http_res
)
raise errors.ServiceUnavailableResponseError(response_data, http_res)
if utils.match_response(http_res, "524", "application/json"):
response_data = unmarshal_json_response(
errors.EdgeNetworkTimeoutResponseErrorData, http_res
)
raise errors.EdgeNetworkTimeoutResponseError(response_data, http_res)
if utils.match_response(http_res, "529", "application/json"):
response_data = unmarshal_json_response(
errors.ProviderOverloadedResponseErrorData, http_res
)
raise errors.ProviderOverloadedResponseError(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)