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

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

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, ground/v1/tools/* — unelte web
researchcreate, retrieve, wait, run/v1/research — cercetare aprofundată
vaultaccount, 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
cardsweather, places, geocode, static_map, fx, unfurl/v1/cards/* — carduri
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 (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â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 (planul Starter sau mai sus).
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 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ț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"}])

Ultima actualizare:

Pe această pagină