Skip to content

SSE Akışı

AI çalıştırma sonuçları, Sunucu Tarafından Gönderilen Etkinlikler (SSE) aracılığıyla gerçek zamanlı olarak yayınlanır. Artan belirteçleri, araç ilerlemesini, iş akışı adımlarını ve terminal olaylarını meydana geldikçe almak için bir çalıştırmanın akış uç noktasına bağlanın.

Akış Uç Noktaları

MethodPathDescriptionAuthRate Limit
GET/ai/runs/:runId/streamStream events for a feature runJWT + Entitlement20/min
GET/ai/sessions/:sessionId/messages/:messageId/streamStream events for a chat messageJWT + Entitlement20/min

Bir Akışa Bağlanma

'Accept: text/event-stream' başlığıyla bir GET isteği göndererek (veya tarayıcının 'EventSource' API'sini kullanarak) bir SSE bağlantısı açın.

POST /ai/features/:featureKey/runs dosyasındaki "id"yi "$RUN_ID" olarak kullanın.

bash
curl -N https://api.chainabit.com/api/v1/ai/runs/$RUN_ID/stream \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: text/event-stream"
javascript
// Using EventSource (browser)
const runId = process.env.RUN_ID; // from POST /ai/features/:featureKey/runs's data.id
const url = `${BASE_URL}/ai/runs/${runId}/stream`;
const eventSource = new EventSource(url, {
  headers: { Authorization: `Bearer ${TOKEN}` },
});

eventSource.addEventListener("message.delta", (e) => {
  const data = JSON.parse(e.data);
  process.stdout.write(data.payload.delta);
});

eventSource.addEventListener("run.settlement.completed", (e) => {
  console.log("Run complete");
  eventSource.close();
});

eventSource.addEventListener("run.error", (e) => {
  const data = JSON.parse(e.data);
  console.error("Error:", data.payload.error);
  eventSource.close();
});
python
import requests, os

run_id = os.environ["RUN_ID"]  # from POST /ai/features/:featureKey/runs's data["id"]

with requests.get(
    f"{BASE_URL}/ai/runs/{run_id}/stream",
    headers={"Authorization": f"Bearer {TOKEN}"},
    stream=True,
) as response:
    for line in response.iter_lines(decode_unicode=True):
        if line.startswith("data: "):
            import json
            event = json.loads(line[6:])
            print(event["type"], event["payload"])

Olay Çerçevesi Formatı

Her olay standart bir SSE çerçevesi olarak gönderilir:

id: 1
retry: 3000
event: message.delta
data: {"eventId":1,"type":"message.delta","runId":"550e8400-...","timestamp":"2026-03-17T14:00:00.123Z","payload":{"delta":"Hello"}}
FieldDescription
idMonotonically increasing event ID
retryReconnection interval in milliseconds (3000ms)
eventEvent type name
dataJSON envelope with full event details

Veri Zarfı Alanları

FieldTypeDescription
eventIdnumberSequential event counter for this run
typestringEvent type
runIdstringThe AI run UUID
stepIdstring | undefinedStep ID
timestampstringISO 8601 event timestamp
payloadobjectEvent-specific data

Etkinlik Türleri

Kategoriye göre düzenlenen 30'dan fazla etkinlik türü:

Bağlantı

Event TypeDescriptionTerminal
stream.connectedEmitted once per connection after headers flush. Carries { runId }. Not buffered — will not appear in event replay.No

Yetenek Yönlendirme

Event TypeDescriptionTerminal
capability.resolvedThe requested AI capability was routed to an executable pathNo

Yaşam Döngüsünü Çalıştır

Event TypeDescriptionTerminal
run.startedRun processing has begunNo
run.status.changedRun status transitionNo
run.model.switchedActive model changedNo
run.cancel_requestedCancellation was requestedNo
run.cancellingCancellation in progressNo
run.cancelledRun cancelled successfullyYes
run.failedRun failed with an errorYes
run.errorRuntime/timeout errorYes

run.model.switched Yükü

json
{
  "eventId": 3,
  "type": "run.model.switched",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-04-15T12:00:00.300Z",
  "payload": {
    "runId": "550e8400-e29b-41d4-a716-446655440000",
    "fromModelKey": "gemini-2.0-flash",
    "fromProvider": "google",
    "toModelKey": "gemini-2.5-flash",
    "toProvider": "google",
    "reason": "model_not_found"
  }
}

Bu etkinlik bilgilendirme amaçlıdır; çalışma yeni modelle kesintisiz olarak devam etmektedir. Müşteriler bunu bir durum göstergesi olarak gösterebilir ancak herhangi bir işlem yapmaları gerekmez.

Mesaj Akışı

Event TypeDescriptionTerminal
message.deltaIncremental token contentNo
message.completedFull message has been assembledNo
message.suggestionsFollow-up suggestion cards for the completed assistant messageNo
message.partially_completedPartial completionNo

message.suggestions Yükü

json
{
  "eventId": 11,
  "type": "message.suggestions",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-04-15T12:00:01.000Z",
  "payload": {
    "messageId": "cm5msg002",
    "suggestions": [
      {
        "suggestion": "Can you make that more practical for this week?",
        "priority": 1
      },
      {
        "suggestion": "What would the first 10 minutes look like?",
        "priority": 2
      }
    ]
  }
}

"message.suggestions", "message.completed"dan hemen sonra (aynı onay işaretiyle) ve "run.settlement.completed"dan önce yayınlanır. Öneri çipleri, asistan yanıtını yazan çağrı modelinin aynısı tarafından üretilir, böylece yanıt kesinleştiği anda ulaşırlar. Yanıtın kopyalanmasının öneri metnini içermemesi için, müşterilerin bu kartları asistan indiriminin dışında oluşturması gerekir.

Araç Çağrıları

Araç olayları, bir konuşma sırasında Chao yerleşik araçları (takvim aramaları, bit sorguları, zincirleme/zincirleme işlemleri, bellek ve bit oluşturma veya tamamlama gibi yazma işlemleri) çağırdığında meydana gelir. Tek bir turda birden fazla takım paralel olarak çağrılabilir.

Event TypeDescriptionTerminal
tool.startedTool call initiatedNo
tool.progressTool execution progressNo
tool.completedTool call finished successfullyNo
tool.failedTool call failed (non-terminal — Chao handles errors gracefully)No
tool.degradedTool or capability returned a graceful fallback stateNo

"tool.started" Yükü

json
{
  "eventId": 4,
  "type": "tool.started",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "stepId": "tc_abc123",
  "timestamp": "2026-04-12T10:00:01.100Z",
  "payload": {
    "toolKey": "calendar.today",
    "callId": "tc_abc123",
    "input": {},
    "activity": {
      "activityType": "tool_read",
      "origin": "chao",
      "label": "Reading calendar",
      "detail": "Starting tool execution.",
      "renderHint": "tool_card",
      "status": "active",
      "subjectType": "calendar",
      "subjectId": "tc_abc123"
    }
  }
}

tool.completed Yükü

json
{
  "eventId": 5,
  "type": "tool.completed",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "stepId": "tc_abc123",
  "timestamp": "2026-04-12T10:00:01.160Z",
  "payload": {
    "toolKey": "calendar.today",
    "callId": "tc_abc123",
    "executionMs": 58,
    "success": true,
    "data": { "items": [] },
    "activity": {
      "activityType": "tool_read",
      "origin": "chao",
      "label": "Calendar complete",
      "detail": "Tool execution completed.",
      "renderHint": "tool_card",
      "status": "completed",
      "subjectType": "calendar",
      "subjectId": "tc_abc123"
    }
  }
}

"tool.failed" Yükü

json
{
  "eventId": 5,
  "type": "tool.failed",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "stepId": "tc_abc123",
  "timestamp": "2026-04-12T10:00:06.105Z",
  "payload": {
    "toolKey": "bits.get",
    "callId": "tc_abc123",
    "executionMs": 5001,
    "success": false,
    "error": "Tool execution timed out",
    "activity": {
      "activityType": "tool_read",
      "origin": "chao",
      "label": "Tool failed",
      "detail": "Tool execution timed out",
      "renderHint": "tool_card",
      "status": "failed",
      "subjectType": "bits",
      "subjectId": "tc_abc123"
    }
  }
}

'tool.failed' bir terminal olayı değildir. Chao hata sonucunu alır ve yanıt oluşturmaya devam eder.

'payload.data'yı takım gözlem çıktısı olarak değerlendirin. Bir kartın oluşturulmasına yardımcı olabilir, ancak Chao'nun asistan mesajı kullanıcıya yönelik sentez olarak kalır.

Araç kartı normalleştirmesi

Ön uç ve mobil istemciler, oluşturma öncesinde araç benzeri yükleri normalleştirmelidir:

Normalized fieldPreferred lookup
toolKeypayload.toolKey ?? payload.key
callIdpayload.callId ?? payload.toolCallId ?? envelope.stepId
inputpayload.input ?? payload.args
outputpayload.data ?? payload.output

payload.activity mevcut olduğunda, activityType, origin, label, detail, renderHint, status, subjectType ve subjectIdden kartları oluşturun.

Onay Kapıları

Chao'nun bir oturumda "mode: "approval" (varsayılan) ile bir yazma veya yok etme eylemi gerçekleştirmesi gerektiğinde, duraklar ve kullanıcının araç çağrısını onaylamasını veya reddetmesini bekler. Bu akışı üç olay yönetir:

Event TypeDescriptionTerminal
tool.approval_requiredChao requires user approval before executing a write/destructive toolNo
tool.approval_responseUser approved or rejected the pending tool callNo
tool.approval_timeoutApproval window (60 s) expired; tool was not executedNo

tool.approval_required Yükü

json
{
  "eventId": 6,
  "type": "tool.approval_required",
  "runId": "550e8400-e29b-41d4-a716-446655440000",
  "stepId": "tc_abc123",
  "timestamp": "2026-04-12T10:00:01.500Z",
  "payload": {
    "runId": "550e8400-e29b-41d4-a716-446655440000",
    "toolCallId": "tc_abc123",
    "toolKey": "bits.create",
    "input": { "title": "Review Q2 metrics", "priority": "high" },
    "activity": {
      "activityType": "approval",
      "origin": "chao",
      "label": "Approval needed",
      "detail": "Review this action before Chao runs it.",
      "renderHint": "status_card",
      "status": "pending",
      "subjectType": "bits",
      "subjectId": "tc_abc123"
    }
  }
}

Kullanıcının kararını şu uç noktalardan biriyle gönderin:

DecisionEndpointBody
ApprovePOST /ai/runs/:runId/tools/:toolCallId/approvenone
RejectPOST /ai/runs/:runId/tools/:toolCallId/reject{ "reason"?: string }

Onayın ardından Chao devam eder ve "tool.approval_response", "tool.started" ve ardından "tool.completed" ifadesini yayınlar. Reddedilirse veya zaman aşımına uğrarsa Chao devam eder ve sonucu açıklar.

Muhakeme ve Etkinlik Özetleri

Kamu müşterileri, ham özel Düşünce Zinciri değil, güvenli etkinlik özetlerini göstermelidir. Araç, onay, planlama ve yetenek olayları arasında "payload.activity"; bu nesneyi durum kartları ve zaman çizelgeleri için kullanın.

Event TypeDescriptionTerminal
tool.progressTool progress/activity updateNo
tool.approval_requiredApproval activity cardNo
plan.step_addedPlanned action summaryNo
capability.resolvedCapability routing summaryNo

Teşhis cot.* etkinlikleri bazı dahili/hata ayıklama oturumlarında görünebilir. Bunlar kamuya açık araç kartı sözleşmesi değildir ve varsayılan olarak son kullanıcılara gösterilmemelidir.

İş Akışı Adımları

Event TypeDescriptionTerminal
workflow.step.startedWorkflow step beganNo
workflow.step.completedWorkflow step finishedNo
workflow.step.failedWorkflow step failedNo
workflow.completedEntire workflow finishedYes

Yerleşim

Event TypeDescriptionTerminal
run.settlement.pendingCredit settlement is processingNo
run.settlement.completedSettlement done, run fully finishedYes

Terminal olayları kısa bir ek sürenin ardından akışın otomatik olarak kapanmasına neden olur.


Son Olay Kimliği ile Yeniden Bağlantı

Bağlantı koparsa kaldığınız yerden devam etmek için "Last-Event-ID" başlığını kullanarak yeniden bağlanın:

bash
curl -N https://api.chainabit.com/api/v1/ai/runs/$RUN_ID/stream \
  -H "Authorization: Bearer $TOKEN" \
  -H "Last-Event-ID: 5"

Sunucu, canlı yayına geçmeden önce "eventId > 5" olan tüm etkinlikleri yeniden oynatır. Çalıştırma tamamlandıktan sonra olaylar 15 dakika süreyle ara belleğe alınır.

JavaScript Yeniden Bağlantı Örneği

javascript
function connectStream(runId, lastEventId = null) {
  const url = new URL(`${BASE_URL}/ai/runs/${runId}/stream`);

  const headers = { Authorization: `Bearer ${TOKEN}` };
  if (lastEventId) {
    headers["Last-Event-ID"] = String(lastEventId);
  }

  const eventSource = new EventSource(url, { headers });
  let latestId = lastEventId || 0;

  eventSource.onmessage = (e) => {
    latestId = Number(e.lastEventId);
  };

  eventSource.onerror = () => {
    eventSource.close();
    // Reconnect after retry interval (3 seconds)
    setTimeout(() => connectStream(runId, latestId), 3000);
  };

  return eventSource;
}

Davranışı Yeniden Dene

Her SSE çerçevesindeki "yeniden dene: 3000" alanı, uyumlu istemcilere (tarayıcı "EventSource" dahil) bağlantı kesilirse 3 saniye sonra otomatik olarak yeniden bağlanmaları talimatını verir. Sunucu, kaçırılan olayları yeniden oynatmak için yeniden bağlantı sırasında "Son Olay Kimliği" başlığını izler.


Hata Olayları

'run.error' olayı akış sırasında bir çalışma zamanı hatasına işaret eder:

event: run.error
data: {"eventId":8,"type":"run.error","runId":"...","timestamp":"...","payload":{"error":"Stream timeout exceeded","code":"stream_timeout"}}
Payload FieldTypeDescription
errorstringHuman-readable error message
codestringError code — see table below
CodeMeaning
execution_errorGeneral error during LLM execution
stream_timeoutConnection open for more than 5 minutes
provider_errorUnhandled upstream provider failure
empty_responseProvider returned no text and no tool calls. The run fails; no automatic failover is attempted for this error code.

'run.error' bir terminal olayıdır; akış gönderildikten sonra kapanır.


Yayın Zaman Aşımı

Yayınlar 5 dakika sürekli bağlantıdan sonra otomatik olarak kapatılır. Çalıştırma o zamana kadar tamamlanmadıysa, "stream_timeout" koduyla birlikte bir "run.error" olayı yayınlanır. İstemcinin, etkinlikleri almaya devam edebilmesi için "Son Etkinlik Kimliği" ile yeniden bağlanması gerekir.


Bağlantı Yaşam Döngüsü

Basit çalıştırma (araç çağrısı yok):

Client                                  Server
  │                                       │
  │──── GET /ai/runs/:id/stream ────────►│
  │                                       │ Set headers (text/event-stream)
  │◄──── event: stream.connected ────────│
  │◄──── (replay missed events) ─────────│
  │                                       │
  │◄──── event: message.delta ───────────│  (real-time events)
  │◄──── event: message.delta ───────────│
  │◄──── event: message.completed ───────│
  │◄──── event: run.settlement.completed─│  (terminal)
  │                                       │
  │──── connection closed ───────────────│

Otomatik araç çağrılarıyla Chao çalıştırması:

Client                                  Server
  │                                       │
  │──── GET /ai/runs/:id/stream ────────►│
  │◄──── event: stream.connected ────────│
  │◄──── event: run.started ─────────────│
  │◄──── event: tool.started ────────────│  (card opens with activity)
  │◄──── event: tool.progress ───────────│  (optional status update)
  │◄──── event: tool.completed ──────────│
  │◄──── event: message.delta ───────────│  (LLM writes response)
  │◄──── event: message.completed ───────│
  │◄──── event: run.settlement.completed─│  (terminal)
  │                                       │
  │──── connection closed ───────────────│

Onay kapısıyla Chao çalıştırması (varsayılan mod):

Client                                  Server
  │                                       │
  │──── GET /ai/runs/:id/stream ────────►│
  │◄──── event: stream.connected ────────│
  │◄──── event: run.started ─────────────│
  │◄──── event: tool.approval_required ──│  (run pauses)
  │                                       │
  │──── POST /ai/runs/:id/tools/:toolCallId/approve ─►│
  │◄──── event: tool.approval_response ──│
  │◄──── event: tool.started ────────────│
  │◄──── event: tool.completed ──────────│
  │◄──── event: message.delta ───────────│
  │◄──── event: message.completed ───────│
  │◄──── event: run.settlement.completed─│  (terminal)
  │                                       │
  │──── connection closed ───────────────│

Hayatta Tut

Proxy zaman aşımlarını önlemek için her 15 saniyede bir kalp atışı yorumu (: canlı tutma) gönderilir.

Yanıt Başlıkları

HeaderValue
Content-Typetext/event-stream; charset=utf-8
Cache-Controlno-cache, no-transform
Connectionkeep-alive
X-Accel-Bufferingno

Built with purpose.