codai-sdk 0.53.0__tar.gz → 0.67.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 (96) hide show
  1. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/CHANGELOG.md +142 -0
  2. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/PKG-INFO +12 -4
  3. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/README.md +11 -3
  4. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/pyproject.toml +3 -1
  5. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/__init__.py +29 -4
  6. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/_http.py +2 -0
  7. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/_operations.py +54 -0
  8. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/_types.py +1532 -21
  9. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/__init__.py +19 -1
  10. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/billing.py +31 -1
  11. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/core.py +6 -2
  12. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/creatives.py +200 -3
  13. codai_sdk-0.67.0/src/codai/resources/lyrics.py +112 -0
  14. codai_sdk-0.67.0/src/codai/resources/media_ops.py +133 -0
  15. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/memory.py +7 -0
  16. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/platform.py +39 -2
  17. codai_sdk-0.67.0/src/codai/resources/productions.py +108 -0
  18. codai_sdk-0.67.0/src/codai/resources/prompts.py +180 -0
  19. codai_sdk-0.67.0/src/codai/resources/research.py +107 -0
  20. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/sandboxes.py +16 -8
  21. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/templates.py +14 -3
  22. codai_sdk-0.67.0/src/codai/resources/vault.py +325 -0
  23. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_billing_referrals.py +15 -0
  24. codai_sdk-0.67.0/tests/test_creatives_cx07.py +146 -0
  25. codai_sdk-0.67.0/tests/test_lyrics.py +72 -0
  26. codai_sdk-0.67.0/tests/test_media_ops.py +74 -0
  27. codai_sdk-0.67.0/tests/test_os_gate.py +48 -0
  28. codai_sdk-0.67.0/tests/test_productions.py +39 -0
  29. codai_sdk-0.67.0/tests/test_prompts.py +67 -0
  30. codai_sdk-0.67.0/tests/test_research.py +91 -0
  31. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_resources.py +1 -3
  32. codai_sdk-0.67.0/tests/test_vault.py +239 -0
  33. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/uv.lock +1 -1
  34. codai_sdk-0.53.0/src/codai/resources/prompts.py +0 -86
  35. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  36. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.github/dependabot.yml +0 -0
  38. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.github/pull_request_template.md +0 -0
  39. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.github/workflows/publish.yml +0 -0
  40. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/.gitignore +0 -0
  41. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/CODE_OF_CONDUCT.md +0 -0
  42. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/CONTRIBUTING.md +0 -0
  43. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/LICENSE +0 -0
  44. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/SECURITY.md +0 -0
  45. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/examples/agent.py +0 -0
  46. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/examples/chat.py +0 -0
  47. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/examples/feedback.py +0 -0
  48. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/examples/streaming.py +0 -0
  49. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/scripts/gen-types.py +0 -0
  50. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/scripts/smoke_local.py +0 -0
  51. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/_resolve_types.py +0 -0
  52. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/_base.py +0 -0
  53. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/abuse_reports.py +0 -0
  54. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/agents.py +0 -0
  55. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/batches.py +0 -0
  56. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/brand_kits.py +0 -0
  57. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/cards.py +0 -0
  58. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/chat.py +0 -0
  59. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/environments.py +0 -0
  60. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/exports.py +0 -0
  61. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/lists.py +0 -0
  62. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/messages.py +0 -0
  63. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/provenance.py +0 -0
  64. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/referrals.py +0 -0
  65. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/resolve.py +0 -0
  66. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/responses.py +0 -0
  67. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/schedules.py +0 -0
  68. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/sessions.py +0 -0
  69. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/shares.py +0 -0
  70. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/transcripts.py +0 -0
  71. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/triggers.py +0 -0
  72. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/usage_keys.py +0 -0
  73. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/src/codai/resources/voice_revocations.py +0 -0
  74. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/conftest.py +0 -0
  75. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_abuse_reports.py +0 -0
  76. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_batches.py +0 -0
  77. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_brand_kits.py +0 -0
  78. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_cards.py +0 -0
  79. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_creatives.py +0 -0
  80. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_creatives_documents.py +0 -0
  81. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_creatives_e11.py +0 -0
  82. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_creatives_e11b.py +0 -0
  83. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_environments_exec.py +0 -0
  84. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_exports.py +0 -0
  85. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_http.py +0 -0
  86. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_lists.py +0 -0
  87. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_memory.py +0 -0
  88. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_parity.py +0 -0
  89. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_provenance.py +0 -0
  90. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_resolve.py +0 -0
  91. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_sandboxes.py +0 -0
  92. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_settings.py +0 -0
  93. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_shares_e12a.py +0 -0
  94. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_templates.py +0 -0
  95. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_transcripts.py +0 -0
  96. {codai_sdk-0.53.0 → codai_sdk-0.67.0}/tests/test_voice_revocations.py +0 -0
