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

استكشاف الأخطاء وإصلاحها

إصلاحات عملية للمشكلات التي ستواجهها فعلًا: حدود المزوّدين، خصائص Windows/Docker، تزامن SQLite، الحالات الحدّية للتقطيع العربي، والفجوات المعروفة في قاعدة الشيفرة التي كشفها التدقيق. كل بند مُشار إليه بالمصدر.

الأخطاء متعددة المسارات (نفس الميزة، عدة مسارات كود): ابدأ بـ خريطة التشخيص — جدولا «العَرَض → أول الملفات» و «X مرتبط بـ Y». ثم عُد إلى هنا للحلول التشغيلية البديلة.


1. مشكلات المزوّد والنماذج اللغوية (LLM)

Section titled “1. مشكلات المزوّد والنماذج اللغوية (LLM)”

1.1 “Function not found” / 404 على نداءات الأدوات (NVIDIA NIM)

Section titled “1.1 “Function not found” / 404 على نداءات الأدوات (NVIDIA NIM)”

السبب: بعض المزوّدين (لا سيما NVIDIA NIM) يرفضون تعريفات الأدوات.

ما الذي تفعله كاظمه: يكتشف llm_provider.py:285-300 الشرط status_code == 404 and "function" in detail (و400/422 مع صياغة الأدوات/الدوال) ويُعيد المحاولة مرة واحدة دون أدوات. يظل المتصل يحصل على استجابة نصية.

الحل البديل إن استمر: عطّل الأدوات لذلك المزوّد، أو مرِّر عبر بروكسي متوافق مع OpenAI يترجم تعريفات الأدوات. لا تُزِل فرع الاحتياط أبدًا — إنه ثابت موثَّق.

1.1b خطأ 400 في مخطط الأدوات بعد تفعيل KAZMA_STRICT_TOOLS

Section titled “1.1b خطأ 400 في مخطط الأدوات بعد تفعيل KAZMA_STRICT_TOOLS”

السبب: function.strict: true في OpenAI (كل الخصائص مطلوبة، والاختيارية كـ T | null) ترفضه خوادم محلية كثيرة، وAnthropic Messages، وGemini.

الحل: اترك KAZMA_STRICT_TOOLS دون ضبط. المخططات المغلقة (additionalProperties: false) تبقى مفعّلة. الوسائط الإضافية المخترعة تُهمَل عند execute() كما هي. استخدم response_format فقط في النداءات التي تحتاج ردًّا بصيغة JSON، لا في كل دور دردشة.

1.1d الوكيل لا يكتب ملفات / لا يشغّل الصدفة

Section titled “1.1d الوكيل لا يكتب ملفات / لا يشغّل الصدفة”

السبب: وضع الخطة مفعّل (/plan on أو زر Plan). تُزال أدوات الكتابة/التنفيذ من المخطط حتى توافق.

الحل: /plan go (أو Proceed) لتنفيذ الخطة، أو /plan off للخروج دون تنفيذ. KAZMA_PLAN_MODE=0 يعطّل الميزة.

1.1e تُرسم قائمة تحقق الخطة ثم لا يأتي رد (حفظ الذاكرة / أي دور أدوات)

Section titled “1.1e تُرسم قائمة تحقق الخطة ثم لا يأتي رد (حفظ الذاكرة / أي دور أدوات)”

السبب: يطلب المشرف من النموذج أن يفتح أدوار الأدوات بسياج plan لمنصة العمل. بعض المزوّدين (DeepSeek v4 flash) عندها (1) يُصدِر السياج ويتوقف بلا `tool_calls`، أو (2) يلصق الجواب الحقيقي بعلامات الإغلاق (` Saved.`). لا يغلق CommonMark ذلك السياج أبدًا، فيبقى الجواب مخفيًا داخل كتلة كود. وإذا أسقط عميل SSE أيضًا بعد رموز الخطة، فلن يعرض اللسان إلا قائمة التحقق.

ما الذي تفعله كاظمه (2026-08-26): ملف plan_fence.py هو مصدر الحقيقة. يكمل المشرف تلقائيًا قفزةَ الخطة-فقط مرة واحدة (ليس في وضع /plan). يحفظ respond_node + ‏done.content في SSE/WS الحمولةَ غير الملصوقة. فقاعة الدردشة تجرّد السياج وتعيد رسم done.content بالاستبدال دائمًا.

الحل إن ما زلت تراه على عملية قديمة: حدّث اللسان (الرد موجود في الجلسة). أعِد تشغيل الخادم لالتقاط هذا الكود. /plan go فقط إذا كان زر Plan مفعّلًا.

1.1c كل أداة تعيد [hook] blocked

Section titled “1.1c كل أداة تعيد [hook] blocked”

السبب: أمر PreToolUse أو خطاف داخل العملية يرفض النداءات (agent.hooks.pre_tool، أو مهارة نادت register_pre_tool_hook).

الحل: اضبط KAZMA_TOOL_HOOKS=0 وأعِد التشغيل لتعطيل كل الخطافات. ثم أصلح agent.hooks.pre_tool أو أفرغه. الخطافات ليست HITL — لا تستطيع الموافقة تلقائيًا؛ والرفض قيد إضافي.

1.2 عدم تطابق المزوّد/النموذج (نقطة النهاية الخاطئة)

Section titled “1.2 عدم تطابق المزوّد/النموذج (نقطة النهاية الخاطئة)”

العَرَض: تذهب الطلبات إلى نقطة نهاية API خاطئة بعد تبديل النماذج.

السبب: تغيير النموذج دون تبديل المزوّد.

الحل: استخدم دائمًا set_active_model() (يبدّل المزوّد تلقائيًا عبر find_provider_for_model()) أو set_active_provider() — لا تضبط أحدهما دون الآخر أبدًا. يصحح get_client() تلقائيًا (model_registry.py:275-303) لكنه لا يحفظ تغيير المزوّد إلا عندما يكون model is None.

تحقق:

نافذة طرفيّة
kazma status # shows active provider/model

السبب (تاريخي): كان عميل OpenAI-compatible العام يرسل دائمًا Authorization: Bearer.

الآن: يمر مرور Anthropic عبر AnthropicProvider (/messages، x-api-key). لا ترسل نماذج Anthropic-native عبر LLMProvider العام — يجب أن يُبقي get_client() / find_provider_for_model() المزوّد والنموذج مقترنين (AGENTS.md §1).

1.4 معالجة تحديد المعدل (429)

Section titled “1.4 معالجة تحديد المعدل (429)”

يعيد كاظمه المحاولة عند 429 فعلًا بتراجع أُسّي + ‏Retry-After في LLMProvider.chat() وفي مسار /messages الأصلي لـ Anthropic. استنفادُ 429 يعطي LLMError(transient=True, kind=rate_limit_exhausted) — حلقة إعادة محاولة المشرف تحترم transient. إن ظللت تحرق الميزانية رغم ذلك:

  • اخفض التزامن (BoundedConcurrency، الافتراضي 5)، أو
  • ضع بروكسي تحديد معدل أمام المزوّد.

1.5 قاطع التكلفة لا يوقف الإنفاق الجامح

Section titled “1.5 قاطع التكلفة لا يوقف الإنفاق الجامح”

السبب (تاريخي): كان CostCircuitBreaker موجودًا كـ dataclass ولم يكن على الحلقة الحية.

الآن: يُنشأ لكل وكيل (agent_runner.py) ويُدار على المشرف: record_user_interaction() عند كل دور وارد، وshould_halt() قبل نداء LLM، وrecord_cost() بعده (graph_supervisor.py). الإيقاف يفرض RESPOND برسالة ميزانية ⚠️ — وهو لا يؤلّف جوابًا مزيفًا. اضبط KAZMA_MAX_COST / KAZMA_SILENCE_WINDOW أو الإعدادات → التكلفة.

1.6 ModelRegistry “not initialized” (RuntimeError)

Section titled “1.6 ModelRegistry “not initialized” (RuntimeError)”

العَرَض: ‏RuntimeError: ModelRegistry not initialized. Call initialize_model_registry() first. عند الاستيراد أو عند نداء get_model_registry().

السبب: يجب أن يعمل initialize_model_registry(config_store) مرة واحدة قبل أن يستخدم أي مستهلك السجلَّ. يُنشأ المفرد (model_registry.py) بإنشاء كسول.

الحل:

from kazma_core.config_store import get_config_store
from kazma_core.model_registry import initialize_model_registry
cs = get_config_store()
initialize_model_registry(cs)

في الاختبارات، استخدم fixture تلائي التفعيل (autouse) يعيد التهيئة لكل اختبار:

