تخطَّ إلى المحتوى

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

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


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 مع لغة الأدوات/الدوال) ويُعيد المحاولة مرة واحدة بدون أدوات. لا يزال المتصل يحصل على استجابة نصية.

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

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.

التحقق:

Terminal window
kazma status # shows active provider/model

1.3 عدم تطابق ترويسة مصادقة Anthropic

Section titled “1.3 عدم تطابق ترويسة مصادقة Anthropic”

السبب: يُعلِن الإعداد المسبق لـ Anthropic عن auth_header: x-api-key، لكن LLMProvider.chat() يُرسِل دائمًا Authorization: Bearer (llm_provider.py:171-172). ترويسة الإعداد المسبق لا تسري إلا أثناء discover_models().

الإصلاح: وجّه Anthropic عبر وكيل (proxy) متوافق مع OpenAI، أو وسّع LLMProvider ليحترم auth_header الخاص بالإعداد المسبق للدردشة.

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

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

لا تمتلك كاظمة أي تراجع خلفي (backoff) لـ 429. لا تُعيد طبقة إعادة المحاولة (retry.py:107-109) محاولة أخطاء 4xx صراحةً. إذا وصلت إلى حدود المعدّل، فإمّا:

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

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

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

السبب: CostCircuitBreaker (الافتراضي 0.50$، صمت 5 دقائق) هو dataclass مستقل — غير موصول تلقائيًا بـ chat(). يجب على طبقة الوكيل استدعاء record_cost / record_user_interaction / should_halt.

الإصلاح: صِل قاطع الدائرة في حلقة الوكيل لديك، أو اضبط KAZMA_MAX_COST / KAZMA_SILENCE_WINDOW وشغّله صراحةً.

1.6 ModelRegistry “غير مهيّأ” (RuntimeError)

Section titled “1.6 ModelRegistry “غير مهيّأ” (RuntimeError)”

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

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

الإصلاح:

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، لكن الطلب التالي يستخدم القيمة القديمة.

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

الإصلاح:

  1. يجب أن تتشارك جميع مسارات الكود المُفرد (singleton) — 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 (يفقد جميع الإعدادات أثناء التشغيل) ثم أعد التشغيل.

2.1 “يبدو أن وكيلي لا يتذكّر أي شيء”

Section titled “2.1 “يبدو أن وكيلي لا يتذكّر أي شيء””

السبب الجذري (الأرجح): استرجاع الذاكرة ليس تلقائيًا. يسترجع وكيل الدردشة فقط عندما يستدعي النموذج اللغوي memory_search طوعًا. لا يوجد حقن للسياق المسترجَع في الموجّه (prompt)، ولا دمج من قصير الأمد إلى دائم. انظر الذاكرة وRAG ← الحالة الصادقة.

الحلول البديلة:

  • وجّه النموذج (عبر system_prompt) لاستدعاء memory_search للاستعلامات ذات الصلة وmemory_store للحقائق المهمة.
  • بالنسبة للاسترجاع التلقائي أثناء المحادثات الطويلة، انتبه إلى أن خطوة استرجاع الذاكرة في عملية الدمج (compaction) هي لا-عملية (no-op) في التوصيل الافتراضي (agent_runner.py:162-166 لا يمرّر memory_store إلى create_authority). يعمل فقط التلخيص عبر النموذج اللغوي.

2.2 أخطاء distance(embedding, ?) من search_backend.py

Section titled “2.2 أخطاء distance(embedding, ?) من search_backend.py”

السبب: يستدعي _vector_search (search_backend.py:343,354) الدالة distance(...)، وهي ليست دالة صالحة في sqlite-vec. يُلقي المسار استثناءً ويُرجِع [] من كتلة except.

لماذا على الأرجح لم ترها: لا يمرّر المستدعون semantic_search=True مع تضمين (embedding). كما أن SQLiteMemoryBackend (وكيل self.memory) لا يُستعلم عنه أثناء استرجاع الدردشة على أي حال.

2.3 sqlite-vec “غير محمَّل” رغم تثبيته

Section titled “2.3 sqlite-vec “غير محمَّل” رغم تثبيته”

السبب: يُشغّل search_backend.py:55-60 الاستعلام SELECT sqlite_version() (ينجح دائمًا) ولا يستدعي load_extension قط، لذا فـ _vec_available غير موثوق. النمط الصحيح (المُستخدَم في swarm/memory/sqlite_vec.py:73-89) هو conn.load_extension("vec0") + تحقّق عبر SELECT vec_version().

2.4 عدم تطابق أبعاد التضمين (embedding)

Section titled “2.4 عدم تطابق أبعاد التضمين (embedding)”

