codai-sdk 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. codai_sdk-0.3.0/CHANGELOG.md +92 -0
  2. codai_sdk-0.3.0/PKG-INFO +158 -0
  3. codai_sdk-0.3.0/README.md +134 -0
  4. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/pyproject.toml +11 -4
  5. codai_sdk-0.3.0/scripts/gen-types.py +326 -0
  6. codai_sdk-0.3.0/scripts/smoke_local.py +141 -0
  7. codai_sdk-0.3.0/src/codai/__init__.py +315 -0
  8. codai_sdk-0.3.0/src/codai/_http.py +393 -0
  9. codai_sdk-0.3.0/src/codai/_operations.py +135 -0
  10. codai_sdk-0.3.0/src/codai/_types.py +3116 -0
  11. codai_sdk-0.3.0/src/codai/resources/__init__.py +92 -0
  12. codai_sdk-0.3.0/src/codai/resources/_base.py +32 -0
  13. codai_sdk-0.3.0/src/codai/resources/agents.py +73 -0
  14. codai_sdk-0.3.0/src/codai/resources/chat.py +165 -0
  15. codai_sdk-0.3.0/src/codai/resources/core.py +209 -0
  16. codai_sdk-0.3.0/src/codai/resources/environments.py +183 -0
  17. codai_sdk-0.3.0/src/codai/resources/messages.py +126 -0
  18. codai_sdk-0.3.0/src/codai/resources/platform.py +199 -0
  19. codai_sdk-0.3.0/src/codai/resources/responses.py +100 -0
  20. codai_sdk-0.3.0/src/codai/resources/sessions.py +151 -0
  21. codai_sdk-0.3.0/src/codai/resources/triggers.py +107 -0
  22. codai_sdk-0.3.0/tests/conftest.py +148 -0
  23. codai_sdk-0.3.0/tests/test_http.py +163 -0
  24. codai_sdk-0.3.0/tests/test_parity.py +121 -0
  25. codai_sdk-0.3.0/tests/test_resources.py +331 -0
  26. codai_sdk-0.1.0/CHANGELOG.md +0 -23
  27. codai_sdk-0.1.0/PKG-INFO +0 -69
  28. codai_sdk-0.1.0/README.md +0 -48
  29. codai_sdk-0.1.0/src/codai/__init__.py +0 -338
  30. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  31. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  32. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.github/dependabot.yml +0 -0
  33. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.github/pull_request_template.md +0 -0
  34. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.github/workflows/publish.yml +0 -0
  35. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/.gitignore +0 -0
  36. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/CODE_OF_CONDUCT.md +0 -0
  37. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/CONTRIBUTING.md +0 -0
  38. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/LICENSE +0 -0
  39. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/SECURITY.md +0 -0
  40. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/examples/agent.py +0 -0
  41. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/examples/chat.py +0 -0
  42. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/examples/feedback.py +0 -0
  43. {codai_sdk-0.1.0 → codai_sdk-0.3.0}/examples/streaming.py +0 -0
