codai docs
SDK-uri

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-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.

AtributMetodeGateway
chat.completionscreate, streamPOST /v1/chat/completions
messagescreate, streamPOST /v1/messages — protocolul Anthropic Messages
responsescreate, streamPOST /v1/responses — protocolul OpenAI Responses
embeddingscreatePOST /v1/embeddings
audiotranscribe, transcribe_detailed, speech, speech_detailed/v1/audio/*
tokenscreatePOST /v1/tokens
modelslistGET /v1/models
healthget, ready, status/health, /health/ready, /status
agentsrun; runs.create, runs.get, runs.steps, runs.stats, runs.cancel, runs.stream/v1/agents/*
toolssearch, fetch/v1/tools/*
taskslist, pending, stats, get, confirm/v1/tasks/*
sessionscreate, list, get, update, delete, dispatch, stream; events.*, controls.*, lease.*, shares.*/v1/sessions/*
deviceslist, update, delete, dispatch_inbox/v1/devices/*
hostslist, exec, post_result, stream/v1/hosts/*
orgscreate, list; members.list, members.add, members.remove/v1/orgs/*
accountget, update/v1/account
receiptgetGET /v1/receipt
feedbacksubmitPOST /v1/feedback
phone_modelslistGET /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âmpTipSursă
contentstrTextul asistentului din prima alegere.
rawdictRăspunsul complet de formă OpenAI.
request_idstr | Nonex-request-id — îl trimiți la feedback().
routed_tostr | Nonex-codai-routed-to.
exec_verifystr | Nonex-codai-exec-verify pe codai-labs.
usagedict | 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 | None

Feedback

client.feedback(request_id, 1)                    # 👍
client.feedback(request_id, -1, comment="greșit") # 👎, comment ≤ 500 caractere

SDK-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țiuneHeader trimisEfect
session_idX-Codai-Session-IdMemorie de sesiune, sticky routing, chitanțe per sesiune. La nivel de client sau per apel.
agent_mode=TrueX-Codai-Mode: agentBuclă plan-and-execute pe gateway (Pro+).
compact="auto"X-Codai-Compact: autoCompactare deterministă server-side a contextului. Doar chat().
best_of=3 / best_of=0X-Codai-Best-OfForț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ți

CodaiError.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"}])

Pe această pagină