@pytest.fixture(autouse=True)
def _init_model_registry(tmp_path):
from kazma_core.config_store import ConfigStore
from kazma_core.model_registry import initialize_model_registry, reset_model_registry
db_path = str(tmp_path / "test_registry.db")
cs = ConfigStore(db_path=db_path) # isolated per-test store
initialize_model_registry(cs)
yield
reset_model_registry()

لا تنادِ reset_model_registry() في منتصف التشغيل إلا إذا أعدت التهيئة فورًا بعدها.

1.7 فشل اكتشاف النماذج / قائمة نماذج فارغة

Section titled “1.7 فشل اكتشاف النماذج / قائمة نماذج فارغة”

العَرَض: يعيد ModelRegistry.discover_models(provider_name) القيمة []، أو يكون GET /api/swarm/models فارغًا رغم وجود مزوّد مضبوط.

السبب: ليس لدى المزوّد base_url، ولا api_key (عندما تكون المصادقة مطلوبة)، أو غير مفعّل، أو لا يكشف نقطة نهاية متوافقة مع /models، أو أن فشل اكتشاف سابقًا مخزّن مؤقتًا في _discovered_models.

الحل:

from kazma_core.model_registry import get_model_registry
registry = get_model_registry()
print(registry.get_provider("openai")) # check base_url / api_key / enabled
print(registry.list_providers())
import asyncio
print(asyncio.run(registry.discover_models("openai"))) # explicit rediscovery

يسجّل الاكتشاف سبب الفشل — راجع سجلات الإقلاع.

1.8 الملف النشط يعيد قيمًا فارغة / افتراضية

Section titled “1.8 الملف النشط يعيد قيمًا فارغة / افتراضية”

العَرَض: يعيد get_active_profile() القيمة \{"provider": "custom", "base_url": "", "model": "", "api_key": ""\} رغم وجود إعدادات محفوظة.

السبب: لا مزوّد نشط مضبوط؛ السجل يرجع إلى مفاتيح llm.* القديمة، وهي أيضًا فارغة.

الحل:

registry.set_active_provider(
provider="deepseek",
base_url="https://api.deepseek.com/v1",
api_key="sk-...",
model="deepseek-chat",
)
# or, within the active provider only:
registry.set_active_model("deepseek-reasoner")

تحقق من الاستمرارية عبر get_config_store().get("registry.active_provider") / ...active_model.

1.9 الإعدادات لا تستمر بعد تبديل نموذج/مزوّد

Section titled “1.9 الإعدادات لا تستمر بعد تبديل نموذج/مزوّد”

العَرَض: تبدّل النموذج/المزوّد في الواجهة أو CLI، لكن الطلب التالي يستخدم القيمة القديمة.

السبب: استُخدمت نسخة/مسار قاعدة ConfigStore آخر مختلف للحفظ؛ أو تجاوز التعديل السجلَّ (فلم يُبطَل العميل المخزّن مؤقتًا)؛ أو أن عميلًا قديمًا ما زال قيد الاستخدام.

الحل:

  1. يجب أن تتشارك كل مسارات الكود المفردَ نفسه — get_config_store() (kazma-data/settings.db). لا تنشئ أبدًا ConfigStore() ثانيًا لنفس القاعدة (تنازع أقفال SQLite).
  2. أكّد القيم المخزنة: get_config_store().get_all() مقابل cs.export_yaml().
  3. عدّل عبر السجل (set_active_provider / set_active_model)، لا عبر cs.set() مباشرة على مفاتيح غير متصلة — السجل يملك الملف النشط وإبطال مخزن العميل المؤقت.
  4. لإرجاع مفتاح إلى قيمته الافتراضية في YAML: get_config_store().delete("registry.active_model"). ولإجراء إعادة تعيين كاملة: احذف kazma-data/settings.db (يفقد كل إعدادات التشغيل) وأعِد التشغيل.

1.10 “Model fallback: <provider> has no usable API key”

Section titled “1.10 “Model fallback: <provider> has no usable API key””

العَرَض: لافتة تحذير في واجهة الويب (مع زر Open Providers)، والرسالة نفسها على منصات الدردشة: يجيب كاظمه بنموذج مزوّد آخر غير الذي ضبطته. صيغة الـ failover تقرأ «Model failover: <model> failed, <backup> answered».

السبب: ليس لدى المزوّد المضبوط مفتاح يمكن لكاظمه استخدامه، فبدّل سجل النماذج إلى مزوّد لديه مفتاح. أو، مع تفعيل agent.nonstop.failover، ظل النموذج الأساسي يفشل وأجابت سلسلة الـ failover. حتى 2026-09-25 كان مفتاح المزوّد المحفوظ في الإعدادات مخزّنًا تحت مستأجر الطلب الذي حفظه، وعلى تثبيت فيه KAZMA_PRODUCTION=1 لم يستطع الإقلاع قراءته: كل إقلاع يبدّل المزوّدين بينما المفتاح موجود هناك. الآن تُخزَّن مفاتيح المزوّدين للتثبيت كله، والمفاتيح المحفوظة بالطريقة القديمة تُرقّى إلى نطاق التثبيت عند الإقلاع.

الحل: افتح الإعدادات → Providers & Connectors → LLM Providers، أدخِل المفتاح (أو أعِد إدخاله) واضغط Test. تختفي اللافتة عند أول طلب يستخدم المزوّد المضبوط، وتستلم منصات الدردشة رسالة «تم الحل». يعرض kazma doctor أي مزوّد سيستخدمه السجل.

ما دام الـ fallback قائمًا، تتكرر رسالة الدردشة مرتين على الأكثر يوميًا (والـ failover: كل 15 دقيقة). KAZMA_OPS_ALERTS=0 يكتم رسائل الدردشة؛ اللافتة تبقى.


محدَّث يوليو 2026 (بعد التحويل إلى V2) — يستخدم كاظمه الآن محرك V2 المعرفي (معتقدات ثنائية الزمن، استرجاع PPR) بوصفه رصة الذاكرة الوحيدة. أزيلت رصة ChromaDB / VectorMemory / ‏RRF رباعية الطبقات القديمة. البنود أدناه تعكس معمارية V2.

2.1 «يبدو أن وكيلي لا يتذكر شيئًا»

Section titled “2.1 «يبدو أن وكيلي لا يتذكر شيئًا»”

تعمل ذاكرة V2 بطريقتين:

  1. أدوات LLM — يستطيع النموذج نداء memory_search / memory_store في أي وقت. كلاهما يمر عبر V2: ‏recall() للقراءة وmutate_belief() للكتابة.
  2. حقن الضغط — عندما تبلغ المحادثة 80% من نافذة السياق، يسترجع CompactionEngine تلقائيًا أفضل 5 ذكريات ذات صلة عبر recall.search() في V2 ويحقنها في رسالة النظام الجديدة بوصفها ## Relevant Memories.

إن كانت الذكريات ما زالت لا تطفو إلى السطح:

  • يحتاج استرجاع V2 إلى الـ embedder المشترك (get_embedder()). تحقق من pip install -e ".[rag]" (sentence-transformers + sqlite-vec). بدونه يتراجع الاسترجاع إلى مطابقة كلمات مفتاحية عبر FTS5 فقط. وعلى Postgres، نفّذ أيضًا CREATE EXTENSION vector وإلا بقي البحث الكثيف على sqlite-vec / فارغًا (KAZMA_PGVECTOR=0 يفرض الوضع المحلي).
  • تحقق من /api/memory/v2/health — إن كان beliefs.active يساوي 0، فلم تُستخلص معتقدات بعد (الاستخلاص بعد الدور يعمل على خيط خلفي + طابور؛ امنحه بضعة أدوار).
  • تحقق من لوحة V2 في لوحة التحكم (/api/memory/v2/graph) — تؤكد أن رسم المعتقدات فيه محتوى.
  • وجّه النموذج (عبر system_prompt) إلى نداء memory_store استباقيًا للوقائع المهمة.

2.2 استرجاع V2 يعيد نتائج فارغة / مشكلات الـ embedder

Section titled “2.2 استرجاع V2 يعيد نتائج فارغة / مشكلات الـ embedder”

السبب: الحزمة الإضافية [rag] غير مثبتة، أو فشل تحميل الـ embedder.

ماذا يحدث: يلتقط recall() في V2 كل الفشل ويعيد RecallResult فارغًا — تقول memory_search إن البحث غير مكتمل (مطابقات الكلمات فقط)، ولا تقول أبدًا "No relevant memories found."، ويحصل الضغط على []. لا ينهار النظام أبدًا؛ لكنه بلا استرجاع دلالي (قد تُظهر مطابقة كلمات FTS5 نتائج مع ذلك).

