osyra
osyra — client for Osyra's narrow OpenAI-compatible inference surface.
import os
from osyra import OpenAI
client = OpenAI(
token_provider=lambda: os.environ["OSYRA_ACCESS_TOKEN"],
) # base_url defaults to https://api.osyra.ai/v1
resp = client.chat.completions.create(
model=os.environ["OSYRA_MODEL"],
messages=[{"role": "user", "content": "Hello!"}],
)Sync (``OpenAI``) and async (``AsyncOpenAI``) clients; the native ``Osyra`` / ``AsyncOsyra`` aliases; ``client.chat.completions`` (non-streaming + streaming SSE), ``client.embeddings``, ``client.models.list()``, the native ``client.osyra.*`` surface (models wired; cost/routing/health pending an edge route — AP00023 OQ-2), the three Osyra extras (osyra_workspace / osyra_cache_ttl / osyra_pii_mask -> X-Osyra-* headers), canonical API-key/OAuth auth, and typed error mapping.
Exact IAM-issued ``osy_(sandbox|test|live)_<43 base64url>`` keys use only ``X-Api-Key``. OAuth JWTs and token-provider results use only ``Authorization: Bearer``. API-key crypto and its KMS HMAC key must be activated per deployment; the production-enabled quickstart therefore uses OAuth. PyPI publish remains EXE-24. See README.md.
Constants
| Name | Value |
| --- | --- |
| DEFAULT_BASE_URL | 'https://api.osyra.ai/v1' |
Classes
class APIConnectionError
Bases: OsyraAPIError
Transport-level failure (DNS/TCP/TLS/timeout) before a status was seen.
class APIStatusError
Bases: OsyraAPIError
A non-2xx HTTP status that does not map to a more specific subclass.
class AsyncOpenAI
Bases: _ClientCore
Async client for the broker's narrow OpenAI-compatible Edge surface.
Example::
import asyncio
import os
from osyra import AsyncOpenAI
async def main():
async with AsyncOpenAI(
token_provider=lambda: os.environ["OSYRA_ACCESS_TOKEN"],
) as client:
return await client.chat.completions.create(
model=os.environ["OSYRA_MODEL"],
messages=[{"role": "user", "content": "Hello!"}],
)
response = asyncio.run(main())Methods
__init__
def __init__(self, api_key: Optional[str] = None, *, token_provider: Optional[Callable[[], Union[str, Awaitable[str]]]] = None, base_url: Optional[str] = None, osyra_workspace: object = UNSET, osyra_cache_ttl: object = UNSET, osyra_pii_mask: object = UNSET, timeout: float = DEFAULT_TIMEOUT, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Optional[Dict[str, str]] = None, allow_insecure: bool = False, http_client: Optional[httpx.AsyncClient] = None) -> Noneaclose (async)
async def aclose(self) -> Nonearequest_json (async)
async def arequest_json(self, method: str, path: str, *, json_body: Optional[Dict[str, Any]], extra_headers: Optional[Dict[str, str]] = None) -> Anyastream_lines (async)
async def astream_lines(self, method: str, path: str, *, json_body: Dict[str, Any], extra_headers: Optional[Dict[str, str]] = None)Open an async streaming response; return (response, async line iterator).
Non-2xx status raises a typed error before any chunk is yielded.
class AuthenticationError
Bases: APIStatusError
401 — missing/invalid/expired credential. Fail-closed (never silent).
class BadRequestError
Bases: APIStatusError
400/422 — malformed request body.
class ChatCompletion (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| choices | List[Choice] | field(default_factory=list) |
| created | int | 0 |
| id | str | '' |
| model | str | '' |
| object | str | 'chat.completion' |
| provider | Optional[str] | None |
| usage | Optional[CompletionUsage] | None |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'ChatCompletion'class ChatCompletionChunk (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| choices | List[ChunkChoice] | field(default_factory=list) |
| created | int | 0 |
| id | str | '' |
| model | str | '' |
| object | str | 'chat.completion.chunk' |
| provider | Optional[str] | None |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'ChatCompletionChunk'class ChatCompletionMessage (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| content | Optional[str] | None |
| role | str | 'assistant' |
Methods
from_dict @classmethod
def from_dict(cls, d: Optional[Dict[str, Any]]) -> 'ChatCompletionMessage'class Choice (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| finish_reason | Optional[str] | None |
| index | int | 0 |
| message | ChatCompletionMessage | field(default_factory=ChatCompletionMessage) |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'Choice'class CompletionUsage (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| completion_tokens | int | 0 |
| estimated_cost_microcents | Optional[int] | None |
| prompt_tokens | int | 0 |
| total_tokens | int | 0 |
Methods
from_dict @classmethod
def from_dict(cls, d: Optional[Dict[str, Any]]) -> Optional['CompletionUsage']class CreateEmbeddingResponse (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| data | List[Embedding] | field(default_factory=list) |
| model | str | '' |
| object | str | 'list' |
| provider | Optional[str] | None |
| usage | Optional[CompletionUsage] | None |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'CreateEmbeddingResponse'class Embedding (dataclass)
Attributes
| Name | Type | Default |
| --- | --- | --- |
| embedding | List[float] | field(default_factory=list) |
| index | int | 0 |
| object | str | 'embedding' |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'Embedding'class InternalServerError
Bases: APIStatusError
5xx — edge/broker/provider failure.
class Model (dataclass)
One model, OpenAI ``/v1/models``-shaped (``id``/``object``/``created``/ ``owned_by``) with the OSYRA-native broker fields surfaced as additive extensions (``provider``/``context_window``/``max_output_tokens``/cost/ ``capabilities``/``available``). A native OpenAI client reads ``id``; OSYRA callers can read the routing/cost metadata.
Attributes
| Name | Type | Default |
| --- | --- | --- |
| available | Optional[bool] | None |
| capabilities | Optional[Dict[str, Any]] | None |
| context_window | Optional[int] | None |
| created | int | 0 |
| id | str | '' |
| input_cost_per_1k | Optional[int] | None |
| max_output_tokens | Optional[int] | None |
| object | str | 'model' |
| output_cost_per_1k | Optional[int] | None |
| owned_by | str | '' |
| provider | Optional[str] | None |
| type | Optional[str] | None |
Methods
from_dict @classmethod
def from_dict(cls, d: Dict[str, Any]) -> 'Model'class ModelList (dataclass)
The OpenAI ``/v1/models`` list envelope: ``{object:"list", data:[Model]}``.
Supports ``len(...)``, iteration, and indexing so ``for m in client.models.list()`` works exactly like the upstream ``openai`` package's ``SyncPage[Model]``.
Attributes
| Name | Type | Default |
| --- | --- | --- |
| data | List[Model] | field(default_factory=list) |
| object | str | 'list' |
Methods
from_response @classmethod
def from_response(cls, d: Any) -> 'ModelList'class NotFoundError
Bases: APIStatusError
404 — route/model not found.
class OpenAI
Bases: _ClientCore
Client for the model broker's narrow OpenAI-compatible Edge surface.
Example::
import os
from osyra import OpenAI
client = OpenAI(
token_provider=lambda: os.environ["OSYRA_ACCESS_TOKEN"],
)
response = client.chat.completions.create(
model=os.environ["OSYRA_MODEL"],
messages=[{"role": "user", "content": "Hello!"}],
)Methods
__init__
def __init__(self, api_key: Optional[str] = None, *, token_provider: Optional[Callable[[], str]] = None, base_url: Optional[str] = None, osyra_workspace: object = UNSET, osyra_cache_ttl: object = UNSET, osyra_pii_mask: object = UNSET, timeout: float = DEFAULT_TIMEOUT, max_retries: int = DEFAULT_MAX_RETRIES, default_headers: Optional[Dict[str, str]] = None, allow_insecure: bool = False, http_client: Optional[httpx.Client] = None) -> Noneclose
def close(self) -> Nonerequest_json
def request_json(self, method: str, path: str, *, json_body: Optional[Dict[str, Any]], extra_headers: Optional[Dict[str, str]] = None) -> AnySend a request, raise typed errors on non-2xx, return parsed JSON.
``json_body=None`` sends no body (e.g. a GET); a dict sends a JSON body. Returns the parsed JSON.
stream_lines
def stream_lines(self, method: str, path: str, *, json_body: Dict[str, Any], extra_headers: Optional[Dict[str, str]] = None)Open a streaming response; return (response, line_iterator).
Non-2xx status raises a typed error before any chunk is yielded.
class OsyraAPIError
Bases: OsyraError
An error returned by the Osyra edge / model broker.
Attributes: message: human-readable message (best-effort extracted from the body). status_code: HTTP status of the failing response (None for transport errors). body: the raw response body (parsed dict if JSON, else the text/None). request_id: the X-Request-Id echoed by the edge, if present.
Methods
__init__
def __init__(self, message: str, *, status_code: Optional[int] = None, body: Any = None, request_id: Optional[str] = None) -> Noneclass OsyraError
Bases: Exception
Base class for all errors raised by the Osyra SDK.
class OsyraNotImplementedError
Bases: OsyraError
A surface the SDK is *designed* for but the platform has not yet wired.
Raised (NEVER returning fake data) by the native ``client.osyra.*`` methods whose broker RPC is not yet projected through the edge REST surface (``estimate_cost`` / ``routing_decision`` / ``provider_health`` — the broker has ``EstimateCost`` / ``EstimateRoutingDecision`` / ``GetProviderHealth`` but no edge route exists today; see AP00023 §12 OQ-2). The message names the missing edge route so the dependency is honest, not silent.
Methods
__init__
def __init__(self, message: str, *, edge_route: Optional[str] = None) -> Noneclass PermissionDeniedError
Bases: APIStatusError
403 — credential valid but lacks the ai:invoke permission, or a cross-tenant osyra_workspace was rejected by the edge (fail-closed).
class RateLimitError
Bases: APIStatusError
429 — edge rate limit. Carries Retry-After (seconds) when present.
Methods
__init__
def __init__(self, *args: Any, retry_after: Optional[float] = None, **kwargs: Any) -> NoneAliases
| Alias | Target | Kind |
| --- | --- | --- |
| APIError | OsyraAPIError | class |
| AsyncOsyra | AsyncOpenAI | class |
| AsyncOsyraOpenAI | AsyncOpenAI | class |
| Osyra | OpenAI | class |
| OsyraAuthenticationError | AuthenticationError | class |
| OsyraOpenAI | OpenAI | class |
| OsyraRateLimitError | RateLimitError | class |
| OsyraWorkspaceError | PermissionDeniedError | class |