يُعلِن kazma.yaml عن storage.vector_dim: 1536، لكن النموذج الفعلي (all-MiniLM-L6-v2) 384-أبعاد. يستخدم مخزن sqlite-vec رباعي الطبقات FLOAT[384] بشكل صحيح. لا تعتمد على قيمة yaml لمنطق الأبعاد.

2.5 استرجاع المستندات الطويلة بشكل سيّئ

Section titled “2.5 استرجاع المستندات الطويلة بشكل سيّئ”

السبب: لا توجد استراتيجية تقسيم (chunking). كل استدعاء memory_store يُضمِّن مستندًا كاملًا واحدًا.

الإصلاح: قسِّم النص الطويل مسبقًا في مهارتك/أداتك قبل استدعاء memory_store.


3. مشكلات الموافقة البشرية في الحلقة (HITL) / السلامة

Section titled “3. مشكلات الموافقة البشرية في الحلقة (HITL) / السلامة”

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

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

التحقق 1 — هل بوابة الرسم البياني (graph) نشطة؟ تمرّ جميع مواقع بناء الإنتاج بـ 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 مضبوط؟ ذلك يُعطّل وضع الفشل المغلق (fail-closed) في الوضع بلا واجهة (headless)/الاختبار. تأكد أنه False في الإنتاج.

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

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

السبب: نقطة نهاية الاستئناف هي POST /api/approve/{thread_id} في routes_direct.py:454 (وليست app.py). تتطلّب KAZMA_SECRET إذا كان مضبوطًا، وتُعمِل الملكية (403 بين المستخدمين المختلفين).

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

3.3 تبقى مهام pipeline “متوقّفة مؤقتًا” بعد إعادة التشغيل

Section titled “3.3 تبقى مهام pipeline “متوقّفة مؤقتًا” بعد إعادة التشغيل”

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

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


4.1 “database is locked” (قفل قاعدة البيانات)

Section titled “4.1 “database is locked” (قفل قاعدة البيانات)”

جميع مخازن كاظمة تستخدم PRAGMA busy_timeout=5000 + تسجيل الكتابة المسبقة (WAL). إذا استمررت في رؤية أخطاء القفل:

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

4.2 الاحتياطي في الذاكرة نشط بصمت

Section titled “4.2 الاحتياطي في الذاكرة نشط بصمت”

إذا فشلت تهيئة SQLite، يُرجِع get_config_store() مخزن _InMemoryStore (إخلاء بـ TTL، ساعة واحدة، 10 آلاف إدخال). حينها لا تصمد الإعدادات عبر إعادة التشغيل. تحقّق من سجلّات بدء التشغيل بحثًا عن أخطاء تهيئة SQLite.


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

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

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

Terminal window
& '.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 تنهار مع المسارات الطويلة أو غير ASCII. إذا واجهت FileNotFoundError على أدلّة مؤقتة عميقة للاختبارات، فعّل المسارات الطويلة (HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled = 1).

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


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

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

يُحمِّل 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 ميبي. حدّ 512Mi في ملف K8s أصغر من اللازم للوكيل الرئيسي مع RAG. استخدم ما لا يقل عن 1 جيبي للوكيل الرئيسي في الحاوية.

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


7. الحالات الحدّية للتقطيع العربي

Section titled “7. الحالات الحدّية للتقطيع العربي”

7.1 قواعد الهمزة المتعارضة

Section titled “7.1 قواعد الهمزة المتعارضة”

يُطبَّع ؤ وئ بواسطة قاعدتين متداخلتين في arabic_tokenizer.py (تطبيع Yeh عند الأسطر 220-232 وقواعد Waw/Ya-Hamza عند الأسطر 154-157). هذا تعارض بسيط معروف؛ في الممارسة القاعدة اللاحقة هي الراجحة. إذا رأيت نتائج بحث غير متّسقة للكلمات التي تحمل همزة، فهذا هو السبب.

7.2 المُجذِّد (stemmer) أساسي

Section titled “7.2 المُجذِّد (stemmer) أساسي”

يقوم المُجذِّد (_init_stemmer، الأسطر 104-130) بتجريد اللواحق/السوابق بالتعابير النمطية فقط — ليس مُؤلِّفًا صرفيًا (lemmatizer). قد لا تنهار صيغ الجمع/الجنس إلى جذر مشترك. لاستدعاء أعلى، فكّر في التطبيع المسبق للاستعلامات أو إضافة مرادفات المجال.

7.3 التطويل (ـ) في النص المخزَّن

Section titled “7.3 التطويل (ـ) في النص المخزَّن”