@@ -6,6 +6,148 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.67.0] - 2026-10-20
10
+
11
+ - Creatives (CX-07/08/09): `creatives.build(..., format=, format_id=, crop_marks=)` builds carousel (`png` | `pdf`)
12
+ and print (`pdf`, PDF/X-4) creatives, which answer HTTP 202 with a queued export job in `export`; new helper
13
+ `is_paged_build(r)` and `creatives.build_and_wait(...)` (build, then `exports.wait` the export).
14
+ - `creatives.post_copy(creative_id, platforms=, language=, brief=, tone=, seq=, idempotency_key=)`
15
+ (`POST /v1/studio/creatives/{id}/post-copy`): caption + hashtags per platform and alt text per slide; token-metered.
16
+ - `creatives.transcript_cut(creative_id, node_id=, remove=, base_seq=, force=)`
17
+ (`POST /v1/studio/creatives/{id}/transcript-cut`): delete transcript word ranges from a video clip; free.
18
+ - `creatives.regenerate_node(creative_id, node_id, prompt=, model=, aspect_ratio=, base_seq=, force=,
19
+ idempotency_key=)` (`POST /v1/studio/creatives/{id}/nodes/{nodeId}/regenerate`): new picture for an image node,
20
+ cast-consistent; billed like an image generation.
21
+ - `media_ops.quote` / `run` / `run_and_wait` accept `mask_png_b64=` for `image.inpaint` / `image.erase`.
22
+ - `videos.create` / `images.generate` document `reference_asset_ids` (Studio image assets as references).
23
+ - Regenerated `_types.py`: `CreativeCast`, `CreativePagedBuildRequest`, `StudioCreativePagedBuild`,
24
+ `CreativePrintLintIssue`, `StudioPostCopyRequest`, `StudioPostCopy`, `CreativeTranscriptCutRequest` / `Result`,
25
+ `CreativeRegenerateNodeRequest` / `Result`; `CreativeOp` gains `trimVideo`, `splitVideo`, `setVideoRate`,
26
+ `addCast`, `updateCast`, `removeCast`; `StudioExport.kind` gains `carousel_png`, `carousel_pdf`, `print_pdf`.
27
+
28
+ ## [0.66.0] - 2026-10-20
29
+
30
+ - New `client.media_ops` for codai Studio media operations (AR-02): `list()`, `quote(op, asset_ids, params)`,
31
+ `run(op, asset_ids, params, idempotency_key=)` (a `media_op.result` for sync ops, a `media_op.job` for async ops),
32
+ `job(id)`, `wait(id, interval=, timeout=)` and `run_and_wait(...)`; helpers `is_media_op_job`,
33
+ `MEDIA_JOB_TERMINAL_STATUSES`.
34
+ - Creatives: `CreativeKind` gains `audio` (songs and podcasts); new generated types `CreativeAudio`,
35
+ `CreativeAudioTrack`, `CreativeAudioClip`, `CreativeAudioSection`, `CreativeAudioFx` and the media-op schemas.
36
+ - New `client.lyrics` (MU-06): `write(brief, language, genre=, mood=, structure=, syllables_per_line=,
37
+ rhyme_scheme=, lines_per_section=, title=, idempotency_key=)` (`POST /v1/studio/lyrics`) and `align(creative_id,
38
+ clip_id, lyrics_text, language=, apply=, base_seq=, retranscribe=, idempotency_key=)` (`POST /v1/studio/lyrics/align`,
39
+ timed lines + LRC).
40
+ - `client.creatives.render_audio(creative_id, formats=, stems=, lrc=, loudness=, title=, idempotency_key=)` (MU-05):
41
+ mixdown + mastering + exports of an `audio` creative. New generated types `StudioLyrics*`,
42
+ `CreativeAudioRenderRequest`, `CreativeAudioRenderAccepted`, `StudioAudioRender`; `RenderCreativeBody` /
43
+ `RenderCreativeResponse202` / `GetRenderResponse` are now video | audio unions. The live jam WebSocket
44
+ (`/v1/studio/jam`) has no Python helper; see the Lyrics & live jam docs page for the protocol.
45
+
46
+ ## [0.65.0] - 2026-10-20
47
+
48
+ - Vault guards v4 (V-18, V-19, V-21, V-32, V-35): `vault.update_settings(default_tier=, guards=)` changes the anomaly
49
+ guards (new host in 30 days, burst, allowed hours; an anomaly forces t4 with reason `anomaly:new_host|burst|hour`);
50
+ `vault.lock(via=)` is the panic lock (revokes grants, denies pending approvals, agent uses then answer
51
+ `vault_locked`); `vault.unlock_challenge()` + `vault.unlock(challenge, proof)` end a lock with a device-key or
52
+ passkey proof over `vault_unlock_message(challenge, device_id_or_passkey)`; `vault.limits()` /
53
+ `vault.set_limits(item_id, per_minute, per_day, units_per_day)` manage per-handle caps (over a cap the broker calls
54
+ raise a 429 error with code `vault_rate_limited` and `Retry-After`); `vault.revoke_task_grants(task)` ends the
55
+ grants of a finished task. Generated types gain `VaultGuards`, `VaultItemLimits`, `VaultLockResult`,
56
+ `VaultUnlockChallenge`.
57
+
58
+ ## [0.64.0] - 2026-10-20
59
+
60
+ - Prompt organisation (PR-04/05/07): prompt rows carry `tags`, `priority` (0–3), `recurrence`
61
+ (`{"every": "day"|"week"|"month", "at"?}` or `{"on": "session_end"}`), `next_prompt_id`, `launch`
62
+ (`{"agent"?, "model"?, "folder"?}`) and `is_template`, also accepted by `prompts.create` / `prompts.update`.
63
+ `prompts.list` takes `tag` (str or list, AND), `priority_min`, `q`, `templates="only"|"exclude"`, `sort` and `order`.
64
+ - New prompt methods: `prompts.export_prompts(format="csv"|"md", ...)` (`GET /v1/prompts/export`, returns the text),
65
+ `prompts.bulk(ids, action, ...)` (`POST /v1/prompts/bulk` → `{"updated": n}`), `prompts.events(id)`
66
+ (`GET /v1/prompts/{id}/events`) and `prompts.instantiate(id)` (`POST /v1/prompts/{id}/instantiate`).
67
+ - Generated types: `Prompt` gains the organise fields, new `PromptRecurrence`, `PromptLaunchConfig`, `PromptEvent`,
68
+ `PromptBulkRequest`; sessions gain `stub` (create with `stub: True` for a title-only mirror) and
69
+ `SessionControlKind` gains `hydrate` (session owner only) to ask the executor for the transcript.
70
+
71
+ ## [0.63.0] - 2026-10-19
72
+
73
+ - Sandboxes v2 are generally available and the default backend: `sandboxes.create()` without `backend` starts a
74
+ v2 pod (the gateway falls back to v1 when v2 is unavailable for the key; read `backend` on the reply). Pass
75
+ `backend="v1"` for Cloud Run.
76
+ - v2 now accepts `egress` (`pypi` / `npm` preset or an allowlist, through the codai egress proxy), `inputs` on
77
+ exec and `artifacts()`; the image ships Node 24 + npm. `snapshot()` stays v1 only (409 `not_supported_on_v2`).
78
+ - Documented caps: 5 running v2 sandboxes per user (429 `sandbox_concurrency_limit`), 10 paused per user
79
+ (429 `sandbox_paused_limit` on `pause()`), platform capacity 503 `sandbox_capacity` (retry). Docstrings only;
80
+ no signature changes.
81
+
82
+ ## [0.62.0] - 2026-10-20
83
+
84
+ - New `client.os_gate` for the OS protection gate: `policy()` (`GET /v1/policy`, `{"os_gate": {"allow_override": bool}}`
85
+ folded over every org of the caller, strictest wins; a 503 `policy_unavailable` means keep your cached value) and
86
+ `record_event(action, checks, surface, app_version, at)` (`POST /v1/os-gate/events`, 202 `{"ok": True}`; audit an
87
+ override granted/revoked with check ids, surface, app version and time only). Typed shapes `PolicyResponse`,
88
+ `OsGateEvent`, `OsGateEventAccepted` in `codai._types`.
89
+
90
+ ## [0.61.0] - 2026-10-20
91
+
92
+ - `client.memory.delete_all()` (`DELETE /v1/memory?confirm=all`, AL-234): erase every memory of your account in one
93
+ call; returns `{"deleted": {tier: n}, "total": n}`.
94
+
95
+ ## [0.60.0] - 2026-10-19
96
+
97
+ - Vault approvals bind the request preview and use number matching (V-30/V-31): `vault.use` / `vault.http` /
98
+ `vault.resolve` answers carry `match_number`; `vault.decide(..., match_number=...)` sends the number the user
99
+ tapped with a device or passkey proof over the approve/v3 message (403 `match_required` / `match_mismatch`).
100
+
101
+ ## [0.59.0] - 2026-10-19
102
+
103
+ - New `client.productions` for codai Studio brief → promo video (RC-20): `create(brief, language=, aspect_ratio=,
104
+ starter=, voice=, narration=, budget_micro_usd=, title=, idempotency_key=)`, `retrieve(id)`, `wait(id)`, `run(brief)`.
105
+
106
+ ## [0.58.0] - 2026-10-19
107
+
108
+ - Studio templates (RC-29): `client.templates.list(source=, locale=, month=)`; lists include the 40 built-in starter
109
+ templates (`source: "starter"`, ids `starter:<slug>:<en|ro>`) after your own. A starter id works in `retrieve`,
110
+ `creatives.create({"template": ...})` and batch `template_id`.
111
+
112
+ ## [0.57.0] - 2026-10-19
113
+
114
+ - New `client.vault.devices` for hardware-backed device approval keys (V-27): `challenge()`,
115
+ `enroll(device_id, kind, name, surface, public_key, nonce, vault_signature, device_signature, attestation=)`,
116
+ `list()`, `rename(device_id, name)` and `revoke(device_id)`.
117
+ - `vault.decide(..., proof=)` sends a v2 proof (`{"type": "device", "device_id", "signature"}` or
118
+ `{"type": "passkey", "response"}`); `signature` is now optional (a deny needs no proof), passing both raises
119
+ `ValueError`, and `step_up_acr` is deprecated (ignored by the gateway).
120
+ - Regenerated `_types.py` from the current OpenAPI spec.
121
+
122
+ ## [0.56.0] - 2026-10-19
123
+
124
+ - New `client.research` for async deep research (`POST /v1/research`, `GET /v1/research/{id}`):
125
+ `create(question, time_budget_s=, max_sources=, include_domains=, published_after=, output_schema=, wait_s=,
126
+ idempotency_key=)`, `retrieve(job_id)`, `wait(job_id, interval=3.0, timeout=360.0)` and `run(question, ...)`
127
+ (create + wait). `RESEARCH_TERMINAL_STATUSES` exported.
128
+ - `tools.search` / `tools.fetch` docstrings and generated types follow the shared web tools contract (domain,
129
+ publish-date and freshness filters, `content_chars`, `published_at` vs `crawled_at`, `notes`; fetch `max_chars`
130
+ default 8000, max 40000).
131
+ - Regenerated `_types.py` from the current OpenAPI spec.
132
+
133
+ ## [0.55.0] - 2026-10-19
134
+
135
+ - `billing.studio_quote(action, ...)` — `GET /v1/studio/quote`: the price of a codai Studio action (USD and wallet
136
+ EUR micros) and your spendable balance before you run it.
137
+ - `ext={"idempotency_key": ...}` sends `Idempotency-Key`: a retried billed Studio POST replays the first answer
138
+ instead of charging twice (24 h).
139
+ - Paid Studio calls can now answer 402 `insufficient_funds` (`quote_micro_eur`, `balance_micro_eur`) as a `CodaiError`.
140
+
141
+ ## [0.54.0] - 2026-10-18
142
+
143
+ - Vault: `client.vault` covers every `/v1/vault/*` route (account, settings, vaults, items, cloud copy, rules,
144
+ grants, events, approvals + `decide`, and the agent broker `catalog` / `use` / `http_call` / `resolve`). The server
145
+ only stores ciphertext built client-side; the broker calls never return secret values. Typed dicts for the
146
+ `Vault*` schemas.
147
+ - Studio share links: `creatives.create_share(..., expires_in_days=...)` also accepts `"never"`; omitted now means 30 days
148
+ (was: never expires).
149
+ - Public review dicts carry `decided_by_kind` (`"self_declared"`): the approver name is typed by the link holder, not verified.
150
+
9
151
  ## [0.53.0] - 2026-10-17
