تخطَّ إلى المحتوى
kazma.
البحث في كاظمه والتوثيق
EN

كيف يجري الدور

الدور هو كل ما تفعله كاظمه بين رسالة وجوابها. تتتبّع هذه الصفحة رسالة واحدة عبر النظام كله:

Email Sara that the report is ready.

تصل على Telegram، وتحتاج أداة ترسل شيئًا خارج كاظمه، فتتوقف لموافقتك. وهذا يجعلها جولة جيدة. تقول كل خطوة ما يحدث، ولماذا بُني على هذا النحو، وأين الشيفرة. وللآليات نفسها، راجع الهندسة داخل كاظمه. ولخريطة المكوّنات، راجع البنية المعمارية.

sequenceDiagram
    participant U as You (Telegram)
    participant G as Gateway
    participant S as Supervisor
    participant M as Model
    participant W as Tool worker
    participant R as Gate registry
    participant T as email_send

    U->>G: "Email Sara that the report is ready."
    G->>S: turn input (history, this turn's notes, memory)
    S->>M: messages + tools
    M-->>S: call email_send(to, subject, body)
    S->>W: tool call
    W->>W: can it run? commitment check
    W->>R: register gate (pending)
    W-->>U: approval card with buttons
    Note over S,W: graph paused, checkpoint saved
    U->>R: Approve (claims the gate)
    R->>W: resume, keyed by the interrupt id
    W->>T: receipt recorded, then send
    T-->>W: sent
    W->>S: tool result
    S->>M: messages + result
    M-->>S: "Done: emailed Sara."
    S-->>G: final answer (turn closed, memory written)
    G-->>U: "Done: emailed Sara."

يستقبل محوّل Telegram الرسالة ويسجّل ما يحدث لها: تُسلَّم، أو تُسقط مع سبب (ليس صاحبها في قائمة المستخدمين المسموح لهم، أو أنها من روبوت، أو حارس الإغراق عند 30 رسالة في الدقيقة). وتنتهي كل رسالة في إحدى هاتين الحالتين، فيستطيع اختبار الإعدادات أن يخبرك بما آلت إليه آخر رسالة.

تحتفظ البوابة بمعرّف محادثة Telegram ومعرّف الرسالة في مخزن جلساتها الخاص. ولا يدخلان حالة الوكيل أبدًا. يرى الرسم معرّف خيط واسم منصة، ولا يُستعاد عنوان الرد إلا حين يُرسل الجواب. وهذا يُبقي تفاصيل المنصة خارج المحادثات المحفوظة، ويمنع عنوان محادثة من التسرّب إلى دور محادثة أخرى. وقفل واحد لكل خيط يمنع رسالتين من المحادثة نفسها من التداخل.

أين: kazma_gateway/adapters/telegram.py، وkazma_gateway/receive_log.py، وkazma_gateway/agent_handler/graph.py (_handler_body)، وkazma_gateway/agent_handler/store.py (_build_target_id).

تأتي المحادثة حتى الآن من نقطة حفظ LangGraph. وقبل إرسالها إلى أي مكان، تُزال الملاحظات التي كانت تخص الدور السابق: كتلة بيئته، وكتلة ذاكرته، وتثبيت «آخر رسالة». ثم تُضاف ملاحظات هذا الدور. ودون هذه الخطوة، أرسل الدور الرابع من محادثة ذات مرة ست عشرة ملاحظة نظام إلى النموذج، منها مساحة العمل التي كان المستخدم قد انتقل عنها.

ويسجّل الدور أيضًا مساحة العمل التي يبدأ فيها. فإن توقف لاحقًا طلبًا للموافقة، استأنف في المجلد نفسه حتى لو بدّل أحدهم المستودع في الأثناء. ويحدّ حدّ زمني اختياري (الإعدادات ← النظام) كل جزء جارٍ من الدور. ولا يُحتسب الوقت الذي يقضيه في انتظارك.

أين: kazma_core/agent/turn_input.py (build_turn_messages)، وkazma_core/turn_notes.py، وkazma_core/agent/turn_workspace.py، وkazma_core/agent/turn_budget.py.

المشرف هو عقدة LangGraph التي تستدعي النموذج. في كل استدعاء يضع موجّه كاظمه الأساسي أولًا، مع تاريخ اليوم بمنطقتك الزمنية. وفي أول استدعاء من الدور يسأل الذاكرة أيضًا عن أي شيء يخص السؤال، ومكتبة المعرفة عن المقاطع المطابقة. ولا تُحقن ذكرى إلا حين يتجاوز دليلها حدًّا أدنى. والدليل هو كم هي أقرب في المعنى إلى السؤال من الخلفية، مضافًا إليه نصيبها من كلمات السؤال. وهنا قد تجد من تكون سارة. وتعرض محادثة الويب الذكريات التي استخدمها الدور.

يمر استدعاء النموذج عبر سجل النماذج، الذي يبدّل النموذج والمزوّد معًا دائمًا. فاسم نموذج يُرسل إلى نقطة اتصال مزوّد خاطئ يفشل. وتُنقل ملاحظات النظام إلى رأس قائمة الرسائل، لأن الخوادم المحلية الصارمة ترفض رسالة نظام بعد أول رسالة من المستخدم. وتُعاد محاولة أخطاء الشبكة وحدود المعدّل؛ وما سواها يفشل فورًا. وإن اضطرت كاظمه إلى الانتقال إلى نموذج آخر، تُبلَّغ بذلك.

أين: kazma_core/agent/graph_supervisor.py (supervisor_node)، وkazma_core/agent/graph_helpers.py، وkazma_core/memory/recall.py، وkazma_core/model_registry.py، وkazma_core/llm_provider.py (hoist_system_messages).

يجيب النموذج باستدعاء: email_send(to=..., subject=..., body=...). ويتعامل معه عامل الأدوات بهذا الترتيب:

  1. هل يمكن تشغيله أصلًا؟ الاستدعاء الذي سيرفضه هذا التثبيت على أي حال، كأمر صدفة والصدفة المضيفة معطّلة أو متصفح لا يستطيع هذا الجهاز تشغيله، يُجاب عنه فورًا. ولا تُعرض له بطاقة موافقة، لأن بطاقة لشيء لا يمكن تشغيله لن تفعل سوى إهدار موافقتك.
  2. فحص الالتزام. يحلّ authorize_effect الطلب مقابل ما تعرفه كاظمه. ويمكنه أن يمرّر الاستدعاء، أو يعيد كتابة معاملاته (تاريخ نسبي مربوط بالذاكرة، أو منشور X مستبدَل بمسودته المحفوظة)، أو يطرح سؤال توضيح بخيارات، أو يرفضه.
  3. الموافقة. email_send أداة من طبقة الخطر، فيستدعي العامل interrupt() في LangGraph. يتوقف الرسم، وتُحفظ حالته في نقطة الحفظ، ويُكتب صف pending في سجل البوابات، وتصل البطاقة إلى Telegram بزرَّي الموافقة والرفض.

أين: kazma_core/agent/graph_tool_worker.py (tool_worker_node، و_refuse_unrunnable_calls، و_commitment_resolve_gate)، وkazma_core/safety/commitment/authorize.py، وkazma_core/safety/hitl.py.

تضغط «موافقة». فتحجز الضغطة صف البوابة بالمقارنة-والمبادلة، والقرار الأول على أي واجهة هو النافذ. والضغطة الثانية، أو تبويب ويب قديم، تتلقى القرار الذي اتُّخذ بدل اتخاذ قرار آخر. ويُستأنف الرسم بأمر مربوط بمعرّف المقاطعة لذلك السؤال. ولو لم تجب خلال مهلة الموافقة (300 ثانية افتراضيًا)، لما جرى الاستدعاء، ولقال الجواب إن الموافقة انتهت مهلتها، لا إنك رفضتها.

أين: kazma_core/safety/hitl_gates.py، وkazma_gateway/agent_handler/hitl.py، وkazma_ui/routes_direct/misc.py (مسار الموافقة على الويب).

6. تعمل الأداة، مع إيصال

Section titled “6. تعمل الأداة، مع إيصال”

قبل أن يعمل email_send، يكتب دفتر الآثار إيصالًا لهذا الاستدعاء بالذات. وبعد أن يعمل، تُسجَّل النتيجة قبل أن يتقدم الرسم. ولو أُعيد تشغيل كاظمه بين هاتين اللحظتين، لوجدت المحاولة التالية إيصالًا بدأ ولم ينتهِ. ولن ترسل بريدًا ثانيًا: يتوقف الدور ويقول إن النتيجة مجهولة. والنص العائد من الخارج (صفحة ويب، أو بريد تلقيته، أو مستند) يُسيَّج على أنه بيانات قبل أن يقرأه النموذج.

أين: kazma_core/agent/effect_journal.py، وkazma_core/agent/tool_registry.py، وkazma_core/safety/prompt_fence.py.

يرى النموذج النتيجة ويكتب ردّه. وتتحقق الخطوة الأخيرة أولًا من فشل الدور. فإن فشل استدعاء نموذج بعد إعادة محاولاته، لا يُكتب ملخص فوق الفجوة: تتلقى رسالة ⚠️ مع تلميح. وإلا تعمل بضع ضمانات ضيقة. إحداها تجمع الجواب في فقرة واحدة حين تطلب ذلك؛ وأخرى تحافظ على كائن JSON طلبت نسخه كما هو. ولـ Telegram وDiscord وSlack، تُعاد كتابة الجداول أسطرًا لتُقرأ على الهاتف.

أين: kazma_core/agent/graph_respond.py (respond_node)، وkazma_core/agent/answer_format.py، وkazma_gateway/chat_tables.py.

دالة واحدة، close_turn، تقرّر أن الدور انتهى: الرسم انتهى، ولا موافقة معلّقة. وتحفظ الرد. فإن رفضت قاعدة البيانات الحفظ، يذهب الرد إلى ملف انتظار منفصل بدل أن يبقى في الذاكرة المؤقتة وحدها. وتسلّم أيضًا السؤال والجواب إلى الذاكرة. تكتب الذاكرة المحادثة بعد الدور مباشرة، ثم تستخرج الحقائق على مرحلتين: مرحلة سريعة قائمة على القواعد، ومرحلة قائمة على النموذج تُوضع في الطابور لتعمل لاحقًا. وكلتاهما تحمل وقت حدوث الدور، فلا تستطيع مرحلة متأخرة أن تكتب فوق شيء قلته بعده. وتأتي رموز الدور وتكلفته من سجل الاستدعاءات، فيُحتسب كل أجزاء الدور الذي توقف مؤقتًا.

أين: kazma_ui/turn_runtime.py (close_turn)، وkazma_core/memory/consolidator.py (remember_turn)، وkazma_ui/session_spool.py.

يراقب مشرف الأعمال الدور كأي عمل آخر. ودور المحادثة الذي لا خطوة له لعشر دقائق تصله بطاقة حادثة في المحادثة، بأزرار لإغلاقه أو لطلب تشخيصه من كاظمه (الأعمال الجارية). وفوق هذا كله، يراقب kazma_guard.py الخادم نفسه. فلا يعيد تشغيله إلا حين يتوقف عن الإجابة، وإعادة التحميل مع --when-idle تنتظر حتى لا يجري أي دور.