يُحذَف التطويل عند التقطيع، لذا لن يحتوي content_arabic المخزَّن عليه — لكن إذا استعلمت بنص خام يحتوي ـ، يُطبَّق نفس التطبيع، فتعمل المطابقات على أي حال.


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

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

غير متزامنة. لا تعتمد على أيٍّ منها وحدها لـ “إصدار كاظمة”.

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

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

السلسلة "litellm" تبوّب فقط فرع النموذج الاحتياطي (llm_provider.py:336). كاظمة لا تنفّذ import litellm قط. إذا أشرت إلى وكيل LiteLLM، استخدم http://host:4000/v1 كـ base_url.

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

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

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

8.4 mcp.servers[].trust لا-عملية (no-op)

Section titled “8.4 mcp.servers[].trust لا-عملية (no-op)”

السلسلة trust: trusted في إعداد MCP في kazma.yaml لا يقرؤها أي كود. إنها توثيق فقط. “مستويات الثقة” ليست ميزة في الكود.

8.5 /undo و/edit مجرّد هيكل (stubs)

Section titled “8.5 /undo و/edit مجرّد هيكل (stubs)”

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

8.6 UnifiedModelRegistry هو مجرّد ModelRegistry

Section titled “8.6 UnifiedModelRegistry هو مجرّد ModelRegistry”

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


عندما يكون شيء ما خاطئًا، انتقل عبر هذه:

Terminal window
# 1. Is the server up? Versions sane?
kazma status
# 2. Health
curl -s http://127.0.0.1:8000/health/details | jq
# 3. Active provider/model
curl -s http://127.0.0.1:8000/api/provider/active | jq
# 4. Gateway adapters
curl -s http://127.0.0.1:8000/api/gateway/status | jq
# 5. Swarm status + breaker states
curl -s http://127.0.0.1:8000/api/swarm/status | jq
curl -s http://127.0.0.1:8000/api/swarm/circuit-breakers | jq
# 6. Pending HITL approvals
curl -s http://127.0.0.1:8000/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
  • تتبّع الطرفية ← KazmaTracer (backend="console") يكتب إلى stdout عبر kazma_core/tracing.py
Terminal window
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;"
Terminal window
nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits

على نظام بدون GPU من NVIDIA أو تعريفات، يُلقي هذا خطأً ويتراجع kazma_core/telemetry.py إلى الأصفار.

9.4 إعادة ضبط المُفردات (singleton) (اختبار أو استعادة)

Section titled “9.4 إعادة ضبط المُفردات (singleton) (اختبار أو استعادة)”
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()

10.1 “متّصل” لكن لا ردود

Section titled “10.1 “متّصل” لكن لا ردود”

العَرَض: يُظهر 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 من أحرف غير مُهرّبة.

الإصلاح:

Terminal window
# 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="".

بالنسبة لأخطاء النموذج اللغوي (LLM) 401/403، مفتاح المُزوّد هو المشكلة — حدّثه في الإعدادات ← النماذج/المُزوّدون. يُعيد 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)
Terminal window
grep "cid-abc123def456" /var/log/kazma.log

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


11. مركز المُزوّدين والموصِلات (UI)

Section titled “11. مركز المُزوّدين والموصِلات (UI)”

11.1 يُظهر المُزوّد “معطّلًا”/“متدهورًا” / يفشل Test Connection

Section titled “11.1 يُظهر المُزوّد “معطّلًا”/“متدهورًا” / يفشل Test Connection”

العَرَض: تُظهر بطاقة مُزوّد في الإعدادات ← المُزوّدون والموصِلات الحالة down/degraded، أو يُرجِع Test Connection الخطأ Cannot connect to <base_url> / HTTP 401.

السبب: Base URL خاطئ/غير قابل للوصول؛ مفتاح API مفقود/منتهٍ/غير صالح؛ المُزوّد مُعطَّل؛ أو نقطة نهاية /models الخاصة بالمُزوّد ليست متوافقة مع OpenAI.

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

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

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

السبب: الرمز غير محفوظ؛ الرمز مُلغًى؛ Slack يحتاج Bot Token (xoxb-...) لمُحوّل Web API الاستطلاعي (لا Socket Mode)؛ Discord يتوقّع Authorization: Bot <TOKEN>.

الإصلاح: تُشغّل الخلفية فحص صحة غير مدمِّر:

  • Telegram ← GET https://api.telegram.org/bot<TOKEN>/getMe
  • Discord ← GET https://discord.com/api/v10/users/@me مع Authorization: Bot <TOKEN>
  • Slack ← POST https://slack.com/api/auth.test مع رمز البوت