10
152
 
11
153
  - Sandboxes v2 (closed canary): `sandboxes.create(backend="v2", template=...)` with templates `codai-base`,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codai-sdk
3
- Version: 0.53.0
3
+ Version: 0.67.0
4
4
  Summary: Official Python SDK for the codai AI gateway — chat, messages, responses, streaming, agents, sessions, hosts, tasks, account.
5
5
  Project-URL: Homepage, https://codai.ro
6
6
  Project-URL: Repository, https://github.com/codai-ro/codai-sdk-python
@@ -35,13 +35,21 @@ Zero dependencies (stdlib only), Python 3.9+.
35
35
  pip install codai-sdk
36
36
  ```
37
37
 
38
- > You need a codai API key. Get one at **[codai.ro](https://codai.ro)**.
39
- > The import name stays `codai`:
38
+ > **The package is `codai-sdk`.** `pip install codai` installs an unrelated
39
+ > project from another author that uses the same import name and will shadow
40
+ > this SDK. If `from codai import Codai` fails, run `pip uninstall codai` and
41
+ > `pip install codai-sdk`.
42
+
43
+ You need a codai API key — keys start with `codai_`. Create one at
44
+ **[hub.codai.ro](https://hub.codai.ro)** and export it as `CODAI_API_KEY`.
45
+ The import name is `codai`:
40
46
 
41
47
  ```python