الحل: ‏pip install -e ".[rag]". يُحمَّل الـ embedder (‏BAAI/bge-m3 محلي افتراضيًا) عند أول استخدام؛ ابحث في سجل الإقلاع عن [Memory] V2 embedder ready. إن كانت التضمينات البعيدة مضبوطة (memory.embedding.provider: openai-compatible)، فتحقق من مفتاح API + ‏base_url.

2.3 عدم تطابق أبعاد التضمين (شكلي)

Section titled “2.3 عدم تطابق أبعاد التضمين (شكلي)”

قد يصرّح kazma.yaml بـ storage.vector_dim: 1024، لكن النموذج الافتراضي (BAAI/bge-m3) بـ 1024 بُعدًا. هذه القيمة معلوماتية؛ يقرأ vector_engine.py في V2 البُعد الفعلي من الـ embedder وقت التشغيل. لا تعتمد على قيمة الإعداد في منطق الأبعاد.

2.4 أخطاء V1 الموثَّقة سابقًا (تاريخية)

Section titled “2.4 أخطاء V1 الموثَّقة سابقًا (تاريخية)”

أُصلحت هذه في إعادة إصلاح الذاكرة ليوليو 2026 وصارت بلا أثر (أزيل كود V1 في التحويل V1→V2):

  • خطأ دالة distance() في SQL → يستخدم V2 ‏vector_engine.py (sqlite-vec / numpy).
  • إيجابية كاذبة في _vec_available → يجري vector_engine.py في V2 اختبار دخان لـ vec_version().
  • الطبقة 1 من المحوّل رباعي الطبقات ميتة / انهيار المستدعين عند فك الطبقات → أزيل محوّل V1؛ يعيد recall.search() في V2 شكل list[dict] متسقًا.

3.1 أدوات الخطر تنفَّذ دون موافقة

Section titled “3.1 أدوات الخطر تنفَّذ دون موافقة”

الفحص 1 — هل بوابة الرسم مفعّلة؟ كل مواقع بناء الإنتاج تمرر hitl_config (انظر الأمن والسلامة §2.2). إن كتبت بناءً مخصصًا عبر create_supervisor_graph() دون hitl_config، فالبوابة خامدة.

الفحص 2 — هل الأداة في القائمة الصحيحة؟ هناك ثلاث قوائم:

  • مسار الرسم: kazma.yaml safety.hitl.require_approval_for.
  • ناقل السرب: _EXTENDED_DANGER (swarm/safety.py:23).
  • MCP: ‏classify_mcp_tool القائم على النقوش. الإضافة إلى واحدة لا تضيف إلى الأخريات.

الفحص 3 — هل allow_headless_danger=True مضبوط؟ هذا يعطّل الفشل المغلق في الوضع بلا واجهة/الاختبار. تأكد أنه False في الإنتاج.

3.2 إيقافات HITL لا تُستأنف أبدًا

Section titled “3.2 إيقافات HITL لا تُستأنف أبدًا”

السبب: نقطة نهاية الاستئناف هي POST /api/approve/\{thread_id\} في routes_direct/misc.py (وليست في app.py). تتطلب KAZMA_SECRET إن كان مضبوطًا، وتفرض الملكية (‏403 بين المستخدمين).

الحل: تأكد أن المستدعي للموافقة يملك حقول الهوية المطابقة والسر الصحيح.

3.3 مهام الخط تبقى بحالة «paused» بعد إعادة التشغيل

Section titled “3.3 مهام الخط تبقى بحالة «paused» بعد إعادة التشغيل”

السبب: يعيد restore_paused_tasks() تسليح مهلات الرفض التلقائي عند الإقلاع (checkpoint_manager.py:222-230). إن لم تصل الموافقة قط خلال checkpoint_timeout، تُرفض المهمة تلقائيًا.

الحل: وافق قبل انقضاء المهلة، أو ارفع checkpoint_timeout في البيانات التصويرية للمهمة (metadata).


تستخدم كل مخازن كاظمه PRAGMA busy_timeout=5000 + ‏WAL. إن ظللت ترى أخطاء أقفال رغم ذلك:

  • كاتب واحد في كل مرة. يسمح WAL بقرّاء متزامنين لكن كاتبًا واحدًا. معاملات الكتابة الطويلة تحجب غيرها حتى 5 ثوانٍ.
  • استخدم batch_set() للكتابات متعددة المفاتيح (ذرّية، معاملة واحدة) بدلًا من التكرار على set().
  • استخدم get_config_store() دائمًا — إنشاء ConfigStore() مباشرة يتجاوز المفرد وقد يفتح اتصالًا ثانيًا.
  • لا تشارك اتصالًا بين العمليات. كاظمه أحادي العملية؛ إن انشأقت عمالًا، فلكل منها اتصاله وسيتنازعون على ملف القاعدة نفسه.

4.2 تعذّر تهيئة تخزين الإعدادات

Section titled “4.2 تعذّر تهيئة تخزين الإعدادات”

إذا فشلت تهيئة SQLite أو PostgreSQL، يرفع get_config_store() خطأ عدم توفر، ويتوقف الإقلاع الإنتاجي قبل تشغيل العمال أو الأتمتة. أُزيل بديل الذاكرة القابل للكتابة السابق. افحص سجلات الإقلاع وأعد التخزين المُهيّأ إلى الخدمة؛ واتبع فشل حفظ الإعدادات قبل إعادة أي كتابة.


5.1 سلسلة الأوامر في PowerShell

Section titled “5.1 سلسلة الأوامر في PowerShell”

لا تستخدم أبدًا && أو || في PowerShell. استخدم ; وتحقق من $LASTEXITCODE (وفق AGENTS):

نافذة طرفيّة
& '.venv\Scripts\python.exe' -m pytest kazma-core/tests/ -v
if ($LASTEXITCODE -ne 0) { Write-Error "tests failed" }

5.2 طول المسار / المسارات غير ASCII

Section titled “5.2 طول المسار / المسارات غير ASCII”

مسار المستودع G:\GitHubRepos\kazma والمحتوى العربي في kazma.yaml/القوالب سليمان، لكن بعض أدوات Windows تتعثر مع المسارات الطويلة أو غير اللاتينية. إن صادفت FileNotFoundError في أدلة مؤقتة عميقة التداخل للاختبارات، فعّل المسارات الطويلة (HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled = 1).

يحتوي جذر المستودع على أدلة .pytest_tmp_* كثيرة (مخلّفات تشغيلات الاختبار). إنها فوضى يتجاهلها git؛ حذفها آمن: Remove-Item -Recurse -Force .pytest_tmp_*.


6.1 عدم تطابق مسار وحدة تخزين المتجهات

Section titled “6.1 عدم تطابق مسار وحدة تخزين المتجهات”

يقوم docker-compose.yml بتضمين kazma_vectors:/root/.kazma/vector_memory، لكن الحاوية تعمل بمستخدم kazma (الدليل الرئيسي /home/kazma). اضبط KAZMA_VECTOR_PATH=/app/kazma-data/vector_memory (بمحاذاة وحدة تخزين البيانات) لتجنب الكتابة إلى مسار غير مُضمَّن.

6.2 نفاد الذاكرة (OOM) مع حزم RAG الإضافية

Section titled “6.2 نفاد الذاكرة (OOM) مع حزم RAG الإضافية”

قد يتجاوز ChromaDB + sentence-transformers حد 512 ميبي. امنح حاوية الوكيل الرئيسي 1 جيبي على الأقل مع RAG (لا يأتي مع كاظمه أي بيان Kubernetes).

استخدم /api/gateway/status (كما يفعل docker-compose.yml) أو /health/live — وليس /api/v1/health، الذي كان تابعًا لواجهة Hub API (أُزيلت).


7.1 كيف يُطابَق النص العربي

Section titled “7.1 كيف يُطابَق النص العربي”

تطبّع مكتبة المعرفة العربية بالطريقة نفسها حين تفهرس النص وحين تبحث فيه (kazma_core/documents/arabic.py، fold_for_search): تُحذف الحركات والتطويل ومحارف التحكم في الاتجاه؛ وتُوحَّد صور الألف المهموزة والتاء المربوطة والألف المقصورة وحوامل الهمزة وصور الحروف الفارسية/الأردية؛ وتصير الأرقام العربية الهندية أرقامًا ASCII؛ وتُدمج المسافات المتتالية. فالكلمة المكتوبة بالحركات أو بدونها، وبالتطويل أو الهمزة أو بدونهما، تجد المقاطع نفسها. ويطبّع استرجاع الذاكرة كلمات السؤال وكلمات الذكرى بالطريقة نفسها حين يقيس مقدار ما تحمله الذكرى من السؤال (memory/query_terms.py)، ويقارن بينهما بالمعنى أيضًا.