يبقى الحفظ مُعطَّلًا حتى ينجح الاختبار. بعد الحفظ، انقر Refresh Gateway (أو أعد تشغيل الخادم) حتى يُلتقط الرمز الجديد.

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. واجهة طرفية (TUI) (kazma-tui)

Section titled “12. واجهة طرفية (TUI) (kazma-tui)”

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

Section titled “12.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=..., ...)).

12.2 تُظهر لوحة المعلومات “N/A” في كل مكان

Section titled “12.2 تُظهر لوحة المعلومات “N/A” في كل مكان”

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

الإصلاح:

Terminal window
uv pip install -e ".[tui]" # or: pip install textual psutil

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

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

الإصلاح:

Terminal window
nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits

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

12.4 تنهار الـ TUI عند بدء التشغيل (خطأ استيراد / Python أقل من 3.11)

Section titled “12.4 تنهار الـ TUI عند بدء التشغيل (خطأ استيراد / Python أقل من 3.11)”

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

الإصلاح:

Terminal window
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.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.1.1 أمر kazma غير موجود / نقطة الدخول مفقودة

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

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

الإصلاح:

Terminal window
uv sync --all-extras
uv pip install -e .
which kazma && kazma --help # PowerShell: Get-Command kazma
# fallback if the entry point won't work:
python -m kazma_cli --help

13.3 إكمال التبويب في الصدفة (shell tab-completion)

Section titled “13.3 إكمال التبويب في الصدفة (shell tab-completion)”

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

الإصلاح:

Terminal window
kazma completion install {bash|zsh|powershell}
kazma completion --list-models # verify dynamic lists; init registry first if this errors
kazma completion --list-providers

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

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


14. لوحة السرب والعاملون

Section titled “14. لوحة السرب والعاملون”

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 خطأ/انتهاء مهلة عامل / قاطع دائرة مفتوح”

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

الإصلاح:

Terminal window
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:8000/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 غير موصول بالمحرّك — يستدعي kazma-ui/kazma_ui/swarm_panel.py الدالة wire_engine_events(engine, _sse_bus) في _current_engine()؛ إذا كان المحرّك أقدم من الناقل، تُفقد الأحداث. أو لم يُرجِع الإرسال task_id؛ أو خطأ JS في الواجهة الأمامية في swarm.js dispatchTask().

الإصلاح:

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

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

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

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

الإصلاح:

Terminal window
curl http://localhost:8000/api/swarm/tasks/<task_id>

يجب أن تحمل الاستجابة 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 وأن swarm.js renderTaskDetailHTML() يقرأ 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
Terminal window
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 لـ pipeline مفقودة (swarm/pipeline)

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

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

العَرَض: يجب أن تتوقّف مهمة pipeline عند نقطة تفتيش، لكن لا تظهر بطاقة 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
}
Terminal window
curl -X POST http://localhost:8000/api/swarm/tasks/<task_id>/approve
curl -X POST http://localhost:8000/api/swarm/tasks/<task_id>/reject

تأكد أن restore_paused_tasks() يعمل عند بدء التشغيل (وإلا تُرفَض المهام المتوقّفة تلقائيًا عند checkpoint_timeout الخاص بها — انظر §3.3).


يجمع هذا الملف النتائج القابلة للتنفيذ من التدقيق الكامل بالإضافة إلى التنقيح التشغيلي من وثائق المشغّلين السابقة. أهم الفخاخ للمشغّلين الجدد:

  1. الذاكرة اختيارية (§2.1) — لا تفترض التذكّر.
  2. ثلاث قوائم HITL (§3.2) — إضافة أداة خطيرة في مكان واحد لا تكفي.
  3. يضبط KAZMA_SECRET مصادقة الموافقة (§3.2) — اضبطه دائمًا.
  4. تنشر ملفات K8s الشيء الخاطئ (Deployment §4) — لا تُطبِّقها للوكيل الرئيسي.
  5. لا توجد معالجة 429 (§1.4) — استخدم proxy أو قيّد المعدّل خارجيًا.
  6. آليتا HITL (§3.2 مقابل §14.6) — موافقة استدعاء أداة الوكيل (/api/approve/{thread_id}) ≠ نقاط تفتيش swarm/pipeline (/api/swarm/tasks/{id}/approve).
  7. استخدم دائمًا get_config_store() (§4.1، §1.9) — لا تُنشئ ConfigStore() مباشرةً لقاعدة البيانات المشتركة.

المصدر: نُقِلت §1.6–§1.9، و§9.1–§9.4، و§10–§14 من دليل استكشاف أخطاء المشغّلين الأصلي وأُعيد التحقق منها؛ صُحِّحت المراجع القديمة TelegramWorker/hermes وبناء ConfigStore() المباشر.