48
+ import os
49
+
42
50
  from codai import Codai
43
51
 
44
- client = Codai(api_key="ck-...", session_id="my-project")
52
+ client = Codai(api_key=os.environ["CODAI_API_KEY"], session_id="my-project")
45
53
 
46
54
  # Chat (OpenAI-compatible, smart-routed)
47
55
  result = client.chat([{"role": "user", "content": "Explain asyncio.gather"}])
@@ -11,13 +11,21 @@ Zero dependencies (stdlib only), Python 3.9+.
11
11
  pip install codai-sdk
12
12
  ```
13
13
 
14
- > You need a codai API key. Get one at **[codai.ro](https://codai.ro)**.
15
- > The import name stays `codai`:
14
+ > **The package is `codai-sdk`.** `pip install codai` installs an unrelated
15
+ > project from another author that uses the same import name and will shadow
16
+ > this SDK. If `from codai import Codai` fails, run `pip uninstall codai` and
17
+ > `pip install codai-sdk`.
18
+
19
+ You need a codai API key — keys start with `codai_`. Create one at
20
+ **[hub.codai.ro](https://hub.codai.ro)** and export it as `CODAI_API_KEY`.
21
+ The import name is `codai`:
16
22
 
17
23
  ```python
24
+ import os
25
+
18
26
  from codai import Codai
