إنتقل إلى المحتوى الرئيسي

عقد SSE wire

تقوم AI chat endpoints ببث Server-Sent Events (text/event-stream). توثق هذه الصفحة عقد control-stream المستخدم بواسطة POST /chat/control/stream. ومصدر الحقيقة هو parser + types داخل @kaleidr/inference-ui (packages/inference-ui/src/control/sse.ts و types.ts). إذا كنت تستخدم kaleidr.js، فإن chat bundle يقوم بالتحليل نيابة عنك — ولا تحتاج هذه الصفحة إلا لبناء custom client.

تستخدم /chat/summary/stream و/chat/button/stream عقود SSE مختلفة ولا تشملها هذه الصفحة. لا تعِد استخدام control-stream parser مع تلك endpoints.

قاعدة التوافق

يجب على العملاء تجاهل أسماء events غير المعروفة. قد تتم إضافة events جديدة إلى العقد المستقر دون version bump. أما downstream events الموثقة في جدول "diagnostic / experimental" أدناه فهي ليست ضمن contract — ويتجاهلها العميل الرسمي وقد تختفي.

الأحداث المستقرة

Payloads هي ما يفترضه control parser. لا يحتوي start على field باسم phase (فهو يظهر فقط في phase events).

event:PayloadMeaning
(unnamed){ text }prose token تدريجي. وقد يحتوي على markers بصيغة [[Place]].
phase{ type: "phase", phase, session_id }lifecycle قبل stream.
start{ type: "start", session_id, purpose? }تم فتح stream.
place{ name, coordinates: { lat, lng }, address?, category?, source?, id? }مكان تم حله (merge-by-name → map pin). وتشير source: "vendor" إلى place من البيانات التي رفعتها المؤسسة.
place_linkedplace fields + is_update?إثراء place تم إرساله مسبقًا.
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count?, is_partial? }Map actions (fitBounds / route / highlight) قبل اكتمال الرد.
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }خيارات إزالة الغموض — اعرضها كخيارات قابلة للنقر وأرسل send_text للخيار كرسالة المستخدم التالية.
route_clear{}مسح جميع overlays قبل وصول routes جديدة. Stable.
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, connectors?, color?, label? }turn متعلق بالرحلة — route محسوبة من engine، تُرسل قبل prose لكي تستطيع الخريطة الرسم أثناء streaming للإجابة.
quota{ type: "quota", product, meter, tier, used, limit, reset_at, period }meter أثناء stream — اعرض الميزانية المتبقية.
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens? }terminal envelope — النتيجة الكاملة.
error{ type: "error", message, code?, partial_text? }خطأ نهائي.
: keep-alivecomment lineProxy keep-alive (~10s). تجاهله.

تمت الإزالة: grounding (2026-09-05). ما زال Grounding يؤثر في الإجابة لكنه لا يضع frame على wire.

تشخيصي / تجريبي (غير ضمن العقد)

هذه implementation details يتم إرسالها. ويتجاهلها العميل الرسمي؛ لا تعتمد عليها.

event:PayloadNotes
debug{ scope, … }تشخيص داخلي. قد يتغير أو يختفي.
place_name_found{ name, is_early? }غير ضمن contract؛ يتجاهله العميل الرسمي.

Tokens والبيانات المنظمة

تقوم events غير المسماة ببث prose عادية. وقد تحمل [[Place]] markers ضمن النص حيث تتم الإشارة إلى place (مثل …cafes near [[Louvre]]…) — أزلها للحصول على display نظيف، أو تجاهل prose تمامًا وشغّل UI من structured events.

تصل structured data كـ events، وليس داخل prose أبدًا. تظهر resolved places عبر placeplace_linked للـ metadata المتأخرة) أثناء geocode؛ وتصل map actions عبر early_actions؛ وتصل routes عبر route بعد route_clear؛ أما authoritative final payload فهو event باسم end. عادةً ما يعرض client pins من place events عند وصولها ويعتبر end مصدر الحقيقة.

عميل بسيط

const res = await fetch(`${API}/inference-api/b2b/v1/chat/control/stream`, {
method: 'POST',
headers: { 'X-Api-Key': key, 'Content-Type': 'application/json', Accept: 'text/event-stream' },
body: JSON.stringify({ messages: [{ role: 'user', content: 'cafes near the Louvre' }] }),
});
const reader = res.body.getReader();
// …decode chunks, split on \n\n, parse `event:` + `data:` lines
// IMPORTANT: ignore any unknown event name (forward-compat rule above).

راجع Endpoints لمعرفة request bodies و Errors للتعامل مع حالات الفشل.