codai-sdk 0.7.0__tar.gz → 0.52.1__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.
- codai_sdk-0.52.1/CHANGELOG.md +731 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/LICENSE +1 -1
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/PKG-INFO +22 -1
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/README.md +21 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/pyproject.toml +1 -1
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/__init__.py +111 -1
- codai_sdk-0.52.1/src/codai/_operations.py +388 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/_resolve_types.py +14 -0
- codai_sdk-0.52.1/src/codai/_types.py +9035 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/__init__.py +83 -0
- codai_sdk-0.52.1/src/codai/resources/abuse_reports.py +44 -0
- codai_sdk-0.52.1/src/codai/resources/batches.py +161 -0
- codai_sdk-0.52.1/src/codai/resources/billing.py +64 -0
- codai_sdk-0.52.1/src/codai/resources/brand_kits.py +125 -0
- codai_sdk-0.52.1/src/codai/resources/cards.py +249 -0
- codai_sdk-0.52.1/src/codai/resources/core.py +880 -0
- codai_sdk-0.52.1/src/codai/resources/creatives.py +691 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/environments.py +68 -0
- codai_sdk-0.52.1/src/codai/resources/exports.py +48 -0
- codai_sdk-0.52.1/src/codai/resources/lists.py +97 -0
- codai_sdk-0.52.1/src/codai/resources/memory.py +51 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/platform.py +45 -2
- codai_sdk-0.52.1/src/codai/resources/prompts.py +86 -0
- codai_sdk-0.52.1/src/codai/resources/provenance.py +45 -0
- codai_sdk-0.52.1/src/codai/resources/referrals.py +28 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/resolve.py +33 -1
- codai_sdk-0.52.1/src/codai/resources/sandboxes.py +220 -0
- codai_sdk-0.52.1/src/codai/resources/schedules.py +166 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/sessions.py +32 -4
- codai_sdk-0.52.1/src/codai/resources/shares.py +141 -0
- codai_sdk-0.52.1/src/codai/resources/templates.py +35 -0
- codai_sdk-0.52.1/src/codai/resources/transcripts.py +319 -0
- codai_sdk-0.52.1/src/codai/resources/usage_keys.py +39 -0
- codai_sdk-0.52.1/src/codai/resources/voice_revocations.py +29 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/tests/conftest.py +3 -2
- codai_sdk-0.52.1/tests/test_abuse_reports.py +37 -0
- codai_sdk-0.52.1/tests/test_batches.py +93 -0
- codai_sdk-0.52.1/tests/test_billing_referrals.py +132 -0
- codai_sdk-0.52.1/tests/test_brand_kits.py +178 -0
- codai_sdk-0.52.1/tests/test_cards.py +129 -0
- codai_sdk-0.52.1/tests/test_creatives.py +202 -0
- codai_sdk-0.52.1/tests/test_creatives_documents.py +84 -0
- codai_sdk-0.52.1/tests/test_creatives_e11.py +78 -0
- codai_sdk-0.52.1/tests/test_creatives_e11b.py +89 -0
- codai_sdk-0.52.1/tests/test_environments_exec.py +55 -0
- codai_sdk-0.52.1/tests/test_exports.py +123 -0
- codai_sdk-0.52.1/tests/test_lists.py +92 -0
- codai_sdk-0.52.1/tests/test_memory.py +42 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/tests/test_parity.py +7 -1
- codai_sdk-0.52.1/tests/test_provenance.py +29 -0
- codai_sdk-0.52.1/tests/test_resources.py +1213 -0
- codai_sdk-0.52.1/tests/test_sandboxes.py +133 -0
- codai_sdk-0.52.1/tests/test_settings.py +45 -0
- codai_sdk-0.52.1/tests/test_shares_e12a.py +149 -0
- codai_sdk-0.52.1/tests/test_templates.py +58 -0
- codai_sdk-0.52.1/tests/test_transcripts.py +174 -0
- codai_sdk-0.52.1/tests/test_voice_revocations.py +23 -0
- codai_sdk-0.52.1/uv.lock +294 -0
- codai_sdk-0.7.0/CHANGELOG.md +0 -149
- codai_sdk-0.7.0/src/codai/_operations.py +0 -148
- codai_sdk-0.7.0/src/codai/_types.py +0 -3160
- codai_sdk-0.7.0/src/codai/resources/core.py +0 -209
- codai_sdk-0.7.0/tests/test_resources.py +0 -455
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.github/dependabot.yml +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.github/pull_request_template.md +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.github/workflows/publish.yml +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/.gitignore +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/CODE_OF_CONDUCT.md +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/CONTRIBUTING.md +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/SECURITY.md +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/examples/agent.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/examples/chat.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/examples/feedback.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/examples/streaming.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/scripts/gen-types.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/scripts/smoke_local.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/_http.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/_base.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/agents.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/chat.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/messages.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/responses.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/src/codai/resources/triggers.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/tests/test_http.py +0 -0
- {codai_sdk-0.7.0 → codai_sdk-0.52.1}/tests/test_resolve.py +0 -0
|
@@ -0,0 +1,731 @@
|
|
|
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.52.1] - 2026-10-16
|
|
10
|
+
|
|
11
|
+
- `WalletLedgerEntry.source` literal gains `sandbox_charge`: the agent sandbox exec-time debit (EUR 0.10 per
|
|
12
|
+
exec-hour after 10 free exec-hours a month), written every 5 minutes once sandbox billing is switched on.
|
|
13
|
+
|
|
14
|
+
## [0.52.0] - 2026-10-16
|
|
15
|
+
|
|
16
|
+
- `provenance.check(file, content_type=...)` — public AI-provenance checker (`POST /v1/public/provenance/check`,
|
|
17
|
+
no key needed, at most 25 MB; `file` is bytes or a path): reports C2PA manifest presence and claimed issuer, the
|
|
18
|
+
WAV RIFF INFO, MP3 ID3 and MP4 `udta/meta` AI marks and image XMP. `signature_verified` and `synthid_checked`
|
|
19
|
+
are always `False`.
|
|
20
|
+
|
|
21
|
+
## [0.51.0] - 2026-10-16
|
|
22
|
+
|
|
23
|
+
- `client.sandboxes` (beta) — agent sandboxes over REST (`/v1/sandboxes`): `create` / `list` / `retrieve`, `exec`
|
|
24
|
+
(blocking; `exit_code`, `stdout`, `stderr` and a reproducibility `receipt`), `exec_stream` (generator of event
|
|
25
|
+
dicts: `start`, `stdout`, `stderr`, `truncated`, `exit`, `error`), `files.put` / `files.get` (returns `SandboxFile`
|
|
26
|
+
with `data` + `sha256`) / `files.list`, `artifacts` (scanned files from `/workspace/out` with signed 1 h links),
|
|
27
|
+
`snapshot`, `delete` and one-shot `run`. `exec`, `exec_stream` and `run` accept `idempotency_key=`.
|
|
28
|
+
- Chat `tools` items may now be `{"type": "codai_sandbox", "egress": ..., "template": ...}` (`ChatSandboxTool` in
|
|
29
|
+
`codai._types`): the gateway runs bash / Python server-side in a sandbox per session and returns the artifacts.
|
|
30
|
+
- REST exec over Environments: `environments.exec(env_id, {"command": ..., "op": ..., "args": ..., "timeout_ms": ...})`
|
|
31
|
+
(blocking relay op, shell results flattened to `exit_code` / `stdout` / `stderr`), `environments.files.list` /
|
|
32
|
+
`get` / `put` (UTF-8 text, ≤ 2 MB) and `environments.jobs.start` / `get` (status + output). No WebSocket client
|
|
33
|
+
needed; 409 `environment_offline`, 504 `host_timeout`.
|
|
34
|
+
|
|
35
|
+
## [0.50.0] - 2026-10-16
|
|
36
|
+
|
|
37
|
+
- `abuse_reports.create(share_token, surface, category, explanation, reporter_name, reporter_email, good_faith=True)` —
|
|
38
|
+
`POST /v1/studio/abuse-reports` (public, no key needed): DSA art. 16 notice about illegal or abusive content on a
|
|
39
|
+
codai Studio share (`surface="share"`) or review (`"review"`) link — categories `voice_without_consent`,
|
|
40
|
+
`impersonation`, `fraud`, `election`, `illegal_other`, `other`. Answers 202
|
|
41
|
+
`{id, object: "studio.abuse_report", status: "open"}`, also for an unknown link (no enumeration). Never retried.
|
|
42
|
+
`CreateStudioAbuseReportBody` / `CreateStudioAbuseReportResponse` types.
|
|
43
|
+
|
|
44
|
+
## [0.49.0] - 2026-10-16
|
|
45
|
+
|
|
46
|
+
- `resolve.list(status=None, limit=None, cursor=None)` — `GET /v1/resolve/jobs`, your Resolve jobs newest first
|
|
47
|
+
(`{"jobs", "next_cursor"}`; `status` = a string or a list sent as a comma list), and `resolve.iterate(status, limit)`,
|
|
48
|
+
a generator that follows `next_cursor`. `ResolveJob` gains `issue_url` and `issue_title`; `ResolveJobList` type.
|
|
49
|
+
- `billing` (READ-ONLY, never starts a payment): `billing.get()` — `GET /v1/billing`; `billing.invoices(limit=None)` —
|
|
50
|
+
`GET /v1/billing/invoices`; `billing.watch_balance(threshold_eur, on_low, interval_s=60, max_checks=None)` polls
|
|
51
|
+
`get()` and calls `on_low(balance_eur, billing)` once per crossing below the threshold.
|
|
52
|
+
- `referrals`: `referrals.get()` — `GET /v1/referrals`; `referrals.redeem(code)` and `referrals.set_consent(bool)` call
|
|
53
|
+
`PATCH /v1/account` with `referral_code` / `referral_consent`.
|
|
54
|
+
|
|
55
|
+
## [0.48.0] - 2026-10-16
|
|
56
|
+
|
|
57
|
+
- `voice_revocations.create(email, voice_owner_name, details, evidence_url=None)` — `POST /v1/studio/voice-revocations`
|
|
58
|
+
(public, no key needed): asks for a voice cloned in codai Studio to be taken down; answers 202
|
|
59
|
+
`{id, object: "studio.voice_revocation", status: "open"}` and never echoes the input (only the sha256 of the e-mail
|
|
60
|
+
is stored). Never retried. `CreateVoiceRevocationBody` / `CreateVoiceRevocationResponse` types. Custom (cloned) voices
|
|
61
|
+
themselves are not in the SDK while the feature flag is off.
|
|
62
|
+
|
|
63
|
+
## [0.47.0] - 2026-10-16
|
|
64
|
+
|
|
65
|
+
- Lottie export: `creatives.export_lottie(id, format=None, formats=None, seq=None, container=None)` —
|
|
66
|
+
`GET /v1/studio/creatives/{id}/export.lottie` exports a video creative as a Lottie animation (Bodymovin JSON with
|
|
67
|
+
embedded images, or a dotLottie `.lottie` archive with `container="dotlottie"`; `formats="all"` for every format),
|
|
68
|
+
free and synchronous: the export comes back already `succeeded` with a signed `url` and the fidelity report in
|
|
69
|
+
`warnings`. `creatives.download_lottie(...)` returns the file itself (`{bytes, filename, content_type}`).
|
|
70
|
+
`StudioExport` gains `kind` (`"fcpxml"` | `"lottie"`) and `container` (Lottie only); `ExportCreativeLottieResponse`.
|
|
71
|
+
|
|
72
|
+
## [0.46.0] - 2026-10-16
|
|
73
|
+
|
|
74
|
+
- `ai_label` (`"none"` | `"corner"` | `"end_card"`, EU AI Act art. 50(4)): in the `renders.create` / `renders.render`
|
|
75
|
+
body, as `creatives.render(id, ai_label=...)` and `batches.create(..., ai_label=...)` / `dry_run`. Burns a visible
|
|
76
|
+
"AI-generated" label (corner for the whole video, or a ~2 s end card) into the MP4. Omitted = `corner` when the render
|
|
77
|
+
uses TTS narration or AI-generated images, else `none`; `none` with TTS narration is a 400 `ai_label_required`.
|
|
78
|
+
Render replies report the resolved `ai_label`, and so do `renders.list` items (`"none"` for renders from before the
|
|
79
|
+
label existed).
|
|
80
|
+
|
|
81
|
+
## [0.45.2] - 2026-10-16
|
|
82
|
+
|
|
83
|
+
- `client.memory.list/search/create/delete` — your persistent memory over REST (`/v1/memory`), the same store
|
|
84
|
+
the MCP memory tools use. Search and create are metered as `memory:search` / `memory:create`.
|
|
85
|
+
|
|
86
|
+
## [0.45.1] - 2026-10-15
|
|
87
|
+
|
|
88
|
+
- `allow_remix` on view share links now defaults to `false` server-side (E-13 legal review): pass
|
|
89
|
+
`allow_remix: true` to let link holders remix the creative into their own account.
|
|
90
|
+
|
|
91
|
+
## [0.45.0] - 2026-10-15
|
|
92
|
+
|
|
93
|
+
- Share links: `creatives.create_share(id, kind, label=None, expires_in_days=None, seq=None, allow_remix=None,
|
|
94
|
+
can_approve=None)` — `POST /v1/studio/creatives/{id}/shares` returns the public `url` and its `token` once;
|
|
95
|
+
`creatives.list_shares(id)` and `creatives.revoke_share(id, share_id)`.
|
|
96
|
+
- Review: `creatives.review(id)`, `request_review(id)`, `reset_review(id)` (`draft` → `in_review` → `approved` |
|
|
97
|
+
`changes_requested`, approval pins the version); threads: `review_threads(id, status=None)`,
|
|
98
|
+
`create_review_thread(id, body, node_id=None, scene_id=None, t_ms=None)`, `reply_review_thread`,
|
|
99
|
+
`resolve_review_thread`, `reopen_review_thread`, `delete_review_comment`.
|
|
100
|
+
- New `client.shares` (token or whole link): `get(link, format=None, locale=None)` (no key needed),
|
|
101
|
+
`remix(link, title=None)`, and through review links `comment(link, name, body, …)`, `reply`, `resolve`, `reopen`,
|
|
102
|
+
`decide(link, name, decision, seq, note=None)`. `codai.share_token_from(value)` extracts the token. All free.
|
|
103
|
+
- Generated types: `StudioShare*`, `StudioReview*`, `StudioPublicShare`, `StudioPublicReview`, `StudioRemix*`.
|
|
104
|
+
|
|
105
|
+
## [0.44.0] - 2026-10-15
|
|
106
|
+
|
|
107
|
+
- Localisation: `creatives.locales(id, locale=None, units=None, offset=None, limit=None)` —
|
|
108
|
+
`GET /v1/studio/creatives/{id}/locales`; `creatives.localize(id, locales, tone=None, glossary=None, only_missing=None,
|
|
109
|
+
voice=None, base_seq=None, force=None)` — `POST /v1/studio/creatives/{id}/localize` translates every text into up to
|
|
110
|
+
10 BCP-47 locales as per-locale overrides in one new version (token-metered; `voice=True` narrates voice clips again,
|
|
111
|
+
billed); `creatives.fork_locale(id, locale, title=None, seq=None)` —
|
|
112
|
+
`POST /v1/studio/creatives/{id}/locales/{locale}/fork` saves a locale as a new creative.
|
|
113
|
+
- `locale=` keyword on `creatives.compiled`, `render`, `frame`, `captions_srt`, `captions_vtt` and `lint`. Lint
|
|
114
|
+
codes `missing_translation`, `stale_translation`, `text_overflow_locale` and issue `locale`; new ops
|
|
115
|
+
`setLocaleText`, `setLocale`, `setLocalization`.
|
|
116
|
+
- Batches: new `client.batches` — `create(source, csv=None, sheet=None, delimiter=None, mapping=None, title=None,
|
|
117
|
+
render=None, quality=None, format=None, localize=None)`, `dry_run(...)` (same arguments, nothing stored), `list`,
|
|
118
|
+
`get(id, rows=None, status=None, offset=None, limit=None)`, `cancel`, `retry`, `export_csv` (status CSV text),
|
|
119
|
+
`zip` (ZIP of finished renders) and `wait(id, interval=3.0, timeout=600.0)`.
|
|
120
|
+
- Generated types: `CreativeLocaleStatus`, `CreativeLocaleUnit`, `CreativeLocalizeRequest`, `CreativeLocalizeResult`,
|
|
121
|
+
`CreativeLocaleForkRequest`, `CreativeLocaleForkResult`, `StudioBatch*`.
|
|
122
|
+
|
|
123
|
+
## [0.43.0] - 2026-10-15
|
|
124
|
+
|
|
125
|
+
- Auto-captions: `creatives.captions(id, clip_id=None, preset=None, node_id=None, script=None, language=None,
|
|
126
|
+
retranscribe=None, base_seq=None, force=None)` — `POST /v1/studio/creatives/{id}/captions` transcribes a voice clip
|
|
127
|
+
word by word (words cached on the asset, free next time), corrects the spelling with the script and adds or updates a
|
|
128
|
+
captions node as one new version (`node_id`, `words`, `cached`, `corrected`, `cost_micro_usd`; a fresh
|
|
129
|
+
transcription is billed at the speech-to-text rate). `creatives.captions_srt(id, node_id=None, seq=None)` /
|
|
130
|
+
`captions_vtt(...)` return the captions as SRT / WebVTT text.
|
|
131
|
+
- Platforms: `creatives.adapt(id, platforms, focal=None, base_seq=None, force=None)` —
|
|
132
|
+
`POST /v1/studio/creatives/{id}/adapt` adds one format per platform (`tiktok`, `reels`, `shorts`, `feed-square`,
|
|
133
|
+
`feed-portrait`, `youtube`) with text kept inside the platform safe zone; `focal="vision"` (token-metered) finds
|
|
134
|
+
image focal points. New ops `adaptFormat` and `setControl`.
|
|
135
|
+
- Lint: issues gain `format` and `fixable` and the codes `empty_list`, `off_brand_color`,
|
|
136
|
+
`outside_platform_safe_zone`, `text_too_small`, `missing_alt`, `missing_captions`, `reading_speed`, `flashing`;
|
|
137
|
+
the result adds `fixable`. `creatives.lint_fix(id, codes=None, agent=None, base_seq=None, force=None)` —
|
|
138
|
+
`POST /v1/studio/creatives/{id}/lint/fix`: deterministic fixes are free, `agent=True` adds one billed `codai` turn.
|
|
139
|
+
- Tweak panel: `creatives.controls(id)` — `GET /v1/studio/creatives/{id}/controls`.
|
|
140
|
+
- Render aspect ratio `4:5` (1080×1350).
|
|
141
|
+
- Generated types: `CreativeCaptionsRequest`, `CreativeCaptionsResult`, `CaptionPresetId`, `PlatformId`,
|
|
142
|
+
`CreativeAdaptRequest`, `CreativeAdaptResult`, `CreativeLintCode`, `CreativeLintFixRequest`,
|
|
143
|
+
`CreativeLintFixResult`, `Control`, `PanelControl`, `CreativeControls`.
|
|
144
|
+
|
|
145
|
+
## [0.42.0] - 2026-10-14
|
|
146
|
+
|
|
147
|
+
- Brand kits as Design Tokens (DTCG 2025.10): kits now carry `dtcg` (the canonical document), `contrast` (WCAG ratio
|
|
148
|
+
- `aa` for text/background, primary/background, background/primary, accent/background, secondary/background) and
|
|
149
|
+
`updated_at`; `tokens` also carries the document aliases (`color.bg`, `color.fg`, `color.accent`,
|
|
150
|
+
`font.heading`, `font.body`), extra colours and `radius`.
|
|
151
|
+
- `brand_kits.create(name, tokens=… | dtcg=…, logo_asset_id=…, source_url=…)` — `POST /v1/studio/brand-kits`
|
|
152
|
+
(exactly one of `tokens` / `dtcg`, else `ValueError`; 400 `invalid_tokens`), `brand_kits.update(id, name=…,
|
|
153
|
+
tokens=…, dtcg=…, logo_asset_id=…)` — `PATCH /v1/studio/brand-kits/{id}` (`logo_asset_id=None` removes the logo),
|
|
154
|
+
`brand_kits.export_dtcg(id)` — `GET /v1/studio/brand-kits/{id}/dtcg`. Free.
|
|
155
|
+
- `brand_kits.extract(url=None, name=None, logo_asset_id=None)` — exactly one of `url` / `logo_asset_id` (else
|
|
156
|
+
`ValueError`); from a logo image one vision turn reads the palette (400 `unsupported_media`).
|
|
157
|
+
- `creatives.restyle(id, brand_kit_id=None, tokens=None, base_seq=None, snap=None, fonts=None, force=None)` —
|
|
158
|
+
`POST /v1/studio/creatives/{id}/restyle`: re-applies a kit as one new version (literal brand colours become token
|
|
159
|
+
refs, `snap` maps the rest to the nearest kit colour, fonts by role, locked nodes skipped unless `force`). Free.
|
|
160
|
+
- Generated types: `BrandKitDtcg`, `BrandKitContrastPair`, `BrandKitCreateRequest`, `BrandKitUpdateRequest`,
|
|
161
|
+
`CreativeRestyleRequest`.
|
|
162
|
+
|
|
163
|
+
## [0.41.0] - 2026-10-14
|
|
164
|
+
|
|
165
|
+
- Documents as creatives: `creatives.from_document(document_id)` — `POST /v1/studio/documents/{id}/creative` turns a
|
|
166
|
+
Studio deck / doc / sheet into an editable creative (slides = scenes with `layout` + `notes`, doc pages = a `flow`
|
|
167
|
+
group, sheets = a `cell_grid` + chart nodes; nodes carry semantic `role`s). Idempotent: returns the creative plus
|
|
168
|
+
`document_id` and `existing` (HTTP 201 new / 200 already linked). Free.
|
|
169
|
+
- `creatives.build(creative_id, seq=None, preview=None, filename=None)` — `POST /v1/studio/creatives/{id}/build` builds
|
|
170
|
+
the creative back into PPTX / DOCX / XLSX as a new version of its document: `{object: "studio.creative_build",
|
|
171
|
+
creative_id, seq, warnings, document}`; 400 `not_supported_for_kind` / `invalid_spec`. Files are free;
|
|
172
|
+
`preview=True` queues the billed document preview.
|
|
173
|
+
- Regenerated `_types.py`: `StudioCreativeFromDocument`, `CreativeBuildRequest`, `StudioCreativeBuild`,
|
|
174
|
+
`Document.creative_id`, `CreativeCompiled.kind`, the `createCreativeFromDocument` / `buildCreative` operations.
|
|
175
|
+
|
|
176
|
+
## [0.40.0] - 2026-10-14
|
|
177
|
+
|
|
178
|
+
- FCPXML export: `creatives.export_fcpxml(id, format=None, seq=None)` — `GET /v1/studio/creatives/{id}/export.fcpxml`
|
|
179
|
+
queues a zip with an FCPXML 1.10 project (one clip + marker per scene, audio on its own lanes) and its media
|
|
180
|
+
(per-scene MP4 segments, voice / music / sfx files) for Final Cut Pro, DaVinci Resolve or Premiere (FCPXML import).
|
|
181
|
+
Returns `{id, status: "queued", creative_id, seq, format, fps, filename, url, expires_at, bytes, rendered_seconds,
|
|
182
|
+
cost_micro_usd, warnings, error, created_at}`; 400 `unsupported_kind` / `unsupported_format` / `too_long`. Only newly
|
|
183
|
+
rendered seconds are billed, at the final render price (cached segments are free).
|
|
184
|
+
- `exports.retrieve(id)` — `GET /v1/studio/exports/{id}` (free); `exports.wait(id, interval=3.0, timeout=900.0)` polls
|
|
185
|
+
until `succeeded` (signed `url`, valid 1 h) or `failed` and returns the final export; `TimeoutError` after `timeout`.
|
|
186
|
+
|
|
187
|
+
## [0.39.0] - 2026-10-14
|
|
188
|
+
|
|
189
|
+
- Templates from your own creatives: `creatives.save_template(id, vars=[…], title=…, seq=…)` —
|
|
190
|
+
`POST /v1/studio/creatives/{id}/template`: each `vars` entry (`{"node_id", "prop": "text" | "image", "key",
|
|
191
|
+
"label"?}`) turns a text node's text or an image node's asset into a template variable (current value = default).
|
|
192
|
+
Returns `{id, title, kind, source_creative_id, source_seq, vars_schema, thumbnail_url, created_at, doc}`; 400
|
|
193
|
+
`node_not_found` / `invalid_pick` / `duplicate_key`. Free; templates are private.
|
|
194
|
+
- `templates.list(kind=…, limit=…)`, `.retrieve(id)` (with `doc`), `.delete(id)` — free.
|
|
195
|
+
- `creatives.create({"kind": …, "template": …, "vars": {…}})` starts version 1 from a template with the var values
|
|
196
|
+
applied (400 `kind_mismatch` / `unknown_var` / `invalid_var_value`, 404 unknown template).
|
|
197
|
+
|
|
198
|
+
## [0.38.0] - 2026-10-14
|
|
199
|
+
|
|
200
|
+
- Cards: `cards.product(url, lang=None)` — `POST /v1/cards/product`: a `products` card block with one item read from
|
|
201
|
+
a public https product page's schema.org `Product` JSON-LD (or OpenGraph product tags): name, image, price +
|
|
202
|
+
currency (lowest offer), old price, rating (0-5), reviews, seller, availability badge (en/ro). Only what the page
|
|
203
|
+
states, never sponsored; SSRF-guarded like `unfurl`, cached 6 h, shares its 500/day limit; 422 `product_not_found`.
|
|
204
|
+
|
|
205
|
+
## [0.37.0] - 2026-10-14
|
|
206
|
+
|
|
207
|
+
- Brand kits: `brand_kits.extract(url, name=…)` — `POST /v1/studio/brand-kits/extract`: fetches a public https page
|
|
208
|
+
(SSRF-guarded), one bounded `codai` model turn picks the palette (primary, secondary, accent, background, text) and
|
|
209
|
+
the heading / body fonts, the logo is stored as an `image` asset. Returns `{id, name, source_url, tokens,
|
|
210
|
+
logo_asset_id, logo_url, logo_mime_type, created_at}`; 400 `url_blocked`, 422 `fetch_failed` / `extract_failed`,
|
|
211
|
+
504 `timeout`. Token-metered (`codai::brand-kit-extract`).
|
|
212
|
+
- `brand_kits.list(limit=…)`, `.retrieve(id)`, `.delete(id)` — free.
|
|
213
|
+
- `creatives.create({"kind": …, "brand_kit_id": …})` applies a kit to version 1 (`brand = {kitId, tokens}` + logo asset).
|
|
214
|
+
|
|
215
|
+
## [0.36.0] - 2026-10-14
|
|
216
|
+
|
|
217
|
+
- A/B variants of a creative: `creatives.variants(id, base_seq=…, count=…, focus=[…], brief=…, render=…, format=…)`
|
|
218
|
+
— `POST /v1/studio/creatives/{id}/variants`: one bounded `codai` model turn proposes up to 5 variants (focus hook /
|
|
219
|
+
title / cta / visual / copy), each saved as a fork with the ops applied plus a queued draft render. Returns
|
|
220
|
+
`{group_id, base_seq, variants: [{creative_id, label, rationale, applied_ops, head_seq, render_id}]}`; 422
|
|
221
|
+
`no_edit`, 504 `timeout` after 90 s. Token-metered (`codai::creative-variants`), draft renders billed on their poll.
|
|
222
|
+
- `creatives.list_variants(id)` — `GET …/variants`: the latest group with `status` and the stored render state.
|
|
223
|
+
- `creatives.pick_variant(id, variant_id, base_seq=…)` — `POST …/variants/{variantId}/pick`: the winner's ops onto the
|
|
224
|
+
original (rebased like `edit`, 409 `stale` on overlap), statuses updated.
|
|
225
|
+
|
|
226
|
+
## [0.35.0] - 2026-10-14
|
|
227
|
+
|
|
228
|
+
- `SessionControlKind` gains `pause` and `resume`: `POST /v1/sessions/{id}/control` with `kind="pause"`
|
|
229
|
+
parks the running turn at its next step boundary (after the current tool calls), `kind="resume"` continues the
|
|
230
|
+
same turn. Editors may send both (same trust as `cancel`). Executors report the state with a `run_state` event
|
|
231
|
+
`{"state": "paused" | "running"}`.
|
|
232
|
+
|
|
233
|
+
## [0.34.0] - 2026-10-12
|
|
234
|
+
|
|
235
|
+
- `creatives.comment(id, t_ms=…, comment=…, base_seq=…, node_id=…, scene_id=…, apply=…)` —
|
|
236
|
+
`POST /v1/studio/creatives/{id}/comments`: a comment pinned on a frame becomes an edit (one bounded `codai` model
|
|
237
|
+
turn proposes ops, applied like `edit`). Returns `{head_seq, applied_ops, summary, version}`; 409 `stale` on an
|
|
238
|
+
overlapping change, 422 `no_edit` when the model made no edit, 504 `timeout` after 60 s. Token-metered
|
|
239
|
+
(`codai::creative-comment`).
|
|
240
|
+
|
|
241
|
+
## [0.33.0] - 2026-10-12
|
|
242
|
+
|
|
243
|
+
- `creatives.frame(id, t_ms=[…], format=…, exact=…, version=…)` — `POST /v1/studio/creatives/{id}/frame` now returns
|
|
244
|
+
PNG still frames (`{object: "studio.creative.frames", status: "succeeded", frames, billed_micro_usd}`) or a running
|
|
245
|
+
job (`{object: "studio.creative.frame_job", status: "running", frame_job_id}`) when they are not ready within ~90 s.
|
|
246
|
+
`exact=True` cuts frames from a draft render of the covering scenes. Cached frames are free; 60 frame jobs per UTC
|
|
247
|
+
day are free, then billed. The old `frame(id, body)` dict form is replaced by keyword arguments.
|
|
248
|
+
- `creatives.frame_job(id, job_id)` — `GET /v1/studio/creatives/{id}/frames/{jobId}`, polls a frame job.
|
|
249
|
+
- `creatives.render` may now answer 200 with the identical existing render (`cached: True`, no new charge); new
|
|
250
|
+
renders carry `cached: False`.
|
|
251
|
+
|
|
252
|
+
## [0.32.0] - 2026-10-12
|
|
253
|
+
|
|
254
|
+
- `cards.route(from_=…, to=…, origin=…, destination=…, mode=…, depart_at=…)` — `GET /v1/cards/route`, travel time
|
|
255
|
+
from Google Routes (`route` summary + `map` block); billed $0.010 traffic-aware driving, $0.005 walk / bike / transit.
|
|
256
|
+
- `cards.track(awb, carrier=…)` — `GET /v1/cards/track`, parcel history (Sameday live; FAN Courier, Cargus, DPD with a
|
|
257
|
+
gateway carrier contract only).
|
|
258
|
+
- `cards.efactura(limit=…)` — `GET /v1/cards/efactura`, your fiscal documents issued through Brivio with their ANAF
|
|
259
|
+
e-Factura status.
|
|
260
|
+
|
|
261
|
+
## [0.31.0] - 2026-10-12
|
|
262
|
+
|
|
263
|
+
- `client.creatives` — codai Studio editable creative documents (ECD) with an append-only version history:
|
|
264
|
+
`list(kind, before, limit)`, `create(body)`, `retrieve(id, seq=None)`, `outline`, `find(id, query)`,
|
|
265
|
+
`subtree(id, ids=None, scene_id=None)`, `edit(id, base_seq, ops, intent=None, author=None, force=None)`
|
|
266
|
+
(`POST /v1/studio/creatives/{id}/ops`; a stale base is rebased, overlapping changes raise `CodaiError` 409
|
|
267
|
+
`stale`), `versions`, `revert(id, seq)`, `fork`, `delete`, `lint`, `compiled` (preview HTML with signed asset URLs)
|
|
268
|
+
and `render` (queues a `codai-render`, HTTP 202; poll `renders.retrieve`). `frame` is reserved (501
|
|
269
|
+
`not_implemented`). Everything except `render` is free.
|
|
270
|
+
- `create_timeline` replies carry `creative_id`; `renders.retrieve` reports `creative_id` for renders linked to a
|
|
271
|
+
creative.
|
|
272
|
+
- Generated types: `Creative*` TypedDicts and the 15 creatives operation aliases.
|
|
273
|
+
|
|
274
|
+
## [0.30.0] - 2026-10-12
|
|
275
|
+
|
|
276
|
+
- `lists` resource — codai Lists + Share to codai: `list`, `create`, `reorder`, `update`, `delete`, `items`, `add`,
|
|
277
|
+
`update_item`, `delete_item`, `image` (`ListItemImage(data, content_type)`), `export_markdown` (str), `share` (`POST /v1/share`,
|
|
278
|
+
201 created / 200 dedupe) and `stream()` (generator) (`event: list` frames).
|
|
279
|
+
- `schedules.audit({ schedule_id?, limit? })` — `GET /v1/schedules/audit`, the append-only scheduler audit log.
|
|
280
|
+
- Generated types: 14 new operations (lists, share, schedule audit).
|
|
281
|
+
|
|
282
|
+
## [0.29.0] - 2026-10-12
|
|
283
|
+
|
|
284
|
+
- `cards.render(block, format=None, width=None, height=None, theme=None, scale=None)` — `POST /v1/cards/render`:
|
|
285
|
+
renders a `chart` or `qr` card block to PNG (default) or SVG on the gateway and returns
|
|
286
|
+
`CardsRendered(data, content_type, width, height)`. Free, 2000 renders per user per day. Mermaid `diagram` / `math`
|
|
287
|
+
blocks are not supported yet (422 `render_unsupported`).
|
|
288
|
+
- Generated types: operation `cardsRender`.
|
|
289
|
+
|
|
290
|
+
## [0.28.0] - 2026-10-11
|
|
291
|
+
|
|
292
|
+
- Studio scene timelines on `client.renders`: `create_timeline(body)` for `POST /v1/studio/timelines` (image/video
|
|
293
|
+
scenes, optional narration billed now and a music bed; HTTP 202, poll with `retrieve`), `regenerate_scene(render_id,
|
|
294
|
+
scene_id, body)` for `POST /v1/studio/renders/{id}/scenes/{scene_id}/regenerate` (a new render with one scene
|
|
295
|
+
replaced) and `list(before=None, limit=None, root_render_id=None)` for `GET /v1/studio/renders` (no polling, no URLs).
|
|
296
|
+
- `retrieve(render_id, expand_assets=True)` sends `?expand=assets`; timeline renders carry `timeline`,
|
|
297
|
+
`parent_render_id`, `root_render_id` and `stage`.
|
|
298
|
+
- Generated types for `StudioRenderList`, `StudioTimelineCreate`, `StudioTimelineAccepted`, `StudioSceneRegenerate`,
|
|
299
|
+
`StudioSceneRegenerateAccepted`, `StudioTimeline`; operations `listRenders`, `createTimeline`, `regenerateRenderScene`.
|
|
300
|
+
|
|
301
|
+
## [0.27.0] - 2026-10-11
|
|
302
|
+
|
|
303
|
+
- `client.cards` — typed card data from `/v1/cards/*`. Every JSON method returns `{"block": ..., "provenance": ...}`
|
|
304
|
+
where `block` is already a valid `@codai/cards` block: `cards.weather(lat, lng, name=None)` (MET Norway, free),
|
|
305
|
+
`cards.places(q=None, lat=None, lng=None, radius=None, type=None, limit=None, lang=None, region=None,
|
|
306
|
+
open_now=None)` (Google Places, billed $0.032 per call, 200/day), `cards.geocode(address)` (map block + raw
|
|
307
|
+
`results`, billed $0.005), `cards.fx(source=None, from_=None, to=None, amount=None, quote=None, symbols=None)`
|
|
308
|
+
(BNR / ECB, free), `cards.unfurl(url)` (links preview block, 500/day) and `cards.static_map(center=None,
|
|
309
|
+
markers=None, ...)` returning `CardsStaticMap(data, content_type, attribution)` for the PNG (billed $0.002, counted
|
|
310
|
+
in the 500/day maps limit).
|
|
311
|
+
- Generated types for `CardDataResponse`; operations `cardsWeather`, `cardsPlaces`, `cardsGeocode`,
|
|
312
|
+
`cardsStaticMap`, `cardsFx`, `cardsUnfurl`.
|
|
313
|
+
|
|
314
|
+
## [0.26.0] - 2026-10-11
|
|
315
|
+
|
|
316
|
+
- `schedules.pause/resume` (vacation mode with optional backfill), `schedules.templates/render_template`, and
|
|
317
|
+
`client.heartbeats` (`list/create/update/delete`) for dead-man-switch monitors of crons codai does not run.
|
|
318
|
+
|
|
319
|
+
## [0.25.0] - 2026-10-11
|
|
320
|
+
|
|
321
|
+
- `client.schedules` — the codai Scheduler: `list`, `create`, `preview` (cron or plain words in English or Romanian →
|
|
322
|
+
next runs + DST warning), `get`, `update`, `delete`, `run_now`, `runs`, `recent_runs`, `decide` (approve / skip a run
|
|
323
|
+
waiting for you) and `stream`; `schedules.hosts.list/update` (devices as hosts: os, kind, tags); and the host executor
|
|
324
|
+
protocol `schedules.executor.claim/heartbeat/result/approve_command`.
|
|
325
|
+
- `transcripts.publish_live` mapped to `publishTranscriptLive` in the operation table.
|
|
326
|
+
|
|
327
|
+
## [0.24.0] - 2026-10-10
|
|
328
|
+
|
|
329
|
+
- `client.settings` — account-level settings shared by every device of the account (per user, not per key):
|
|
330
|
+
`client.settings.get()` for `GET /v1/settings` (full object with defaults, `version` 0 / `updatedAt` None until
|
|
331
|
+
the first write) and `client.settings.update(partial, version=None)` for `PATCH /v1/settings` (deep merge, strict
|
|
332
|
+
validation; a stale `version` raises a 409 `CodaiError` with code `version_conflict`).
|
|
333
|
+
`settings_conflict_current(err)` returns the current state carried by that 409.
|
|
334
|
+
- Generated types for `SettingsResponse`, `UserSettings`, `TranscriptsSettings`, `SettingsPatchRequest`,
|
|
335
|
+
`SettingsConflict`; operations `getSettings`, `patchSettings`.
|
|
336
|
+
|
|
337
|
+
## [0.23.0] - 2026-10-10
|
|
338
|
+
|
|
339
|
+
### Added
|
|
340
|
+
|
|
341
|
+
- `client.documents` — codai Studio documents (`codai-docs`): `create(body)` builds a deck (PPTX), doc (DOCX) or sheet
|
|
342
|
+
(XLSX) from a JSON `spec` (free; `file` is an asset dict with `kind: "document"`), `retrieve(id)` returns it with the
|
|
343
|
+
stored `spec`, `preview(id)` queues a `codai-docs-preview` preview (tagged PDF + page PNGs + contact sheet, HTTP 202),
|
|
344
|
+
`retrieve_preview(preview_id)` polls it and `video(id, body)` turns a deck into an MP4 queued as a `codai-render`
|
|
345
|
+
render (optional narration). Pollers `create_preview_and_wait(id, poll_interval=, timeout=)` returns the succeeded
|
|
346
|
+
preview and `video_and_wait(id, body, poll_interval=, timeout=)` returns a `RenderResult`; both raise
|
|
347
|
+
`RuntimeError` on `failed` and `TimeoutError` on timeout.
|
|
348
|
+
- Generated types: `DocumentCreateRequest`, `Document`, `DocumentPreview`, `DocumentPreviewAccepted`,
|
|
349
|
+
`DocumentVideoRequest`, `DocumentVideoAccepted`, `DeckSpec`, `DocSpec`, `SheetSpec` and their parts; `AssetKind`
|
|
350
|
+
gains `document` and `preview`.
|
|
351
|
+
|
|
352
|
+
## [0.22.0] - 2026-10-10
|
|
353
|
+
|
|
354
|
+
### Added
|
|
355
|
+
|
|
356
|
+
- `client.sfx` — the codai Studio sound-effects library (`codai-sfx`, curated CC0 sounds + a Freesound CC0-only
|
|
357
|
+
fallback): `client.sfx.search(q=, category=, tags=, max_duration=, limit=)` for `GET /v1/studio/sfx` returns
|
|
358
|
+
`SfxSearchResult` (`data`, `source`, `fallback_unavailable` from `x-codai-sfx-fallback: unavailable`; `tags` accepts
|
|
359
|
+
a list) and `client.sfx.import_(sfx_id)` for `POST /v1/studio/sfx/{sfx_id}/import` returns the asset dict
|
|
360
|
+
(`kind: "sfx"`, usable as `asset:<asset_id>` in renders). The method is `import_` because `import` is a Python
|
|
361
|
+
keyword. Both are free.
|
|
362
|
+
- Generated types: `SfxDto`, `SfxCategory`, `SfxList`, `searchSfxResponse`, `importSfxResponse`; `AssetKind` gains
|
|
363
|
+
`sfx`.
|
|
364
|
+
|
|
365
|
+
## [0.21.0] - 2026-10-10
|
|
366
|
+
|
|
367
|
+
### Added
|
|
368
|
+
|
|
369
|
+
- `client.audio.speech_json(body)` for `POST /v1/audio/speech` with `timestamps` and/or `store`: returns
|
|
370
|
+
`SpeechJsonResult` with per-word timings (`words`), decoded `audio` or the stored studio `asset` (kind `speech`,
|
|
371
|
+
usable as `asset:<id>` in renders), `duration_seconds`, `cost_micro_usd` and `timestamps_unavailable`
|
|
372
|
+
(`x-codai-timestamps: unavailable`). Defaults to `codai-speech` and `timestamps: True`.
|
|
373
|
+
- Generated types: speech models `codai-speech` (Chirp 3 HD, 30 native Romanian voices) and
|
|
374
|
+
`codai-speech-expressive` (Gemini 2.5 Flash TTS, honours `instructions`); request fields `language`, `timestamps`,
|
|
375
|
+
`store`; new TypedDicts `SpeechJson`, `SpeechWord`, `MusicTrackMeta`; music request fields `lyrics`,
|
|
376
|
+
`instrumental`, `bpm`, `duration_seconds`, `language` and the `codai-music` / `codai-music-pro` /
|
|
377
|
+
`codai-music-legacy` model enum.
|
|
378
|
+
- `MusicResult.tracks` (per-item `lyrics`, `caption`, `lyrics_match`, `warnings`) and `MusicResult.warnings`
|
|
379
|
+
(e.g. `lyrics_mismatch` for best-effort non-English lyrics).
|
|
380
|
+
|
|
381
|
+
### Changed
|
|
382
|
+
|
|
383
|
+
- `codai-music` is now Lyria 3 Clip (30 s MP3 with vocals); Lyria 2 stays available as `codai-music-legacy`.
|
|
384
|
+
- `audio.speech()` / `speech_detailed()` no longer send the Azure default `voice: "alloy"` for `codai-speech*` models.
|
|
385
|
+
- `music.generate()` client timeout floor raised from 180 s to 300 s (Lyria 3 Pro songs).
|
|
386
|
+
|
|
387
|
+
## [0.20.0] - 2026-10-10
|
|
388
|
+
|
|
389
|
+
### Added
|
|
390
|
+
|
|
391
|
+
- `client.renders` for codai Studio renders (`codai-render`, HyperFrames HTML composition → MP4, up to 180 s at
|
|
392
|
+
1080p): `create(body)` (`POST /v1/studio/renders`, HTTP 202), `retrieve(id)` (`GET /v1/studio/renders/{id}`, status
|
|
393
|
+
- `progress` + `qa`) and `render(body, poll_interval=, timeout=)`, which polls until `succeeded` and returns a
|
|
394
|
+
`RenderResult` (`asset`, `poster_url`, `qa`, `cost_micro_usd`); raises `RuntimeError` on `failed` and
|
|
395
|
+
`TimeoutError` on timeout.
|
|
396
|
+
- Regenerated `_types.py` (`StudioRender*` schemas, the `createRender` / `getRender` operations, the
|
|
397
|
+
`asset_not_found`, `too_many_renders` and `renders_unavailable` error codes).
|
|
398
|
+
|
|
399
|
+
## [0.19.0] - 2026-10-10
|
|
400
|
+
|
|
401
|
+
### Added
|
|
402
|
+
|
|
403
|
+
- `client.assets` for codai Studio assets (`/v1/assets`, owner-scoped, kept 90 days): `list(kind=, before=, limit=)`,
|
|
404
|
+
`iterate()` (follows `next_before`), `retrieve(id)`, `content_url(id)` (fresh 1 h signed URL), `content_path(id)`
|
|
405
|
+
(authenticated `GET /v1/assets/{id}/content` redirect), `content(id)` (bytes) and `delete(id)`.
|
|
406
|
+
- `response_format: "url"` on `images.generate` / `images.edit` and `music.generate` bodies, and
|
|
407
|
+
`response_format="url"` on `videos.retrieve` / `videos.generate`: results are stored as assets and returned in
|
|
408
|
+
`ImagesResult.assets` / `MusicResult.assets` / `VideoResult.asset` (signed URLs) instead of bytes. The default
|
|
409
|
+
`b64_json` behaviour is unchanged.
|
|
410
|
+
- Regenerated `_types.py` (`AssetDto`, `AssetKind`, `AssetList`, `AssetDeleted`, `MediaResponseFormat`, the four asset
|
|
411
|
+
operations, `assets_unavailable` error code).
|
|
412
|
+
|
|
413
|
+
## [0.18.0] - 2026-10-09
|
|
414
|
+
|
|
415
|
+
### Added
|
|
416
|
+
|
|
417
|
+
- codai Studio media (US-only, English prompts): `music.generate(body)` -> `MusicResult` (`POST /v1/audio/music`,
|
|
418
|
+
Lyria 2, 30 s WAV clips, timeout floor 180 s) and `videos.create` / `.retrieve(id)` /
|
|
419
|
+
`.generate(body, poll_interval=5.0, timeout=300.0)` -> `VideoResult` (`POST /v1/videos` + `GET /v1/videos/{id}`,
|
|
420
|
+
Veo 3.1 Fast; raises `RuntimeError` on `failed`/`filtered`, `TimeoutError` on timeout).
|
|
421
|
+
|
|
422
|
+
## [0.17.0] - 2026-10-08
|
|
423
|
+
|
|
424
|
+
### Added
|
|
425
|
+
|
|
426
|
+
- `client.tools.ground(body)` — `POST /v1/tools/ground`: locate a UI element described in words on an inline
|
|
427
|
+
screenshot (codai's self-hosted GUI grounding model).
|
|
428
|
+
|
|
429
|
+
## [0.16.1] - 2026-10-07
|
|
430
|
+
|
|
431
|
+
### Added
|
|
432
|
+
|
|
433
|
+
- Web search result `source` gains `ocw` (MIT OpenCourseWare course records for education queries that name MIT / OCW).
|
|
434
|
+
|
|
435
|
+
## [0.16.0] - 2026-10-06
|
|
436
|
+
|
|
437
|
+
### Added
|
|
438
|
+
|
|
439
|
+
- `transcripts.export(id, "pdf" | "docx")` returns `{bytes, filename, content_type}`; text formats keep returning
|
|
440
|
+
`{text, ...}`.
|
|
441
|
+
- `transcripts.shares.create(id, expires_in_days=None)` / `.list(id)` / `.revoke(id, share_id)` - read-only share
|
|
442
|
+
links (`https://hub.codai.ro/t/<token>`; the token is returned once).
|
|
443
|
+
- `transcripts.public_view(token)` - the read-only view behind a share link.
|
|
444
|
+
- Types regenerated from the gateway spec (`TranscriptShare*`, `PublicTranscript`).
|
|
445
|
+
|
|
446
|
+
## [0.15.3] - 2026-10-06
|
|
447
|
+
|
|
448
|
+
### Added
|
|
449
|
+
|
|
450
|
+
- `TranscriptDetail` types gain `processing` (pending job: `kind`, `attempts`, `max_attempts`, `last_error`,
|
|
451
|
+
`next_attempt_at`) - regenerated from the gateway spec.
|
|
452
|
+
|
|
453
|
+
## [0.15.2] - 2026-10-05
|
|
454
|
+
|
|
455
|
+
### Added
|
|
456
|
+
|
|
457
|
+
- `POST /v1/tools/search` types: request `depth: "fast" | "deep"` (deep = more sources, ~12 s budget); `mode`
|
|
458
|
+
also accepts `fast` / `deep` as an alias (means `codai` with that depth).
|
|
459
|
+
|
|
460
|
+
## [0.15.1] - 2026-10-05
|
|
461
|
+
|
|
462
|
+
### Added
|
|
463
|
+
|
|
464
|
+
- `POST /v1/tools/search` types: request `fallback: "auto" | "off"` (automatic Grounding with Google Search when
|
|
465
|
+
codai results are weak, returned as a separate `google` block + `fallback: { used, reason }`), new intents
|
|
466
|
+
`academic` / `definition` / `education`, and new result sources (`mdn`, `mslearn`, `hn`, `osv`, `endoflife`,
|
|
467
|
+
`openalex`, `crossref`, `arxiv`, `europepmc`, `doaj`, `core`, `wiktionary`, `openstax`, `dexonline`).
|
|
468
|
+
|
|
469
|
+
## [0.15.0] - 2026-10-05
|
|
470
|
+
|
|
471
|
+
### Added
|
|
472
|
+
|
|
473
|
+
- `client.usage.get(query)` → `GET /v1/usage`: your own requests, errors, tasks, tokens and cost grouped by
|
|
474
|
+
`day` | `key` | `device` | `app` | `platform` | `model` | `client` | `tag`, filtered by `key`, `device`, `app`,
|
|
475
|
+
`platform`, `model`, `tag`; `from` / `to` are inclusive `YYYY-MM-DD` (default last 30 days, max 400).
|
|
476
|
+
`cost_micro_usd` is USD micros as a string. Unknown query keys raise `ValueError`.
|
|
477
|
+
- `client.keys.list(include_revoked=False)` → `GET /v1/keys`: your API keys with `kind`, `device_id`, `platform`,
|
|
478
|
+
`client_version`, `tags` and `current`.
|
|
479
|
+
- `client.keys.set_tags(id, tags)` → `PATCH /v1/keys/{id}`: replace a key's tags (≤ 16, each ≤ 32 chars).
|
|
480
|
+
- Generated TypedDicts `UsageReport`, `UsageRow`, `ApiKeyInfo` (+ `getUsage` / `listKeys` / `setKeyTags` aliases).
|
|
481
|
+
|
|
482
|
+
## [0.14.0] - 2026-10-05
|
|
483
|
+
|
|
484
|
+
### Added
|
|
485
|
+
|
|
486
|
+
- `client.transcripts` — Transcripts API: `list` (folder / tag / pinned / status, cursor), `create`, `get`,
|
|
487
|
+
`update`, `delete`, `finalize`, `retranscribe`, `reanalyze`, `add_bookmark`, `rename_speaker`,
|
|
488
|
+
`edit_utterance`, `audio`, `export` (md / txt / srt / vtt / json → `{text, filename, content_type}`),
|
|
489
|
+
`accept_prompt`, `usage`, `search` (lexical / hybrid), `ask`, `stream` (SSE generator), plus
|
|
490
|
+
`transcripts.folders.*` and `transcripts.vocabulary.get|put`.
|
|
491
|
+
- `client.transcripts.upload_audio(data, track=, transcript_id=, chunk_size=, upload_id=, on_progress=)` —
|
|
492
|
+
resumable tus 1.0 upload (`transcripts.uploads.capabilities|create|offset|append`).
|
|
493
|
+
- `PromptSource` gains `transcript`.
|
|
494
|
+
|
|
495
|
+
## [0.13.1] - 2026-10-05
|
|
496
|
+
|
|
497
|
+
### Added
|
|
498
|
+
|
|
499
|
+
- `POST /v1/tools/search` types: request `mode: "codai" | "google"` (default `codai`) and the
|
|
500
|
+
`ToolSearchGoogleResponse` shape (Grounding with Google Search: `answer`, `sources`, `queries`,
|
|
501
|
+
`search_suggestions_html`, `attribution`), plus the `releases` / `registry` / `engine` result sources.
|
|
502
|
+
|
|
503
|
+
## [0.13.0] - 2026-10-05
|
|
504
|
+
|
|
505
|
+
### Added
|
|
506
|
+
|
|
507
|
+
- Pending prompts track delivery: statuses `sent`, `answered`, `verified` and fields `sent_at`, `answered_at`,
|
|
508
|
+
`verified_at`, `match_ref`, `match_turn_id`, `match_score`, `base_sha`, `head_sha`, `report`, `report_at`.
|
|
509
|
+
- `client.prompts.match(id, body)` → `POST /v1/prompts/:id/match`; `client.prompts.verify(id, body)` →
|
|
510
|
+
`POST /v1/prompts/:id/verify` (report: done / partial / not started, what changed, what remains);
|
|
511
|
+
`client.prompts.verify_many(body)` → `POST /v1/prompts/verify`; `client.prompts.stream()` → `GET /v1/prompts/stream`
|
|
512
|
+
(SSE generator of `event: prompt` upserts / deletes).
|
|
513
|
+
|
|
514
|
+
## [0.12.0] - 2026-10-05
|
|
515
|
+
|
|
516
|
+
### Added
|
|
517
|
+
|
|
518
|
+
- `client.audio.speech_stream(body)` → `POST /v1/audio/speech/stream` (`codai-tts-ro`, Azure neural TTS with
|
|
519
|
+
visemes): generator of `{"type": "start"|"audio"|"viseme"|"word"|"done"|"error", ...}`; `audio` events carry the
|
|
520
|
+
decoded `audio_bytes`. `createSpeechStream` in the parity table.
|
|
521
|
+
- `client.system_one.batch(items, questions, timeout_ms=None, fallback=None)` — the same questions about up to 16
|
|
522
|
+
states in one call; `system_one.create` documents the new `items`, `timeout_ms` and `fallback` fields and the
|
|
523
|
+
`fallback_used` response flag.
|
|
524
|
+
- Ephemeral token scope `live` (realtime + audio) accepted by `tokens.create`.
|
|
525
|
+
- `_types.py` regenerated (`SpeechStreamRequest`, `SpeechStreamEvent`, batch fields on `SystemOneRequest` /
|
|
526
|
+
`SystemOneResponse`).
|
|
527
|
+
|
|
528
|
+
### Not included
|
|
529
|
+
|
|
530
|
+
- No realtime (WebSocket) helper: the SDK is zero-dependency and the standard library has no WebSocket client, and
|
|
531
|
+
`/v1/realtime` is outside the OpenAPI parity contract. Use `tokens.create("live")` and any WebSocket client against
|
|
532
|
+
`wss://ai.codai.ro/v1/realtime?model=codai-transcribe-live&language=ro&key=<token>` (protocol in the docs,
|
|
533
|
+
gateway → Embeddings, audio & realtime).
|
|
534
|
+
|
|
535
|
+
## [0.11.0] - 2026-10-02
|
|
536
|
+
|
|
537
|
+
### Added
|
|
538
|
+
|
|
539
|
+
- `client.devices.revoke_self_key()` — `POST /v1/keys/self/revoke`: the calling API key revokes itself (sign out).
|
|
540
|
+
|
|
541
|
+
## [0.10.0] - 2026-09-29
|
|
542
|
+
|
|
543
|
+
### Added
|
|
544
|
+
|
|
545
|
+
- `client.prompts.{list, create, get, update, delete, launch}` — pending prompts (`/v1/prompts/*`):
|
|
546
|
+
ready-to-paste prompts left for a future chat, with `goal_key` supersede, `not_before` reminders
|
|
547
|
+
(`prompt.due` notifications) and `launch` into a new session on a device. `launch` is never retried.
|
|
548
|
+
`_types.py` regenerated (`Prompt`, `PromptCreate`, `PromptPatch`, `PromptCreated`, …).
|
|
549
|
+
|
|
550
|
+
## [0.9.0] - 2026-09-29
|
|
551
|
+
|
|
552
|
+
### Added
|
|
553
|
+
|
|
554
|
+
- `client.sessions.dispatch(session_id, *, device_id=..., text=..., mode="send"|"open", turn_id=..., control_id=...)`
|
|
555
|
+
keyword form. `mode="open"` hands the session off — the target only opens it (no user turn), and
|
|
556
|
+
`text`/`turn_id` are dropped. The positional `body` dict still works (keywords override its keys); a
|
|
557
|
+
`send` without `text` now raises `ValueError` client-side instead of a server `400`.
|
|
558
|
+
- Regenerated `src/codai/_types.py`: `SessionDispatchRequest.mode` (`text` now optional),
|
|
559
|
+
`SessionDispatchResponse.mode`, `SessionControl.mode` (`'open'` on handoff controls) and
|
|
560
|
+
`DeviceListItem.online` (seen in the last 2 minutes).
|
|
561
|
+
- `client.images.edit({"prompt": ..., "image": {"b64_json": ..., "mime_type": ...} | [...]})` →
|
|
562
|
+
`POST /v1/images/edits` (JSON body, 1–14 input images; `mask` unsupported). `editImage` in the
|
|
563
|
+
parity table; `EditImageBody` / `CoreImageEditRequest` types.
|
|
564
|
+
- `ImagesResult.mime_types` and `ImagesResult.data_region` (`x-codai-data-region`, `eu` | `global`).
|
|
565
|
+
- `generate()` types gain `reference_images`, `aspect_ratio`, `image_size` and the
|
|
566
|
+
`codai-image-fast` / `codai-image-pro` model ids.
|
|
567
|
+
|
|
568
|
+
### Changed
|
|
569
|
+
|
|
570
|
+
- `codai-image` is now `gemini-3.1-flash-image` on the Vertex EU endpoint (2.5 is shut down on
|
|
571
|
+
2026-10-02 and served as `codai-image`). `cost_micro_usd` is usage-based (≈ $0.074 per default
|
|
572
|
+
1K image) instead of a flat $0.04. The image request floor timeout is 150 s.
|
|
573
|
+
|
|
574
|
+
## [0.8.0] - 2026-09-29
|
|
575
|
+
|
|
576
|
+
### Added
|
|
577
|
+
|
|
578
|
+
- `client.images.generate({"prompt": ..., "n"?, "size"?, "negative_prompt"?, "model"?})` →
|
|
579
|
+
`POST /v1/images/generations` (base64 only). Backed by `gemini-2.5-flash-image`; `model`
|
|
580
|
+
defaults to `codai-image` (`imagen-4` / `imagen-4-fast` are legacy aliases). Flat $0.04 per
|
|
581
|
+
returned image, reported as `cost_micro_usd`.
|
|
582
|
+
- EXPERIMENTAL, unaudited (HIDE protocol) agent-output signatures — provenance only, never
|
|
583
|
+
authentication:
|
|
584
|
+
- `EnvironmentTask.output_signature: Optional[EnvironmentTaskOutputSignature]` plus the
|
|
585
|
+
`AgentOutputKey` / `AgentOutputVerifyRequest` / `AgentOutputVerifyResult` types
|
|
586
|
+
(regenerated `src/codai/_types.py`).
|
|
587
|
+
- `client.verify.agent_output_key()` → `GET /v1/verify/agent-output/key` and
|
|
588
|
+
`client.verify.agent_output(payload, signature)` → `POST /v1/verify/agent-output`
|
|
589
|
+
(public; never retried, 503 `signing_disabled` when signing is off).
|
|
590
|
+
|
|
591
|
+
## [0.7.0] - 2026-09-27
|
|
592
|
+
|
|
593
|
+
### Added
|
|
594
|
+
|
|
595
|
+
- Resolve pricing experiment (regenerated `src/codai/_resolve_types.py`):
|
|
596
|
+
- `ResolveQuote` `intro_price_micro_eur` / `list_price_micro_eur` — present while the €1
|
|
597
|
+
intro price applies to your first paid accept.
|
|
598
|
+
- `ResolveAccepted` `paid_with` (`ResolvePaidWith`: `intro` | `credit` | `wallet` | `free`)
|
|
599
|
+
and `held_micro_eur`; `ResolveJob.paid_with` once accepted.
|
|
600
|
+
- `ResolveInsufficientFundsError.bundle_url` (`Optional[str]`) — fix-bundle checkout
|
|
601
|
+
(10 t7 fixes for €49), set only for `t7` jobs; also appended to the error message.
|
|
602
|
+
- `client.resolve.balance()` — `GET /v1/resolve/balance` (operation `getResolveBalance`) →
|
|
603
|
+
`ResolveBalance {fix_credits, intro_available, wallet_micro_eur}`.
|
|
604
|
+
|
|
605
|
+
## [0.6.0] - 2026-09-27
|
|
606
|
+
|
|
607
|
+
### Added
|
|
608
|
+
|
|
609
|
+
- Signed Resolve attestations: `ResolveAttestation.signature` (DSSE envelope, `None` for
|
|
610
|
+
pre-signing attestations) and `ResolveAttestationEnvelope` / `ResolveKeys` / `ResolveKey`
|
|
611
|
+
types (regenerated `codai._resolve_types`).
|
|
612
|
+
- `client.resolve.keys()` — `GET /v1/resolve/keys` (operation `getResolveKeys`).
|
|
613
|
+
- `client.resolve.verify_attestation(att, keys=None)` and offline
|
|
614
|
+
`verify_attestation_with_keys(att, keys)` → `{"ok": True, "keyid"}` or
|
|
615
|
+
`{"ok": False, "reason": "UNSIGNED" | "BAD_SIGNATURE" | "STATEMENT_MISMATCH" | "BAD_PAYLOAD_TYPE"}`.
|
|
616
|
+
The statement check is stdlib; the ECDSA signature check needs the optional
|
|
617
|
+
`cryptography` package (lazy import, clear `ImportError` otherwise).
|
|
618
|
+
`attestation_statement(att)` exposes the recomputed statement.
|
|
619
|
+
|
|
620
|
+
## [0.5.0] - 2026-09-27
|
|
621
|
+
|
|
622
|
+
### Added
|
|
623
|
+
|
|
624
|
+
- Resolve job webhooks: `callback_url` on `ResolveIntake`, one-time `callback_secret` on
|
|
625
|
+
`ResolveQuote` / `ResolveDeclined`, and `ResolveWebhookEvent` / `ResolveWebhookEventName` /
|
|
626
|
+
`ResolveWebhookJob` TypedDicts (regenerated `_resolve_types.py`).
|
|
627
|
+
- `verify_resolve_webhook(secret, raw_body, signature_header, tolerance_seconds=300, now=None)`
|
|
628
|
+
— constant-time (`hmac.compare_digest`) check of `x-codai-signature: t=<unix>,v1=<hex>`
|
|
629
|
+
with a timestamp window. Exported from `codai` and `codai.resources`.
|
|
630
|
+
|
|
631
|
+
## [0.4.0] - 2026-09-27
|
|
632
|
+
|
|
633
|
+
### Added
|
|
634
|
+
|
|
635
|
+
- `client.resolve` — codai Resolve (pay per verified fix, `https://resolve.codai.ro`,
|
|
636
|
+
override with `resolve_base_url=`): `submit`, `get`, `accept`, `attestation`,
|
|
637
|
+
`health`, `wait_for`. `ResolveError` / `ResolveInsufficientFundsError` (402 carries
|
|
638
|
+
`topup_url`, `balance`, `required`). `RESOLVE_OPERATION_METHODS` maps every
|
|
639
|
+
`resolve.yaml` operationId; `_resolve_types.py` is generated from it.
|
|
640
|
+
|
|
641
|
+
## [0.3.1] - 2026-09-26
|
|
642
|
+
|
|
643
|
+
### Changed
|
|
644
|
+
|
|
645
|
+
- Regenerated `_types.py`: project prebuild pool fields, environment `prebuild`
|
|
646
|
+
and `prebuild_claimed` on create (CE-0072).
|
|
647
|
+
|
|
648
|
+
## [0.3.0] - 2026-09-25
|
|
649
|
+
|
|
650
|
+
### Added
|
|
651
|
+
|
|
652
|
+
- Projects + environments resources (26 operations), restoring full parity with the gateway
|
|
653
|
+
OpenAPI (88 operations): `projects.{list,create,get,update,delete}`,
|
|
654
|
+
`environments.{list,create,enroll,get,update,start,stop,archive,destroy,enroll_token}`,
|
|
655
|
+
`environments.members.{list,add,set_ssh_key,set_role,remove}`,
|
|
656
|
+
`environments.ports.{list,set,remove}` and `environments.secrets.{list,set,remove}`.
|
|
657
|
+
`enroll`, `create` and `enroll_token` are never retried (the enrolment token is single-use).
|
|
658
|
+
- `_types.py` regenerated: `Project*` and `Environment*` TypedDicts.
|
|
659
|
+
- `system_one.create({"state", "questions"})` — typed decisions from codai-s1 (`POST /v1/systemone`,
|
|
660
|
+
Choice / Score / Noul with calibrated probabilities). Raises on 503 `s1_unavailable`; keep a fallback.
|
|
661
|
+
- `triggers.*`, `notifications.*`, `environments.members.ssh_cert`, `environments.ssh_ca`,
|
|
662
|
+
`environments.tasks.{list,create,get}` — parity with the TypeScript SDK.
|
|
663
|
+
|
|
664
|
+
## [0.2.1] - 2026-09-24
|
|
665
|
+
|
|
666
|
+
### Added
|
|
667
|
+
|
|
668
|
+
- `WalletLedgerEntry.source` literal gains `compute_charge` — the debit written every 10 minutes
|
|
669
|
+
for a running managed cloud environment (F2). Additive; regenerated from the gateway OpenAPI.
|
|
670
|
+
|
|
671
|
+
## [0.2.0] - 2026-09-23
|
|
672
|
+
|
|
673
|
+
### Added
|
|
674
|
+
|
|
675
|
+
- Full gateway coverage: one method per `operationId` in `apps/docs/openapi/en/gateway.yaml`
|
|
676
|
+
(62 operations), grouped like the TypeScript SDK — `client.chat.completions`, `messages`,
|
|
677
|
+
`responses`, `embeddings`, `audio`, `tokens`, `models`, `health`, `agents` (+ `agents.runs`),
|
|
678
|
+
`tools`, `tasks`, `sessions` (+ `events`, `controls`, `lease`, `shares`), `devices`, `hosts`,
|
|
679
|
+
`orgs` (+ `members`), `account`, `receipt`, `feedback`, `phone_models`.
|
|
680
|
+
- `OPERATION_METHODS` (operationId → dotted method path) and `tests/test_parity.py`, which
|
|
681
|
+
parses the OpenAPI spec and fails on a missing, stale or non-callable mapping and when the
|
|
682
|
+
Python table diverges from the TypeScript one.
|
|
683
|
+
- Generated `codai._types` (`TypedDict`s for every schema plus `<operationId>Body` /
|
|
684
|
+
`<operationId>Response`) from `scripts/gen-types.py`; the parity test fails when it is stale.
|
|
685
|
+
- SSE streams: `chat.completions.stream()` / `messages.stream()` / `responses.stream()` return
|
|
686
|
+
iterables with `.text()`, raw chunks/events and a `.final` aggregate (content, tool calls,
|
|
687
|
+
usage, finish reason, routing headers); `agents.runs.stream()`, `sessions.stream()` and
|
|
688
|
+
`hosts.stream()` are generators of `{"event", "data"}` frames.
|
|
689
|
+
- `ext={...}` extension bag on every method covering all documented `X-Codai-*` request
|
|
690
|
+
headers (`effort`, `thinking`, `thinking_budget`, `cache`, `no_task`, `task_id`, `device`,
|
|
691
|
+
`compact`, `best_of`, `share_token`, …) plus raw `headers`; client-wide `defaults`, `device`,
|
|
692
|
+
`device_name`, `device_platform`, `client` constructor options.
|
|
693
|
+
- `CodaiError.code`, `.request_id`, `.retry_after` parsed from the gateway error envelope.
|
|
694
|
+
- Dev extras `pip install -e ".[dev]"` (pyyaml + pytest); an `http.server` stub test suite.
|
|
695
|
+
|
|
696
|
+
### Changed
|
|
697
|
+
|
|
698
|
+
- `__version__` now reports the real version (`0.2.0`; it said `0.1.0` in 0.1.1).
|
|
699
|
+
- `chat_stream()` is built on `chat.completions.stream()`; 429/5xx retries add jitter.
|
|
700
|
+
- Runtime stays zero-dependency (stdlib `urllib`), Python 3.9+.
|
|
701
|
+
|
|
702
|
+
### Backward compatibility
|
|
703
|
+
|
|
704
|
+
- Every 0.1.x method keeps its name, signature and return shape: `chat()`, `chat_stream()`,
|
|
705
|
+
`agents_run()`, `feedback()`, `models()`, `mint_token()`, `embeddings()`, `transcribe()`,
|
|
706
|
+
`speech()`. `chat`, `embeddings`, `models` and `feedback` are callable resource groups, so
|
|
707
|
+
`client.chat([...])` and `client.chat.completions.create({...})` are the same call.
|
|
708
|
+
|
|
709
|
+
## [0.1.1] - 2026-09-13
|
|
710
|
+
|
|
711
|
+
### Changed
|
|
712
|
+
|
|
713
|
+
- Repository moved to https://github.com/codai-ro/codai-sdk-python (project URLs updated). No code changes.
|
|
714
|
+
|
|
715
|
+
## [0.1.0] - 2026-06-23
|
|
716
|
+
|
|
717
|
+
### Added
|
|
718
|
+
|
|
719
|
+
- Initial public release.
|
|
720
|
+
- `Codai.chat()` — OpenAI-compatible completions with codai extensions
|
|
721
|
+
(`session_id`, `agent_mode`, `compact`, `best_of`).
|
|
722
|
+
- `Codai.chat_stream()` — streaming via generator.
|
|
723
|
+
- `Codai.agents_run()` — server-side agent loop.
|
|
724
|
+
- `Codai.feedback()` — thumbs rating on a completed request.
|
|
725
|
+
- `Codai.models()` — list models available to the key.
|
|
726
|
+
- Zero dependencies (stdlib only), Python 3.9+.
|
|
727
|
+
|
|
728
|
+
[Unreleased]: https://github.com/codai-ro/codai-sdk-python/compare/v0.2.0...HEAD
|
|
729
|
+
[0.2.0]: https://github.com/codai-ro/codai-sdk-python/compare/v0.1.1...v0.2.0
|
|
730
|
+
[0.1.1]: https://github.com/codai-ro/codai-sdk-python/compare/v0.1.0...v0.1.1
|
|
731
|
+
[0.1.0]: https://github.com/codai-ro/codai-sdk-python/releases/tag/v0.1.0
|