19
27
 
20
- client = Codai(api_key="ck-...", session_id="my-project")
28
+ client = Codai(api_key=os.environ["CODAI_API_KEY"], session_id="my-project")
21
29
 
22
30
  # Chat (OpenAI-compatible, smart-routed)
23
31
  result = client.chat([{"role": "user", "content": "Explain asyncio.gather"}])
@@ -4,9 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "codai-sdk"
7
- version = "0.53.0"
7
+ version = "0.67.0"
8
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
+
11
+
10
12
  license = "MIT"
11
13
  requires-python = ">=3.9"
12
14
  authors = [{ name = "codai", email = "support@codai.ro" }]
@@ -51,11 +51,19 @@ from .resources import (
51
51
  Creatives,
52
52
  BrandKits,
53
53
  Templates,
54
+ Productions,
55
+ MediaOps,
56
+ Lyrics,
57
+ MEDIA_JOB_TERMINAL_STATUSES,
58
+ is_media_op_job,
59
+ is_paged_build,
54
60
  Exports,
55
61
  Batches,
56
62
  Shares,
57
63
  share_token_from,
58
64
  VoiceRevocations,
65
+ Vault,
66
+ vault_unlock_message,
59
67
  AbuseReports,
60
68
  Provenance,
61
69
  Devices,
@@ -95,6 +103,7 @@ from .resources import (
95
103
  Responses,
96
104
  Sessions,
97
105
  Settings,
106
+ OsGate,
98
107
  Sfx,
99
108
  SfxSearchResult,
100
109
  SystemOne,
@@ -111,6 +120,8 @@ from .resources import (
111
120
  verify_attestation_with_keys,
112
121
  verify_resolve_webhook,
113
122
  settings_conflict_current,
123
+ Research,
124
+ RESEARCH_TERMINAL_STATUSES,
114
125
  )
115
126
 
116
127
  __all__ = [
@@ -139,6 +150,9 @@ __all__ = [
139
150
  "RESOLVE_OPERATION_METHODS",
140
151
  "RESOLVE_ATTESTATION_PAYLOAD_TYPE",
141
152
  "RESOLVE_TERMINAL_STATUSES",
153
+ "Research",
154
+ "RESEARCH_TERMINAL_STATUSES",
155
+ "Vault",
142
156
  "ResolveError",
143
157
  "ResolveInsufficientFundsError",
144
158
  "STREAMING_OPERATIONS",
@@ -150,10 +164,9 @@ __all__ = [
150
164
  "verify_resolve_webhook",
151
165
  "settings_conflict_current",
152
166
  "share_token_from",
167
+ "vault_unlock_message",
153
168
  ]
154
- __version__ = "0.53.0"
155
-
156
-
169
+ __version__ = "0.67.0"
157
170
  class _CallableGroup:
158
171
  """A resource group that is also callable — keeps ``client.chat(...)``,
159
172
  ``client.embeddings(...)``, ``client.models()`` and ``client.feedback(...)``
@@ -229,6 +242,12 @@ class Codai:
229
242
  self.brand_kits = BrandKits(http)
230
243
  # Studio templates saved from your creatives (creatives.save_template); free.
231
244
  self.templates = Templates(http)
245
+ # Studio productions: brief -> storyboard -> images + voice-over -> creative -> draft render -> review.
246
+ self.productions = Productions(http)
247
+ # Studio media operations: background removal, upscale, inpaint, stems, denoise, MIDI, mastering, ACE-Step music.
248
+ self.media_ops = MediaOps(http)
249
+ # Studio lyrics: write (syllable + rhyme checked, token-metered) and align to an audio clip (LRC + setLyrics).
250
+ self.lyrics = Lyrics(http)
232
251
  # Studio FCPXML exports queued with creatives.export_fcpxml; wait() polls until the zip is ready.
233
252
  self.exports = Exports(http)
234
253
  # Studio batches: one creative per CSV / sheet row (free; row translations and renders billed); wait() polls.
@@ -237,6 +256,8 @@ class Codai:
237
256
  self.shares = Shares(http)
238
257
  # Public takedown tickets for voices cloned in codai Studio (no key needed by the route).
239
258
  self.voice_revocations = VoiceRevocations(http)
259
+ # Zero-knowledge credentials vault: ciphertext only; the agent broker calls never return secret values.
260
+ self.vault = Vault(http)
240
261
  # Public DSA notices about codai Studio share / review links (no key needed by the route).
241
262
  self.abuse_reports = AbuseReports(http)
242
263
  # Public AI-provenance checker: which codai marks a file carries (no key needed by the route).
@@ -246,6 +267,8 @@ class Codai:
246
267
  self.health = Health(http)
247
268
  self.agents = Agents(http)
248
269
  self.tools = Tools(http)
270
+ # Async deep research (/v1/research): create / retrieve / wait / run -> cited report + sources.
271
+ self.research = Research(http)
249
272
  # Typed card data (/v1/cards/*): weather / places / geocode / static_map / fx / unfurl -> {block, provenance}.
250
273
  self.cards = Cards(http)
251
274
  self.tasks = Tasks(http)
@@ -255,13 +278,15 @@ class Codai:
255
278
  self.orgs = Orgs(http)
256
279
  self.projects = Projects(http)
257
280
  self.environments = Environments(http)
258
- # Agent sandboxes (beta): isolated gVisor workspaces — exec / exec_stream / files / artifacts / run.
281
+ # Agent sandboxes (backend v2 by default): isolated gVisor workspaces — exec / files / artifacts / run.
259
282
  self.sandboxes = Sandboxes(http)
260
283
  # EXPERIMENTAL (HIDE, unaudited): verify signed agent outputs — provenance only.
261
284
  self.verify = Verify(http)
262
285
  self.account = Account(http)
263
286
  # Account-level settings shared by every device (per user): get() / update(partial, version=...).
264
287
  self.settings = Settings(http)
288
+ # OS protection gate: policy() (org override policy) / record_event(...) (override audit).
289
+ self.os_gate = OsGate(http)
265
290
  # READ-ONLY billing (plan, wallet, invoices, watch_balance); payments only via the returned links.
266
291
  self.billing = Billing(http)
267
292
  # Referral stats + invitees; redeem() / set_consent() go through PATCH /v1/account.
@@ -68,6 +68,8 @@ EXTENSION_HEADERS: Dict[str, str] = {
68
68
  "device_platform": "x-codai-device-platform",
69
69
  "push_token": "x-codai-push-token",
70
70
  "share_token": "x-codai-share-token",
71
+ # Billed codai Studio POSTs: a retry with the same key and body replays the first answer (24 h, no double charge).
72
+ "idempotency_key": "Idempotency-Key",
71
73
  }
72
74
 
73
75
  RequestExtensions = Mapping[str, Any]
@@ -104,6 +104,39 @@ OPERATION_METHODS: Dict[str, str] = {
104
104
  "reopenPublicReviewThread": "shares.reopen",
105
105
  "decidePublicReview": "shares.decide",
106
106
  "createVoiceRevocation": "voice_revocations.create",
107
+ "getVaultAccount": "vault.account",
108
+ "putVaultAccount": "vault.put_account",
109
+ "patchVaultSettings": "vault.update_settings",
110
+ "lockVault": "vault.lock",
111
+ "createVaultUnlockChallenge": "vault.unlock_challenge",
112
+ "unlockVault": "vault.unlock",
113
+ "listVaultLimits": "vault.limits",
114
+ "setVaultItemLimits": "vault.set_limits",
115
+ "revokeVaultTaskGrants": "vault.revoke_task_grants",
116
+ "listVaults": "vault.vaults",
117
+ "createVault": "vault.create_vault",
118
+ "listVaultItems": "vault.items",
119
+ "putVaultItem": "vault.put_item",
120
+ "deleteVaultItem": "vault.delete_item",
121
+ "setVaultItemCloud": "vault.set_item_cloud",
122
+ "listVaultRules": "vault.rules",
123
+ "createVaultRule": "vault.create_rule",
124
+ "deleteVaultRule": "vault.delete_rule",
125
+ "listVaultGrants": "vault.grants",
126
+ "revokeVaultGrant": "vault.revoke_grant",
127
+ "listVaultEvents": "vault.events",
128
+ "listVaultApprovals": "vault.approvals",
129
+ "getVaultApproval": "vault.approval",
130
+ "decideVaultApproval": "vault.decide",
131
+ "createVaultDeviceChallenge": "vault.devices.challenge",
132
+ "enrollVaultDevice": "vault.devices.enroll",
133
+ "listVaultDevices": "vault.devices.list",
134
+ "renameVaultDevice": "vault.devices.rename",
135
+ "revokeVaultDevice": "vault.devices.revoke",
136
+ "vaultCatalog": "vault.catalog",
137
+ "vaultUse": "vault.use",
138
+ "vaultHttp": "vault.http_call",
139
+ "vaultResolve": "vault.resolve",
107
140
  "createStudioAbuseReport": "abuse_reports.create",
108
141
  "checkProvenance": "provenance.check",
109
142
  "createStudioBatch": "batches.create",
@@ -115,6 +148,14 @@ OPERATION_METHODS: Dict[str, str] = {
115
148
  "zipStudioBatch": "batches.zip",
116
149
  "saveCreativeTemplate": "creatives.save_template",
117
150
  "listCreativeTemplates": "templates.list",
151
+ "createStudioProduction": "productions.create",
152
+ "getStudioProduction": "productions.retrieve",
153
+ "listStudioMediaOps": "media_ops.list",
154
+ "quoteStudioMediaOp": "media_ops.quote",
155
+ "runStudioMediaOp": "media_ops.run",
156
+ "getStudioMediaOpJob": "media_ops.job",
157
+ "writeStudioLyrics": "lyrics.write",
158
+ "alignStudioLyrics": "lyrics.align",
118
159
  "getCreativeTemplate": "templates.retrieve",
119
160
  "deleteCreativeTemplate": "templates.delete",
120
161
  "exportCreativeFcpxml": "creatives.export_fcpxml",
@@ -122,6 +163,9 @@ OPERATION_METHODS: Dict[str, str] = {
122
163
  "getStudioExport": "exports.retrieve",
123
164
  "createCreativeFromDocument": "creatives.from_document",
124
165
  "buildCreative": "creatives.build",
166
+ "writeCreativePostCopy": "creatives.post_copy",
167
+ "transcriptCutCreative": "creatives.transcript_cut",
168
+ "regenerateCreativeNode": "creatives.regenerate_node",
125
169
  "createSystemOne": "system_one.create",
126
170
  "createTranscription": "audio.transcribe",
127
171
  "createSpeech": "audio.speech",
@@ -145,6 +189,8 @@ OPERATION_METHODS: Dict[str, str] = {
145
189
  "toolsSearch": "tools.search",
146
190
  "toolsFetch": "tools.fetch",
147
191
  "toolsGround": "tools.ground",
192
+ "createResearch": "research.create",
193
+ "getResearch": "research.retrieve",
148
194
  # Tasks
149
195
  "listTasks": "tasks.list",
150
196
  "listPendingTasks": "tasks.pending",
@@ -252,6 +298,10 @@ OPERATION_METHODS: Dict[str, str] = {
252
298
  "verifyPrompt": "prompts.verify",
253
299
  "verifyPrompts": "prompts.verify_many",
254
300
  "streamPrompts": "prompts.stream",
301
+ "exportPrompts": "prompts.export_prompts",
302
+ "bulkPrompts": "prompts.bulk",
303
+ "listPromptEvents": "prompts.events",
304
+ "instantiatePrompt": "prompts.instantiate",
255
305
  # Transcripts
256
306
  "listTranscripts": "transcripts.list",
257
307
  "createTranscript": "transcripts.create",
@@ -336,6 +386,7 @@ OPERATION_METHODS: Dict[str, str] = {
336
386
  "searchMemories": "memory.search",
337
387
  "createMemory": "memory.create",
338
388
  "deleteMemory": "memory.delete",
389
+ "deleteAllMemories": "memory.delete_all",
339
390
  # Sandboxes
340
391
  "createSandbox": "sandboxes.create",
341
392
  "listSandboxes": "sandboxes.list",
@@ -359,9 +410,12 @@ OPERATION_METHODS: Dict[str, str] = {
359
410
  "patchAccount": "account.update",
360
411
  "getBilling": "billing.get",
361
412
  "listBillingInvoices": "billing.invoices",
413
+ "getStudioQuote": "billing.studio_quote",
362
414
  "getReferrals": "referrals.get",
363
415
  "getSettings": "settings.get",
364
416
  "patchSettings": "settings.update",
417
+ "getPolicy": "os_gate.policy",
418
+ "recordOsGateEvent": "os_gate.record_event",
365
419
  "getReceipt": "receipt.get",
366
420
  "submitFeedback": "feedback.submit",
367
421
  "listPhoneModels": "phone_models.list",