واجهة البرمجة (API) ونقاط التوسعة
سطح HTTP/SSE لواجهة كاظمه على الويب، وعقد أحداث SSE، والأماكن الملموسة لتوسعة الإطار (الأدوات، المزوّدون، المُكيّفات، المهارات، MCP).
1. سطح واجهة HTTP API
Section titled “1. سطح واجهة HTTP API”تُركَّب كل نقاط النهاية بواسطة KazmaAppBuilder في kazma-ui/kazma_ui/app.py:615-709. الموجّهات:
| الموجّه | البادئة/المنطقة | المصدر |
|---|---|---|
health_router | /health/* | health.py |
chat_router | مسارات الصفحات (/chat, …) | chat.py |
settings_router | /settings | settings.py |
skills_router | المهارات | مسارات المهارات |
mcp_router | MCP | مسارات MCP |
agents_router | الوكلاء | مسارات الوكلاء |
providers_router | /api/providers | مسارات المزوّدين |
sse_router | /api/chat/* | sse_chat/ |
telemetry_router | القياس عن بعد | مسارات القياس عن بعد |
dashboard_router | /api/dashboard/* | dashboard.py |
models_router | النماذج | مسارات النماذج |
workspace_router | مساحة العمل | مسارات مساحة العمل |
swarm_router | /api/swarm/* | swarm_panel/ |
monitor_router | المراقبة | مسارات المراقبة |
metrics_router | المقاييس | مسارات المقاييس |
إضافة إلى مسارات مباشرة في routes_direct/ وwebhook تيليجرام شرطي على /api/webhooks/telegram (app.py).
2. نقاط النهاية الرئيسية (مُتحقَّق منها)
Section titled “2. نقاط النهاية الرئيسية (مُتحقَّق منها)”2.1 الدردشة (SSE)
Section titled “2.1 الدردشة (SSE)”| الطريقة | المسار | الغرض |
|---|---|---|
POST | /api/chat/stream | نقل الدردشة الأساسي. الجسم \{message, session_id, model\}. يعيد text/event-stream. (sse_chat/__init__.py) |
POST | /api/chat/sessions | ربط جلسة فارغة بالمستدعي المصادَق عليه قبل فتح مقبس قياسها عن بعد. يتطلب حماية CSRF. |
| GET | /api/chat/sessions | عرض الجلسات. (السطر 547) |
| DELETE | /api/chat/sessions/\{session_id\} | حذف الجلسة. (السطر 555) |
| GET | /api/chat/sessions/\{session_id\}/messages | سجل الجلسة. (السطر 561) |
نقل الرسم البياني:
POST /api/chat/stream. /ws/chat/{session_id}هو ناقل القياس عن بعد / المؤشر: لا يشغّل أي دور ولا يقبل التحكم في الأدوار (الإرسال والموافقة والإيقاف والتوجيه والإلغاء عبر HTTP/SSE؛ ويرفضها المقبس مع ذكر المسار).
2.2 المزوّدون
Section titled “2.2 المزوّدون”| الطريقة | المسار | الغرض |
|---|---|---|
GET | /api/provider/active | المزوّد/النموذج النشط. |
POST | /api/provider/switch | تبديل المزوّد/النموذج النشط. |
GET | /api/providers | عرض المزوّدين، مع مفاتيح مقنَّعة ونماذج مكتشفة وcapabilities معلَنة. |
POST | /api/providers | إضافة مزوّد أو تحديثه. المفتاح المقنَّع **** يعني «أبقِ المخزَّن». |
DELETE | /api/providers/{name} | إزالة مزوّد. |
POST | /api/providers/{name}/toggle | تمكين أو تعطيل. |
POST | /api/providers/{name}/test | فحص صحة — انظر أدناه. |
POST | /api/providers/{name}/discover | جلب قائمة نماذج المزوّد. |
/api/providers/* هي السطح الوحيد للمزوّدين. وُجد مسار موازٍ
/api/settings/providers/* بنفس العمليات الست وحُذف: مساران لمفهوم واحد
هو كيف ينحرفان، وقد انحرف هذا الزوج بما يكفي حتى شُحن إصلاح في المسار
الذي لم يستدعه أحد.
ما يعيده …/test. «قابل للوصول» و«يعمل» ادعاءان مختلفان، لذا
الاستجابة تحملهما معًا:
| الحقل | المعنى |
|---|---|
reachable | أجابت قائمة النماذج. ليس ادعاءً بأن المزوّد يعمل. |
chat_ok | عاد إكمال حقيقي على POST /chat/completions. |
chat_ms, chat_model | زمن استجابة ذلك الإكمال، والنموذج الذي يقول المزوّد أنه خدمه. |
success | كلاهما أعلاه. |
يحل الفحص مفتاحه عبر ModelRegistry.resolve_provider_credentials
ونموذجه عبر ModelRegistry.probe_model_for — نفس المسارات التي تستخدمها
رسالة حقيقية. لا يحل شيئًا يدويًا، ولا يكتب.
تذكر إخفاقات الفحص حالة HTTP وإرشادًا عمليًا. تُستبعد أجسام الاستجابات البعيدة وعناوين الطلبات التي تحمل بيانات اعتماد من التشخيصات.
2.3 موافقة HITL
Section titled “2.3 موافقة HITL”| الطريقة | المسار | الغرض |
|---|---|---|
GET | /api/pending-approvals | موافقات HITL المعلقة. (hitl_approval.py:146) |
POST | /api/approve/\{thread_id\} | الموافقة على أداة متوقفة مؤقتًا أو رفضها. الجسم `{action: “approve” |
2.4 لوحة التحكم
Section titled “2.4 لوحة التحكم”| الطريقة | المسار | الغرض |
|---|---|---|
GET | /api/dashboard/status | نظرة عامة على لوحة التحكم. (dashboard.py:177) |
GET | /api/sessions | قائمة الجلسات — للمشرف فقط (تعرض خيوط كل مستخدم). (السطر 221) |
POST | /api/sessions/clear-all | مسح الجلسات — للمشرف فقط. (السطر 330) |
2.5 السرب
Section titled “2.5 السرب”| الطريقة | المسار | الغرض |
|---|---|---|
GET | /api/swarm/status | حالة السرب. |
GET/POST/DELETE | /api/swarm/workers[/\{name\}] | عمليات CRUD للعمال. |
POST | /api/swarm/dispatch | إرسال مهمة (كل الأنماط عبر type). |
GET | /api/swarm/tasks[/\{id\}] | قائمة المهام / التفاصيل. |
POST | /api/swarm/tasks/\{id\}/approve | الموافقة على نقطة تفتيش خط الأنابيب: 202 بمجرد تسجيل التشغيل المستأنَف؛ ويظهر التقدّم في تدفق المهمة. للمسؤول. |
POST | /api/swarm/tasks/\{id\}/reject | رفض نقطة تفتيش خط الأنابيب. للمسؤول. |
GET | /api/swarm/workers/\{name\}/metrics | مقاييس العامل. |
GET | /api/swarm/circuit-breakers | حالات قواطع الدارة. |
2.6 الصحة
Section titled “2.6 الصحة”| الطريقة | المسار | الغرض |
|---|---|---|
GET | /health/live | الحياة. (health.py:94) |
GET | /health/ready | الجهوزية. (السطر 104) |
GET | /health/details | صحة مفصلة. (السطر 148) |
GET | /api/gateway/status | حالة البوابة/المُكيّف. |
2.7 توافق الذاكرة وواجهات المشغّل
Section titled “2.7 توافق الذاكرة وواجهات المشغّل”| الطريقة | المسار | العقد الحالي |
|---|---|---|
GET | /api/memory/graph | HTTP 410؛ استخدم /api/memory/v2/graph. |
GET | /api/memory/graph/stats | HTTP 410؛ استخدم /api/memory/v2/health. |
GET | /api/memory/graph/export | HTTP 410؛ استخدم سطح الرسم V2. |
GET | /api/memory/graph/search | بحث توافقي تدعمه معتقدات V2. |
POST | /api/memory/graph/clear | يحتاج تأكيدًا وتفويض المستأجر؛ يبطل المعتقدات الحالية مع حفظ التاريخ والحلقات. |
قد لا يكون لتشخيصات المشغّل ونقاط التكامل العامة مستدعٍ في المتصفح عمدًا.
يحتوي tests/test_api_route_callers.py جردها المعتمد وأسباب المستدعين؛ وليس
الغياب من الواجهة معيارًا للحذف. تبقى الاستعادة متاحة عبر
python -m kazma_core.backup.restore؛ انظر التعافي من الكوارث.
3. عقد أحداث SSE
Section titled “3. عقد أحداث SSE”يعيد POST /api/chat/stream أحداثًا مرسلة من الخادم (Server-Sent Events): سطر event: يسمّي الإطار، وسطر data: واحد يحمل كائن JSON. المصدر: kazma-ui/kazma_ui/sse_chat/ (المسار ومُرسِل الدور _streaming.py) وسجل الدور kazma-ui/kazma_ui/delivery.py؛ ويقرؤه المتصفح عبر dispatch في static/js/streaming.js.
إطارات الدور تُسجَّل أولًا. يُكتب كل إطار في سجل المحادثة قبل إرساله، فيحمل سطر id:، وتحمل بياناته seq (الرقم نفسه) وturn_id. والعميل الذي ينقطع تدفقه يعيد الطلب وفيه last_event_id (أو last_seq) بدل رسالة: فيصله إطار resumed، ثم كل إطار فاته، ثم الدور الجاري. والإطار المُعاد عرضه سجلًّا يحمل replay: true؛ ولا تُعرض موافقة معلّقة فيه إلا بعد أن يؤكد سجل البوابات أنها ما زالت مفتوحة. ولا يُعاد عرض إطارات error وcapacity وuser_message وthread_rewound، ولا أي إطار تقول بياناته capacity: true. وفي أثناء الصمت يرسل التدفق أسطر تعليق : keepalive.
event: | متى | حقول data |
|---|---|---|
resumed | أول إطار في كل تدفق يتبع دورًا: رسالة جديدة، وإعادة اتصال، والانتظار بعد موافقة. لا يُسجَّل. | from، وto (أحدث seq في السجل)، وcount (الإطارات المُعاد عرضها)، وgap، وrunning، وsession_id، وthread_id |
token | جزء من الإجابة يُلحق بالترتيب: قطعة متدفقة، أو فاصل فقرة بين استدعاءين للنموذج، أو النص النهائي مقروءًا من نقطة الحفظ حين لم يتدفق شيء، أو إشعار (توقف الدور دون بطاقة موافقة، أو انتهى بلا نص، أو فشل قبل الرد). | content |
tool_call | تبدأ أداة. | tool_name، وtool_call_id (هو نفسه في tool_result الخاص بها)، وinputs (نص JSON، 2,000 حرف على الأكثر) |
tool_result | انتهت الأداة. | tool_name، وtool_call_id، وresult (5,000 حرف على الأكثر) |
memory_explain | أُعطي المشرف ذكريات لهذا السؤال؛ ويحفظ الدور السجل نفسه. | query، وempty، وdetail، وbeliefs، وepisodes، وweekly_summaries، وknowledge (لكل عنصر: id، وkind، وcontent، وscore، وsources)، وsummary (الأعداد) |
turn_heartbeat | كل 10 ثوانٍ تقريبًا دون إطار آخر (كل 8 حين يُستأنف الدور بعد موافقة). | phase (llm أو supervisor أو tool أو resuming)، وcurrent (الأداة)، وdetail، وstep، وelapsed_s |
status_update | بلغ المخطط نهايته وتُكتب الإجابة (status: "synthesizing"، وactive_node: "Respond"). أو مؤشر العميل ليس في السجل (status: "resync"، وseq): فهو أقدم مما يحفظه السجل، أو متقدم عليه بعد إعادة تشغيل الخادم أو ساعة من الخمول، حين يبدأ السجل من جديد عند 1. ينتهي التدفق هنا. ويعيد العميل تحميل المحادثة من المخزن ويأخذ seq مؤشرًا جديدًا له (وإطار resumed يحمل gap يعني الشيء نفسه). | status، ثم active_node أو seq |
status | وصل استئناف ثانٍ إلى دور يعمل أصلًا؛ ويتبع هذا التدفق ذلك الدور. | content، وstatus (thinking) |
context_compacted | قلّص هذا الدور سياق النموذج أو طوى مخرجات أدوات قديمة. | detail، مع أعداد مثل stubbed_segments، وdropped_user، وdropped_assistant |
approval_required | توقف المخطط مؤقتًا لطلب موافقة. لا يتبعه done: يبقى التدفق مفتوحًا، ويستمر الدور فيه بعد POST /api/approve/{thread_id}. | thread_id، وinterrupt_id، وkind، وtool، وargs، وtools، وitems، وmessage، وyolo_allowed، وalways_ask (أداة تطلب الموافقة دائمًا مثل عملية كتابة في X: موافقة لمرة واحدة أو رفض فقط، دون منح للجلسة)، وapproval_deadline، وview وgate_views من سجل البوابات |
hitl | حُسمت موافقة، في هذا التبويب أو تبويب آخر أو تطبيق محادثة. | state (approved أو denied أو timeout)، وinterrupt_id، وtool، وthread_id، وturn_id، وactor، وview، وgate_views |
approval_timeout | لم يُجب أحد في الوقت: لا تُشغَّل الأداة، ويُبلَّغ النموذج بأن الموافقة انتهت صلاحيتها (لا بأنها رُفضت)، وينتهي الدور بإجابته. | thread_id، وinterrupt_id، وtool، وturn_id، وmessage |
capacity | /long أو /plan أو /yolo، يُجاب عنها دون النموذج؛ ويتبعها done فيه capacity: true. | action، وreply، وlong_active وyolo_active، أو plan_active |
error | فشل الطلب أو الدور. قبل أن يبدأ الدور (محتوى ليس JSON، أو رسالة تتجاوز 512,000 حرف، أو رسالة فارغة، أو لا مفتاح API لمزوّد سحابي، أو نفاد ميزانية الجلسة) يكون الإطار الوحيد. | content (بلا تفاصيل داخلية) |
done | انتهى الدور. content هو الإجابة، ويحل محل ما بنته إطارات token. | content، وtokens، وcost، وduration_ms، وinterrupted، وempty، وmodel، وturn_id، وsession_tokens، وsession_cost، وgate_views |
turn_complete | بعد done مباشرة، بالبيانات نفسها. | كما في done |
snapshot | بعد done، حين حفظ «السفر عبر الزمن» هذه الخطوة. | snapshot_id، وiteration، وmodel |
user_message | بدأ تبويب آخر دورًا في هذه المحادثة. لا يصل إلا إلى التدفقات المتصلة بالمحادثة أصلًا، ولا يصل إلى تدفق المُرسِل نفسه، ولا يُعاد عرضه؛ وتأخذه صفحة المحادثة من WebSocket الخاص بها، الذي يحمل السجل نفسه. | content، وturn_id، وclient_msg_id، وsession_id، وts |
thread_rewound | استُعيدت المحادثة إلى خطوة من «السفر عبر الزمن» (من أي واجهة). يعيد كل تبويب مفتوح تحميل المحادثة من المخزن؛ ولا يُعاد عرضه أبدًا. | thread_id، وsession_id، وsnapshot_id، وturn_index، وmessage_count |
ردود دون النموذج. تجيب /reset و/compact واستعمال /swarm المجرد بإطار token وإطار done يحمل content وtokens وcost وduration_ms، ولا تُسجَّل. ويرسل استعمال /research و/replay و/fork الإطارين نفسيهما مع capacity: true، مسجَّلين لتراهما تبويبات المحادثة الأخرى. وينتهي التدفق المتصل بعد done أو turn_complete (إلا إن كان interrupted)، أو بعد error.
انتهاء صلاحية موافقة HITL: إذا نقر المستخدم على موافقة/رفض على بطاقة
انتهت مهلتها أو استُؤنفت بالفعل، يعيد POST /api/approve/{thread_id}
HTTP 409 مع {"status": "expired", "error": "No pending approval for this thread (already resumed or expired)."}. تكشف الواجهة
الأمامية (hitl_approval.js) ذلك وتنقل البطاقة إلى «منتهية أو مستأنفة
بالفعل» ثم تزيلها. والقرار الذي يسمّي بوابة (interrupt_id) حُسمت من قبل،
أو بوابة لمحادثة أخرى، يُرَدّ عليه أيضًا بـ 409: reason: "not_pending"، مع
hitl_state (inflight أو settled أو foreign)، وregistry_state،
وinterrupt_id البوابة.
3.1 مثال جهة العميل (JavaScript)
Section titled “3.1 مثال جهة العميل (JavaScript)”// chat.js uses KS.sse('/api/chat/stream', {...}); the raw shape is:const resp = await fetch('/api/chat/stream', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'Hello', session_id: sess, model: 'gpt-4o-mini' }),});
const reader = resp.body.getReader();const decoder = new TextDecoder();let buffer = '';
while (true) { const { value, done } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true });
// SSE events are separated by blank lines let idx; while ((idx = buffer.indexOf('\n\n')) !== -1) { const block = buffer.slice(0, idx); buffer = buffer.slice(idx + 2); const eventType = (block.match(/^event: (.+)$/m) || [])[1]; const data = JSON.parse(((block.match(/^data: (.+)$/m) || [])[1]) || '{}'); handleEvent(eventType, data); }}
function handleEvent(type, data) { switch (type) { case 'token': appendToken(data.content); break; case 'tool_call': showToolCall(data.tool_name, data.inputs); break; case 'tool_result': showToolResult(data.tool_name, data.result); break; case 'approval_required': promptApproval(data.thread_id, data.interrupt_id, data.tool); break; case 'done': finishTurn(data.content, data.tokens, data.cost); break; case 'error': showError(data.content); break; }}3.2 الموافقة عبر API (Python)
Section titled “3.2 الموافقة عبر API (Python)”import httpx
resp = httpx.post( "http://127.0.0.1:8000/api/approve/<thread_id>", headers={"X-Kazma-Secret": KAZMA_SECRET}, # required if KAZMA_SECRET is set json={"action": "approve", "reason": "looks safe"},)print(resp.status_code, resp.json())4. نقاط التوسعة
Section titled “4. نقاط التوسعة”4.1 إضافة أداة
Section titled “4.1 إضافة أداة”سجّل دالة مع ToolRegistry:
from kazma_core.agent.tool_registry import register_tool
@register_tool( name="weather_lookup", description="Look up current weather for a city.", danger=False, # True → triggers HITL)async def weather_lookup(city: str) -> str: ... return f"Weather in {city}: sunny, 25C"سجّلها أثناء الإقلاع (أو عبر نقطة دخول مهارة). يعرضها المشرف على LLM تلقائيًا. تُولَّد المخططات من تلميحات الأنواع مع additionalProperties: false. تبقى المعاملات الاختيارية اختيارية ما لم يكن KAZMA_STRICT_TOOLS=1. لرد JSON لمرة واحدة (ليس استدعاء أداة)، مرّر response_format= إلى LLMProvider.chat — لا تضعه في كل دورة مشرف.
4.1b خطاطيف الأدوات (PreToolUse / PostToolUse)
Section titled “4.1b خطاطيف الأدوات (PreToolUse / PostToolUse)”from kazma_core.agent.tool_hooks import register_pre_tool_hook, ToolHookDecision
def block_shell(event): cmd = str((event.tool_input or {}).get("command") or "") if "rm -rf" in cmd: return ToolHookDecision(decision="deny", reason="blocked pattern") return None
register_pre_tool_hook(block_shell, matcher="shell_exec")أو YAML (agent.hooks.pre_tool / post_tool): كل مدخل هو {matcher, command, timeout_seconds?}. يستقبل الأمر JSON على stdin (hook_event_name، tool_name، tool_input، وبعد التنفيذ tool_response) وقد يطبع JSON (decision، tool_input / updatedInput، reason، extra) أو يخرج بـ 2 للرفض. الخطاطيف لا تستطيع الموافقة تلقائيًا على HITL. مفتاح الإيقاف: KAZMA_TOOL_HOOKS=0.
4.2 إضافة مزوّد
Section titled “4.2 إضافة مزوّد”المزوّدون مدخلات ConfigStore تحت providers.list. الإعدادات المسبقة العشرة المدمجة في kazma_core/providers.py:13-84. لإضافة نقطة نهاية مخصصة متوافقة مع OpenAI:
from kazma_core.config_store import get_config_storefrom kazma_core.model_registry import get_model_registry
store = get_config_store()reg = get_model_registry()
# Option A: use the 'custom' preset shapereg.upsert_provider( name="my-endpoint", display_name="My Inference Server", base_url="https://infer.example.com/v1", api_key="sk-...", enabled=True,)
# Option B: switch active provider/modelreg.set_active_provider("my-endpoint")reg.set_active_model("my-model-id")أي نقطة نهاية متوافقة مع OpenAI تعمل (vLLM، Together، Groq، Fireworks، …). لمخططات مصادقة غير OpenAI، لاحظ أن LLMProvider.chat() ترسل دائمًا Authorization: Bearer — مرّر عبر وكيل متوافق مع OpenAI إذا كان المصدر يحتاج ترويسة مختلفة.
4.3 إضافة مُكيّف منصة
Section titled “4.3 إضافة مُكيّف منصة”اشتق من BaseAdapter (kazma-gateway/kazma_gateway/gateway.py:239)، ونفّذ الاستقبال/الإرسال، وأنتج IncomingMessage، وسجّله. لأجل HITL السرب على المنصة الجديدة، اشتق أيضًا من BusAdapter (kazma_core/swarm/bus.py:66) وصله في كتلة الفرادى للناقل في app.py.
4.4 إضافة مهارة
Section titled “4.4 إضافة مهارة”انظر المهارات وMCP والأدوات ← إضافة مهارة مخصصة. وقّعها بـ kazma hub sign.
4.5 إضافة خادم MCP
Section titled “4.5 إضافة خادم MCP”انظر المهارات وMCP والأدوات ← تهيئة خادم MCP. تُكتشف الأدوات وقت التشغيل وتُصنَّف بـ classify_mcp_tool.
4.6 إضافة عامل سرب
Section titled “4.6 إضافة عامل سرب”kazma swarm worker add researcher --model deepseek-chat --provider deepseek --type in_process --role researcherأو عبر API:
import httpxhttpx.post("http://127.0.0.1:8000/api/swarm/workers", json={ "name": "researcher", "model": "deepseek-chat", "provider": "deepseek", "worker_type": "in_process", "roles": ["researcher"],})4.7 النفاذ إلى حزمة الذاكرة V2
Section titled “4.7 النفاذ إلى حزمة الذاكرة V2”محرك الإدراك V2 هو الافتراضي للدردشة (استرجاع لكل دور، أدوات، تخزين تلقائي، دمج) ويُستخدم أيضًا من التحسين الذاتي / دفتر الهاتف. (حُذف UnifiedMemoryAdapter الخاص بـ V1 في التحول V1→V2.) شيفرة مخصصة:
from kazma_core.memory.recall import recallfrom kazma_core.paths import primary_memory_dbimport sqlite3
conn = sqlite3.connect(primary_memory_db(), check_same_thread=False)conn.row_factory = sqlite3.Row
result = recall("what does the user prefer?", conn=conn, limit=5)# result.beliefs -> list[RecallHit] of currently-valid beliefs# result.episodes -> list[RecallHit], ranked by evidence (meaning above the question's# background + content words covered); empty when nothing clears the thresholdكتابة معتقد (المسندات الوظيفية تحل محل ما قبلها؛ ومسندات المجموعة تُلحق):
from kazma_core.memory.belief_mutation import mutate_belieffrom kazma_core.paths import primary_memory_db, ops_memory_db
primary = sqlite3.connect(primary_memory_db(), check_same_thread=False)ops = sqlite3.connect(ops_memory_db(), check_same_thread=False)
mutate_belief( primary, "user", "prefers", "dark mode", ops_conn=ops, predicate_type="set", extraction_method="custom", source_session="my-integration",)انظر الذاكرة وRAG.
5. نقاط نهاية القياس عن بعد والقابلية للمراقبة
Section titled “5. نقاط نهاية القياس عن بعد والقابلية للمراقبة”/api/telemetry/*(telemetry_router) — قياس عن بعد لوقت التشغيل./api/dashboard/status— نظرة عامة للوحة التحكم.- مقاييس السرب على
/api/swarm/workers/\{name\}/metrics.
Prometheus
/metricsغير موجود. حزم OTel معلَنة لكن تتبع كاظمه باعث نطاقات داخلي الصنع. انظر البنية ← القابلية للمراقبة.
ملاحظات تدقيق الوثائق
Section titled “ملاحظات تدقيق الوثائق”- نقل الرسم البياني هو SSE (
POST /api/chat/stream). /ws/chat/{session_id}هو ناقل القياس عن بعد / المؤشر: لا يشغّل أي دور ولا يقبل التحكم في الأدوار (الإرسال والموافقة والإيقاف والتوجيه والإلغاء عبر HTTP/SSE؛ ويرفضها المقبس مع ذكر المسار). - حدث SSE
approval_requiredهو الطريقة القياسية لواجهات العرض لإظهار توقفات HITL مؤقتة؛ اقرنه بـPOST /api/approve/\{thread_id\}. - إنفاذ ملكية
/api/approve(403 بين المستخدمين) يعني أن رموز الموافقة لكل مستخدم — لا يستطيع مشرف الموافقة على مهمة مستخدم آخر دون تطابق حقول الهوية. - V2 هي حزمة الذاكرة الوحيدة — الاسترجاع لكل دور والأدوات والتخزين التلقائي والدمج كلها تستخدم
recall()منmemory/recall.py. حُذف مُكيّف V1 رباعي الطبقات (get_adapter()) في التحول V1→V2.

