Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/docs/AI_AGENT_SYSTEM_AUDIT.md
2026-08-21 14:14:21 +00:00

92 KiB
Raw Permalink Blame History

ممیزی سیستم چت و ایجنت هوش مصنوعی حسابیکس

نسخه سند: 2.8
تاریخ ممیزی: ۱۴۰۵/۰۵/۲۸ (۱۸ اوت ۲۰۲۶) — بازبینی runtime: subagent، ابزار موازی، تکرار context
وضعیت: زنده — پس از هر اصلاح، وضعیت آیتم را عوض کنید و در تاریخچهٔ به‌روزرسانی ثبت کنید.
دامنه: چت درون‌برنامه، حلقهٔ ایجنت، ابزارها، حافظه، دانش، مهارت، صوت، تلگرام، CRM AI، تیکت، ورک‌فلو، MCP، مشاهده‌پذیری، UX.

این سند جایگزین سناریوهای اجرایی قبلی نیست. جزئیات فاز ابزارها در AI_EXECUTION_PHASES.md، باگ‌های رفع‌شدهٔ چت در AI_CHAT_ISSUES.md، شکاف پوشش دامنه در AI_CAPABILITY_GAP_SCENARIO_V2.md، و سناریوی subagent / ابزار موازی / cache بینش در AI_AGENT_RUNTIME_CAPABILITIES_SCENARIO.md است. اینجا نقشهٔ کیفیت سطح محصول ایجنت‌محور جهانی است.

صف باگ‌های محصولی که کاربر الان در چت می‌بیند (ابزار، زیر-ایجنت، جدول داخلی، markdown، زبان تفکر، تأیید نوشتن): AI_CHAT_PRODUCT_ISSUES.md.


چگونه از این سند استفاده کنیم

  1. از نقشهٔ سیستم شروع کنید تا لایه را بشناسید.
  2. هر آیتم یک شناسه دارد (AGT-xx, UX-xx, …). وضعیت را فقط از مجموعهٔ زیر انتخاب کنید:
    • باز — هنوز اصلاح نشده
    • در حال اصلاح — در شاخه/PR جاری
    • انجام‌شده — در کد اصلی است؛ معیار پذیرش را تیک بزنید
    • موکول — آگاهانه بعداً
    • نپذیرفته — بررسی شد و تصمیم گرفتیم انجام نشود
  3. بعد از هر اصلاح: وضعیت + تاریخ + یک خط «چه شد» در همان آیتم، و یک سطر در تاریخچه.
  4. وقتی یک بخش کامل سبز شد، امتیاز کارت امتیاز همان بخش را به‌روز کنید.
  5. ممیزی مجدد پیشنهادی: هر اسپرینت برای آیتم‌های P0/P1، هر فصل برای کل سند.

معیار سطح جهانی که در این سند با آن مقایسه می‌کنیم: ChatGPT (حافظه، Canvas، Custom GPT)، Claude (Skills، Artifacts، Computer Use)، Cursor (ایجنت چندمرحله‌ای، resume، subagent)، Intercom Fin / Zendesk AI (پاسخ مبتنی بر دانش با citation)، OpenAI Agents SDK / LangGraph (run state بادوام)، n8n AI Agent (ابزار در اتوماسیون).


خلاصهٔ اجرایی

سیستم فعلی از نظر عرض قابلیت جلوتر از بسیاری از ERPهای منطقه‌ای است: حلقهٔ چندنوبتی با بودجه، حالت اجرا (تحلیلگر / با تأیید / خودکار)، تایم‌لاین تفکر، دانشنامه، حافظهٔ دوم‌لایه، مهارت، صوت محلی، MCP، و حدود ۱۰۰+ ابزار دامنه.

شکاف اصلی با محصولات ایجنت‌محور جهانی عمق runtime و محصول است، نه تعداد tool:

محور وضعیت امروز سطح جهانی
حلقهٔ ایجنت حلقهٔ واحد (استریم + aggregator)؛ run persist و ادامه؛ plan اجباری برای سوال complex؛ subagent موقت (spawn_subagent، سقف ۲×۴ نوبت، بدون write)؛ worker پس‌زمینه هنوز نیست run بادوام، checkpoint، ادامه پس از قطع، subagent
انتخاب ابزار فیلتر کلیدواژه‌ای + سقف ۴۸ + envelope برش نتیجه progressive disclosure / router معنایی / skill-first
UX چت SSE با event id و بنر ادامه؛ Enter-to-send در دسکتاپ؛ حلقهٔ استریم در consume؛ جلسهٔ صوت در کنترلر جدا؛ God Widget هنوز کروم UI را نگه داشته streaming-first، بازیابی اتصال، Canvas/Artifact
دانش و استناد RAG ترکیبی با fallback واژه‌ای؛ chip منبع از envelope ابزار (فاکتور/شخص/سرنخ/فرصت) retrieval با نمره، منبع کلیک‌پذیر، ضد hallucination
ارزیابی substring روی چند کیس پیش‌فرض LLM-as-judge + tool-call assertion + eval در CI
مشاهده‌پذیری logger.info با برچسب AI_METRIC trace کامل (Langfuse/Phoenix)، هزینه، latency، کیفیت
چندرسانه‌ای متن + PDF محدود؛ بدون تصویر در چت تصویر، اسکرین‌شات، اکسل واقعی، صوت هم‌تراز متن
کانال‌های جانبی تلگرام با typing و دکمهٔ تأیید؛ CRM/تیکت حلقه با allowlist (بدون استریم) همان کیفیت ایجنت در همهٔ سطح‌ها

پیشنهاد ترتیب اصلاح (۱۲ هفتهٔ اول): پایداری استریم و resume → شکستن God Objectها → cache نیمه‌پایدار بینش (PRM-04) → انتخاب ابزار skill-first → subagent (AGT-06) → citation قابل کلیک → eval واقعی → چندرسانه‌ای → مشاهده‌پذیری.


کارت امتیاز نسبت به سطح جهانی

امتیاز ۰ تا ۵. پس از اصلاح هر بخش، عدد را عوض کنید.

بخش شناسه امتیاز فعلی هدف ۳ ماه هدف ۱۲ ماه
حلقهٔ ایجنت و بودجه AGT 4.3 4.0 4.5
انتخاب و اجرای ابزار TOOL 4.1 4.0 4.5
امنیت و تأیید نوشتن SEC 4.3 4.0 4.5
استریم و قرارداد SSE STR 4.5 4.5 5.0
Prompt و مدل PRM 4.0 3.5 4.5
حافظه MEM 3.0 4.0 4.5
دانش / RAG / استناد RAG 3.5 4.0 4.5
مهارت و مارکت SKL 3.0 3.5 4.5
UX چت Flutter UX 4.2 4.0 4.5
صوت VOI 3.0 3.5 4.0
تلگرام / CRM / تیکت CHN 3.6 3.0 4.0
ورک‌فلو ایجنت WFA 3.3 3.5 4.0
MCP و کانکتور MCP 2.8 3.5 4.5
ارزیابی و مشاهده‌پذیری OBS 3.0 3.5 4.5
سهمیه و صورتحساب BIL 3.5 4.0 4.5
معماری و تست ARC 3.4 4.0 4.5

نقشهٔ سیستم

کاربر (وب/دسکتاپ/موبایل Flutter)
  ├─ AIChatDialog  (~2586 خط، state متمرکز)
  │    ├─ AIChatStreamController  (SSE state + consume نوبت)
  │    ├─ AIChatStreamTurn  (انباشتگر نوبت)
  │    ├─ AIChatSessionController  (جلسه / پیام / ارسال)
  │    ├─ AIChatVoiceSessionController  (فاز صوت + تفسیر رویداد WS)
  │    ├─ AIChatTurn helpers  (send guard / voice phase / usage patch)
  │    ├─ AIService (Dart, ~1700 خط)
  │    └─ VoiceChatController → WS /ws/ai/voice
  │
  POST /api/v1/ai/chat/sessions/{id}/messages?stream=true
  │
  chat.py  (~2500 خط)
  │    ├─ سهمیه / مدل / execution_mode
  │    ├─ persist پیام کاربر
  │    └─ SSE: status, heartbeat, trace_step, tool_*, content, done
  │
  AIService (Python, ~3600 خط + mixin مسیریابی/سهمیه)  ← قلب سیستم
  │    ├─ build_system_prompt (نقش + دامنه + حافظه + دانش + مهارت)
  │    ├─ filter tools by intent (سقف ۴۸)
  │    ├─ chat_completion_stream  ← حلقهٔ ایجنت
  │    │     ├─ AgentBudget (نوبت / توکن / زمان / بی‌حاصلی)
  │    │     ├─ Exploration / ObservationStore
  │    │     ├─ Goal assessment + continuation
  │    │     ├─ Write guard + execution policy
  │    │     └─ Forced synthesis اگر متن نهایی نیامد
  │    └─ chat_completion  ← aggregator روی همان generator
  │
