Python
Pachetul codai-sdk pentru Python 3.9+ — start rapid, fiecare metodă, extensiile codai și tratarea erorilor.
codai-sdk este clientul oficial Python. Zero dependențe (stdlib urllib), Python 3.9+, sincron. Numele de import este codai.
pip install codai-sdkStart rapid
import os
from codai import Codai
client = Codai(api_key=os.environ["CODAI_API_KEY"], session_id="my-project")
result = client.chat([{"role": "user", "content": "Explică asyncio.gather într-o linie."}])
print(result.content)
print(result.routed_to) # modelul upstream care a servit efectiv
for delta in client.chat_stream([{"role": "user", "content": "salut"}]):
print(delta, end="", flush=True)
run = client.agents_run("Găsește și rezumă TODO-urile din acest codebase")
print(run.result)
if result.request_id:
client.feedback(result.request_id, 1)Configurare
client = Codai(
api_key=os.environ["CODAI_API_KEY"], # obligatoriu — ridică ValueError dacă e gol
base_url="https://ai.codai.ro", # implicit
session_id="my-project", # opțional — memorie de sesiune + sticky routing
timeout=120.0, # secunde, implicit
max_retries=2, # reîncercări pe 429 / 5xx cu backoff exponențial
)Grupuri de resurse
Începând cu 0.2.0 fiecare operație a gateway-ului este accesibilă ca metodă pe client, grupată pe tag exact ca în SDK-ul TypeScript (camelCase devine snake_case). Metodele de nivel superior din 0.1.x de mai jos funcționează neschimbate; chat, embeddings, models și feedback sunt grupuri de resurse apelabile, deci client.chat([...]) și client.chat.completions.create({...}) sunt același apel.
| Atribut | Metode | Gateway |
|---|---|---|
chat.completions | create, stream | POST /v1/chat/completions |
messages | create, stream | POST /v1/messages — protocolul Anthropic Messages |
responses | create, stream | POST /v1/responses — protocolul OpenAI Responses |
embeddings | create | POST /v1/embeddings |
audio | transcribe, transcribe_detailed, speech, speech_detailed | /v1/audio/* |
tokens | create | POST /v1/tokens |
models | list | GET /v1/models |
health | get, ready, status | /health, /health/ready, /status |
agents | run; runs.create, runs.get, runs.steps, runs.stats, runs.cancel, runs.stream | /v1/agents/* |
tools | search, fetch | /v1/tools/* |
tasks | list, pending, stats, get, confirm | /v1/tasks/* |
sessions | create, list, get, update, delete, dispatch, stream; events.*, controls.*, lease.*, shares.* | /v1/sessions/* |
devices | list, update, delete, dispatch_inbox | /v1/devices/* |
hosts | list, exec, post_result, stream | /v1/hosts/* |
orgs | create, list; members.list, members.add, members.remove | /v1/orgs/* |
account | get, update | /v1/account |
receipt | get | GET /v1/receipt |
feedback | submit | POST /v1/feedback |
phone_models | list | GET /v1/phone/models |
Fiecare metodă acceptă un argument opțional ext={...} care acoperă toate headerele de cerere X-Codai-* documentate (effort, thinking, thinking_budget, cache, no_task, task_id, incognito, mode, best_of, compact, device, share_token, … plus headers brute) — vezi headere. Formele cererilor și răspunsurilor sunt disponibile ca TypedDict-uri în codai._types, generate din specificația OpenAPI.
client = Codai(api_key=os.environ["CODAI_API_KEY"], device="5dc0de00-0000-4000-8000-00000000c0da")
r = client.chat.completions.create(
{"messages": messages, "model": "codai"},
ext={"effort": "high", "thinking": True, "thinking_budget": 8192},
)
stream = client.chat.completions.stream({"messages": messages})
for delta in stream: # delte de text; stream.chunks() dă chunk-urile brute
print(delta, end="")
print(stream.final.usage, stream.final.tool_calls)
# fluxurile SSE native codai sunt generatoare de cadre {"event", "data"}
run = client.agents.runs.create({"task": "Rezumă README-ul repo-ului."})
for ev in client.agents.runs.stream(run["id"]):
if ev["event"] == "done":
print(ev["data"]["status"], ev["data"]["result"])
# sesiunile partajate au nevoie de un id de dispozitiv pe client
s = client.sessions.create({"title": "pairing"})
for ev in client.sessions.stream(s["id"], after=0):
print(ev["event"], ev["data"].get("seq"))Chat
result = client.chat(
messages=[{"role": "user", "content": "salut"}],
model="codai", # implicit
temperature=None,
max_tokens=None,
tools=None, # tool-uri OpenAI de tip funcție — tu deții bucla de tool-uri
agent_mode=False, # X-Codai-Mode: agent (Pro+)
compact=None, # "auto" → X-Codai-Compact: auto
best_of=None, # 3 forțează best-of-N, 0 dezactivează
session_id=None, # suprascriere per apel
)ChatResult este un dataclass:
| Câmp | Tip | Sursă |
|---|---|---|
content | str | Textul asistentului din prima alegere. |
raw | dict | Răspunsul complet de formă OpenAI. |
request_id | str | None | x-request-id — îl trimiți la feedback(). |
routed_to | str | None | x-codai-routed-to. |
exec_verify | str | None | x-codai-exec-verify pe codai-labs. |
usage | dict | None | {"prompt_tokens", "completion_tokens"}. |
Tool calls
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
},
}]
first = client.chat([{"role": "user", "content": "Vremea la Cluj?"}], tools=tools)
message = first.raw["choices"][0]["message"]
for call in message.get("tool_calls") or []:
args = json.loads(call["function"]["arguments"])
output = get_weather(args["city"])
final = client.chat([
{"role": "user", "content": "Vremea la Cluj?"},
message,
{"role": "tool", "tool_call_id": call["id"], "content": json.dumps(output)},
], tools=tools)
print(final.content)Streaming
chat_stream() este un generator de delta-uri de text. Parsează frame-urile data:, ignoră keep-alive-urile și se oprește la [DONE].
for delta in client.chat_stream(
[{"role": "user", "content": "Scrie un haiku despre Python."}],
model="codai",
temperature=None,
max_tokens=None,
agent_mode=False,
session_id=None,
):
print(delta, end="", flush=True)chat_stream() dă doar text. Pentru tool calls asamblate, frame-ul final de usage, motivul de oprire și headerele de rutare ale unui răspuns în stream folosești client.chat.completions.stream() și citești .final după iterare (vezi grupuri de resurse); .chunks() dă dict-urile brute chat.completion.chunk. O eroare HTTP înaintea primului byte ridică CodaiError.
Agent server-side
run = client.agents_run(
task="Rezumă punctele cheie ale textului furnizat.", # obligatoriu, ≤ 64 000 caractere
context="…input-ul tău…", # opțional, ≤ 256 000 caractere
system="Răspunde în română.", # opțional, ≤ 32 000 caractere
model=None, # opțional, implicit codai
)
run.result # str
run.model # upstream-ul care a servit
run.event_id # id-ul rândului de usage — îl trimiți la feedback()
run.usage # dict | NoneFeedback
client.feedback(request_id, 1) # 👍
client.feedback(request_id, -1, comment="greșit") # 👎, comment ≤ 500 caractereSDK-ul trimite request_id ca event_id. Voturile alimentează priorurile de rutare pentru toți.
Embeddings
vectors = client.embeddings(["salut", "lume"], model="codai-embed", dimensions=None)
vectors[0] # list[float]Returnează direct o listă de vectori (nu anvelopa brută).
Audio
# Speech-to-text — încărcare multipart, maximum 25 MB. Returnează transcrierea.
with open("clip.webm", "rb") as f:
text = client.transcribe(f.read(), filename="clip.webm", model="codai-transcribe")
# Text-to-speech — returnează byte-i audio (mp3 implicit).
audio = client.speech("Salut de la codai.", model="codai-tts", voice="alloy")
with open("salut.mp3", "wb") as f:
f.write(audio)transcribe() nu reîncearcă — un body multipart nu poate fi retrimis în siguranță.
Tokeni efemeri
minted = client.mint_token("realtime", ttl_seconds=600)
minted["token"] # "codai_eph_v1.…" — îl dai unui client din browser
minted["expires_at"] # timestamp ISO
minted["scope"] # "realtime"Scopuri: "realtime", "audio", "embeddings". TTL 60–3 600 s. Vezi tokeni efemeri.
Modele
for m in client.models():
print(m["id"], m["codai"]["kind"]) # de ex. "codai alias"Returnează lista data din GET /v1/models.
Extensii codai
| Opțiune | Header trimis | Efect |
|---|---|---|
session_id | X-Codai-Session-Id | Memorie de sesiune, sticky routing, chitanțe per sesiune. La nivel de client sau per apel. |
agent_mode=True | X-Codai-Mode: agent | Buclă plan-and-execute pe gateway (Pro+). |
compact="auto" | X-Codai-Compact: auto | Compactare deterministă server-side a contextului. Doar chat(). |
best_of=3 / best_of=0 | X-Codai-Best-Of | Forțează sau dezactivează best-of-N. Doar chat(). |
Orice altceva — tier-uri de effort, pin-uri de thinking, id-uri de task, dispozitiv, tokeni de partajare — trece prin argumentul ext={...} acceptat de fiecare metodă (inclusiv chat() și chat_stream()), cu chei snake_case numite după header (effort, thinking_pin, task_id, …) și un dict headers brut ca portiță de scăpare; vezi grupuri de resurse și pagina header-e.
Erori
from codai import Codai, CodaiError
try:
client.chat([{"role": "user", "content": "salut"}])
except CodaiError as e:
print(e.status, e) # status HTTP (0 pentru eșecuri de rețea după reîncercări)
code = (e.body or {}).get("error", {}).get("code") if isinstance(e.body, dict) else None
if code == "quota_exceeded":
... # alocarea de task-uri a planului consumată — aștepțiCodaiError.body este anvelopa JSON de eroare parsată când gateway-ul a returnat una, altfel None sau byte-ii bruți. Valorile stabile de code sunt listate la limite și prețuri.
Async
Nu există un client asyncio în 0.1.1. Metodele sunt blocante; într-o aplicație async le învelești cu asyncio.to_thread, sau apelezi gateway-ul cu un client HTTP async la alegere — wire formats sunt HTTP simplu.
result = await asyncio.to_thread(client.chat, [{"role": "user", "content": "salut"}])TypeScript
Pachetul codai-sdk pentru Node și runtime-uri edge — configurare, grupuri de resurse cu paritate completă OpenAPI, chat, streaming, agenți, sesiuni, erori și migrarea de la SDK-ul OpenAI.
Sesiuni partajate
O conversație, mai multe dispozitive — gateway-ul păstrează jurnalul ordonat de evenimente; dispozitivul cu uneltele execută; toți ceilalți urmăresc sau ghidează.