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-sdkPachetul se numește codai-sdk. pip install codai instalează un proiect fără legătură cu noi, al altui autor, care folosește același nume de import și ascunde acest SDK. Dacă from codai import Codai dă eroare, rulează pip uninstall codai, apoi pip install codai-sdk.
Start 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, ground | /v1/tools/* — unelte web |
research | create, retrieve, wait, run | /v1/research — cercetare aprofundată |
vault | account, items, put_item, decide, catalog, use, http_call, …; devices.challenge, devices.enroll, devices.list, devices.rename, devices.revoke; seifurile organizației members.list, members.candidates, members.add, members.update, members.remove, rotate_key, set_quorum, vote; simulate_policy, receipt_keys | /v1/vault/* — seif |
cards | weather, places, geocode, static_map, fx, unfurl | /v1/cards/* — carduri |
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 (planul Starter sau mai sus)
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 (planul Starter sau mai sus). |
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 sarcină, 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"}])Ultima actualizare:
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ă.