لا شيء يردّ الكلمات العربية إلى جذورها: الجمع والمؤنث كلمتان مختلفتان في البحث بالكلمات. يعالج بحث الذاكرة الجموع البسيطة وأداة التعريف والسوابق أحادية الحرف (memory/query_terms.py)، ويجد بحثه بالمعنى الصيغ القريبة. أما في مكتبة المعرفة فابحث بالصيغة التي يستخدمها النص، أو أضف الصيغ الأخرى.


8. غرابات الإطار / البناء

Section titled “8. غرابات الإطار / البناء”

ثلاث سلاسل إصدارات مستقلة:

  • pyproject.toml: ‏0.3.0
  • kazma.yaml agent.version: ‏0.2.0
  • نص --help في CLI: ‏v0.2.0

إنها غير متزامنة. لا تعتمد على أي منها منفردة لتحديد «إصدار كاظمه».

8.2 models.router لا يستورد LiteLLM

Section titled “8.2 models.router لا يستورد LiteLLM”

قيمة models.router: kazma تسمية فقط. لا ينفّذ كاظمه import litellm أبدًا. لاستخدام بروكسي LiteLLM مع المزوّدين المتوافقين مع OpenAI، اضبط KAZMA_LITELLM_URL (أو llm.gateway.url). تبقى Anthropic/Azure/Bedrock/Gemini الأصلية وOllama/LM Studio المحلية اتصالًا مباشرًا. KAZMA_LITELLM=0 يعطّله. يمكنك أيضًا توجيه base_url لمزوّد واحد إلى http://host:4000/v1.

8.3 .env.example يذكر متغيرات بيئة غير مستخدمة

Section titled “8.3 .env.example يذكر متغيرات بيئة غير مستخدمة”

يظهر DEEPSEEK_API_KEY وANTHROPIC_API_KEY في .env.example لكن لا يقرؤهما أي كود. أدخِل مفاتيح هذين المزوّدين عبر قائمة المزوّدين في ConfigStore بدلًا من ذلك. لا تضيّع وقتًا في التساؤل لماذا لا يكون لضبطهما أي أثر.

8.4 mcp.servers[].trust: trusted يتخطى الموافقات

Section titled “8.4 mcp.servers[].trust: trusted يتخطى الموافقات”

القيمة trust: trusted على خادم MCP تتخطى بطاقة الموافقة لأدوات ذلك الخادم، باستثناء الأدوات المسماة كبيانات اعتماد؛ وفي الإنتاج (KAZMA_PRODUCTION=1) تُتجاهل ما لم يكن KAZMA_MCP_TRUSTED_IN_PROD=1. أبقِ القيمة الافتراضية approval_required ما لم تثق بكل أداة يعرضها الخادم. «درجات الثقة» بما يتجاوز ذلك ليست ميزة في الكود. (وصفت هذه الصفحة الإعداد بأنه بلا أثر حتى 2026-09-30.)

8.5 الأمران /undo و/edit مجرّد هيكل

Section titled “8.5 الأمران /undo و/edit مجرّد هيكل”

كلا الأمرين الشرطيين موجودان في نظام المساعدة لكنهما «غير منفَّذين بعد» صراحةً (slash_commands.py:257, 267). لا تعلن عنهما للمستخدمين.

8.6 UnifiedModelRegistry هو نفسه ModelRegistry

Section titled “8.6 UnifiedModelRegistry هو نفسه ModelRegistry”

الاسم البديل (model_registry.py:950) موجود للتوافق مع الوراء. إنهما الصنف نفسه.


عندما يكون ثمة خطأ ما، امضِ على هذه:

نافذة طرفيّة
# 1. Is the server up? Versions sane?
kazma status
# 2. Health
curl -s http://127.0.0.1:9090/health/details | jq
# 3. Active provider/model
curl -s http://127.0.0.1:9090/api/provider/active | jq
# 4. Gateway adapters
curl -s http://127.0.0.1:9090/api/gateway/status | jq
# 5. Swarm status + breaker states
curl -s http://127.0.0.1:9090/api/swarm/status | jq
curl -s http://127.0.0.1:9090/api/swarm/circuit-breakers | jq
# 6. Pending HITL approvals
curl -s http://127.0.0.1:9090/api/pending-approvals | jq

فعّل تسجيل JSON للحصول على تشخيصات مهيكلة:

logging:
level: DEBUG
format: json

أو فعّل مسجّلات التصحيح في الكود:

import logging
for name in ("kazma_core", "kazma_gateway", "kazma_ui"):
logging.getLogger(name).setLevel(logging.DEBUG)
  • إعدادات ConfigStore ← kazma-data/settings.db
  • TaskStore السرب ← kazma-data/swarm_tasks.db
  • جلسات البوابة ← kazma-data/sessions.db
  • نقاط تفتيش LangGraph ← kazma-data/checkpoints.db
  • مخزن المستندات ← kazma-data/document-store/ (documents.db بما فيه الفهرس والمهام وحجوزات الاستلام وسجل التدقيق، إضافة إلى الملفات المعنونة بمحتواها)؛ وفي تثبيت يعمل على Postgres تكون المهام، والفهرس افتراضيًا، جداول في Postgres ولا يبقى هنا إلا الملفات. الجاهزية: GET /api/documents/ops/readiness
  • تتبّع الطرفية ← KazmaTracer (backend="console") يكتب إلى stdout عبر kazma_core/tracing/
نافذة طرفيّة
sqlite3 kazma-data/swarm_tasks.db \
"SELECT id, type, status, workers, created_at FROM swarm_tasks ORDER BY created_at DESC LIMIT 10;"
sqlite3 kazma-data/swarm_tasks.db \
"SELECT worker, date, tasks_completed, tasks_failed, avg_latency FROM swarm_worker_metrics ORDER BY date DESC LIMIT 10;"
نافذة طرفيّة
nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits

على نظام بلا GPU من NVIDIA أو بلا مشغّل، يفشل هذا الأمر ويرجع kazma_core/telemetry.py إلى أصفار.

9.4 إعادة تعيين المفردات (اختبار أو استرداد)

Section titled “9.4 إعادة تعيين المفردات (اختبار أو استرداد)”
from kazma_core.model_registry import reset_model_registry
from kazma_core.swarm.engine import set_swarm_engine
from kazma_core.tracing import get_trace_store
import kazma_core.tracing as _tracing
reset_model_registry()
set_swarm_engine(None)
ts = get_trace_store()
ts._traces.clear(); ts._total_cost = 0.0; ts._total_tokens = 0
# or fully replace the global TraceStore:
_tracing._trace_store = TraceStore()

العَرَض: يعرض GET /api/gateway/status محوّل Telegram بحالة connected، لكن البوت لا يردّ وعمق الطابور في ارتفاع.

السبب: لم يُسجَّل معالج الرسائل (GatewayManager.on_message() لم يُنادَ قط)؛ مهمة استماع المحوّل انهارت وترك ردُّ اكتمال BaseAdapter.start() القيمةَ _running قديمةً؛ رمز بوت غير صالح/مفقود؛ ما زال webhook مسجلًا (getUpdates → 409)؛ allowed_users يرشّح المرسل خارجًا؛ أو أن المعالج يرمي استثناءً عند كل رسالة.

الحل:

  1. أكّد أن المعالج مسجَّل: gateway_manager.on_message(create_graph_handler(agent)).
  2. راجع سجلات المحوّل للتحقق من getMe — ينادي adapters/telegram.py على getMe عند الإقلاع ويضبط _running = False عند رمز سيئ.
  3. يُنادى deleteWebhook تلقائيًا في TelegramAdapter.listen() — تحقق أنه عمل.
  4. إن كان allowed_users غير فارغ، فلا تُعالَج إلا معرّفات مستخدمي Telegram تلك (TelegramAdapter.set_allowed_users([...])).
  5. افحص gateway.stats بحثًا عن handler_registered وqueue_depth.

10.2 أخطاء Telegram ‏401 / 403 / 409 / 400

Section titled “10.2 أخطاء Telegram ‏401 / 403 / 409 / 400”