سطح‌های دیگر (همان حلقه؛ UX استریم هنوز فقط چت درون‌برنامه)
  ├─ TelegramAIChatService  (typing + دکمهٔ تأیید/رد)
  ├─ /ai/crm/*  (ابزار فقط‌خواندنی CRM، سقف ۴ نوبت)
  ├─ /support/tickets/{id}/ai-suggest-reply  (ابزار مالی فقط‌خواندنی، سقف ۴ نوبت)
  ├─ Workflow AIAgentAction
  ├─ /ai/mcp  (JSON-RPC روی HTTP)
  └─ scheduled tasks (کرون ثابت، ۴ تسک built-in)

اندازهٔ فعلی (بدهی معماری):

فایل خطوط نقش
hesabixAPI/app/services/ai/ai_service.py ~3600 ارکستراسیون حلقه (routing/quota جدا)
hesabixAPI/app/services/ai/ai_model_router.py ~370 mixin مسیریابی مدل
hesabixAPI/app/services/ai/ai_usage_meter.py ~370 mixin سهمیه و لاگ مصرف
hesabixAPI/adapters/api/v1/ai/chat.py ~2500 API چت
hesabixUI/.../ai_chat_dialog.dart ~2586 UI و state
hesabixAPI/app/services/ai/function_registry.py ~1900 ثبت ابزار
hesabixUI/.../ai_service.dart ~1700 کلاینت API
بستهٔ app/services/ai/ ۱۰۷ فایل زیرسیستم‌ها

قرارداد وضعیت آیتم‌ها

هر آیتم این قالب را دارد:

### شناسه — عنوان
- وضعیت: باز
- اولویت: P0 | P1 | P2 | P3
- مالک پیشنهادی: backend / flutter / infra / product
- فایل‌های اصلی: …
- مشکل: …
- معیار پذیرش سطح جهانی: …
- پیشنهاد اصلاح: …
- یادداشت اصلاح: (خالی تا انجام شود)

اولویت: P0 مانع تجربه یا امنیت است؛ P1 فاصلهٔ واضح با رقبا؛ P2 کیفیت؛ P3 تمایز بلندمدت.


A. حلقهٔ ایجنت و Runtime

AGT-01 — Run state سبک است؛ resume واقعی وجود ندارد

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend + flutter
  • فایل‌ها: ai_agent_run.py، ai_agent_run_store.py، adapters/db/models/ai_agent_run.py، chat.py، ai_chat_dialog.dart
  • مشکل: AgentRunState صریحاً «FSM کامل نیست». extract_agent_run_checkpoint فقط از function_results می‌خواند و کامنت می‌گوید UI ادامه هنوز پیاده نشده. قطع شبکه، kill سرور، یا رسیدن به سقف بودجه یعنی از دست رفتن کار. محصولات جهانی (Cursor، ChatGPT، Claude) run را persist می‌کنند و دکمهٔ Continue دارند.
  • معیار پذیرش: پس از قطع استریم، کاربر بتواند همان run_id را ادامه دهد؛ ابزارهای تکراری دوباره اجرا نشوند؛ todos جلسه حفظ شوند.
  • پیشنهاد:
    1. جدول ai_agent_runs با run_id, session_id, phase, iteration, observation_store, budget_snapshot, status.
    2. هر نوبت tool یک checkpoint بنویسد.
    3. API POST .../runs/{run_id}/continue و رویداد SSE run_resumed.
    4. در UI دکمهٔ «ادامهٔ تحلیل» وقتی پیام done با stop_reason=budget|disconnect است.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — جدول ai_agent_runs، checkpoint هر نوبت tool، POST /sessions/{id}/runs/{run_id}/continue، رویداد run_resumed/agent_run، بنر «ادامهٔ تحلیل». حلقه هنوز داخل همان درخواست HTTP است (AGT-02). میگریشن 20260817_000002_ai_agent_runs.

AGT-02 — حلقه داخل یک درخواست HTTP زندگی می‌کند

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: adapters/api/v1/ai/chat.py (_stream_message_response)، ai_run_hub.py، ai_sse_event_buffer.py
  • مشکل: کل حلقه تا ۳۰۰ ثانیه (سوال پیچیده) روی یک اتصال SSE است. persist پس از disconnect با _schedule_stream_persist_after_disconnect بهتر از هیچ است، اما worker جدا برای ایجنت وجود ندارد. مقیاس و timeout پروکسی (nginx) شکننده است.
  • معیار پذیرش: اجرای ایجنت روی job/queue با fan-out رویداد به کلاینت؛ قطع مرورگر اجرای سرور را نکشد.
  • پیشنهاد: الگوی «run در پس‌زمینه + SSE/WS subscribe». مشابه OpenAI Assistants runs یا LangGraph Server.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — AgentRunHub producer را مستقل از مشترک SSE نگه می‌دارد؛ Stop فقط با API cancel. بافر SSE حافظه+Redis. اگر run روی worker دیگر باشد، _iter_run_sse همان بافر را حین poll replay می‌کند نه فقط heartbeat. صف جدا (Celery) عمداً نیست.

AGT-03 — سقف بودجه و ضد حلقه خوب است؛ سیگنال به کاربر ضعیف است

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: ai_budget.py، ai_stream_helpers.py، ai_error_recovery_banner.dart، ai_chat_dialog.dart
  • مشکل: بودجهٔ چندبعدی (نوبت ۳–۱۵، توکن، wall-clock، ۲ نوبت بی‌حاصل، تمدید حداکثر ۲ بار) طراحی پخته‌ای است. وقتی حلقه به‌خاطر unproductive یا identical tool repeats می‌ایستد، کاربر اغلب فقط یک پاسخ ناقص یا سنتز اجباری می‌بیند؛ دلیل توقف و «چه داده کم است» شفاف نیست.
  • معیار پذیرش: در UI و متن نهایی: دلیل توقف + یافته‌های جمع‌شده + پیشنهاد ادامه با یک کلیک.
  • پیشنهاد: stop_reason را در done و در پیام ذخیره کنید؛ بنر «تحلیل ناقص ماند چون …» با CTA ادامه.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — stop_reason / stop_message_fa روی رویداد done؛ بنر ادامه متن stop_message_fa را نشان می‌دهد. یافته‌های جمع‌شده هنوز در پنل استدلال است نه داخل بنر.

AGT-04 — Forced synthesis و پاسخ زودهنگام هنوز dual-path هستند

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_deliverable_answer.py، ai_service.py (پایان استریم)، chat.py (persist)
  • مشکل: تشخیص «پاسخ تحویلی» چند ماژول موازی دارد؛ در persist فقط log می‌شود و کاربر پاسخ نیمه‌کاره می‌بیند. تست‌ها خوب‌اند اما در پروداکشن هنوز hallucination وضعیت («فاکتوری نیست») بدون tool ممکن است برسد.
  • معیار پذیرش: اگر query_expects_tool_use و evidence نیست، هرگز done با ادعای دادهٔ کسب‌وکار نرود؛ یا tool اجباری یا سوال شفاف‌سازی.
  • پیشنهاد: یک دروازهٔ واحد قبل از persist؛ کیس eval برای «بدون tool جواب نده».
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — is_deliverable_answer ادعای داده بدون tool را رد می‌کند؛ gate_ungrounded_assistant_content قبل از persist و در پایان استریم متن را با شفاف‌سازی عوض می‌کند؛ final_content روی done UI را با نسخهٔ persist هم‌تراز می‌کند. سلام و سوال شفاف‌سازی حفظ می‌شود. eval suite طلایی هنوز OBS-01 است.

AGT-05 — Planning و todos جلسه هنوز اختیاری و دیرهنگام‌اند

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend + flutter
  • فایل‌ها: ai_session_todo_service.py، ai_function_extensions_session_todos.py، ai_agent_todo_list.dart، ai_constants.py (PLANNING_STEP_MIN_CHARS)
  • مشکل: todos سقف ۲۰ آیتم دارند و در UI نمایش داده می‌شوند. «plan» در استریم اغلب فقط یک trace_step آرایشی با متن هدف است (ai_service.py حدود ۲۹۲۵–۲۹۳۵) نه فراخوانی مدل برنامه‌ریز یا DAG ابزار. در AI_CHAT_ISSUES.md هم برنامه‌ریزی زودهنگام به‌عنوان پیشنهاد مانده. Cursor قبل از ابزار یک plan مرئی می‌سازد. Intent فیلتر قبلاً create_session_plan را قبل از منطق expose حذف می‌کرد مگر کلیدواژهٔ «مرحله/گام».
  • معیار پذیرش: برای سوال complex، قبل از اولین tool یک plan با todos ساخته شود و کاربر بتواند آیتم را رد/تأیید کند.
  • پیشنهاد: toolهای plan را در iteration 0 اجباری کنید وقتی complexity=complex؛ UI plan را بالای thread پین کند.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — ابزارهای plan در allowlist با prefer_names/forced_names می‌مانند (حتی بدون کلیدواژهٔ برنامه). برای complex بدون برنامهٔ باز، prompt require_first و در OpenAI/Anthropic tool_choice روی create_session_plan است؛ medium فقط expose می‌شود. برنامه بالای پنل استدلال پین می‌شود. کاربر می‌تواند آیتم باز را از UI skipped/done کند (PATCH .../todos/{id}، فقط از pending/in_progress).

AGT-06 — Subagent / کار موازی وجود ندارد

  • وضعیت: انجام‌شده (فاز ۰–۲؛ UI و citation ادغام موکول)
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: ai_subagent.py، ai_function_extensions_subagent.py، ai_service.py (handle_function_calls_async)، function_registry.py، ai_agent_run.py؛ سناریو: AI_AGENT_RUNTIME_CAPABILITIES_SCENARIO.md
  • مشکل: همهٔ کار در یک حلقه و یک مدل است. هیچ ابزار spawn/delegate نیست. ایجنت‌های جهانی برای «گزارش فروش + موجودی + بدهکاران» چند subagent موازی می‌زنند، منتظر اتمام می‌مانند یا قطع می‌کنند، بعد نتیجه را نقد و ادغام می‌کنند. GAP-07 (شخصیت ثابت حسابدار/انباردار) این قابلیت نیست.
  • معیار پذیرش: والد بتواند حداکثر ۲ زیر-اجرا با allowlist و سقف ۴ نوبت بسازد؛ پیش‌فرض بدون write؛ cancel والد فرزند را هم ببندد؛ نتیجه به‌صورت envelope + citation به والد برگردد؛ سوال ساده spawn نکند.
  • پیشنهاد: الگوی Cursor Task tool / LangGraph subgraph روی همان AIService با operation=subagent. بعد از AGT-01 و سقف TOOL-06.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — بررسی کد: صفر hit برای spawn/subagent در سرویس AI. اولویت از P3 به P1. سناریوی فاز ۰–۴ نوشته شد. ۱۴۰۵/۰۵/۲۸ (همان روز) — فاز ۰–۲: ابزارهای spawn_subagent / await_subagent / cancel_subagent؛ حلقهٔ تو در تو analyzer با سقف ۲ همزمان و ۴ نوبت؛ write در فرزند fail-closed؛ سوال ساده ابزار spawn نمی‌بیند؛ cancel والد فرزندان در حال اجرا را قطع می‌کند. persist جدول SQL و trace_step kind=subagent (فاز ۳–۴) موکول. شکاف UI برای کاربر: AI_CHAT_PRODUCT_ISSUES.md آیتم CHAT-02.

AGT-07 — شاخهٔ مرده در ادامهٔ evidence (prior_goal_reached)

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_agent_continuation.py
  • مشکل: بعد از if had_evidence: return … بلوک prior_goal_reached هرگز اجرا نمی‌شد.
  • معیار پذیرش: یا شاخه حذف شود، یا ترتیب شرط‌ها طوری باشد که prior_goal_reached قبل از return شواهد ارزیابی شود؛ تست واحد برای هر دو مسیر.
  • پیشنهاد: بازنویسی assess_text_round_evidence با جدول تصمیم صریح (loop / todos / discovery / evidence / prior).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — شرط prior_goal_reached به قبل از بلوک thoughts منتقل شد؛ تست test_stop_when_prior_goal_reached_with_evidence.

AGT-08 — آستانهٔ حلقهٔ ابزار تکراری خیلی تند است

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_constants.py (AGENT_MAX_IDENTICAL_TOOL_REPEATS = 1، AGENT_MAX_IDENTICAL_TOOL_FAILURES = 2)، ai_goal_assessment.py
  • مشکل: دومین فراخوانی عیناً همان tool+args حلقه را می‌بندد. برای صفحه‌بندی (offset) یا تأیید پس از mismatch ممکن است false positive باشد.
  • معیار پذیرش: تکرار مجاز اگر args فرق کند (مثلاً page) یا اگر نتیجهٔ قبلی خطا/خالی بوده؛ در غیر این صورت stop با پیام واضح.
  • پیشنهاد: کلید loop شامل نام + canonical args + کد نتیجهٔ قبلی.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — موفقیت عیناً تکراری همان سقف ۱؛ خطا/خالی/تأیید تا ۲ بار مجاز است (classify_tool_result_outcome). offset متفاوت loop نیست.

B. ابزارها (Function calling)

TOOL-01 — انتخاب ابزار کلیدواژه‌ای است و سقف ۴۸ دارد

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend
  • فایل‌ها: ai_tool_intent.py، ai_tool_rank.py، ai_service.get_available_functions، tests/test_ai_tool_intent_gold.py
  • مشکل: با ~۱۱۳ tool، مدل در هر درخواست حداکثر ۴۸ تا را می‌بیند. اگر intent اشتباه دسته را حدس بزند (مثلاً «باسلام» در integration نیاید)، مدل ابزار را hallucinate یا از query عمومی استفاده می‌کند. کاتالوگ برای سوال «چه ابزارهایی داری؟» خوب است، اما routing روزمره ضعیف است.
  • معیار پذیرش: recall ابزار درست روی مجموعهٔ طلایی سوالات دامنه ≥ ۹۵٪؛ هیچ tool بدون entry در intent/permission/l10n اضافه نشود (از قبل در چک‌لیست فازها هست).
  • پیشنهاد:
    1. کوتاه‌مدت: embedding کوچک روی (name, description, examples) برای ranking به‌جای/در کنار regex.
    2. میان‌مدت: skill-first — فقط core (~۱۲) + ابزارهای skill فعال + ۲ دستهٔ top.
    3. مثال‌های few-shot per tool در schema (مدل‌های جدید با این خیلی بهتر انتخاب می‌کنند).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — سقف ۴۸ با رتبهٔ واژه‌ای (نام+alias) به‌جای الفبا؛ تاریخچه به select_tool_names می‌رسد؛ مهارت با دامنه اتحاد می‌شود نه جایگزینی؛ دسته/کلیدواژه برای کیف پول، سرفصل، کالا، بدهکار، hscript. مجموعه طلایی ۱۶ کیس با recall ≥ ۹۵٪. embedding هنوز نیست (مرحله بعد).

TOOL-02 — God registry و ثبت ناقص نقش‌ها

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: function_registry.py خطوط ۱۶۳۵–۱۶۴۸
  • مشکل: _register_operator_functions، _register_admin_functions، _register_business_owner_functions همگی pass با کامنت «بعداً». نقش در enum هست اما ابزار اختصاصی نیست. اپراتور پشتیبانی و ادمین همان ابزار کاربر را با prompt امنیتی می‌گیرند.
  • معیار پذیرش: کاتالوگ جدا برای operator (تیکت، جلسه، وضعیت سیستم) و admin (tenant، usage، eval) با permission سخت.
  • پیشنهاد: هر نقش یک ماژول ai_function_extensions_<role>.py؛ پیش‌فرض deny.
  • یادداشت اصلاح:

TOOL-03 — پوشش دامنه هنوز ناقص است (فاز ۹)

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend + product
  • فایل‌ها: AI_EXECUTION_PHASES.md فاز ۹، ai_function_extensions_phase8.py
  • مشکل: گزارشات/قالب/باشگاه MVP شده؛ هنوز خرید افزونه، sync باسلام، conflict، ووکامرس overview، ساخت قالب و preview PDF از چت نیست. قالب اعلان ۰٪.
  • معیار پذیرش: سناریوهای پذیرش بخش ۵ در AI_CAPABILITY_GAP_SCENARIO_V2.md همه سبز.
  • پیشنهاد: همان فاز ۹؛ هر tool جدید را به eval طلایی وصل کنید.
  • یادداشت اصلاح:

TOOL-04 — نتایج ابزار کوتاه و بدون schema پایدار برای UI

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend + flutter
  • فایل‌ها: ai_tool_result.py، ai_constants.py (MAX_TOOL_RESULT_JSON_CHARS / MAX_TOOL_RESULT_RECORDS)، ai_citation_service.py، ai_chat_table_widget.dart، ai_tool_envelope.dart
  • مشکل: برش ۶۰۰۰ کاراکتر باعث از دست رفتن ردیف‌های گزارش می‌شود؛ مدل جمع می‌بندد. Citation با حدس کلید items/data/results ساخته می‌شود نه با قرارداد اجباری. جدول/نمودار به markdown یا spec وابسته است.
  • معیار پذیرش: هر tool read یک ToolResultEnvelope با records, summary, citations[], truncated برگرداند؛ UI جدول را از envelope بکشد نه از markdown.
  • پیشنهاد: envelope واحد + صفحه‌بندی اجباری (offset/limit) در همهٔ list toolها.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — لایهٔ dispatch: اگر نتیجه بزرگ باشد envelope معتبر با truncated/omitted_count/citations/note ساخته می‌شود (دیگر JSON وسط قطع نمی‌شود). Citation اول از citations می‌خواند. UI اگر markdown جدول نداشته باشد از رکوردهای ابزار جدول می‌کشد. بازنویسی تک‌تک list toolها و offset/limit اجباری هنوز نیست. ۱۴۰۵/۰۵/۲۷ — اثر جانبی: همان جدول خودکار _reasoning_trace را با ستون‌های trace_id/step_id/kind نشان می‌دهد (CHAT-03).

TOOL-05 — کش ابزار فقط TTL کوتاه و درون‌جلسه‌ای است

  • وضعیت: باز
  • اولویت: P3
  • مالک: backend
  • فایل‌ها: ai_tool_cache.py، TOOL_CACHE_TTL_SEC = 60
  • مشکل: ۶۰ ثانیه برای داشبورد خوب است؛ برای گزارش سنگین کوتاه است. بین جلسات اشتراک نیست. invalidation روی write مشخص نیست.
  • معیار پذیرش: پس از write موفق، کلیدهای مرتبط همان موجودیت invalidate شوند؛ TTL قابل تنظیم per-tool.
  • پیشنهاد: tag محور (entity:invoice:123) و drop روی write guard success.
  • یادداشت اصلاح:

TOOL-06 — اجرای موازی ابزار بدون سقف و بدون تراکنش

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_tool_parallel.py، ai_service.py (handle_function_calls_async)، ai_constants.py (MAX_PARALLEL_READ_TOOLS = 4)
  • مشکل: همهٔ toolهای یک نوبت موازی‌اند. چند write + چند read روی همان موجودیت race می‌کنند؛ invalidation کش بعد از هر write است نه اتمیک برای کل round. stampede روی DB در سوال پیچیده محتمل است.
  • معیار پذیرش: سقف همزمانی (مثلاً ۴)؛ writeها سریال؛ readهای readonly موازی؛ ترتیب پایدار در trace.
  • پیشنهاد: semaphore + جدا کردن write/read در round.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — دسته‌بندی پایدار read/write؛ read حداکثر ۴تایی موازی؛ write سد سریال؛ ترتیب مدل حفظ می‌شود. تراکنش اتمیک کل round هنوز نیست. ۱۴۰۵/۰۵/۲۸ — تأیید شد مدل مجاز است چند tool_calls در یک نوبت بدهد (parallel_tool_calls غیرفعال نشده؛ prompt مسیریابی موازی را تشویق می‌کند). شکاف باقی: نمایش موازی در UI، و قفل tool_choice روی plan در نوبت صفر complex. ۱۴۰۵/۰۵/۲۸ — فاز A–B و سقف prompt: متریک tool_round_parallel (tool_calls_in_round / parallel_read_count)؛ کیس eval طلایی فروش+موجودی+بدهکار با min_tools_in_round؛ در routing سقف ۴ read نوشته شد. فاز C (UI موازی) موکول.

TOOL-07 — tool_choice=required فقط برای OpenAI

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_service.py، ai_provider.py Anthropic stream، ai_constants.py (PROVIDERS_WITH_FORCED_TOOLS)
  • مشکل: در iteration اول وقتی needs_tools است، OpenAI مجبور به tool می‌شود؛ Anthropic/Local این سیگنال را نمی‌گیرند. مسیر غیر OpenAI بیشتر در معرض پاسخ زودهنگام است.
  • معیار پذیرش: معادل Anthropic (tool_choice / disable_parallel مطابق API جاری) یا prompt اجباری یکسان؛ تست با هر provider.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — required → {"type":"any"} و function object → {"type":"tool","name":…}. Local هنوز بدون tool_choice است.

C. امنیت، تأیید نوشتن، چندمستأجری

SEC-01 — تأیید نوشتن با تطبیق دقیق JSON شکننده است

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: ai_write_guard.py (resolve_approved_write)، ai_execution_policy.py، ai_write_approval_banner.dart
  • مشکل: تأیید فقط اگر function و arguments با JSON canonical عیناً یکی باشند. اگر مدل بعد از تأیید فیلد بی‌ضرری را عوض کند → APPROVAL_MISMATCH. تجربهٔ جهانی: کارت تأیید با diff و تأیید «همین عملیات» با id پایدار، نه hash کل args.
  • معیار پذیرش: هر write یک approval_id می‌گیرد؛ تأیید روی id است؛ تغییر args نیاز به تأیید مجدد با diff دارد.
  • پیشنهاد: جدول/فیلد pending approvals در session؛ UI diff فارسی.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — هر APPROVAL_REQUIRED یک approval_id دارد. اگر فقط یک کارت برای همان تابع در انتظار باشد، آرگومان ذخیره‌شده اجرا می‌شود (نه آرگومان جهش‌یافتهٔ مدل). دو کارت هم‌نام هنوز تطبیق دقیق می‌خواهند. UI diff فارسی هنوز نیست.

SEC-02 — MCP می‌تواند write را با query string باز کند

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend
  • فایل‌ها: adapters/api/v1/ai/mcp.py، ai_mcp_service.py
  • مشکل: approve_writes=true روی URL یعنی هر کلاینت MCP با همان API key می‌تواند ابزار مخرب را بدون HITL بزند.
  • معیار پذیرش: MCP به‌صورت پیش‌فرض read-only؛ write فقط با header/body امضاشده یا همان کارت تأیید آسنکرون؛ هرگز query flag.
  • پیشنهاد: حذف query؛ scope در API key (ai:tools:read / ai:tools:write)؛ audit log اجباری.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — query flag حذف شد؛ _approve_writes در آرگومان ابزار نادیده گرفته می‌شود؛ فقط params.approve_writes === true در JSON-RPC مجاز است. scope API key هنوز باز است.

SEC-03 — کانکتور HTTP SSRF را تا حدی می‌بندد؛ هنوز کامل نیست

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_connector_service.py، tests/test_ai_connector_security.py
  • مشکل: بلاک IP خصوصی، metadata AWS/GCP، و scheme محدود شده. DNS rebinding (resolve به عمومی سپس به خصوصی)، IPv6 link-local، و redirect به metadata ممکن است باقی بماند. فقط GET/POST.
  • معیار پذیرش: resolve DNS سپس بررسی IP نهایی؛ رد redirect به غیرعمومی؛ allowlist دامنه per کسب‌وکار.
  • پیشنهاد: تست‌های test_ai_connector_security.py را با rebinding و IPv6 گسترش دهید.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — IPv6 link-local، IPv4-mapped خصوصی، و metadata IP مسدود است؛ trust_env=False؛ پاسخ ۳xx بدون دنبال کردن و بدون افشای Location به مدل برمی‌گردد. پین TLS به IP resolveشده هنوز نیست؛ allowlist دامنه per کسب‌وکار هنوز نیست.

SEC-04 — دفاع prompt injection و نشت PII عمدتاً prompt است نه کنترل

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_untrusted.py، ai_knowledge_service.py، crm_ai.py
  • مشکل: sanitize فقط توکن Harmony را پاک می‌کند. دستورات امنیتی اپراتور/ادمین در prompt هستند. CRM AI شماره موبایل را خام به مدل می‌فرستد. دانشنامه و کانکتور می‌توانند دستور «ignore previous» تزریق کنند.
  • معیار پذیرش: جداسازی دادهٔ بازیابی‌شده در بلاک quoteشده؛ ماسک PII قبل از LLM برای کانال‌های غیرضروری؛ تست حمله روی دانشنامه و tool result.
  • پیشنهاد: سیاست «tool output is untrusted data»؛ redaction لایهٔ میانی؛ eval امنیتی جدا.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — سیاست untrusted در prefix استاتیک prompt؛ دانشنامه داخل <untrusted_knowledge>؛ موبایل/ایمیل CRM ماسک می‌شود. نتیجهٔ ابزار JSON خام می‌ماند تا function calling نشکند. eval حمله روی tool result هنوز نیست.

SEC-05 — لیست استاتیک WRITE_FUNCTIONS با registry هم‌گام نیست

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_write_guard.py (WRITE_FUNCTIONS)، AIFunction.requires_approval
  • مشکل: دو منبع حقیقت. اگر tool جدید requires_approval=True داشته باشد ولی در fallback نباشد، مسیر بدون registry ناامن می‌شود (مثلاً MCP که is_write_function(name) را گاهی بدون registry صدا می‌زند).
  • معیار پذیرش: یک منبع: فقط registry؛ تست که هر requires_approval در مسیر MCP/workflow هم بایستد.
  • پیشنهاد: حذف تدریجی WRITE_FUNCTIONS؛ fail-closed اگر function در registry نیست.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — با registry، requires_approval منبع حقیقت است و نام ناشناخته fail-closed (write) است. بدون registry همان لیست استاتیک می‌ماند. حذف کامل لیست استاتیک هنوز نیست.

D. استریم، قرارداد SSE، پایداری اتصال

STR-01 — بدون Last-Event-ID و reconnect

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend + flutter
  • فایل‌ها: ai_stream_helpers.py، ai_sse_event_buffer.py، ai_sse_client_web.dart / stub، ai_chat_stream_controller.dart، ai_service.dart
  • مشکل: اگر تب پس‌زمینه شود، پروکسی قطع کند، یا Wi-Fi بپرد، استریم می‌میرد. ChatGPT/Claude از event id و replay استفاده می‌کنند. کلاینت وب و غیر وب SSE جدا دارند.
  • معیار پذیرش: reconnect با Last-Event-ID تا ۱۵ دقیقه؛ UI بدون پیام تکراری؛ اگر run در پس‌زمینه است (AGT-02) فقط subscribe مجدد.
  • پیشنهاد: id: در هر SSE؛ بافر حلقوی per run در Redis؛ Dart: retry با backoff.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — id: + sse_id؛ بافر حافظه ۱۵ دقیقه و dual-write به Redis اگر فعال باشد؛ کلاینت Last-Event-ID؛ subscribe مجدد روی run زنده (AGT-02).

STR-02 — مسیر non-stream هنوز بزرگ و دوگانه است

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_stream_aggregate.py، ai_service.chat_completion، chat.py، تلگرام/CRM/تیکت/ورک‌فلو
  • مشکل: مسیر غیر استریم exploration، Plan C، سنتز اجباری، tool_choice=required و wall-clock وسط استریم را ندارد. تلگرام/CRM/تیکت/ورک‌فلو روی همین مسیر نازک‌اند؛ کیفیت ایجنت بین کانال‌ها دوشاخه شده.
  • معیار پذیرش: یک حلقهٔ واحد؛ non-stream فقط aggregator روی همان generator.
  • پیشنهاد: chat_completion را به consume کردن chat_completion_stream تبدیل کنید.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — chat_completion فقط aggregate_chat_completion_stream است؛ temperature_override به استریم رسید. ۱۴۰۵/۰۵/۳۰ — UX استریم CRM/تیکت در CHN-02 بسته شد.

STR-03 — heartbeat و status خوب‌اند؛ event id و schema نسخه‌بندی ندارند

  • وضعیت: در حال اصلاح
  • اولویت: P2
  • مالک: backend + flutter
  • فایل‌ها: AI_CHAT_ISSUES.md جدول SSE، ai_stream_event.dart، ai_stream_helpers.format_sse_payload
  • مشکل: قرارداد در markdown است نه در OpenAPI/JSON Schema. کلاینت قدیمی با فیلد جدید می‌شکند یا نادیده می‌گیرد. trace_id در ISSUES به‌عنوان پیشنهاد مانده.
  • معیار پذیرش: protocol_version در اولین event؛ schema تولیدشده؛ trace_id/run_id روی همهٔ eventها.
  • پیشنهاد: Pydantic مدل برای SSE + تست سازگاری Dart.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — هر رویداد SSE فیلد schema_version (ثابت SSE_SCHEMA_VERSION) دارد. OpenAPI/Pydantic برای کل قرارداد و trace_id اجباری روی همهٔ eventها هنوز نیست.

STR-04 — Local/Ollama در استریم ابزار ندارد

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_provider.py کلاس LocalProvider (~۸۰۶)
  • مشکل: هم chat_completion و هم stream، tools را به Ollama نمی‌فرستند. ایجنت روی مدل محلی عملاً چت متنی است. Timeout جدا (۶۰/۱۲۰) با ثابت‌های OpenAI (۱۲۰/۱۸۰) ناهماهنگ است. httpx sync client در سازنده.
  • معیار پذیرش: tool call در Ollama (API /api/chat با tools) در stream parse شود؛ اگر مدل پشتیبانی نکند، خطا واضح به UI.
  • پیشنهاد: آداپتور OpenAI-compatible برای vLLM/Ollama؛ حذف مسیر اختصاصی شکننده.
  • یادداشت اصلاح:

STR-05 — رویداد done فیلدهای حیاتی سرویس را دور می‌ریزد

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend + flutter
  • فایل‌ها: chat.py، ai_stream_helpers.py، ai_stream_event.dart، ai_service.dart
  • مشکل: سرویس روی chunk پایانی agent_budget، awaiting_approval، citations_context، execution_mode، resolved_model می‌فرستاد؛ لایهٔ API هنگام rebuild آن‌ها را دور می‌ریخت.
  • معیار پذیرش: همهٔ فیلدهای done سرویس به کلاینت برسند؛ تست قرارداد SSE که فیلدها drop نشوند.
  • پیشنهاد: مدل Pydantic واحد برای SSE + message_id پس از persist.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — build_chat_done_sse_data + capture کامل در chat.py؛ کلاینت awaitingApproval / بودجهٔ تمدید را می‌خواند.

STR-06 — پاسخ نهایی اغلب توکن‌استریم واقعی نیست + پد nginx

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_service.py (برش مصنوعی ~۴۸ کاراکتر + asyncio.sleep(0) هنگام سنتز از trace)؛ chat.py حدود ۱۳۷۵–۱۳۷۷ (کامنت پد ~۲KB روی هر event)
  • مشکل: وقتی پاسخ از trace سنتز می‌شود کاربر «تایپ شدن» ساختگی می‌بیند نه توکن مدل. پد ۲KB برای هر heartbeat/status پهنای باند را در تحلیل طولانی بالا می‌برد.
  • معیار پذیرش: اگر متن از مدل است، delta واقعی؛ پد فقط روی event اول یا با flag محیطی برای nginx buffering.
  • یادداشت اصلاح:

E. Prompt، مدل، زبان

PRM-01 — ترکیب prompt از چند بلوک؛ بودجهٔ سیستم ۳۲k کاراکتر

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_system_prompt.py، ai_prompt_cache.py، ai_untrusted.py، ai_usage_meter.py
  • مشکل: نقش + حسابداری + routing + فیلتر + visualization + workflow + حافظه + دانش + مهارت + execution_mode. برای مدل‌های کوچک overload است؛ برای مدل‌های بزرگ prefix cache کمک می‌کند (PROMPT_CACHE_ENABLED) اما ترتیب بلاک‌ها برای cache Anthropic/OpenAI باید پایدار باشد. تغییر یک بلاک کل cache را می‌شکند.
  • معیار پذیرش: بلاک استاتیک (نقش، سیاست) جدا از بلاک داینامیک (دانش، حافظه جلسه)؛ hit rate cache در usage log دیده شود.
  • پیشنهاد: اندازه‌گیری cached_tokens در داشبورد ادمین؛ کوتاه کردن routing با skill-first (TOOL-01).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — StructuredSystemPrompt از قبل static/dynamic جدا بود. سیاست untrusted به static_core اضافه شد (پایدار برای cache). cached_tokens در context مصرف لاگ و شمارندهٔ usage_logged می‌آید. داشبورد ادمین هنوز نیست.

PRM-02 — تخمین پیچیدگی و routing مدل heuristic است

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_tool_intent.estimate_query_complexity، ai_constants (REASONING_EFFORT_BY_COMPLEXITY)، AI_OPERATION_*
  • مشکل: medium/complex با طول و کلیدواژه. سوال کوتاه «تراز آزمایشی فروردین» ممکن است simple شود و iteration=3 بگیرد. مدل auto بر همین سیگنال است.
  • معیار پذیرش: روی مجموعهٔ طلایی، complexity با برچسب انسانی ≥ ۸۰٪ توافق؛ هزینهٔ مدل auto نسبت به دستی بهتر یا برابر با کیفیت برابر.
  • پیشنهاد: classifier سبک یا چند قانون دامنه (نام گزارش = complex/medium اجباری).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — نام گزارش‌های حسابداری (تراز آزمایشی، بدهکاران، کاردکس، …) حداقل medium است؛ چند دامنهٔ واقعی یا متن بلند complex می‌شود. classifier مدل هنوز نیست.

PRM-03 — تاریخچه با سقف ۴۰ پیام و خلاصهٔ ترکیبی

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_history_summarizer.py، MAX_HISTORY_MESSAGES = 40، CONTEXT_INPUT_TOKEN_BUDGET = 28000
  • مشکل: بودجهٔ ۲۸k توکن برای مدل‌های ۲۰۰k–۱M خیلی محافظه‌کارانه است و برای گزارش‌های بلند تنگ. خلاصهٔ LLM usage دارد اما خلاصه به‌عنوان پیام first-class پایدار (مثل ChatGPT memory of conversation) مشخص نیست. fallback قاعده‌ای فقط برش متن است.
  • معیار پذیرش: خلاصهٔ جلسه persist شود و در prompt با برچسب «خلاصهٔ قطعی» بیاید؛ بودجه بر اساس context window مدل انتخاب شود نه ثابت جهانی.
  • پیشنهاد: per-model budget از کاتالوگ مدل؛ hierarchical summary (جلسه / بخش).
  • یادداشت اصلاح:

PRM-04 — بینش و بلوک runtime هر نوبت به مدل می‌روند؛ در تاریخچه تکرار نمی‌شوند

  • وضعیت: انجام‌شده (فاز ۰–۱؛ دانش-به‌ابزار و خط «بینش به‌روز شد» موکول)
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: build_system_prompt_stream، ai_system_prompt.py، ai_prompt_cache.py، ai_insight_service.py (INSIGHTS_CACHE_TTL_SEC = 300)، ai_context_budget.py؛ سناریو: AI_AGENT_RUNTIME_CAPABILITIES_SCENARIO.md
  • مشکل: هر پیام جدید HTTP جدا است. system از نو ساخته می‌شود: نقش (cacheپذیر) + شناسه کسب‌وکار (cacheپذیر) + datetime/حافظه/بینش/دانش/مهارت/کانکتور/پیوست/todo (dynamic). پیام‌های جلسه در DB این بلوک‌ها را ندارند — فرض «تکرار داخل تاریخچه» نادرست است. تکرار واقعی در ورودی مدل است و cache ارائه‌دهنده فقط prefix ثابت را می‌پوشاند. دانش حتی وابسته به متن سوال است (query_needs_knowledge).
  • معیار پذیرش: در usage نوبت دوم همان جلسه، اگر KPI عوض نشده، cache_read_tokens برای لایهٔ بینش/حافظه دیده شود؛ بینش در ردیف‌های ai_chat_message ذخیره نشود؛ دانش از prefix ثابت خارج بماند.
  • پیشنهاد: لایهٔ semi_static با hash محتوا و TTL هم‌تراز کش بینش (۵ دقیقه، هم‌راستا با Anthropic ephemeral). دانش را به ابزار بازیابی بسپارید نه به system هر سوال.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — مسیر کد تأیید شد. کش ۳۰۰ثانیه‌ای فقط SQL را کم می‌کند نه توکن ارسالی. همان روز فاز ۰–۱: لایهٔ semi_static (حافظه+بینش+کانکتور) با breakpoint جدا در Anthropic/OpenAI؛ datetime/دانش/مهارت در dynamic ماند؛ context_usage فیلدهای static_tokens / semi_static_tokens / insights_tokens / runtime_tokens را می‌فرستد. دانش هنوز در system است اگر query_needs_knowledge (فاز ۲ موکول).

F. حافظه

MEM-01 — دو نسل حافظه هم‌زمان (متن آزاد + آیتم)

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: ai_memory_service.py، ai_memory_item_service.py، ai_memory_structured.py، ai_chat_memory_sheet.dart
  • مشکل: دستورات همیشگی (۴۰۰۰ کاراکتر) و آیتم‌های v2 (fact/term/preference/goal/hint، سقف ۲۰۰). structured در upsert نادیده گرفته می‌شود (سازگاری عقب‌رو). کاربر باید بداند دستیار «چه چیزی را به خاطر سپرده» — ChatGPT این را شفاف کرده.
  • معیار پذیرش: یک UI واحد: دستورات من / حقایق یادگرفته / در انتظار تأیید؛ هر آیتم قابل حذف؛ یادگیری خودکار فقط با دستهٔ auto-approve.
  • پیشنهاد: deprecate متن آزاد به‌جز «custom instructions»؛ بقیه فقط item.
  • یادداشت اصلاح:

MEM-02 — یادگیری از فیدبک محدود و بدون بازخورد به کاربر

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_memory_feedback_service.py، ai_memory_hooks.py، ai_memory_proactive_service.py، MAX_MEMORY_FEEDBACK_UPDATES_PER_DAY = 8
  • مشکل: سقف روزانه در dict درون‌پرداز (_feedback_daily) است و با چند worker غلط می‌شود. schedule_memory_update_after_chat با asyncio.create_task اگر loop نباشد شکننده است. استخراج با regex است نه LLM. format_memory_goal_hint_for_insights خالی برمی‌گردد. تست‌ها فقط extract/strip/merge را می‌پوشانند نه CRUD آیتم و hooks.
  • معیار پذیرش: پس از thumbs-down، پیشنهاد «این را به خاطر بسپار» با پیش‌نمایش؛ سقف روزانه در Redis/DB؛ تست hooks.
  • پیشنهاد: HITL برای hint/goal؛ auto فقط برای preference/term.
  • یادداشت اصلاح:

G. دانشنامه، RAG، استناد

RAG-01 — ایندکس embedding ممکن است بی‌صدا شکست بخورد

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: backend
  • فایل‌ها: ai_knowledge_service.py، ai_chat_knowledge_sheet.dart
  • مشکل: اگر pgvector یا API امبدینگ نباشد، سند ذخیره می‌شد و جستجو بی‌خبر به overlap واژه برمی‌گشت.
  • معیار پذیرش: وضعیت ایندکس در UI (آماده / واژه‌ای / خطا)؛ reindex با گزارش تعداد chunk؛ عدم pass خاموش.
  • پیشنهاد: وضعیت روی سند (index_status); آلارم ops اگر نرخ fallback بالا باشد.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — شکست ایندکس لاگ می‌شود؛ API فیلدهای index_status / chunk_count / embedded_count برمی‌گرداند؛ شیت دانش برچسب معنایی/واژه‌ای/خطا نشان می‌دهد. ستون DB هنوز اضافه نشده.

RAG-02 — استناد برای کاربر قابل کلیک و الزام‌آور نیست

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: ai_citation_service.py، ai_citation_chips.dart، ai_stream_helpers.py، ai_eval_assertions.py
  • مشکل: citation به system prompt تزریق می‌شود تا مدل «تشویق» شود ارجاع بدهد. Perplexity/Fin منبع را اجباری و لینک می‌کنند. اینجا حدس از کلیدهای JSON و حداکثر ۸ منبع است.
  • معیار پذیرش: هر عدد/ادعا از tool یا دانش یک chip لینک به موجودیت UI داشته باشد؛ اگر منبع نباشد، مدل حق عدد قطعی ندارد.
  • پیشنهاد: post-processor: اگر عدد در خروجی است و در envelope نیست، هشدار «بدون منبع».
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — منابع ساخت‌یافته در _citations persist و روی done می‌آیند؛ chip زیر پاسخ برای فاکتور/شخص/سرنخ/فرصت/گردش‌کار/سند انبار لینک می‌شود. prompt عدد بدون منبع را منع می‌کند؛ اگر پاسخ مالی باشد و منبعی نباشد هشدار UI نشان داده می‌شود. دروازهٔ persist که متن را بازنویسی کند هنوز نیست.

RAG-03 — دانش از فایل‌های آفیس/تصویر تغذیه نمی‌شود

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_attachment_service.py (ALLOWED_EXTENSIONS بدون xlsx/docx/تصویر؛ PDF جداگانه و در لیست مجاز نیست در حالی که parser دارد)
  • مشکل: ناسازگاری PDF در allowlist. اکسل حسابداری رایج است و پشتیبانی نمی‌شود. تصویر فاکتور/کارت ملی برای ERP حیاتی است و در چت vision نیست.
  • معیار پذیرش: PDF در allowlist؛ xlsx به جدول؛ تصویر با مدل vision در همان جلسه.
  • پیشنهاد: پایپلاین پیوست → متن/جدول/تصویر چندبخشی در پیام user (content parts).
  • یادداشت اصلاح:

H. مهارت‌ها (Skills) و مارکت

SKL-01 — فعال‌سازی مهارت با overlap واژه است؛ اسکریپت اجرا نمی‌شود

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_skill_runtime.py (_tokenize، سقف ۳ مهارت، ۱۲k کاراکتر بدنه)، ai_activated_skill_chips.dart، AI_SKILLS_MARKETPLACE_PHASES.md
  • مشکل: فاز ۱ portable: ZIP + SKILL.md. اسکریپت‌ها هشدار «اجرا نمی‌شوند». انتخاب با اشتراک توکن توضیحات — مهارت‌های فارسی با slug انگلیسی فعال نمی‌شوند. Anthropic native (فاز ۲) و مارکت UGC (فاز ۳) باز است.
  • معیار پذیرش: progressive disclosure استاندارد agentskills.io: metadata همیشه، بدنه فقط با match قوی یا انتخاب کاربر؛ اعلام صریح در UI که کدام مهارت فعال شد.
  • پیشنهاد: chip مهارت در composer (مثل mention)؛ embedding روی description؛ sandbox برای scripts در فاز بعد.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — match روی slug داخل پرسش؛ مهارت فعال‌شده در _activated_skills persist و به‌صورت chip زیر پاسخ دیده می‌شود. اجرای اسکریپت و chip در composer هنوز نیست.

SKL-02 — UI مهارت از API جلوتر/عقب‌تر است و تست Flutter ندارد

  • وضعیت: باز
  • اولویت: P2
  • مالک: flutter
  • فایل‌ها: ai_chat_skills_sheet.dart، ai_skill_marketplace_card.dart، ai_skills_admin_page.dart
  • مشکل: شیت‌ها وجود دارند اما جریان import ZIP، سازگاری، و خطای script برای کاربر عادی مبهم است.
  • معیار پذیرش: کاربر غیر فنی بتواند یک مهارت رسمی را نصب، فعال و در یک چت تست کند زیر ۲ دقیقه.
  • پیشنهاد: onboarding مهارت با یک پکیج نمونهٔ حسابداری.
  • یادداشت اصلاح:

I. رابط کاربری چت (Flutter)

UX-01 — God Widget و state غیرقابل تست

  • وضعیت: در حال اصلاح
  • اولویت: P0
  • مالک: flutter
  • فایل‌ها: ai_chat_dialog.dart (~2586)، ai_chat_session_controller.dart، ai_chat_stream_turn.dart، ai_chat_voice_session.dart، ai_chat_turn.dart، ai_chat_message_sheet.dart، ai_service.dart (~1736)، ai_chat_resume.dart، ai_chat_stream_controller.dart
  • مشکل: جلسه، استریم، صوت، پیوست، مدل، execution mode، فیدبک، سایدبار، تأیید نوشتن همه در یک State. در AI_CHAT_ISSUES.md هم Riverpod/Bloc پیشنهاد شده. تست UI قبلاً فقط ai_markdown_table_parser_test.dart بود.
  • معیار پذیرش: dialog نازک؛ کنترلرها جدا (session, stream, composer, voice)؛ پوشش تست برای ارسال، لغو، تأیید write، reconnect.
  • پیشنهاد: استخراج AIChatSessionController؛ golden test برای empty/streaming/error.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — برش اول تا سوم: resume / approval / turn helpers. برش چهارم: شیت اقدامات پیام. برش پنجم: AIChatSessionController مالک جلسه/پیام‌ها و planChatSend. برش ششم (۱۴۰۵/۰۵/۲۸): حلقهٔ SSE به AIChatStreamController.consume و AIChatStreamTurn. برش هفتم: AIChatVoiceSessionController و interpretVoiceServerEvent؛ ساخت VoiceChatController هنوز در dialog است.

UX-02 — i18n ناقص در سطح چت

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: flutter
  • فایل‌ها: ai_chat_dialog.dart، ai_chat_composer.dart، ai_write_approval_banner.dart، ai_chat_l10n.dart، app_en.arb / app_fa.arb
  • مشکل: بخشی از برچسب ابزار l10n شده؛ snackbar و tooltip و لیبل حالت اجرا هنوز فارسی hardcoded. محصول چندزبانه است.
  • معیار پذیرش: صفر رشتهٔ کاربرنما در Dart/Python بدون کلید l10n برای سطح چت.
  • پیشنهاد: اسکریپت grep رشته‌های فارسی در lib/widgets/ai.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — کلیدهای ارسال/تأیید جلسه. ۱۴۰۵/۰۵/۲۸ — کروم composer، app bar، بنر تأیید نوشتن و شیت اقدامات پیام به arb رفت. پاسخ خالی دستیار: aiChatEmptyAssistantReply. snackbarهای چت، شیت حافظه، شیت دانشنامه، خطاهای صوت و تنظیمات صدا l10n شدند. منوی بیشتر، دیالوگ سهمیه، حالت اجرا و slash هنوز hardcoded است.

UX-03 — تجربهٔ سطح ChatGPT هست؛ Canvas / Artifact نیست

  • وضعیت: باز
  • اولویت: P2
  • مالک: flutter + backend
  • فایل‌ها: ai_chat_message_body.dart، ai_chat_table_widget.dart، ai_chat_chart_widget.dart
  • مشکل: جدول، نمودار، کد قابل کپی، trace، todos موجودند. خروجی بلند (گزارش ماهانه، پیش‌نویس قرارداد، HScript) داخل حباب می‌ماند. Claude Artifacts و ChatGPT Canvas سند را کنار چت ویرایش می‌کنند.
  • معیار پذیرش: برای export / گزارش / HScript یک پنل کناری با نسخه و «اعمال در سیستم».
  • پیشنهاد: reuse استودیو HScript (onApplyHScriptCode از قبل هست) به‌صورت Artifact عمومی.
  • یادداشت اصلاح:

UX-04 — جستجو، پین، فورک هست؛ اشتراک و شاخهٔ مرئی ضعیف است

  • وضعیت: باز
  • اولویت: P2
  • مالک: flutter
  • فایل‌ها: API fork/export/messages/search، ai_session_pins_store.dart، ai_conversation_rail.dart
  • مشکل: فورک سمت سرور هست؛ UX شاخه‌ها مثل ChatGPT (درخت پیام) نیست. اشتراک لینک امن با انقضا نیست.
  • معیار پذیرش: نمایش «این گفت‌وگو از جلسه X منشعب شد»؛ export PDF/Excel علاوه بر Markdown.
  • پیشنهاد: بعد از پایدار شدن استریم.
  • یادداشت اصلاح:

UX-05 — دسترسی‌پذیری و موبایل

  • وضعیت: در حال اصلاح
  • اولویت: P2
  • مالک: flutter
  • مشکل: RTL رعایت شده. composer در مرکز/پایین حالت ChatGPT دارد. Voice چت متنی را قفل می‌کند. Focus و screen reader برای trace/approval مشخص نیست. صفحهٔ چت در موبایل با سایدبار و شیت‌های زیاد شلوغ است.
  • معیار پذیرش: تأیید نوشتن با کیبورد؛ announce وضعیت استریم برای TalkBack/VoiceOver؛ composer در موبایل همیشه قابل‌مشاهده.
  • پیشنهاد: ممیزی a11y جدا روی AIChatComposer و AIWriteApprovalBanner.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — Semantics(liveRegion) روی بنر تأیید و برچسب «در حال پاسخ»؛ دکمهٔ ارسال label دارد. کیبورد Enter برای تأیید بنر هنوز نیست.

UX-06 — Slash commandها ثابت و فارسی‌اند

  • وضعیت: باز
  • اولویت: P3
  • مالک: flutter
  • فایل‌ها: ai_chat_composer.dart (kSlashCommands)
  • مشکل: هفت دستور ثابت. به مهارت، نقش، یا داده‌های زنده وصل نیستند. پیشنهادهای پویا API جدا دارند (/suggestions) اما slash نه.
  • معیار پذیرش: slash از پیشنهادهای سرور + مهارت‌های نصب‌شده ساخته شود.
  • یادداشت اصلاح:

UX-07 — باگ بازیابی خطا در استریم UI

  • وضعیت: انجام‌شده
  • اولویت: P0
  • مالک: flutter
  • فایل‌ها: ai_chat_dialog.dart (_runAssistantStream)
  • مشکل: بنر پاسخ خالی در همان setState پاک می‌شد؛ chunk.error حباب استریم را رها می‌کرد؛ onError و chunk خطا دوبار هندل می‌شدند.
  • معیار پذیرش: یک مسیر خطا؛ بنر خالی‌بودن پاسخ دیده شود؛ پس از error استریم پاک و retry کار کند.
  • پیشنهاد: تست واحد روی AIChatStreamController + تست ویجت برای error/empty.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — خطا و پاسخ خالی بنر را نگه می‌دارند؛ partial روی error ذخیره می‌شود؛ parse SSE دیگر onError جدا برای error typed صدا نمی‌زند. تست ویجت هنوز باز است.

UX-08 — ویجت‌های ناتمام و APIهای بی‌استفاده در چت

  • وضعیت: باز
  • اولویت: P2
  • مالک: flutter
  • فایل‌ها: ai_chat_toolbar.dart، ai_conversation_rail.dart، ai_conversation_nav_sheet.dart؛ updateChatSession(title:) بدون UI
  • مشکل: ریل/ناوبری/تولبار ساخته شده‌اند ولی flag طراحی خاموش است — نشانهٔ نیمه‌کاره ماندن بازطراحی. تغییر عنوان جلسه API دارد و در UI نیست. پین فقط SharedPreferences محلی است و بین دستگاه‌ها همگام نیست. Enter در دسکتاپ newline است نه ارسال.
  • معیار پذیرش: یا ویجت مرده حذف شود یا در محصول روشن شود؛ rename در سایدبار؛ پین سمت سرور یا صریحاً «فقط این دستگاه».
  • پیشنهاد: بعد از پایدار شدن استریم.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — Enter-to-send دسکتاپ در UX-09 انجام شد؛ بقیهٔ این آیتم (ریل خاموش، rename، پین) باز است.

UX-09 — بدون mention موجودیت و بدون Enter-to-send

  • وضعیت: در حال اصلاح
  • اولویت: P2
  • مالک: flutter
  • مشکل: Cursor/ChatGPT با @ فایل یا موجودیت را به context می‌آورند. اینجا مهارت و دانش در منوی بیشتر دفن شده‌اند. دسکتاپ بدون میانبر ارسال است.
  • معیار پذیرش: @مشتری / @کالا / @فاکتور با جستجوی زنده؛ Enter ارسال و Shift+Enter خط جدید (قابل تنظیم).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — در عرض غیر فشرده Enter ارسال می‌کند و Shift+Enter خط جدید می‌گذارد؛ موبایل newline می‌ماند. Enter روی overlay دستور slash همان دستور را اعمال می‌کند. mention موجودیت هنوز باز است.

J. صوت

VOI-01 — پایپلاین محلی پخته است؛ کیفیت و هم‌ترازی با متن فاصله دارد

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend + flutter
  • فایل‌ها: docs/AI_VOICE_CHAT_IMPLEMENTATION.md، voice_ws.py، VoiceChatController
  • مشکل: STT/VAD/TTS روی سرور خودتان (Piper فارسی) تمایز حریم خصوصی است. کیفیت TTS/STT از ابر پایین‌تر است. چت متنی هنگام صوت قفل می‌شود. رویدادهای voice_status با trace متنی یکی نیستند.
  • معیار پذیرش: کاربر بتواند وسط صوت به متن سوییچ کند بدون از دست رفتن context؛ latency perceived < ۱.۵s برای عبارت کوتاه.
  • پیشنهاد: barge-in؛ نمایش transcript زنده در همان thread؛ متریک WER روی نمونهٔ فارسی حسابداری.
  • وضعیت: باز (کیفیت TTS/STT و WER هنوز کامل نیست؛ UX سه‌حالته پیاده شد)
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — دیکته و بلندخوانی جدا از تماس؛ composer هنگام تماس قفل نیست؛ مدل/حالت اجرا/STT/TTS به WS پاس می‌شود؛ approval_required به بنر تأیید می‌رسد. کیفیت ابری وابسته به سیاست allow_cloud_audio است. WER فارسی هنوز معیار جدا می‌خواهد.

VOI-02 — احراز هویت WS با api_key در اولین فریم

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: مستند صوت، voice_ws.py
  • مشکل: طراحی بهتر از query string است. باید timeout برای فریم auth، محدودیت نرخ، و بستن اتصال بدون auth سخت باشد.
  • معیار پذیرش: بدون auth پس از N ثانیه drop؛ rate limit per user؛ عدم ذخیره صوت مگر opt-in (از قبل voice_data_collection_enabled).
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — سقف اتصال همزمان صوت per user (VoiceSessionGuard) اضافه شد؛ handshake بدون کلید همچنان timeout دارد. rate limit ریزتر روی utterance باقی است.

K. کانال‌های جانبی (تلگرام، CRM، تیکت، چت وب)

چت وب وردپرس (HesabixChatPlugin + CrmWebChatPage) چت انسان با بازدیدکننده است نه ایجنت حسابیکس. در این سند جدا می‌ماند تا با AI chat قاطی نشود.

CHN-01 — تلگرام همان ایجنت را با UX پیام‌رسان ضعیف اجرا می‌کند

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: telegram_ai_chat_service.py، telegram_ai_chat_text.py، telegram_ai_chat_handler.py، telegram_provider.py
  • مشکل: منوی دکمه و اتصال به جلسهٔ AI هست. استریم، trace، کارت تأیید نوشتن، جدول و نمودار در تلگرام معادل ندارند. قطع پیام طولانی، نبود typing پایدار، و تأیید write در callback نیازمند طراحی جداست.
  • معیار پذیرش: write بدون تأیید در تلگرام ممکن نباشد؛ پاسخ‌های بلند صفحه‌بندی شوند؛ وضعیت «در حال تحلیل» دیده شود.
  • پیشنهاد: تلگرام فقط روی همان run API (AGT-02) subscribe کند؛ تأیید با inline button = approval_id.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — execution_mode=supervised و approve_writes=False؛ نتایج ابزار persist می‌شوند؛ پاسخ بلند صفحه‌بندی می‌شود. دکمهٔ inline ai:approve:{id} / ai:reject:{id} و sendChatAction(typing) اضافه شد. استریم و جدول در تلگرام هنوز نیست (عمداً خارج از معیار پذیرش این آیتم).

CHN-02 — CRM AI و پیشنهاد تیکت غیر استریم و بدون ابزار دامنهٔ کامل

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend + flutter
  • فایل‌ها: adapters/api/v1/ai/crm_ai.py، ai_crm_parse.py، adapters/api/v1/support/ai_tickets.py، ai_channel_policy.py، ai_channel_stream.py، crm_ai_assistant_widget.dart، ai_ticket_assistant.dart
  • مشکل: یک completion با context متنی (حتی PII). بدون SSE، بدون function calling کامل، بدون citation. suggest-deal-probability در parse ناموفق به ۵۰٪ برمی‌گردد — عدد ساختگی خطرناک است. تاریخچهٔ فعالیت نازک (حدود ۵–۱۰ مورد). تست endpoint وجود ندارد.
  • معیار پذیرش: همان حلقهٔ ایجنت با ابزار محدود همان موجودیت؛ اگر احتمال قابل استخراج نیست خطا/نامشخص نه ۵۰؛ استریم در ویجت.
  • پیشنهاد: operation=crm_assist با tool allowlist؛ نمایش در crm_ai_assistant_widget.dart.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — fallback ۵۰ حذف شد. حلقه با execution_mode=analyzer، allowlist فقط‌خواندنی، سقف ۴ نوبت، حصار untrusted، و فیلدهای tools_used/citations. ۱۴۰۵/۰۵/۳۰ — ?stream=true روی خلاصهٔ سرنخ/فرصت و پیشنهاد تیکت؛ ویجت متن و وضعیت را زنده نشان می‌دهد و توقف قطع می‌کند. احتمال معامله همچنان JSON است (عدد پارس‌شده).

CHN-03 — چت وب CRM باید مسیر ارجاع به ایجنت داشته باشد

  • وضعیت: باز
  • اولویت: P3
  • مالک: product
  • مشکل: اپراتور در صندوق ورودی است؛ ایجنت حسابداری در صفحهٔ دیگر. Fin/Intercom ایجنت را روی همان ویجت مشتری می‌گذارند (با دانش و escalation).
  • معیار پذیرش: دکمهٔ «پیشنهاد پاسخ با AI» در صندوق CRM با استناد به دانش کسب‌وکار — نه جایگزینی انسان بدون سیاست.
  • یادداشت اصلاح:

L. ایجنت در ورک‌فلو

WFA-01 — نود AI Agent شبیه n8n است اما از حلقهٔ چت جداست

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: app/services/workflow/actions/ai_agent_action.py، ai_workflow_agent_policy.py
  • مشکل: max_iterations پیش‌فرض ۵، tools_mode all/category/custom، خروجی JSON. احتمالاً chat_completion غیر استریم. ابزارهای create_workflow به‌طور پیش‌فرض denylist — خوب. اما بودجه، write guard، execution_mode، و trace چت را reuse نمی‌کند. خطر حلقهٔ ورک‌فلو↔ایجنت.
  • معیار پذیرش: همان write guard و audit؛ log trace در اجرای ورک‌فلو؛ سقف هزینه per execution.
  • پیشنهاد: فراخوانی AIService با operation=workflow_agent و allowlist اجباری؛ هرگز tools=all در پروداکشن پیش‌فرض نباشد.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — ابزارهای نوشتنی پیش‌فرض حذف می‌شوند مگر allow_writes؛ حالت اجرا analyzer (یا supervised اگر write دیده شود) و approve_writes=False. denylist گردش‌کار سر جایش است. سقف هزینهٔ جدا و tools_mode پیش‌فرض all هنوز مانده.

WFA-02 — سیاست ورک‌فلو جدا (ai_workflow_agent_policy.py) باید منبع حقیقت واحد شود

  • وضعیت: در حال اصلاح
  • اولویت: P2
  • مالک: backend
  • مشکل: چند سیاست موازی (چت execution_mode، workflow policy، MCP approve). ناسازگاری یعنی یک مسیر write را بی‌تأیید رد می‌کند.
  • معیار پذیرش: ماتریس واحد «تابع × کانال × حالت اجرا × تأیید».
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — ai_channel_policy.py شروع ماتریس است (allowlist CRM/تیکت، سقف نوبت، حفظ لیست ابزار کالر تا routing «ساده» کاتالوگ ورک‌فلو را دور نریزد). denylist گردش‌کار هنوز در ai_workflow_agent_policy.py جداست.

M. MCP و کانکتورهای خارجی

MCP-01 — پروتکل قدیمی و فقط tools روی HTTP JSON-RPC

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_mcp_service.py (MCP_PROTOCOL_VERSION = "2024-11-05")، adapters/api/v1/ai/mcp.py
  • مشکل: استاندارد ۲۰۲۵ resources/prompts/sampling و انتقال SSE/stdio را دارد. listChanged: false. کلاینت‌های Cursor/Claude Desktop انتظار handshake و notifications دارند. این endpoint بیشتر یک RPC ابزار است تا MCP کامل. کلاینت MCP وجود ندارد — ایجنت نمی‌تواند سرور MCP خارجی کسب‌وکار را مصرف کند (برخلاف Cursor).
  • معیار پذیرش: سازگاری با spec جاری؛ resources برای دانشنامه؛ prompts برای مهارت؛ بدون write از طریق query (SEC-02)؛ حداقل یک MCP client برای کانکتور خارجی.
  • پیشنهاد: سرور MCP جدا (stdio برای دسکتاپ، SSE برای کلود) با همان registry.
  • یادداشت اصلاح:

N. ارزیابی، مشاهده‌پذیری، عملیات

OBS-01 — Eval برابر substring است

  • وضعیت: در حال اصلاح
  • اولویت: P0
  • مالک: backend
  • فایل‌ها: ai_eval_service.py (DEFAULT_EVAL_CASES)، ai_eval_assertions.py، ai_eval_schedule_service.py، مدل‌های ai_eval_*
  • مشکل: سه کیس پیش‌فرض با expected_substrings. زمان‌بندی cron و min_pass_rate هست. _schedule_fired درون‌حافظه است و در چند worker تکراری/ازدست‌رفته می‌شود. این برای رگرسیون prompt کافی نیست: ابزار درست، عدد درست، عدم write بدون تأیید را نمی‌سنجد. حدود ۴۶ فایل test_ai_* (~۳۳۰۰ خط) عمدتاً حلقهٔ ایجنت را می‌پوشانند نه محصول.
  • معیار پذیرش: هر PR روی ابزار/prompt یک suite: tool_called، no_write_without_approval، citation_present، language_fa. LLM-as-judge برای روانی. Fail CI اگر pass_rate < آستانه. قفل زمان‌بندی در Redis/DB.
  • پیشنهاد: کیس‌ها از تیکت‌های واقعی (باscrub)؛ اتصال به ai_eval_premature.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — امتیازدهی tool_called، no_write_without_approval، citation_present، language_fa و fluency_ok بدون LLM؛ tests/test_ai_eval_gold_ci.py اگر pass_rate آفلاین < MIN_OFFLINE_EVAL_PASS_RATE باشد CI را می‌شکند. زمان‌بندی با SELECT … FOR UPDATE و slot در last_run_at قفل می‌شود. LLM-as-judge و fail روی pass_rate زنده هنوز نیست.

OBS-02 — متریک فقط لاگ است

  • وضعیت: در حال اصلاح
  • اولویت: P1
  • مالک: backend + infra
  • فایل‌ها: ai_ops_metrics.py (log_ai_event + شمارندهٔ درون‌پردازه‌ای)
  • مشکل: بدون داشبورد latency p50/p95، هزینه per business، نرخ fallback دانش، نرخ APPROVAL، نرخ stop_reason. دیباگ پروداکشن بدون trace_id سخت است.
  • معیار پذیرش: هر run یک trace با spanهای prompt_build، llm_round، tool، persist؛ قابل جستجو per session.
  • پیشنهاد: OpenTelemetry + (Langfuse یا Phoenix)؛ حداقل Prometheus counters.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — هر log_ai_event شمارندهٔ فرآیند را زیاد می‌کند؛ metric_snapshot() برای تست/دیباگ. Prometheus و OTel هنوز نیست.

OBS-03 — فیدبک کاربر به بهبود مدل/prompt حلقه نشده

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_feedback_service.py، ai_feedback_analytics_service.py، API /feedback/analytics
  • مشکل: thumbs و analytics endpoint هست. حلقهٔ بسته به eval set یا memory HITL کامل نیست.
  • معیار پذیرش: هر هفته ۱۰ نمونهٔ thumbs-down وارد eval شود.
  • یادداشت اصلاح:

O. سهمیه، مدل، BYOK

BIL-01 — سهمیه قبل از چت اجباری است؛ شفافیت هزینه وسط چت کم است

  • وضعیت: باز
  • اولویت: P2
  • مالک: flutter + backend
  • فایل‌ها: _ensure_chat_availability، ai_quota_helpers.py، ai_chat_model_chip.dart (modelPricingHint)
  • مشکل: چک اشتراک خوب است. کاربر وسط جلسه نمی‌بیند این پاسخ چقدر واحد مصرف کرد (جز در done). مدل auto ممکن است مدل گران resolve کند بدون توضیح.
  • معیار پذیرش: بعد از هر پاسخ: توکن، هزینهٔ تقریبی، مدل واقعی؛ اگر resolve با requested فرق داشت نشان داده شود (requested_model در usage context از قبل هست).
  • پیشنهاد: chip مدل بعد از پاسخ «اجرا شد با X».
  • یادداشت اصلاح:

BIL-02 — تسک زمان‌بندی‌شده فقط ۴ الگوی ثابت

  • وضعیت: باز
  • اولویت: P2
  • مالک: product + backend
  • فایل‌ها: ai_scheduled_task_service.py
  • مشکل: گزارش هفتگی / معوق / موجودی کم / خلاصه ماهانه. کاربر نمی‌تواند «هر روز بدهکاران بالای X» بسازد. این همان «background agent» محصولات جهانی است.
  • معیار پذیرش: تسک سفارشی با prompt + cron + کانال تحویل (ایمیل/درون‌برنامه) با سقف هزینه.
  • یادداشت اصلاح:

P. معماری، داده، تست

ARC-01 — God Object سمت سرور

  • وضعیت: در حال اصلاح
  • اولویت: P0
  • مالک: backend
  • فایل‌ها: ai_service.py ~3600، ai_model_router.py، ai_usage_meter.py
  • مشکل: سهمیه، routing مدل، prompt، حلقه، tool dispatch، usage در یک کلاس. تغییر استریم ریسک رگرسیون سهمیه دارد. موازی‌سازی توسعه سخت است.
  • معیار پذیرش: AIService نمای نازک؛ AgentLoop, PromptBuilder, UsageMeter, ModelRouter جدا؛ همان تست‌های موجود سبز.
  • پیشنهاد: استخراج تدریجی بدون big-bang؛ شروع از chat_completion_stream.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — AIModelRouterMixin و AIUsageMeterMixin از کلاس جدا شدند؛ امضای عمومی AIService عوض نشده. حلقهٔ استریم و check_availability هنوز داخل God Object است.

ARC-02 — DB سنکرون داخل executor

  • وضعیت: باز
  • اولویت: P2
  • مالک: backend
  • مشکل: در ISSUES به‌عنوان باقی‌مانده ثبت شده. برای مقیاس چت همزمان، pool و thread starvation محتمل است.
  • معیار پذیرش: مسیر استریم بدون block لوپ؛ session کوتاه per tool یا async SQLAlchemy.
  • یادداشت اصلاح:

ARC-03 — مدل پیام برای ایجنت ناقص است

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • فایل‌ها: ai_chat_message.py — function_calls/function_results به‌صورت Text JSON؛ نقش FUNCTION در enum هست
  • مشکل: trace، budget، todos داخل function_results با کلیدهای _agent_* قاچاق می‌شوند. گزارش و مهاجرت سخت است. پیام tool به‌عنوان ردیف first-class ذخیره نمی‌شود.
  • معیار پذیرش: ستون‌های جدا یا JSONB typed؛ جدول ai_chat_message_parts (text, tool_call, tool_result, trace).
  • پیشنهاد: مهاجرت تدریجی؛ خواندن backward compatible.
  • یادداشت اصلاح:

ARC-04 — تست Flutter تقریباً صفر است

  • وضعیت: انجام‌شده
  • اولویت: P1
  • مالک: flutter
  • مشکل: یک تست پارسر جدول. استریم، تأیید، لغو، مدل chip بدون تست.
  • معیار پذیرش: تست واحد برای AIChatStreamController (بدون UI) پوشش eventهای SSE؛ ویجت تست برای approval banner.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — تست واحد برای stream controller (begin/clear، delta، tool+approval، heartbeat، done، cancel snapshot، merge trace)، extractPendingApprovalOpsFromResults، و AIChatResumeHint. ۱۴۰۵/۰۵/۲۸ — consume نوبت استریم؛ interpretVoiceServerEvent (ready/dummy TTS/transcript/delta/done/timeout/empty). ویجت‌تست بنر تأیید هنوز نیست.

ARC-05 — مسیر dual chat_completion با ThreadPoolExecutor موقت

  • وضعیت: انجام‌شده
  • اولویت: P2
  • مالک: backend
  • فایل‌ها: ai_service.py — chat_completion_sync
  • مشکل: ساخت pool به ازای هر فراخوانی sync از context async؛ هزینه و پیچیدگی. بعد از STR-02 حذف می‌شود.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — حلقهٔ دوگانه حذف شد (STR-02). chat_completion_sync از pool مشترک _executor استفاده می‌کند؛ asyncio.run تودرتو برای ورک‌فلو از context async هنوز لازم است.

ARC-06 — پوشش تست زیرسیستم‌ها نازک است

  • وضعیت: باز
  • اولویت: P1
  • مالک: backend
  • مشکل: تست قوی روی continuation/budget/routing/write-guard است. تقریباً بدون تست: CRUD حافظهٔ آیتم و hooks، skill runtime/marketplace، hybrid RAG/pgvector، MCP JSON-RPC، invoke کانکتور، صوت، CRM AI، citation/attachment/export، اجرای eval suite، AIAgentAction، ترکیب prompt_service.
  • معیار پذیرش: برای هر زیرسیستم در کارت امتیاز حداقل یک تست مسیر اصلی + یک تست شکست (ایندکس، approval، SSRF).
  • پیشنهاد: شروع با MCP write-approval، memory item CRUD، skill select_skills_for_query، CRM probability بدون fallback ۵۰.
  • یادداشت اصلاح: ۱۴۰۵/۰۵/۲۶ — تست citation/eval assertion و MCP write-guard اضافه شد؛ موج دهم: router mixin، untrusted/PII، SSRF IPv6، gold eval CI، شمارندهٔ متریک. CRUD حافظه، RAG/pgvector، صوت و ورک‌فلو هنوز نازک است.

Q. شکاف قابلیت محصول (سطح جهانی که هنوز نیست)

این‌ها عمداً P3اند مگر اینکه محصول تصمیم بگیرد زودتر.

شناسه قابلیت رقیب مرجع وضعیت
GAP-01 Computer use / مرور UI حسابیکس Claude Computer Use, OpenAI Operator باز
GAP-02 تصویر فاکتور → سند ChatGPT vision باز (RAG-03)
GAP-03 همکاری چندکاربره روی یک جلسه ChatGPT shared باز
GAP-04 ایجنت پس‌زمینهٔ سفارشی ChatGPT scheduled, Cursor background باز (BIL-02)
GAP-05 فروشگاه مهارت عمومی با پول GPT Store / Claude skills فاز ۳ سند مهارت
GAP-06 پاسخ صوتی دوطرفه هم‌تراز GPT-4o Realtime OpenAI Realtime جزئی (VOI)
GAP-07 چند ایجنت تخصصی (حسابدار، انباردار، فروش) Custom GPT / Agent teams باز — جدا از AGT-06 (subagent موقت)
GAP-08 شبیه‌سازی what-if مالی با sandbox Copilot for Finance باز

ماتریس اولویت ۱۲ هفته

اسپرینت‌ها پیشنهادی‌اند؛ ترتیب را با ظرفیت تیم عوض کنید.

هفته تمرکز آیتم‌ها
۱–۲ ایمنی و پایداری SEC-02✓، STR-01✓، STR-05✓، UX-07✓، RAG-01✓، AGT-01✓
۳–۴ معماری قابل حرکت ARC-01 (شروع: ModelRouter+UsageMeter mixin)، STR-02✓، UX-01 (resume + approval + turn helpers)، AGT-07✓، AGT-03✓، AGT-04✓، ARC-05✓
۵–۶ ابزار درست TOOL-01✓، TOOL-06✓، AGT-05✓، TOOL-04✓، TOOL-07✓
۷–۸ اعتماد پاسخ RAG-02✓، AGT-08✓، OBS-01 (assertion + gold CI)، ARC-06 (شروع)
۹–۱۰ کانال‌ها CHN-01✓، CHN-02 حلقه+allowlist (استریم ویجت مانده)، WFA-01✓، WFA-02 شروع ماتریس، SEC-01✓، SEC-05✓، PRM-02✓، SKL-01 (chip)
۱۱–۱۲ چت و مشاهده UX-09 Enter-to-send، UX-01 شیت پیام + SessionController + consume استریم + VoiceSession، UX-02 snackbar/حافظه/دانش، PRM-04✓ لایهٔ semi_static، TOOL-06✓ متریک موازی، AGT-06✓ قرارداد+حلقه+cancel subagent

فاز ۹ ابزار دامنه (TOOL-03) می‌تواند موازی با هفتهٔ ۵–۸ جلو برود اگر مالک محصول جدا باشد.


چک‌لیست هر Pull Request مربوط به AI

کپی کنید داخل توصیف PR:

  • ابزار جدید: function_registry + ai_permission_map + ai_tool_intent + ai_tool_keys + ai_chat_l10n + write guard اگر نوشتنی است
  • کیس eval یا تست واحد برای رفتار جدید
  • SSE: اگر event جدید است، Dart model + نسخه پروتکل
  • بدون رشتهٔ کاربرنما hardcoded (FA/EN)
  • اگر حلقه عوض شد: مسیر stream و non-stream یا تجمیع واحد
  • این سند: وضعیت آیتم + یک سطر تاریخچه

فهرست فایل‌های لنگر (برای مرور جزبه‌جز)

بک‌اند هسته
ai_service.py · ai_model_router.py · ai_usage_meter.py · ai_agent_run.py · ai_agent_continuation.py · ai_goal_assessment.py · ai_budget.py · ai_execution_policy.py · ai_write_guard.py · ai_untrusted.py · ai_tool_intent.py · ai_tool_result.py · ai_tool_parallel.py · ai_subagent.py · ai_system_prompt.py · ai_prompt_cache.py · ai_insight_service.py · ai_citation_service.py · ai_eval_assertions.py · function_registry.py · ai_provider.py · prompt_service.py · adapters/api/v1/ai/chat.py

حافظه و دانش
ai_memory_service.py · ai_memory_item_service.py · ai_knowledge_service.py · ai_embedding_service.py · ai_citation_service.py · ai_attachment_service.py

مهارت / MCP / ورک‌فلو
ai_skill_runtime.py · ai_mcp_service.py · ai_connector_service.py · workflow/actions/ai_agent_action.py

کانال
telegram_ai_chat_service.py · telegram_ai_chat_handler.py · telegram_ai_chat_text.py · ai_channel_policy.py · adapters/api/v1/ai/crm_ai.py · adapters/api/v1/support/ai_tickets.py · adapters/api/v1/ai/voice_ws.py

فرانت
ai_chat_dialog.dart · ai_chat_stream_controller.dart · ai_chat_stream_turn.dart · ai_chat_voice_session.dart · ai_chat_session_controller.dart · ai_chat_turn.dart · ai_chat_composer.dart · ai_chat_composer_keys.dart · ai_chat_message_sheet.dart · ai_chat_memory_sheet.dart · ai_chat_knowledge_sheet.dart · ai_chat_message_body.dart · ai_chat_resume.dart · ai_citation_chips.dart · ai_tool_envelope.dart · ai_write_approval_banner.dart · crm_ai_assistant_widget.dart · lib/services/ai_service.dart

ثابت‌ها
ai_constants.py — هر تغییر سقف اینجا باید در این سند منعکس شود.


تاریخچهٔ به‌روزرسانی

تاریخ نسخه چه تغییر کرد
۱۴۰۵/۰۵/۲۶ 1.0 ممیزی اولیه از روی کد؛ همهٔ آیتم‌ها باز
۱۴۰۵/۰۵/۲۶ 1.1 ادغام یافته‌های خط‌به‌خط: done ناقص (STR-05)، باگ خطای UI (UX-07)، شاخهٔ مرده continuation (AGT-07)، ابزار موازی (TOOL-06)، تست زیرسیستم (ARC-06)، CRM احتمال ۵۰، MCP بدون کلاینت
۱۴۰۵/۰۵/۲۶ 1.2 پیاده‌سازی موج اول: STR-05، UX-07، AGT-07، SEC-02، RAG-01
۱۴۰۵/۰۵/۲۶ 1.3 موج دوم: TOOL-06 سقف موازی ابزار، AGT-01 جدول+API+UI ادامه، STR-01 event id و Last-Event-ID، CHN-02 حذف fallback احتمال ۵۰
۱۴۰۵/۰۵/۲۶ 1.4 موج سوم: STR-02 aggregator حلقهٔ واحد، AGT-04 دروازهٔ persist بدون ابزار، AGT-03 بنر ادامه با stop_message، ARC-05 pool مشترک
۱۴۰۵/۰۵/۲۶ 1.5 موج چهارم: TOOL-01 رتبهٔ واژه‌ای سقف ۴۸، تاریخچه+اتحاد مهارت، مجموعه طلایی recall
۱۴۰۵/۰۵/۲۶ 1.6 موج پنجم: AGT-05 ابزار plan در allowlist و tool_choice برای complex؛ UX-01 برش resume hint؛ ARC-04 تست واحد Flutter
۱۴۰۵/۰۵/۲۶ 1.7 موج ششم: TOOL-04 envelope برش نتیجه؛ TOOL-07 tool_choice آنتروپیک؛ پین برنامه در UX؛ جدول از رکورد ابزار
۱۴۰۵/۰۵/۲۶ 1.8 موج هفتم: AGT-08 تکرار ابزار پس از خطا؛ AGT-05 رد/تأیید todo توسط کاربر؛ UX-01 برش collectPendingApprovalOps
۱۴۰۵/۰۵/۲۶ 1.9 موج هشتم: RAG-02 chip استناد قابل کلیک؛ OBS-01 assertionهای tool/write/citation/language بدون LLM
۱۴۰۵/۰۵/۲۶ 2.0 موج نهم: SEC-01 approval_id؛ SEC-05 fail-closed؛ WFA-01 بدون write پیش‌فرض؛ PRM-02 گزارش کوتاه medium؛ CHN-01 صفحه‌بندی+persist؛ SKL-01 chip مهارت
۱۴۰۵/۰۵/۲۶ 2.1 موج دهم: ARC-01 mixin مسیریابی/سهمیه؛ UX-01 turn helpers؛ OBS-01 دروازه CI + fluency + قفل زمان‌بندی؛ SEC-03/۰۴ SSRF و untrusted؛ PRM-01 سیاست استاتیک؛ OBS-02 شمارنده
۱۴۰۵/۰۵/۲۶ 2.2 موج یازدهم: حفظ tools کالر؛ سیاست کانال CRM/تیکت؛ تأیید inline تلگرام + typing؛ chip ابزار/استناد CRM
۱۴۰۵/۰۵/۲۸ 2.3 موج دوازدهم (چت): Enter-to-send دسکتاپ؛ شیت اقدامات پیام جدا؛ l10n کروم composer/app bar/بنر تأیید؛ liveRegion دسترسی‌پذیری
۱۴۰۵/۰۵/۲۸ 2.4 موج سیزدهم (چت): AIChatSessionController برای جلسه/پیام؛ planChatSend؛ بدون جابه‌جایی حلقهٔ استریم
۱۴۰۵/۰۵/۲۸ 2.5 موج چهاردهم (چت): حلقهٔ SSE در AIChatStreamController.consume؛ AIChatStreamTurn؛ l10n پاسخ خالی؛ تست نوبت استریم
۱۴۰۵/۰۵/۲۸ 2.6 موج پانزدهم (چت): AIChatVoiceSessionController + تفسیر رویداد صوت؛ l10n snackbar چت و شیت حافظه/دانش
۱۴۰۵/۰۵/۲۸ 2.7 بررسی runtime: AGT-06 بدون subagent (P1)؛ TOOL-06 موازی read موجود؛ PRM-04 تکرار بینش در system نه در تاریخچه؛ سناریوی اجرا
۱۴۰۵/۰۵/۲۸ 2.8 PRM-04 لایهٔ semi_static + تفکیک توکن context_usage؛ TOOL-06 متریک موازی و eval چنددامنه‌ای؛ AGT-06 spawn/await/cancel با سقف ۲×۴ و fail-closed نوشتن
۱۴۰۵/۰۵/۲۷ 2.8+ لینک صف محصولی AI_CHAT_PRODUCT_ISSUES.md (CHAT-01…06 از گزارش کاربر)
۱۴۰۵/۰۵/۳۰ 2.9 CHN-02 استریم CRM/تیکت؛ replay بافر حین poll چند-ورکر؛ schema_version روی SSE