Skip to content

Commit 197d9b3

Browse files
njbrakeclaude
andcommitted
Option C: rebuild SDK as a thin shell over the generated typed core
Replace the OpenAI-SDK delegation with a hand-written shell over the OpenAPI-generated core (otari._client), generated from the otari spec. The gateway is only OpenAI-compatible and has endpoints (notably the Anthropic-shaped /messages) the OpenAI SDK cannot represent; generating from the otari spec models the real contract. Core (unmodified generator output) replaces the old _control_plane subpackage and covers every endpoint with typed request/response models. Shell (the real work): - Auth modes preserved: platform -> Authorization: Bearer <token>; non-platform -> Otari-Key: Bearer <key>; control-plane -> Authorization: Bearer <admin/master key>. Fed into the generated ApiClient default headers and the streaming shim's httpx requests. - Ergonomic methods keep the existing public names/signatures (completion/response/embedding/moderation/rerank/list_models/batches) and add message(...) for the previously-missing /messages endpoint. control_plane accessor now backed by _client. - SSE streaming shim (_streaming.py): the generated core buffers and cannot stream, so stream=True does a raw httpx streaming POST, parses text/event-stream framing, terminates on [DONE], and yields typed ChatCompletionChunk (chat) / parsed JSON (responses, messages). - Typed error mapping: generated ApiException (.status/.body) -> the errors.py hierarchy (Authentication 401/403, InsufficientFunds 402, ModelNotFound 404, BatchNotComplete 409, RateLimit 429, GatewayTimeout 504, UpstreamProvider 502/5xx, UnsupportedCapability cross-mode, generic OtariError). The streaming path adapts failed responses through the same mapper. - Async client wraps the sync generated core via asyncio.to_thread and streams natively over httpx.AsyncClient. Drop the openai dependency from inference. Update ruff/mypy excludes to src/otari/_client. Rewrite unit tests to mock the generated transport (RESTClientObject.request) and respx for SSE; control-plane integration tests updated to import from _client and verified green against a live gateway. Note: chat streaming cannot be live-verified in this sandbox (no provider key on the gateway); the SSE shim is unit-tested over mocked chunk bytes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5a13bac commit 197d9b3

202 files changed

Lines changed: 25369 additions & 2183 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,21 @@ response = client.response(
195195
print(response.output_text)
196196
```
197197

198+
### Messages API (Anthropic-shaped)
199+
200+
The gateway's `/messages` endpoint (Anthropic message shape) is exposed via
201+
`message(...)`. Set `stream=True` to iterate raw message-stream event dicts.
202+
203+
```python
204+
message = client.message(
205+
model="anthropic:claude-3-5-sonnet",
206+
messages=[{"role": "user", "content": "Hello!"}],
207+
max_tokens=256,
208+
)
209+
210+
print(message.content)
211+
```
212+
198213
### Embeddings
199214

200215
```python

pyproject.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ classifiers = [
2222
"Typing :: Typed",
2323
]
2424
dependencies = [
25-
"openai>=1.99.3",
25+
# Streaming shim (raw SSE over httpx); the generated core cannot stream.
2626
"httpx>=0.25.0",
27-
# Runtime deps of the generated control-plane client (otari._control_plane).
27+
# Runtime deps of the OpenAPI-generated core (otari._client).
2828
"urllib3>=2.1.0",
2929
"python-dateutil>=2.8.2",
3030
"pydantic>=2.0.0",
@@ -40,6 +40,7 @@ Issues = "https://github.com/mozilla-ai/otari-sdk-python/issues"
4040
dev = [
4141
"pytest>=8.0",
4242
"pytest-asyncio>=0.24",
43+
"respx>=0.21",
4344
"ruff>=0.8",
4445
"mypy>=1.13",
4546
]
@@ -57,8 +58,8 @@ markers = [
5758
[tool.ruff]
5859
target-version = "py311"
5960
line-length = 120
60-
# Generated control-plane client (OpenAPI Generator output) is not hand-linted.
61-
extend-exclude = ["src/otari/_control_plane"]
61+
# Generated core client (OpenAPI Generator output) is not hand-linted.
62+
extend-exclude = ["src/otari/_client"]
6263

6364
[tool.ruff.lint]
6465
select = ["E", "F", "I", "N", "W", "UP", "S", "B", "A", "C4", "DTZ", "T10", "ISC", "ICN", "PIE", "PT", "RSE", "RET", "SIM", "TID", "TCH", "ARG", "PLC", "PLE", "PLW", "TRY", "FLY", "PERF", "RUF"]
@@ -77,10 +78,10 @@ python_version = "3.11"
7778
strict = true
7879
warn_return_any = true
7980
warn_unused_configs = true
80-
# Generated control-plane client (OpenAPI Generator output) is not type-checked here.
81-
exclude = ["src/otari/_control_plane/"]
81+
# Generated core client (OpenAPI Generator output) is not type-checked here.
82+
exclude = ["src/otari/_client/"]
8283

8384
[[tool.mypy.overrides]]
84-
module = ["otari._control_plane.*"]
85+
module = ["otari._client.*"]
8586
ignore_errors = true
8687
ignore_missing_imports = true

src/otari/__init__.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
platform_token="your-token-here",
1010
)
1111
12-
response = await client.completion(
12+
response = client.completion(
1313
model="openai:gpt-4o-mini",
1414
messages=[{"role": "user", "content": "Hello!"}],
1515
)
@@ -33,23 +33,20 @@
3333
UpstreamProviderError,
3434
)
3535
from otari.types import (
36-
AsyncStream,
3736
BatchRequestItem,
3837
BatchResult,
3938
BatchResultError,
4039
BatchResultItem,
4140
ChatCompletion,
4241
ChatCompletionChunk,
43-
ChatCompletionMessageParam,
4442
CreateBatchParams,
4543
CreateEmbeddingResponse,
46-
EmbeddingCreateParams,
4744
ListBatchesOptions,
48-
Model,
45+
MessageResponse,
46+
ModelObject,
47+
ModerationResponse,
4948
OtariClientOptions,
50-
Response,
51-
ResponseStreamEvent,
52-
Stream,
49+
RerankResponse,
5350
)
5451

5552
try:
@@ -60,7 +57,6 @@
6057

6158
__all__ = [
6259
"AsyncOtariClient",
63-
"AsyncStream",
6460
"AuthenticationError",
6561
"BatchNotCompleteError",
6662
"BatchRequestItem",
@@ -69,23 +65,21 @@
6965
"BatchResultItem",
7066
"ChatCompletion",
7167
"ChatCompletionChunk",
72-
"ChatCompletionMessageParam",
7368
"ControlPlane",
7469
"CreateBatchParams",
7570
"CreateEmbeddingResponse",
76-
"EmbeddingCreateParams",
7771
"GatewayTimeoutError",
7872
"InsufficientFundsError",
7973
"ListBatchesOptions",
80-
"Model",
74+
"MessageResponse",
8175
"ModelNotFoundError",
76+
"ModelObject",
77+
"ModerationResponse",
8278
"OtariClient",
8379
"OtariClientOptions",
8480
"OtariError",
8581
"RateLimitError",
86-
"Response",
87-
"ResponseStreamEvent",
88-
"Stream",
82+
"RerankResponse",
8983
"UnsupportedCapabilityError",
9084
"UpstreamProviderError",
9185
]

0 commit comments

Comments
 (0)