@@ -0,0 +1,92 @@
1
+ # Changelog
2
+
3
+ All notable changes to `codai-sdk` are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.3.0] - 2026-09-25
10
+
11
+ ### Added
12
+
13
+ - Projects + environments resources (26 operations), restoring full parity with the gateway
14
+ OpenAPI (88 operations): `projects.{list,create,get,update,delete}`,
15
+ `environments.{list,create,enroll,get,update,start,stop,archive,destroy,enroll_token}`,
16
+ `environments.members.{list,add,set_ssh_key,set_role,remove}`,
17
+ `environments.ports.{list,set,remove}` and `environments.secrets.{list,set,remove}`.
18
+ `enroll`, `create` and `enroll_token` are never retried (the enrolment token is single-use).
19
+ - `_types.py` regenerated: `Project*` and `Environment*` TypedDicts.
20
+ - `system_one.create({"state", "questions"})` — typed decisions from codai-s1 (`POST /v1/systemone`,
21
+ Choice / Score / Noul with calibrated probabilities). Raises on 503 `s1_unavailable`; keep a fallback.
22
+ - `triggers.*`, `notifications.*`, `environments.members.ssh_cert`, `environments.ssh_ca`,
23
+ `environments.tasks.{list,create,get}` — parity with the TypeScript SDK.
24
+
25
+ ## [0.2.1] - 2026-09-24
26
+
27
+ ### Added
28
+
29
+ - `WalletLedgerEntry.source` literal gains `compute_charge` — the debit written every 10 minutes
30
+ for a running managed cloud environment (F2). Additive; regenerated from the gateway OpenAPI.
31
+
32
+ ## [0.2.0] - 2026-09-23
33
+
34
+ ### Added
35
+
36
+ - Full gateway coverage: one method per `operationId` in `apps/docs/openapi/en/gateway.yaml`
37
+ (62 operations), grouped like the TypeScript SDK — `client.chat.completions`, `messages`,
38
+ `responses`, `embeddings`, `audio`, `tokens`, `models`, `health`, `agents` (+ `agents.runs`),
39
+ `tools`, `tasks`, `sessions` (+ `events`, `controls`, `lease`, `shares`), `devices`, `hosts`,
40
+ `orgs` (+ `members`), `account`, `receipt`, `feedback`, `phone_models`.
41
+ - `OPERATION_METHODS` (operationId → dotted method path) and `tests/test_parity.py`, which
42
+ parses the OpenAPI spec and fails on a missing, stale or non-callable mapping and when the
43
+ Python table diverges from the TypeScript one.
44
+ - Generated `codai._types` (`TypedDict`s for every schema plus `<operationId>Body` /
45
+ `<operationId>Response`) from `scripts/gen-types.py`; the parity test fails when it is stale.
46
+ - SSE streams: `chat.completions.stream()` / `messages.stream()` / `responses.stream()` return
47
+ iterables with `.text()`, raw chunks/events and a `.final` aggregate (content, tool calls,
48
+ usage, finish reason, routing headers); `agents.runs.stream()`, `sessions.stream()` and
49
+ `hosts.stream()` are generators of `{"event", "data"}` frames.
50
+ - `ext={...}` extension bag on every method covering all documented `X-Codai-*` request
51
+ headers (`effort`, `thinking`, `thinking_budget`, `cache`, `no_task`, `task_id`, `device`,
52
+ `compact`, `best_of`, `share_token`, …) plus raw `headers`; client-wide `defaults`, `device`,
53
+ `device_name`, `device_platform`, `client` constructor options.
54
+ - `CodaiError.code`, `.request_id`, `.retry_after` parsed from the gateway error envelope.
55
+ - Dev extras `pip install -e ".[dev]"` (pyyaml + pytest); an `http.server` stub test suite.
56
+
57
+ ### Changed
58
+
59
+ - `__version__` now reports the real version (`0.2.0`; it said `0.1.0` in 0.1.1).
60
+ - `chat_stream()` is built on `chat.completions.stream()`; 429/5xx retries add jitter.
61
+ - Runtime stays zero-dependency (stdlib `urllib`), Python 3.9+.
62
+
63
+ ### Backward compatibility
64
+
65
+ - Every 0.1.x method keeps its name, signature and return shape: `chat()`, `chat_stream()`,
66
+ `agents_run()`, `feedback()`, `models()`, `mint_token()`, `embeddings()`, `transcribe()`,
67
+ `speech()`. `chat`, `embeddings`, `models` and `feedback` are callable resource groups, so
68
+ `client.chat([...])` and `client.chat.completions.create({...})` are the same call.
69
+
70
+ ## [0.1.1] - 2026-09-13
71
+
72
+ ### Changed
73
+
74
+ - Repository moved to https://github.com/codai-ro/codai-sdk-python (project URLs updated). No code changes.
75
+
76
+ ## [0.1.0] - 2026-06-23
77
+
78
+ ### Added
79
+
80
+ - Initial public release.
81
+ - `Codai.chat()` — OpenAI-compatible completions with codai extensions
82
+ (`session_id`, `agent_mode`, `compact`, `best_of`).
83
+ - `Codai.chat_stream()` — streaming via generator.
84
+ - `Codai.agents_run()` — server-side agent loop.
85
+ - `Codai.feedback()` — thumbs rating on a completed request.
86
+ - `Codai.models()` — list models available to the key.
87
+ - Zero dependencies (stdlib only), Python 3.9+.
88
+
89
+ [Unreleased]: https://github.com/codai-ro/codai-sdk-python/compare/v0.2.0...HEAD
90
+ [0.2.0]: https://github.com/codai-ro/codai-sdk-python/compare/v0.1.1...v0.2.0
91
+ [0.1.1]: https://github.com/codai-ro/codai-sdk-python/compare/v0.1.0...v0.1.1
92
+ [0.1.0]: https://github.com/codai-ro/codai-sdk-python/releases/tag/v0.1.0
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.5
2
+ Name: codai-sdk
3
+ Version: 0.3.0
4
+ Summary: Official Python SDK for the codai AI gateway — chat, messages, responses, streaming, agents, sessions, hosts, tasks, account.
5
+ Project-URL: Homepage, https://codai.ro
6
+ Project-URL: Repository, https://github.com/codai-ro/codai-sdk-python
7
+ Project-URL: Issues, https://github.com/codai-ro/codai-sdk-python/issues
8
+ Author-email: codai <support@codai.ro>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,codai,gateway,llm,openai-compatible
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Topic :: Software Development :: Libraries
19
+ Requires-Python: >=3.9
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=8.0; extra == 'dev'
22
+ Requires-Dist: pyyaml>=6.0; extra == 'dev'
23
+ Description-Content-Type: text/markdown
24
+
25
+ # codai-sdk — Python SDK
26
+
27
+ [![PyPI version](https://img.shields.io/pypi/v/codai-sdk.svg)](https://pypi.org/project/codai-sdk/)
28
+ [![Python versions](https://img.shields.io/pypi/pyversions/codai-sdk.svg)](https://pypi.org/project/codai-sdk/)
29
+ [![license](https://img.shields.io/pypi/l/codai-sdk.svg)](./LICENSE)
30
+
31
+ Official Python client for the [codai](https://codai.ro) AI gateway.
32
+ Zero dependencies (stdlib only), Python 3.9+.
33
+
34
+ ```bash
35
+ pip install codai-sdk
36
+ ```
37
+
38
+ > You need a codai API key. Get one at **[codai.ro](https://codai.ro)**.
39
+ > The import name stays `codai`:
40
+
41
+ ```python
42
+ from codai import Codai
43
+
44
+ client = Codai(api_key="ck-...", session_id="my-project")
45
+
46
+ # Chat (OpenAI-compatible, smart-routed)
47
+ result = client.chat([{"role": "user", "content": "Explain asyncio.gather"}])
48
+ print(result.content)
49
+ print(result.routed_to) # which model actually served
50
+
51
+ # Streaming
52
+ for delta in client.chat_stream([{"role": "user", "content": "hi"}]):
53
+ print(delta, end="", flush=True)
54
+
55
+ # Server-side agent loop
56
+ run = client.agents_run("Find and summarize the TODOs in this codebase")
57
+ print(run.result)
58
+
59
+ # Feedback (improves routing for everyone)
60
+ client.feedback(result.request_id, 1)
61
+ ```
62
+
63
+ ## codai extensions
64
+
65
+ | Option | Effect |
66
+ | ----------------- | ------------------------------------ |
67
+ | `session_id` | Session memory + routing stickiness |
68
+ | `agent_mode=True` | Plan-and-execute loop (Pro+) |
69
+ | `compact="auto"` | Server-side context compaction |
70
+ | `best_of=0/3` | Disable / force best-of-N ensembling |
71
+
72
+ ## Resource groups (0.2.0)
73
+
74
+ Every gateway operation is a method on the client, grouped exactly like the
75
+ TypeScript SDK (`camelCase` → `snake_case`). The 0.1.x helpers above still
76
+ work — `client.chat([...])` and `client.chat.completions.create({...})` are
77
+ the same call. Every method takes an optional `ext={...}` bag of `X-Codai-*`
78
+ headers (`effort`, `thinking`, `thinking_budget`, `cache`, `no_task`,
79
+ `task_id`, `device`, `compact`, `best_of`, `share_token`, … plus raw `headers`).
80
+
81
+ | Attribute | Methods | Gateway |
82
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
83
+ | `chat.completions` | `create`, `stream` | `POST /v1/chat/completions` |
84
+ | `messages` | `create`, `stream` | `POST /v1/messages` (Anthropic wire) |
85
+ | `responses` | `create`, `stream` | `POST /v1/responses` (OpenAI Responses wire) |
86
+ | `embeddings` | `create` | `POST /v1/embeddings` |
87
+ | `audio` | `transcribe`, `transcribe_detailed`, `speech`, `speech_detailed` | `/v1/audio/*` |
88
+ | `tokens` | `create` | `POST /v1/tokens` |
89
+ | `models` | `list` | `GET /v1/models` |
90
+ | `health` | `get`, `ready`, `status` | `/health`, `/health/ready`, `/status` |
91
+ | `agents` | `run`; `runs.create/get/steps/stats/cancel/stream` | `/v1/agents/*` |
92
+ | `tools` | `search`, `fetch` | `/v1/tools/*` |
93
+ | `tasks` | `list`, `pending`, `stats`, `get`, `confirm` | `/v1/tasks/*` |
94
+ | `sessions` | `create`, `list`, `get`, `update`, `delete`, `dispatch`, `stream`; `events.*`, `controls.*`, `lease.*`, `shares.*` | `/v1/sessions/*` |
95
+ | `devices` | `list`, `update`, `delete`, `dispatch_inbox` | `/v1/devices/*` |
96
+ | `hosts` | `list`, `exec`, `post_result`, `stream` | `/v1/hosts/*` |
97
+ | `orgs` | `create`, `list`; `members.list/add/remove` | `/v1/orgs/*` |
98
+ | `account` | `get`, `update` | `/v1/account` |
99
+ | `receipt` | `get` | `GET /v1/receipt` |
100
+ | `feedback` | `submit` | `POST /v1/feedback` |
101
+ | `phone_models` | `list` | `GET /v1/phone/models` |
102
+
103
+ ```python
104
+ from codai import Codai, CodaiError
105
+
106
+ client = Codai(api_key="codai_...", device="5dc0de00-0000-4000-8000-00000000c0da")
107
+
108
+ # Chat with extension headers; raw chunks + aggregate on streams
109
+ r = client.chat.completions.create(
110
+ {"model": "codai", "messages": [{"role": "user", "content": "hi"}]},
111
+ ext={"effort": "high", "thinking": True, "thinking_budget": 8192},
112
+ )
113
+ print(r.content, r.routed_to, r.usage)
114
+
115
+ stream = client.chat.completions.stream({"messages": [{"role": "user", "content": "hi"}]})
116
+ for delta in stream: # text deltas; stream.chunks() for raw chunk dicts
117
+ print(delta, end="")
118
+ print(stream.final.usage, stream.final.tool_calls)
119
+
120
+ # Anthropic / OpenAI Responses wires
121
+ client.messages.create({"messages": [{"role": "user", "content": "hi"}], "max_tokens": 200}).text
122
+ client.responses.create({"input": "hi"}).output_text
123
+
124
+ # Async agent run + SSE progress
125
+ run = client.agents.runs.create({"task": "Summarise the repo README."})
126
+ for ev in client.agents.runs.stream(run["id"]):
127
+ if ev["event"] == "done":
128
+ print(ev["data"]["status"], ev["data"]["result"])
129
+
130
+ # Tasks, account, receipt
131
+ page = client.tasks.list(limit=20)
132
+ print(client.account.get()["plan"], client.receipt.get(since="2026-09-01T00:00:00Z"))
133
+
134
+ # Shared sessions (needs a device id on the client) and hosts
135
+ s = client.sessions.create({"title": "pairing"})
136
+ for ev in client.sessions.stream(s["id"], after=0):
137
+ print(ev["event"], ev["data"].get("seq"))
138
+ print(client.hosts.list())
139
+
140
+ try:
141
+ client.orgs.members.add("org-1", {"user_id": "u", "role": "member"})
142
+ except CodaiError as e:
143
+ print(e.status, e.code, e.request_id, e.retry_after)
144
+ ```
145
+
146
+ Typed request/response shapes live in `codai._types` (generated from the
147
+ OpenAPI spec — `TypedDict`s such as `ChatCompletionRequest`, `Task`,
148
+ `SessionEvent`, `CreateSessionShareResponse`).
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]"
154
+ .venv/Scripts/python -m pytest -q # unit + OpenAPI parity tests, no network
155
+ .venv/Scripts/python scripts/gen-types.py # regenerate src/codai/_types.py
156
+ ```
157
+
158
+ MIT © codai
@@ -0,0 +1,134 @@
1
+ # codai-sdk — Python SDK
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/codai-sdk.svg)](https://pypi.org/project/codai-sdk/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/codai-sdk.svg)](https://pypi.org/project/codai-sdk/)
5
+ [![license](https://img.shields.io/pypi/l/codai-sdk.svg)](./LICENSE)
6
+
7
+ Official Python client for the [codai](https://codai.ro) AI gateway.
8
+ Zero dependencies (stdlib only), Python 3.9+.
9
+
10
+ ```bash
11
+ pip install codai-sdk
12
+ ```
13
+
14
+ > You need a codai API key. Get one at **[codai.ro](https://codai.ro)**.
15
+ > The import name stays `codai`:
16
+
17
+ ```python
18
+ from codai import Codai
19
+
20
+ client = Codai(api_key="ck-...", session_id="my-project")
21
+
22
+ # Chat (OpenAI-compatible, smart-routed)
23
+ result = client.chat([{"role": "user", "content": "Explain asyncio.gather"}])
24
+ print(result.content)
25
+ print(result.routed_to) # which model actually served
26
+
27
+ # Streaming
28
+ for delta in client.chat_stream([{"role": "user", "content": "hi"}]):
29
+ print(delta, end="", flush=True)
30
+
31
+ # Server-side agent loop
32
+ run = client.agents_run("Find and summarize the TODOs in this codebase")
33
+ print(run.result)
34
+
35
+ # Feedback (improves routing for everyone)
36
+ client.feedback(result.request_id, 1)
37
+ ```
38
+
39
+ ## codai extensions
40
+
41
+ | Option | Effect |
42
+ | ----------------- | ------------------------------------ |
43
+ | `session_id` | Session memory + routing stickiness |
44
+ | `agent_mode=True` | Plan-and-execute loop (Pro+) |
45
+ | `compact="auto"` | Server-side context compaction |
46
+ | `best_of=0/3` | Disable / force best-of-N ensembling |
47
+
48
+ ## Resource groups (0.2.0)
49
+
50
+ Every gateway operation is a method on the client, grouped exactly like the
51
+ TypeScript SDK (`camelCase` → `snake_case`). The 0.1.x helpers above still
52
+ work — `client.chat([...])` and `client.chat.completions.create({...})` are
53
+ the same call. Every method takes an optional `ext={...}` bag of `X-Codai-*`
54
+ headers (`effort`, `thinking`, `thinking_budget`, `cache`, `no_task`,
55
+ `task_id`, `device`, `compact`, `best_of`, `share_token`, … plus raw `headers`).
56
+
57
+ | Attribute | Methods | Gateway |
58
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
59
+ | `chat.completions` | `create`, `stream` | `POST /v1/chat/completions` |
60
+ | `messages` | `create`, `stream` | `POST /v1/messages` (Anthropic wire) |
61
+ | `responses` | `create`, `stream` | `POST /v1/responses` (OpenAI Responses wire) |
62
+ | `embeddings` | `create` | `POST /v1/embeddings` |
63
+ | `audio` | `transcribe`, `transcribe_detailed`, `speech`, `speech_detailed` | `/v1/audio/*` |
64
+ | `tokens` | `create` | `POST /v1/tokens` |
65
+ | `models` | `list` | `GET /v1/models` |
66
+ | `health` | `get`, `ready`, `status` | `/health`, `/health/ready`, `/status` |
67
+ | `agents` | `run`; `runs.create/get/steps/stats/cancel/stream` | `/v1/agents/*` |
68
+ | `tools` | `search`, `fetch` | `/v1/tools/*` |
69
+ | `tasks` | `list`, `pending`, `stats`, `get`, `confirm` | `/v1/tasks/*` |
70
+ | `sessions` | `create`, `list`, `get`, `update`, `delete`, `dispatch`, `stream`; `events.*`, `controls.*`, `lease.*`, `shares.*` | `/v1/sessions/*` |
71
+ | `devices` | `list`, `update`, `delete`, `dispatch_inbox` | `/v1/devices/*` |
72
+ | `hosts` | `list`, `exec`, `post_result`, `stream` | `/v1/hosts/*` |
73
+ | `orgs` | `create`, `list`; `members.list/add/remove` | `/v1/orgs/*` |
74
+ | `account` | `get`, `update` | `/v1/account` |
75
+ | `receipt` | `get` | `GET /v1/receipt` |
76
+ | `feedback` | `submit` | `POST /v1/feedback` |
77
+ | `phone_models` | `list` | `GET /v1/phone/models` |
78
+
79
+ ```python
80
+ from codai import Codai, CodaiError
81
+
82
+ client = Codai(api_key="codai_...", device="5dc0de00-0000-4000-8000-00000000c0da")
83
+
84
+ # Chat with extension headers; raw chunks + aggregate on streams
85
+ r = client.chat.completions.create(
86
+ {"model": "codai", "messages": [{"role": "user", "content": "hi"}]},
87
+ ext={"effort": "high", "thinking": True, "thinking_budget": 8192},
88
+ )
89
+ print(r.content, r.routed_to, r.usage)
90
+
91
+ stream = client.chat.completions.stream({"messages": [{"role": "user", "content": "hi"}]})
92
+ for delta in stream: # text deltas; stream.chunks() for raw chunk dicts
93
+ print(delta, end="")
94
+ print(stream.final.usage, stream.final.tool_calls)
95
+
96
+ # Anthropic / OpenAI Responses wires
97
+ client.messages.create({"messages": [{"role": "user", "content": "hi"}], "max_tokens": 200}).text
98
+ client.responses.create({"input": "hi"}).output_text
99
+
100
+ # Async agent run + SSE progress
101
+ run = client.agents.runs.create({"task": "Summarise the repo README."})
102
+ for ev in client.agents.runs.stream(run["id"]):
103
+ if ev["event"] == "done":
104
+ print(ev["data"]["status"], ev["data"]["result"])
105
+
106
+ # Tasks, account, receipt
107
+ page = client.tasks.list(limit=20)
108
+ print(client.account.get()["plan"], client.receipt.get(since="2026-09-01T00:00:00Z"))
109
+
110
+ # Shared sessions (needs a device id on the client) and hosts
111
+ s = client.sessions.create({"title": "pairing"})
112
+ for ev in client.sessions.stream(s["id"], after=0):
113
+ print(ev["event"], ev["data"].get("seq"))
114
+ print(client.hosts.list())
115
+
116
+ try:
117
+ client.orgs.members.add("org-1", {"user_id": "u", "role": "member"})
118
+ except CodaiError as e:
119
+ print(e.status, e.code, e.request_id, e.retry_after)
120
+ ```
121
+
122
+ Typed request/response shapes live in `codai._types` (generated from the
123
+ OpenAPI spec — `TypedDict`s such as `ChatCompletionRequest`, `Task`,
124
+ `SessionEvent`, `CreateSessionShareResponse`).
125
+
126
+ ## Development
127
+
128
+ ```bash
129
+ python -m venv .venv && .venv/Scripts/python -m pip install -e ".[dev]"
130
+ .venv/Scripts/python -m pytest -q # unit + OpenAPI parity tests, no network
131
+ .venv/Scripts/python scripts/gen-types.py # regenerate src/codai/_types.py
132
+ ```
133
+
134
+ MIT © codai
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "codai-sdk"
7
- version = "0.1.0"
8
- description = "Official Python SDK for the codai AI gateway — chat, streaming, agents, feedback, models."
7
+ version = "0.3.0"
8
+ description = "Official Python SDK for the codai AI gateway — chat, messages, responses, streaming, agents, sessions, hosts, tasks, account."
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.9"
@@ -22,10 +22,17 @@ classifiers = [
22
22
  ]
23
23
  dependencies = []
24
24
 
25
+ [project.optional-dependencies]
26
+ dev = ["pyyaml>=6.0", "pytest>=8.0"]
27
+
25
28
  [project.urls]
26
29
  Homepage = "https://codai.ro"
27
- Repository = "https://github.com/dragoscv/codai-sdk-python"
28
- Issues = "https://github.com/dragoscv/codai-sdk-python/issues"
30
+ Repository = "https://github.com/codai-ro/codai-sdk-python"
31
+ Issues = "https://github.com/codai-ro/codai-sdk-python/issues"
29
32
 
30
33
  [tool.hatch.build.targets.wheel]
31
34
  packages = ["src/codai"]
35
+
36
+ [tool.pytest.ini_options]
37
+ testpaths = ["tests"]
38
+ pythonpath = ["src"]