السبب:

  • 401 → رمز البوت خاطئ/منتهٍ/ملغًى.
  • 403 → البوت ليس عضوًا في المجموعة/القناة، أو المستخدم حظره.
  • 409 على getUpdates → ما زال webhook مسجلًا.
  • 400 على sendMessage → خطأ تحليل Markdown من محارف غير مهروبة.

الحل:

نافذة طرفيّة
# validate the token directly
curl https://api.telegram.org/bot<TOKEN>/getMe
# clear a stale webhook
curl https://api.telegram.org/bot<TOKEN>/deleteWebhook

بالنسبة لـ 400 الصادر، يعيد المحوّل المحاولة تلقائيًا مرة واحدة دون parse_mode. إن ناديت sendMessage يدويًا، فاهرّب محارف Markdown الخاصة (_، *، `، [) أو اضبط parse_mode="".

بالنسبة لـ 401/403 من LLM، فالمشكلة في مفتاح المزوّد — حدّثه في الإعدادات → Models/Providers. يخطّط retry.py هذه إلى الرسالة الودية “The model request was rejected due to an invalid or missing API key.”

10.3 طابور ناقل البوابة ممتلئ / محوّل غير متصل

Section titled “10.3 طابور ناقل البوابة ممتلئ / محوّل غير متصل”

العَرَض: يبلغ GET /api/gateway/status أن queue_depth عند 100 (الـ maxsize الافتراضي)، أو أن محوّلًا بحالة offline؛ رسائل مُسقَطة مع asyncio.QueueFull.

السبب: المعالج بطيء/محجوب؛ أو مهمة listen() للمحوّل رمت استثناءً غير معالَج وخرجت؛ أو لا معالج مسجلًا.

الحل:

  1. افحص gateway.stats (handler_registered، queue_depth، running لكل محوّل).
  2. انقل العمل الثقيل بعيدًا عن مسار المستهلك. الافتراضي للطابور هو maxsize=100 (GatewayManager.__init__) — لا ترفعه إلا إذا حسّنت أيضًا إنتاجية المستهلك.
  3. إن كان محوّل ما offline، فاعثر على الاستثناء الأصلي في السجلات (رد اكتمال BaseAdapter في gateway.py يسجّله). أصلح السبب الجذري، ثم أعِد تشغيل البوابة.
  4. نادِ دائمًا GatewayManager.on_message(handler) قبل GatewayManager.start().

10.4 تتبّع رسالة عبر correlation_id

Section titled “10.4 تتبّع رسالة عبر correlation_id”

تحصل كل IncomingMessage على correlation_id عند الدخول — field(default_factory=lambda: f"cid-\{uuid.uuid4().hex[:12]\}") (gateway.py). يُنقل عبر الناقل لكنه لا يُحقن تلقائيًا في المسجّلات اللاحقة.

async def handler(msg: IncomingMessage):
logger.info("[%s] Processing message from %s", msg.correlation_id, msg.sender_id)
نافذة طرفيّة
grep "cid-abc123def456" /var/log/kazma.log

للتتبع إلى داخل الرسم/السرب، أضِفه إلى حالة الرسم أو إلى SwarmTask.metadata في معالجك.


11. مركز المزوّدين والموصلات (الواجهة)

Section titled “11. مركز المزوّدين والموصلات (الواجهة)”

11.1 المزوّد يعرض «down»/«degraded» / فشل اختبار الاتصال (Test Connection)

Section titled “11.1 المزوّد يعرض «down»/«degraded» / فشل اختبار الاتصال (Test Connection)”

العَرَض: بطاقة مزوّد في الإعدادات → Providers & Connectors تعرض down/degraded، أو تعيد Test Connection القيمة Cannot connect to &lt;base_url&gt; / Cannot connect to &lt;base_url&gt; (connection failed) / HTTP 401.

السبب: Base URL خاطئ/غير قابل للوصول؛ مفتاح API مفقود/منتهٍ/غير صالح؛ المزوّد معطّل؛ أو أن نقطة نهاية /models للمزوّد ليست متوافقة مع OpenAI. Cannot connect to &lt;base_url&gt; (connection failed) (سابقًا HTTP None: غير المفيد) تعني أن كل نقطة نهاية مرشحة رمت استثناءً — عادةً مضيف/منفذ خاطئ، أو أن الخادم يعمل في WSL لكن المزوّد المحلي (Ollama/LM Studio) يعمل على مضيف Windows: داخل WSL، ‏127.0.0.1 هو آلة WSL الافتراضية، لا Windows. وجّه Base URL للمزوّد إلى المضيف الذي يشغّل الخادم (عنوان بوابة WSL — ip route show default).

الحل: حرّر المزوّد، تحقق من Base URL، ألصق المفتاح الحالي، انقر Test Connection (الخلفية تضرب /models وتبلغ عن الكمون أو خطأ HTTP الدقيق). يظل زر Save معطّلًا حتى ينجح الاختبار. عند 401، أعِد توليد المفتاح من لوحة المزوّد. للخوادم المحلية (Ollama، LM Studio)، تأكد أن الخادم يعمل وأن الـ URL يحمل اللاحقة /v1 (مثل http://127.0.0.1:11434/v1).

11.2 فشل اختبار موصل المنصة (Telegram / Discord / Slack)

Section titled “11.2 فشل اختبار موصل المنصة (Telegram / Discord / Slack)”

السبب: الرمز غير محفوظ؛ الرمز ملغًى؛ سلاك يحتاج Bot Token (xoxb-...) لمحوّل Web API بالاستطلاع (لا Socket Mode)؛ ديسكورد يتوقع Authorization: Bot &lt;TOKEN&gt;.

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

11.3 عنصر نائب السر المقنّع يكتب فوق المفتاح الحقيقي

Section titled “11.3 عنصر نائب السر المقنّع يكتب فوق المفتاح الحقيقي”

العَرَض: تحرّر مزوّدًا، تترك حقل مفتاح API كـ ****XXXX، تحفظ، فيتوقف المزوّد عن المصادقة.

السبب: تحفظ الخلفية السر الموجود فقط عندما تتعرّف على القيمة بوصفها عنصر نائب مقنّعًا (*** أو محتويًا ****). الصيغة غير المتوقعة قد تُحفظ بوصفها المفتاح الحقيقي.

الحل: اترك القيمة المقنّعة دون تغيير للإبقاء على السر الموجود، أو أفرِغ الحقل وألصق السر الجديد كاملًا. إن راودك شك في أن العنصر النائب قد حُفظ، فأفرِغ + أعِد اللصق + اختبر + احفظ. تحقق:

from kazma_core.model_registry import get_model_registry
provider = get_model_registry().get_provider("openai")
print(provider.get("api_key", "")[:4]) # should NOT be "****"

11.4 سلوك الاختبار قبل الحفظ

Section titled “11.4 سلوك الاختبار قبل الحفظ”

يظل الحفظ معطّلًا لأي مزوّد/موصل حتى ينجح Test Connection (المدخلات الجديدة والتحريرات). للمدخلات القائمة، يملأ فتحُ النافذة السرَّ المقنّع مسبقًا ويعلم المدخل «مختبرًا»، فيمكنك الحفظ دون إعادة اختبار إن كان السر لم يتغير.


12. بحث الويب ومقاييس لوحة التحكم

Section titled “12. بحث الويب ومقاييس لوحة التحكم”

12.1 الصفحة الطويلة لا تعرض إلا البداية

Section titled “12.1 الصفحة الطويلة لا تعرض إلا البداية”

السبب: يعيد read_url نافذة (الافتراضي 16k). كان الرسم يحصر أيضًا أدوات البحث عند 4k حدًّا صارمًا؛ تستخدم أدوات البحث الآن KAZMA_TOOL_RESULT_RESEARCH_MAX_CHARS (الافتراضي 16k).

الحل: انتقل داخل الصفحة بـ offset / max_chars، أو read_url_to_file ثم digest_research_file / read_research_chunk. انظر بحث الويب.

12.2 البحث لا يعيد شيئًا / نتائج متذبذبة

Section titled “12.2 البحث لا يعيد شيئًا / نتائج متذبذبة”

السبب: حدود معدل DuckDuckGo؛ احتياط Bing HTML هشّ.

الحل: شغّل SearXNG واضبط KAZMA_SEARXNG_URL. لجلب الصفحات سياسة محلية فقط منفصلة؛ وتحتاج الخدمات المستضافة وضعًا صريحًا وقائمة سماح بالمزوّدين. راجع البحث على الويب.

12.3 جدار البوتات / استخلاص فارغ

Section titled “12.3 جدار البوتات / استخلاص فارغ”

السبب: تحدّي CDN أو هيكل SPA بجافاسكربت.

الحل: ثبّت Playwright (pip install -e ".[web]" وplaywright install chromium). تحتاج Jina/Firecrawl المستضافة وضع جلب صريحًا وقائمة سماح بالمزوّدين مع الاعتماد. لا يمكن فتح جميع المواقع تلقائيًا.

يمكن إعادة فتح زحف معرفة منقطع في صفحة المعرفة. يواصل الاستئناف العمل المعلق بالسياسة الأصلية، ويتخطى آثار الطلبات والفهرسة غير المؤكدة. تبقى إيصالات البيانات الوصفية وBFS والصفحات المكتملة بعد إعادة الاتصال؛ ويظل الاكتشاف الناقص جزئيًا بصورة ظاهرة. يعرض /kb status <library_id> وresearch_readiness(job_id=...) المهمة المحفوظة دون إعادة الجلب.

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

12.4 التكلفة الإجمالية / الرموز في لوحة التحكم تعرض $0 / 0 بعد دور دردشة

Section titled “12.4 التكلفة الإجمالية / الرموز في لوحة التحكم تعرض $0 / 0 بعد دور دردشة”

السبب (تاريخي): كانت API/WS ترسل سلاسل مثل "$0.0043" / "27,127" فأصبحت Number(...) في JS تساوي NaN. أُصلح إلى مقاييس رقمية + تحليل آمن.

ما زال صحيحًا: الإجماليات هي TraceStore محلية للعملية — إعادة التشغيل تصفّرها. ميزانية قاطع التكلفة منفصلة عن الفوترة الدائمة. «قاطع الدائرة» في لوحة التحكم هو قاطع التكلفة، لا قواطع عمال السرب. أعِد تحميل /dashboard تحديثًا قسريًا بعد الترقية.

أمر متوقع. استخدم دردشة اللغة الطبيعية أو /swarm research …. انظر بحث الويب والأسئلة الشائعة.


13.1 لوحة التحكم تتجمد / المقاييس تتوقف عن التحديث

Section titled “13.1 لوحة التحكم تتجمد / المقاييس تتوقف عن التحديث”

السبب: نداء متزامن في مسار التحديث كل ثانيتين يحجب حلقة أحداث Textual. ينادي MetricsDashboard._do_refresh() (kazma-tui/kazma_tui/dashboard.py) على TraceStore.recent() وMetricsCollector.get_all_metrics() وSwarmEngine._workers نداءً متزامنًا — أي حجب يجمّد الواجهة. استثناء يقع عند كل تحديث يترك المقاييس عالقة عند آخر قيمة سليمة لها.

الحل: راجع السجلات بحثًا عن Dashboard refresh failed؛ تأكد أن psutil مثبَّت وأن kazma-core قابل للاستيراد. لعزل مصدر مخصص حاجب، حقنه من الباني (MetricsDashboard(hardware_monitor=..., trace_store=..., ...)).

13.2 لوحة التحكم تعرض “N/A” في كل مكان

Section titled “13.2 لوحة التحكم تعرض “N/A” في كل مكان”

السبب: لوحة التحكم للقراءة فقط وترجع إلى N/A عند غياب أي مصدر: غياب psutil (يفشل استيراد HardwareMonitor)؛ فراغ TraceStore (‏RPM يساوي None)؛ عدم توفر MetricsCollector/SwarmEngine؛ أو تشغيل خارج حلقة أحداث.

الحل:

نافذة طرفيّة
uv pip install -e ".[tui]" # or: pip install textual psutil

تحقق أن المصادر تُستورد، ثم ولّد بعض نشاط التتبع (‏RPM يكون N/A عند الخمول).

السبب: يشغّل kazma_core/telemetry.py الأمر nvidia-smi عبر صدفة خارجية. إن لم يكن في PATH، أو كان المشغّل مفقودًا، أو انتهت مهلة العملية الفرعية، أو كان الـ GPU ليس من NVIDIA، يرجع إلى أصفار (سجل بمستوى التصحيح).

الحل:

نافذة طرفيّة
nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits

إن فشل ذلك، فلا تستطيع واجهة TUI عرض VRAM — ثبّت مشغّل NVIDIA / أضِف nvidia-smi إلى PATH. على الأنظمة غير العاملة بـ NVIDIA، القيمة N/A متوقعة (تدهور رشيق).

13.4 واجهة TUI تنهار عند الإقلاع (خطأ استيراد / Python < 3.11)

Section titled “13.4 واجهة TUI تنهار عند الإقلاع (خطأ استيراد / Python < 3.11)”

السبب: ‏textual غير مثبَّت؛ أو بايثون أقدم من 3.11؛ أو ModelRegistry غير مهيأ قبل تأليف ترويسة TUI (header.py ينادي get_model_registry())؛ أو فشل استيراد kazma-core.

الحل:

نافذة طرفيّة
uv pip install -e ".[tui]"
python --version # must be ≥ 3.11
from kazma_core.config_store import get_config_store
from kazma_core.model_registry import initialize_model_registry
from kazma_tui.app import main
initialize_model_registry(get_config_store()) # before the TUI reads the profile
main()

13. واجهة سطر الأوامر (CLI)

Section titled “13. واجهة سطر الأوامر (CLI)”

13.1 kazma.yaml يخالف الإعداد الجاري

Section titled “13.1 kazma.yaml يخالف الإعداد الجاري”

السبب: يتجاوز ConfigStore (config_store.py) ‏kazma.yaml وقت التشغيل. قاعدة SQLite ‏(kazma-data/settings.db) هي مصدر الحقيقة لأي مفتاح كُتب عبر الواجهة/CLI/الكود؛ ومتغيرات البيئة تتجاوز كليهما.

الحل:

from kazma_core.config_store import get_config_store
cs = get_config_store()
print(cs.get("llm.model"), cs.get("registry.active_model")) # active values
print(cs.export_yaml()) # YAML base
cs.delete("registry.active_model") # revert one key to YAML default

لإعادة تعيين كاملة: rm kazma-data/settings.db (تفقد كل إعدادات التشغيل) وأعِد التشغيل.

13.2 الأمر kazma غير موجود / نقطة الدخول مفقودة

Section titled “13.2 الأمر kazma غير موجود / نقطة الدخول مفقودة”

السبب: غير مثبَّت، أو مثبَّت في venv غير مفعّل؛ نقطة دخول pyproject.toml (kazma = "kazma_cli.main:main") لم تُوصَّل (وضع قابل للتحرير غير متوافق)؛ على Windows السكربت ليس على PATH.

الحل:

نافذة طرفيّة
# Kazma is installed but the command is missing: reinstall its packages, keeping your extras
python -m kazma_cli update --reinstall -y
# Not installed in this venv: from the install folder, with Kazma stopped (adds packages, removes none)
uv pip install -e ".[rag,tui]" # put the extras you use in the brackets
which kazma && kazma --help # PowerShell: Get-Command kazma
# fallback if the entry point won't work:
python -m kazma_cli --help

13.3 الإكمال بالتاب في الصدفة

Section titled “13.3 الإكمال بالتاب في الصدفة”

السبب: سكربت الإكمال غير مثبَّت للصدفة النشطة؛ --list-models/--list-providers يحتاجان ModelRegistry (يرجعان إلى احتياط إن كان غير مهيأ)؛ fpath في zsh / مصدر bash-PowerShell مفقود.

الحل:

نافذة طرفيّة
kazma completion install {bash|zsh|powershell}
kazma completion --list-models # verify dynamic lists; init registry first if this errors
kazma completion --list-providers

أعِد تشغيل الصدفة (أو نفّذ المصدر بالمسار المطبوع) بعد التثبيت.

ملفات النماذج (profiles): ‏save_model_profile(name, profile) وget_model_profile(name) وlist_model_profiles() دوال سجل صالحة (model_registry.py) للقطات المسمّاة \{provider, base_url, model, api_key\}. لاحظ: تُخزَّن الـ profiles تحت models.saved.\{name\} في ConfigStore — لا يوزّعها أي عامل.


14.1 OutputValidator يرفض خطة العامل

Section titled “14.1 OutputValidator يرفض خطة العامل”

السبب: حملت حمولة الإرسال validation_schema (مخطط JSON أو نموذج Pydantic) في metadata، ولم يطابقه خرج العامل. يرفض OutputValidator (swarm/reliability.py) قبل قبول النتيجة.

الحل:

  1. افحص validation_schema في حمولتك وحاذِ توجيه العامل معها.
  2. تأكد أن العامل يعيد JSON صالحًا دون أسوار Markdown (يُحلَّل JSON المتسلسل نصًّا).
  3. أزِل validation_schema من الحمولة إن لم يكن التحقق لازمًا.

14.2 خطأ عامل / مهلة / قاطع دائرة مفتوح

Section titled “14.2 خطأ عامل / مهلة / قاطع دائرة مفتوح”

السبب: فشل نداء LLM للعامل؛ أو تجاوزت المهمة timeout (الافتراضي 300 ثانية، swarm/worker.py)؛ أو أن قاطع الدائرة (swarm/reliability.py) قد فُتح بعد فشل متكرر.

الحل:

نافذة طرفيّة
kazma swarm circuit-breaker worker-1 # inspect
kazma swarm circuit-breaker worker-1 --reset # reset once the root cause is fixed
curl -X POST http://localhost:9090/api/swarm/workers/worker-1/circuit-breaker/reset

ارفع مهلة المهمة الواحدة للأعمال الطويلة فعلًا: \{"workers": ["worker-1"], "task": "...", "timeout": 600\}.

14.3 المهمة لا تظهر في المهام النشطة (Active Tasks)

Section titled “14.3 المهمة لا تظهر في المهام النشطة (Active Tasks)”

السبب: ناقل SSE غير موصول بالمحرك. تسجّل لوحة السرب ناقلها لدى SwarmService ‏(kazma-ui/kazma_ui/swarm_panel/__init__.py)، ويوصله SwarmService.resolve_engine() ‏(kazma_ui/services.py) بأي محرك يحلّه، ومنه محرك يُنشأ لاحقًا؛ ويُسجَّل فشل التوصيل على مستوى DEBUG ‏(wire_engine_events failed during resolve_engine). أو أن الإرسال لم يعِد task_id؛ أو خطأ JS أمامي في dispatchTask() في swarm.js.

الحل:

  1. أكّد أن wire_engine_events() قد عمل وأن المحرك حُصل عليه بعد توفر ناقل SSE.
  2. تحقق من استجابة الإرسال عن task_id:
    نافذة طرفيّة
    curl -X POST http://localhost:9090/api/swarm/dispatch -H "Content-Type: application/json" \
    -d '{"workers":["worker-1"],"task":"test"}'
  3. افتح طرفية المتصفح لرؤية أخطاء swarm.js؛ وأكّد أن تيار SSE يستجيب:
    نافذة طرفيّة
    curl -N http://localhost:9090/api/swarm/tasks/&lt;task_id&gt;/stream

14.4 لوحة النتائج فارغة / نافذة تفاصيل المهمة فارغة

Section titled “14.4 لوحة النتائج فارغة / نافذة تفاصيل المهمة فارغة”

السبب: يعشّش SwarmTask.to_dict() حقول النتيجة تحت result، لكن الواجهة تتوقعها في المستوى الأعلى — ‏_flatten_swarm_task() في swarm_panel/routes_tasks.py هو الجسر. إن فوّت حقلًا، تعرض الواجهة لا شيء. أو أن عنصر النافذة مفقود من القالب / تقرأ viewTaskDetail() المفتاح الخاطئ.

الحل:

نافذة طرفيّة
curl http://localhost:9090/api/swarm/tasks/&lt;task_id&gt;

ينبغي أن تحمل الاستجابة task_id وstatus وworker_results وaggregated_output وsynthesized_output وduration_seconds وtotal_cost وtotal_tokens في المستوى الأعلى. إن نقص حقل جديد، فرَقِّه من قاموس result المتعشّش في _flatten_swarm_task(). أكّد وجود عنصر task-detail-modal في templates/swarm.html وأن renderTaskDetailHTML() في swarm.js يقرأ task.worker_results / task.individual_opinions / task.synthesized_output.

14.5 فقدان سجل المهام عند إعادة التشغيل

Section titled “14.5 فقدان سجل المهام عند إعادة التشغيل”

السبب: أُنشئ SwarmEngine دون TaskStore مشترك، فلا تعيش المهام إلا في الذاكرة وتُفقد عند إعادة التشغيل. يكتب TaskStore الافتراضي إلى kazma-data/swarm_tasks.db.

الحل:

from kazma_core.swarm.engine import get_swarm_engine
engine = get_swarm_engine()
print(engine.task_store) # must not be None
نافذة طرفيّة
ls -la kazma-data/swarm_tasks.db
sqlite3 kazma-data/swarm_tasks.db ".tables"

إن أنشأت SwarmEngine يدويًا، فمرِّر دائمًا TaskStore نفسه:

from kazma_core.swarm.engine import SwarmEngine
from kazma_core.swarm.config import SwarmConfig
from kazma_core.swarm.task_store import TaskStore
engine = SwarmEngine(SwarmConfig(enabled=True, workers=[]), task_store=TaskStore())

14.6 نقطة تفتيش HITL للخط مفقودة (swarm/pipeline)

Section titled “14.6 نقطة تفتيش HITL للخط مفقودة (swarm/pipeline)”

آليتا HITL، لا تخلط بينهما. هذا القسم عن نقاط تفتيش swarm/pipeline (POST /api/swarm/tasks/\{id\}/approve|reject). أما بوابة موافقة نداءات أدوات الوكيل فهي نقطة نهاية مختلفة — POST /api/approve/\{thread_id\} (routes_direct/misc.py) — وتغطى في §3.2.

العَرَض: مهمة خط ينبغي أن تتوقف عند نقطة تفتيش، لكن لا تظهر بطاقة HITL، أو أن الموافقة/الرفض لا يفعلان شيئًا.

السبب: لم تُرسَل المهمة بـ metadata.hitl_checkpoints (فهارس خطوات تبدأ من 1 تحدث عندها الوقفة)؛ أو لم يُوصَل ناقل SSE فلم يصل حدث checkpoint إلى الواجهة؛ أو لم يُستعد HITLCheckpointHandler من TaskStore بعد إعادة التشغيل (يجب أن يعمل SwarmEngine.restore_paused_tasks() عند الإقلاع)؛ أو أن الموافقة/الرفض يستهدفان task_id الخاطئ.

الحل:

payload = {
"workers": ["worker-1", "worker-2"],
"task": "...",
"type": "pipeline",
"metadata": {"hitl_checkpoints": [1]}, # pause before step 1
}
نافذة طرفيّة
curl -X POST http://localhost:9090/api/swarm/tasks/&lt;task_id&gt;/approve
curl -X POST http://localhost:9090/api/swarm/tasks/&lt;task_id&gt;/reject

تأكد أن restore_paused_tasks() يعمل عند الإقلاع (وإلا تُرفض المهام المتوقفة تلقائيًا عند checkpoint_timeout — انظر §3.3).


15. الربط الإنتاجي والمصادقة (v0.9+)

Section titled “15. الربط الإنتاجي والمصادقة (v0.9+)”

العَرَض: يعرض Edge/Chrome رسالة «تعذّر الوصول إلى هذه الصفحة» / ‏ERR_CONNECTION_RESET على المنفذ 9090. يفشل curl الخاص بفحص الصحة أيضًا. قد تظن أن كاظمه قد تعطّلت بعد سحبٍ للتحديثات.

السبب (شائع): IP Helper / ‏portproxy في Windows ‏(WSL2، Docker Desktop، Hyper-V) يستمع على 127.0.0.1:9090 ويوجّه إلى IP لـ WSL ميت. هذا ليس عملية كاظمه Python. للتأكيد:

نافذة طرفيّة
netsh interface portproxy show all
# typical bad row:
# 127.0.0.1 9090 → 172.x.x.x 9090
Get-NetTCPConnection -LocalPort 9090 -State Listen |
Select-Object OwningProcess
# if OwningProcess is svchost (iphlpsvc), Kazma is not serving that port

الحل:

نافذة طرفيّة
# Easiest: run Kazma on a free port
kazma serve 9091
# open http://127.0.0.1:9091/
# Optional: remove stale proxy (Admin PowerShell) if you own that rule:
# netsh interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=9090

تحقق من كاظمه (لا من البروكسي):

نافذة طرفيّة
curl http://127.0.0.1:9091/health
# expect JSON with "status":"ok"

15.1 الخادم لا يبدأ على ربط عام دون سر

Section titled “15.1 الخادم لا يبدأ على ربط عام دون سر”

السبب: يرفض CLI/serve الربط خارج loopback عند غياب KAZMA_SECRET، أو يرفض السر الافتراضي التاريخي السيئ المعروف.

الحل:

نافذة طرفيّة
# set a strong secret, then:
export KAZMA_SECRET='…' # PowerShell: $env:KAZMA_SECRET='…'
export KAZMA_HOST=0.0.0.0
kazma serve 9090

المنفذ المحلي الافتراضي هو 9090 (وليس 8000). فضّل loopback لمشغّل واحد: KAZMA_HOST=127.0.0.1.

15.2 YOLO / أدوات الخطر في الإنتاج

Section titled “15.2 YOLO / أدوات الخطر في الإنتاج”

مع KAZMA_PRODUCTION=1، يُحجب YOLO حجبًا صارمًا ما لم يُضبط KAZMA_ALLOW_YOLO=1 (تجنّبه في الإنتاج الحقيقي). NullBus يفشل مغلقًا. انظر قائمة الإنتاج.

15.3 الـ API يعيد 401 عند كل نداء /api/*

Section titled “15.3 الـ API يعيد 401 عند كل نداء /api/*”

السبب: رفض افتراضي للمصادقة عند وجود سر مضبوط؛ أو كوكي/جلسة مفقودة؛ أو ترويسة سر خاطئة.

الحل: لِج عبر /login، وأرسل كوكي الجلسة، أو استخدم ترويسة السر الموثَّقة لأتمتة المشغّل الواحد. المسارات المفتوحة: /health، /health/live، /health/ready.


الدليل الكامل: تكامل البريد.

16.1 Google: “has not completed the Google verification process” / access_denied

Section titled “16.1 Google: “has not completed the Google verification process” / access_denied”

السبب: تطبيق موافقة OAuth في وضع Testing؛ لا يستطيع تسجيل الدخول إلا المستخدمون الاختباريون المدرَجون.

الحل: Cloud Console → شاشة موافقة OAuth → Test users → أضِف بريدك في Gmail. واصل متجاوزًا تحذير التطبيق غير الموثَّق (أمر متوقع للاستضافة الذاتية).

16.2 Gmail API ‏403 insufficient authentication scopes / insufficientPermissions

Section titled “16.2 Gmail API ‏403 insufficient authentication scopes / insufficientPermissions”

السبب: يحمل الرمز نطاقَي profile/email فقط — لم تُمنَح نطاقات بريد Gmail (أو لم تُدرَج على شاشة الموافقة).

الحل: فعّل Gmail API. شاشة الموافقة → النطاقات → أضِف https://www.googleapis.com/auth/gmail.modify و…/gmail.send. الإعدادات → البريد → Disconnect → Connect with Google → وافق على وصول Gmail (وليس «الاطلاع على عنوان بريدك الإلكتروني» فقط).

16.3 IMAP/POP يرفض كلمة مرور Gmail

Section titled “16.3 IMAP/POP يرفض كلمة مرور Gmail”

السبب: لا تقبل Google كلمات مرور الحساب العادية لـ IMAP/POP.

الحل: استخدم كلمة مرور تطبيق من Google (يتطلب 2FA) أو فضّل OAuth.

16.4 فشل IMAP/POP لمايكروسوفت على M365

Section titled “16.4 فشل IMAP/POP لمايكروسوفت على M365”

السبب: كثير من المستأجرين يعطّلون المصادقة الأساسية.

الحل: استخدم Microsoft Graph OAuth (الإعدادات → البريد → OAuth).


العَرَض: تعيد عملية حفظ الإعدادات HTTP 503 مع code: config_store_unavailable، أو يتعذر بدء الخادم لأن تخزين الإعدادات غير متاح. هذا فشل في التحقق من الحفظ الدائم، وليس حفظًا ناجحًا في ذاكرة مؤقتة.

  1. افحص خلفية التخزين المُهيّأة ونقطة فحص الجاهزية /health/ready. في PostgreSQL، أعد خدمة قاعدة البيانات واتصالها. في SQLite، افحص أذونات الوصول والمساحة الحرة وأقفال الكتابة المتنافسة. لا تبدّل الخلفيات ولا تحذف قاعدة البيانات لتجاوز الخطأ.
  2. اترك الحارس المُدار يتعافى من فشل الإقلاع. إذا لزمت إعادة تحميل بعد استعادة التخزين، استخدم الحارس مع --reload --when-idle كما يشرح النشر؛ ولا تبدأ خادمًا ثانيًا.
  3. أعد تحميل الإعدادات وقارن قيمها الحالية بالتغييرات المقصودة قبل المحاولة. قد يُفقد الإقرار بعد كتابة مثبتة؛ وإعادة كل طلب فاشل تلقائيًا قد تكرر إجراءً.

يتضمن الرد Retry-After: 5، لكن الواجهة لا تعيد إرسال الكتابة تلقائيًا. لا يُؤكَّد الحفظ إلا بعد قبول التخزين الدائم له. انظر الإعدادات ودليل المشغّل.

تنبيهات البحث والنتائج الغائبة والسعة

Section titled “تنبيهات البحث والنتائج الغائبة والسعة”
العرضما تفحصهالخطوة التالية
انتهى البحث دون تنبيه اكتمالالإعدادات → النظام → جلب الويب → قراءة إعدادات التنبيهات؛ يلزم تفعيل المراقبة والاكتمالافتح التنفيذ المحفوظ. يبقى السجل المكتمل القديم صامتًا في أول إقلاع للمراقب؛ وتحتفظ عمليات البحث العادية برد المحادثة. ولا يُنبَّه عن crawl_site أو run_research_pipeline شغّله الوكيل في دوره؛ فنتيجته في إجابة الوكيل.
تحذير غياب تقدم مرصودالمرحلة المحفوظة وعدد المصادر والآثار الدائمة؛ النبضة وحدها ليست تقدمًاافحص قبل الإلغاء. لا يفشل التحذير العمل أو يعيد محاولته؛ ويزيله التقدم المستأنف.
تعذر قائمة النتائج أو انقطع البث الحيتحذير الصفحة الدائم وحالة الجلسة أو المهمة المحفوظةأعد الاتصال وحمّل الحالة؛ لا تستنتج خلو النتائج أو النجاح من قراءة فاشلة.
إشعار خارجي مطلوب أو فاشل أو غير مؤكدإيصال الإشعار ومسارات التشغيل المضبوطةقبول المنصة وحده يعني التسليم. افحص المسار؛ لا تُعاد الإرسالات غير المؤكدة تلقائيًا.
رصيد قديم أو مجهول أو فشل مزوّدالحالة المحفوظة ورمز الاستجابة الفعلي وآخر رصد للرصيديحصل تحديث صريح مسموح على رصيد مدعوم أحدث؛ حصص الطلبات المحلية ليست رصيدًا مفوترًا.
رفض جلسة خلفية جديدة لسعة السجلالسجل المشترك، بما فيه بحث المحادثة القديم؛ 256 صفًا/128MiBراجع وصدّر ثم احذف السجل المنتهي عمدًا لتحرير السعة. لا تحررها الأرشفة وحدها؛ ولا يحدث حذف تلقائي.
مراقبة البحث والزحف غير متاحةنص التنبيه نفسه يذكر السبب والمدة؛ سجلات الخادم وتخزين الإعداداتلا يُرسل التنبيه إلا بعد أن يتوقف المراقب عن العمل 5 دقائق (إعادة تشغيل قاعدة البيانات أو Docker تنتهي قبل ذلك)، وتتبعه رسالة “عادت المراقبة” حين يعمل من جديد. ويُظهر الجرس الفحص الفائت فورًا. أصلح التخزين أو عطل المراقب.

راجع البحث على الويب لنطاق الجلب المحلي أولًا والاستئناف الصريح وحدود المتصفح على المنصات.

يوحّد هذا الملف التدقيقات مع دليل المشغّل السابق (archive/docs-loose/TROUBLESHOOTING.md — دُمج في §1.6–1.9 و§9–14). الأمور التي يجب الحذر منها:

  1. الذاكرة اختيارية (opt-in) (§2.1) — لا تفترض الاسترجاع.
  2. ثلاث قوائم HITL (§3.2) — إضافة أداة خطر في مكان واحد لا يكفي.
  3. KAZMA_SECRET يبوّب مصادقة الموافقة (§3.2) — اضبطه دائمًا.
  4. المنفذ الافتراضي 9090 (§15.1) — قد تذكر عينات قديمة 8000.
  5. لا معالجة لـ 429 (§1.4) — بروكسي أو خنق من الخارج.
  6. آليتا HITL (§3.2 مقابل §14.6) — /api/approve/{thread_id} مقابل موافقة مهمة السرب.
  7. get_config_store() دائمًا (§4.1، §1.9) — لا تنشئ أبدًا ConfigStore() للقاعدة المشتركة.