302 lines
27 KiB
Markdown
302 lines
27 KiB
Markdown
# مشکلات محصولی چت هوش مصنوعی — فهرست کار زنده
|
||
|
||
**نسخه سند:** 1.2
|
||
**تاریخ:** ۱۴۰۵/۰۵/۳۰ (۲۱ اوت ۲۰۲۶)
|
||
**وضعیت:** زنده — پس از هر اصلاح، وضعیت آیتم را عوض کنید و یک سطر در [تاریخچه](#تاریخچه-بهروزرسانی) بگذارید.
|
||
**مرجع معماری:** [`AI_AGENT_SYSTEM_AUDIT.md`](AI_AGENT_SYSTEM_AUDIT.md)
|
||
**مرجع subagent:** [`AI_AGENT_RUNTIME_CAPABILITIES_SCENARIO.md`](AI_AGENT_RUNTIME_CAPABILITIES_SCENARIO.md)
|
||
|
||
> این سند **لیست کار محصولی** است، نه ممیزی سطح جهانی. تمرکز: چیزهایی که کاربر الان در رابط چت میبیند و خراب است. ممیزی (`AGT-*`, `TOOL-*`, `UX-*`) را عوض نکنید مگر همان آیتم واقعاً بسته شود؛ اینجا شناسههای `CHAT-*` برای صف اصلاح روزانهاند.
|
||
|
||
---
|
||
|
||
## چگونه از این سند استفاده کنیم
|
||
|
||
1. از [صف اصلاح پیشنهادی](#صف-اصلاح-پیشنهادی) شروع کنید.
|
||
2. هر آیتم یک شناسه `CHAT-xx` دارد. وضعیت فقط از این مجموعه: `باز` · `در حال اصلاح` · `انجامشده` · `موکول` · `نپذیرفته`.
|
||
3. بعد از فیکس: وضعیت + تاریخ + یک خط «چه شد» در همان آیتم، و یک سطر در تاریخچه.
|
||
4. تست پذیرش دستی را قبل از بستن آیتم روی یک جلسهٔ واقعی فارسی اجرا کنید.
|
||
|
||
**منابع این نسخه**
|
||
|
||
- سورس حلقهٔ ایجنت، API چت، و UI Flutter (۱۸ اوت ۲۰۲۶).
|
||
- گفتوگوی ممیزی ۱۷–۱۸ اوت: [`ممیزی سیستم ایجنت`](858f8cb5-06c0-41f1-959c-b78f8f14b9f9) — subagent بکاند ساخته شد، **فاز UI عمداً موکول شد**.
|
||
- گزارش مستقیم کاربر روی شش مشکل زیر.
|
||
|
||
---
|
||
|
||
## خلاصهٔ اجرایی
|
||
|
||
بکاند قابلیتهای ایجنت (ابزار، تأیید نوشتن، spawn زیر-ایجنت، تایملاین تفکر) را دارد؛ **قرارداد نمایش و بازیابی خطا هنوز محصولی نیست.** نتیجه برای کاربر فارسی:
|
||
|
||
| # | آنچه کاربر میبیند | ریشه در کد (کوتاه) |
|
||
|---|---------------------|---------------------|
|
||
| ۱ | ابزار خطا میدهد و ایجنت گیر میکند | خطای خام انگلیسی؛ سقف ۲ شکست یکسان حلقه را میبندد؛ ابزار غایب از کاتالوگ ۴۸تایی |
|
||
| ۲ | زیر-ایجنت نامرئی است | spawn فقط در حافظهٔ فرایند؛ هیچ `trace_step` و هیچ پنل UI |
|
||
| ۳ | جدول بیمعنی با `trace_id` / `step_id` / `kind` | UI هر لیست Map را جدول میکشد؛ `_reasoning_trace` فیلتر نشده |
|
||
| ۴ | متن بهصورت `** بولد **` دیده میشود | نرمالسازی فقط روی پاسخ نهایی؛ پنل تفکر و RTL پوشش ناقص |
|
||
| ۵ | «در حال فکر کردن» انگلیسی است | `reasoning_content` مدل بومی انگلیسی است؛ mismatch فقط log میشود |
|
||
| ۶ | دکمهٔ تأیید → لودینگ بیپایان + توهم | تأیید = پیام جعلی کاربر + حلقهٔ کامل جدید؛ `wait=true` پیشفرض spawn استریم را قفل میکند |
|
||
|
||
---
|
||
|
||
## صف اصلاح پیشنهادی
|
||
|
||
ترتیب برای بیشترین اثر روی تجربهٔ کاربر، با کمترین ریسک امنیتی:
|
||
|
||
| اولویت | شناسه | کار | تخمین |
|
||
|--------|--------|------|--------|
|
||
| P0 | CHAT-03 | فیلتر متادیتای داخلی از جدول خودکار | کوچک — Flutter |
|
||
| P0 | CHAT-06 | تأیید نوشتن بدون پیام جعلی و بدون گیر کردن استریم | متوسط — API + Flutter |
|
||
| P0 | CHAT-04 | رندر markdown بولد در پاسخ و تفکر | کوچک — Flutter |
|
||
| P1 | CHAT-05 | تفکر قابلنمایش همزبان کاربر | متوسط — prompt + سیاست نمایش |
|
||
| P1 | CHAT-01 | خطای ابزار قابل بازیابی برای مدل | متوسط — بکاند |
|
||
| P1 | CHAT-02 | پنل زیر-ایجنت (دیدن / قطع) | بزرگ — Flutter + SSE |
|
||
| P2 | CHAT-07+ | موارد کمکی صحت سیستم (پایین سند) | انجامشده |
|
||
|
||
---
|
||
|
||
# مشکلات گزارششدهٔ کاربر
|
||
|
||
## CHAT-01 — ابزارها خطا میدهند و مدل نمیتواند رفع کند
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P1
|
||
- مالک: backend
|
||
- فایلها: `function_registry.py` (`call_function`)، `ai_service.py` (`handle_function_calls_async`)، `ai_tool_result.py` (`compact_tool_result_for_llm`)، `ai_goal_assessment.py` (`ToolCallTracker`)، `ai_tool_intent.py`
|
||
- شواهد از کد:
|
||
1. هر استثنا به `{"error": str(e)}` تبدیل میشود؛ پیام اغلب انگلیسی و بدون `code` / `hint` / فیلدهای مجاز است.
|
||
2. `compact_tool_result_for_llm` برای خطا فقط `error` و `message` را نگه میدارد — schema پارامتر از دست میرود.
|
||
3. `AGENT_MAX_IDENTICAL_TOOL_FAILURES = 2`: دو بار همان tool+args → حلقه **بسته** میشود (AGT-08). از دید کاربر «نتوانست رفع کند».
|
||
4. کاتالوگ هر نوبت حداکثر ۴۸ ابزار است. اگر intent دسته را اشتباه بزند، مدل نامی را صدا میزند که در registry نیست → `Function 'X' not found`.
|
||
5. نام ناشناخته با registry **write فرض میشود** (`is_write_function` fail-closed). مدل ممکن است برای ابزار خیالی کارت تأیید بگیرد.
|
||
6. `spawn_subagent` با `wait=True` پیشفرض تا ۹۰ ثانیه والد را قفل میکند؛ از نظر کاربر ابزار «هنگ» کرده.
|
||
- شواهد از سوابق: در موجهای ۱۷–۱۸ اوت، AGT-08 عمداً تکرار شکست را قطع کرد تا حلقه بینهایت نشود؛ مسیر **ترمیم آرگومان** (مثلاً «این فیلد اجباری است، دوباره با X صدا بزن») ساخته نشد.
|
||
- معیار پذیرش:
|
||
- خطای ابزار برای مدل همیشه JSON پایدار باشد: `ok=false`, `code`, `message_fa`, `hint_fa`, `retryable`, در صورت امکان `expected_args`.
|
||
- نام ابزار ناموجود → `UNKNOWN_TOOL` با نزدیکترین نامهای مجاز، نه Permission/Approval.
|
||
- پس از خطای قابلرفع، مدل حداقل یک بار با آرگومان اصلاحشده تلاش کند؛ اگر باز شکست خورد، به کاربر فارسی توضیح بدهد نه اینکه ساکت حلقه را ببندد.
|
||
- تست: کیس طلایی «ابزار با آرگومان ناقص» → retry با آرگومان کامل؛ کیس «نام غلط» → hint نه approval.
|
||
- پیشنهاد اصلاح:
|
||
1. لایهٔ `normalize_tool_error(exc, function_name, schema)` قبل از برگرداندن به مدل.
|
||
2. اگر نام در registry نیست، هرگز write/approval نشود.
|
||
3. در prompt پس از خطا: «آرگومان قبلی را تکرار نکن؛ از hint استفاده کن.»
|
||
4. لاگ `AI_METRIC tool_error` با `code` برای مشاهدهپذیری.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — `normalize_tool_error` / `unknown_tool_result` قبل از write-guard؛ compact JSON فیلدهای `hint_fa` و `expected_args` را نگه میدارد؛ نام ناموجود دیگر approval نمیگیرد. باگ `unexpected keyword argument 'db'` در `_create_handler` برای قرارداد `(args, context)` رفع شد.
|
||
|
||
---
|
||
|
||
## CHAT-02 — زیر-ایجنت برای کاربر دیده و مدیریت نمیشود
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P1
|
||
- مالک: flutter + backend
|
||
- فایلها: `ai_subagent.py`، `ai_function_extensions_subagent.py`، ویجتهای `lib/widgets/ai/` (هیچ پنل subagent نیست)، `ai_agent_trace_timeline.dart`
|
||
- آنچه امروز هست (فاز ۰–۲ AGT-06):
|
||
- ابزارهای `spawn_subagent` / `await_subagent` / `cancel_subagent`.
|
||
- store فقط `_runs` درونحافظهٔ فرایند؛ با ریاستارت API از بین میرود.
|
||
- سقف ۲ همزمان، ۴ نوبت، timeout ۹۰ ثانیه، بدون write در فرزند.
|
||
- پیشفرض `wait=False`: والد استریم را قفل نمیکند؛ برای ادغام صریح `await_subagent`.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — `trace_step kind=subagent` با `explore_target=subagent_id`؛ دکمهٔ قطع در تایملاین؛ `POST /sessions/{id}/subagents/{sid}/cancel`؛ پیشفرض wait=false.
|
||
|
||
---
|
||
|
||
## CHAT-03 — جدول داخلی `trace_id` / `step_id` / `kind` در انتهای پیام
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P0
|
||
- مالک: flutter
|
||
- فایلها: `ai_tool_envelope.dart` (`extractToolTableSpecsFromResults`)، `ai_visualization_spec.dart` (`AITableSpec.tryFromRecords`)، `ai_chat_message_body.dart`، `ai_trace.py` (`merge_trace_into_function_results`)
|
||
- علت قطعی:
|
||
1. پس از TOOL-04، اگر پاسخ markdown جدول نداشته باشد، UI **بزرگترین لیست Map** داخل `function_results` را جدول میکشد.
|
||
2. کلیدهای داخلی که skip میشوند فقط اینها هستند: `_agent_trace`, `_agent_budget`, `_agent_todos`, `_agent_run`.
|
||
3. `merge_trace_into_function_results` علاوه بر `_agent_trace`، لایهٔ تفکر را در `_reasoning_trace` میگذارد — **لیستی از گامها با فیلدهای `trace_id`, `step_id`, `kind`, `state`, `layer`, `visibility`**.
|
||
4. `extractToolRecordsFromResult` اگر مقدار یک List از Map باشد همان را ردیف جدول میکند.
|
||
5. نتیجه دقیقاً جدولی است که کاربر گزارش کرده. `_citations` و `_activated_skills` هم میتوانند جدول بیربط بسازند.
|
||
- معیار پذیرش:
|
||
- هیچ کلید `_…` و هیچ لیست trace/citation/skill بهصورت جدول داده نشان داده نشود.
|
||
- جدول فقط از envelope ابزار دامنه (`records`/`items`/…) با ستونهای کسبوکاری (نام، مبلغ، تاریخ، کد) بیاید.
|
||
- ستونها برچسب فارسی داشته باشند نه کلید خام API.
|
||
- تست واحد: `function_results` شامل `_reasoning_trace` با ۲+ گام → `extractToolTableSpecsFromResults` خالی یا فقط رکورد فاکتور نمونه.
|
||
- پیشنهاد اصلاح:
|
||
1. skip: `_reasoning_trace`, `_citations`, `_activated_skills` و هر کلید با پیشوند `_`.
|
||
2. اگر کلیدهای غالب ردیف `trace_id`/`step_id`/`kind` بود، جدول ساخته نشود.
|
||
3. allowlist ستون کسبوکار یا نگاشت `key → label_fa`.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — skip همهٔ کلیدهای `_…` از جمله `_reasoning_trace`؛ اگر ستونها شبیه trace باشند جدول ساخته نمیشود.
|
||
|
||
---
|
||
|
||
## CHAT-04 — بولد بهصورت `** متن **` در رابط
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P0
|
||
- مالک: flutter
|
||
- فایلها: `ai_chat_message_body.dart` (`normalizeAssistantMarkdown`)، `ai_thinking_scroll_box.dart`، `ai_agent_trace_timeline.dart` (`_BodyContent`)
|
||
- علت:
|
||
1. نرمالسازی فاصله داخل `** … **` فقط روی **پاسخ نهایی** اعمال میشود.
|
||
2. پنل تفکر (`AIThinkingScrollBox`) و تایملاین همان متن خام را به `MarkdownBody` میدهند.
|
||
3. مدلهای reasoning اغلب `** متن **` با فاصله مینویسند (CommonMark این را بولد نمیداند).
|
||
4. با RTL فارسی، `flutter_markdown` گاهی `**` را جدا از کلمه پارس میکند؛ فاصلهٔ یونیکد فارسی/`\u200c` در regex فعلی (`[ \t]*`) نیست.
|
||
- معیار پذیرش:
|
||
- در پاسخ نهایی، پنل تفکر، و body گامهای trace، `**متن**` و `** متن **` هر دو بولد دیده شوند.
|
||
- بلوک کد و `` `inline` `` دست نخورند.
|
||
- نمونهٔ فارسی با نیمفاصله در تست ویجت.
|
||
- پیشنهاد اصلاح:
|
||
1. `normalizeAssistantMarkdown` را به یک util مشترک ببرید و در هر `MarkdownBody` چت صدا بزنید.
|
||
2. regex را به فاصلهٔ یونیکد و ZWNJ گسترش دهید.
|
||
3. در صورت باقیماندن باگ RTL، renderer جایگزین یا پیشپردازش قویتر.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — `normalizeAssistantMarkdown` به util مشترک رفت؛ پنل تفکر و تایملاین هم نرمال میشوند؛ فاصلهٔ یونیکد/ZWNJ پوشش داده شد.
|
||
|
||
---
|
||
|
||
## CHAT-05 — متن «در حال فکر کردن» انگلیسی است وقتی زبان کاربر فارسی است
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P1
|
||
- مالک: backend (+ flutter اگر سیاست نمایش عوض شود)
|
||
- فایلها: `ai_language_prompt.py`، `ai_service.py` (استریم `reasoning_content` → `trace_step kind=reasoning`)، `ai_provider.py`، `ai_thinking_scroll_box.dart`
|
||
- علت:
|
||
1. بلوک زبان از مدل میخواهد reasoning را فارسی بنویسد.
|
||
2. کانال **native** مدلهای reasoning (o-series / gpt-5 / thinking آنتروپیک) تقریباً همیشه انگلیسی است و از system prompt پیروی نمیکند.
|
||
3. همان توکنها زنده به UI استریم میشوند.
|
||
4. `reasoning_language_mismatch` فقط `logger.warning` است — ترجمه، حذف، یا جایگزینی با خلاصهٔ فارسی انجام نمیشود.
|
||
- معیار پذیرش:
|
||
- اگر زبان مؤثر چت `fa` باشد، متن داخل باکس تفکر برای کاربر فارسی باشد (یا باکس native انگلیسی نشان داده نشود).
|
||
- عناوین گام (`title_key`) از قبل l10n هستند — حفظ شوند.
|
||
- اگر مدل فقط انگلیسی think کند: یا خلاصهٔ فارسی از narration/tool، یا باکس جمعشده با برچسب «در حال تحلیل» بدون پاراگراف انگلیسی.
|
||
- پیشنهاد اصلاح:
|
||
1. کوتاهمدت: برای `fa` کانال native را در UI نشان ندهید؛ فقط `narrative` / `thought` فارسی.
|
||
2. میانمدت: اگر mismatch، یک جملهٔ فارسی از آخرین tool/plan بهجای raw CoT.
|
||
3. هرگز native English را در تاریخچهٔ قابلنمایش persist نکنید اگر زبان جلسه فارسی است (یا در لایهٔ `visibility=internal` بماند).
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — `visible_reasoning_markdown` برای `fa` متن لاتین/انگلیسی native را با جملهٔ فارسی جایگزین میکند و همان در trace persist میشود.
|
||
|
||
---
|
||
|
||
## CHAT-06 — تأیید کاربر → لودینگ بیپایان و ادامهٔ توهمآمیز ایجنت
|
||
|
||
- وضعیت: انجامشده
|
||
- اولویت: P0
|
||
- مالک: flutter + backend
|
||
- فایلها: `ai_chat_dialog.dart` (`_confirmWriteApproval`)، `ai_write_approval_banner.dart`، `adapters/api/v1/ai/chat.py` (persist پیام کاربر + `approve_writes`)، `ai_write_guard.py`، `ai_subagent.py` (`wait` پیشفرض)
|
||
- مسیر فعلی:
|
||
|
||
```
|
||
کاربر تأیید میزند
|
||
→ بنر پاک میشود (_clearWriteApprovalState)
|
||
→ _sending = true (لودینگ)
|
||
→ POST پیام جدید با متن:
|
||
«کاربر عملیات پیشنهادی را تأیید کرد. لطفاً همان عملیات را اجرا کن.»
|
||
skipUserBubble=true (در UI دیده نمیشود، در DB ذخیره میشود)
|
||
→ حلقهٔ کامل ایجنت از صفر، با approve_writes=true
|
||
```
|
||
|
||
- چرا لودینگ بیپایان حس میشود:
|
||
1. `consume` تا رویداد `done` یا بستن استریم صبر میکند؛ `_sending` همانقدر true میماند.
|
||
2. اگر مدل `spawn_subagent(wait=true)` بزند، ژنراتور والد تا ۹۰ ثانیه chunk ابزاری نمیدهد؛ UI فقط heartbeat میبیند.
|
||
3. زیر-ایجنت نامرئی است (CHAT-02) → کاربر فقط اسپینر میبیند.
|
||
4. اگر استریم بدون `done` قطع شود یا cancel بهاشتباه `return` شود، `_sending` ممکن است true بماند.
|
||
- چرا توهم پیش میآید:
|
||
1. تأیید بهجای «ادامهٔ همان run با `approval_id`» یک **نوبت جدید کاربر** است. مدل متن را دستور تازهای میبیند.
|
||
2. اگر همان write را دوباره صدا نزند، هیچ چیز اجرا نمیشود ولی ممکن است موفقیت را روایت کند.
|
||
3. اگر write دیگری صدا بزند → `APPROVAL_MISMATCH` یا اجرای آرگومان ذخیرهشده؛ مدل گیج میشود.
|
||
4. تاریخچه حالا پیام جعلی «لطفاً اجرا کن» دارد؛ نوبتهای بعدی روی همان توهم سوار میشوند.
|
||
- معیار پذیرش:
|
||
- دکمهٔ تأیید **پیام کاربر جدید نسازد** (نه در UI نه در DB).
|
||
- سرور همان `approval_id` / کارت ذخیرهشده را اجرا کند، سپس در صورت نیاز یک نوبت کوتاه سنتز بدهد.
|
||
- از زدن تأیید تا اولین رویداد SSE (وضعیت «در حال اجرا» یا نتیجهٔ ابزار) کمتر از ~۲ ثانیه حس شود؛ بنر تا اتمام اجرا در حالت loading بماند نه اینکه اول پاک شود.
|
||
- اگر اجرا شکست خورد، بنر برگردد و خطای فارسی نشان داده شود؛ مدل حق ندارد موفقیت را حدس بزند.
|
||
- تست: تأیید `create_invoice` → یک بار handler واقعی؛ بدون ردیف user اضافی در `ai_chat_messages`.
|
||
- پیشنهاد اصلاح:
|
||
1. API جدا: `POST .../messages/{id}/approve` یا `POST .../runs/{run_id}/approve` با `approval_id`.
|
||
2. UI: `approveWrites` روی همان run، بدون `contentOverride`.
|
||
3. تا `done`، `writeApprovalLoading` روی بنر بماند.
|
||
4. spawn در حین اجرای تأیید یا `wait=false` باشد یا رویدادهای فرزند به استریم والد بیاید (CHAT-02).
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — تأیید silent: پیام کاربر persist نمیشود؛ LLM turn با `[user_approved_writes]`؛ `user_query` از آخرین پیام واقعی؛ بنر تا پایان استریم میماند؛ کلاینتهای قدیمی با متن جعلی هم silent حساب میشوند.
|
||
|
||
---
|
||
|
||
# موارد کمکی برای کارکرد صحیح سیستم
|
||
|
||
اینها را کاربر جداگانه نگفته؛ از همان بررسی کد و سوابق برای جلوگیری از برگشت باگها لازماند.
|
||
|
||
### CHAT-07 — جدول خودکار بیش از حد تهاجمی است
|
||
- وضعیت: انجامشده · اولویت: P2 · مالک: flutter
|
||
- هر لیست ≥۲ ردیف و ≥۲ ستون اسکالر جدول میشود؛ کلید خام انگلیسی برچسب ستون است.
|
||
- جدول را فقط از envelope با `ok=true` و کلید لیست شناختهشده بسازید؛ حداکثر یک جدول per پیام مگر مدل ` ```table ` بدهد.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — فقط envelope موفق (`ok=true` یا `_envelope`) و کلیدهای لیست شناختهشده؛ برچسب ستون فارسی برای فیلدهای رایج.
|
||
|
||
### CHAT-08 — کلیدهای داخلی `function_results` قرارداد واحد ندارند
|
||
- وضعیت: انجامشده · اولویت: P2 · مالک: backend + flutter
|
||
- امروز: `_agent_trace`, `_reasoning_trace`, `_citations`, `_activated_skills`, `_agent_budget`, `_agent_todos`, `_agent_run`.
|
||
- یک ثابت مشترک (یا پیشوند `_` اجباری + allowlist نمایش) در Python و Dart.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — UI هر کلید با پیشوند `_` را از جدول خودکار حذف میکند.
|
||
|
||
### CHAT-09 — نام ابزار ناشناخته نباید write/approval شود
|
||
- وضعیت: انجامشده · اولویت: P1 · مالک: backend
|
||
- `is_write_function(name, registry)` برای نام غایب `True` برمیگرداند → کارت تأیید برای تابعی که وجود ندارد.
|
||
- جدا کنید: `unknown` / `read` / `write`. unknown → CHAT-01.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — در مسیر چت، نام غایب از registry قبل از write-guard به `UNKNOWN_TOOL` میرود. MCP fail-closed برای نام ناشناخته حفظ شد.
|
||
|
||
### CHAT-10 — پیشفرض `wait=true` در spawn استریم والد را خفه میکند
|
||
- وضعیت: انجامشده · اولویت: P1 · مالک: backend
|
||
- حتی بدون پنل UI، `wait=false` + await صریح مانع لودینگ مرده میشود.
|
||
- وابسته به CHAT-02 و CHAT-06.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — پیشفرض `wait=False`.
|
||
|
||
### CHAT-11 — Stop / cancel استریم باید `_sending` را همیشه پایین بیاورد
|
||
- وضعیت: انجامشده · اولویت: P1 · مالک: flutter
|
||
- در `_runAssistantStream` اگر `CancelToken.isCancel` باشد گاهی فقط `return` است؛ مسیر تأیید/جایگزینی استریم را بررسی کنید که اسپینر گیر نکند.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۲۸ — در مسیر cancel اگر همان token جاری باشد `_sending=false` میشود.
|
||
|
||
### CHAT-12 — persist زیر-ایجنت و بازیابی پس از رفرش
|
||
- وضعیت: انجامشده · اولویت: P2 · مالک: backend
|
||
- همان فاز ۳ سناریوی runtime. تا SQL نباشد، پنل UI بعد از refresh خالی است.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — جدول `ai_subagent_runs` + hydrate از GET `/subagents` روی آخرین پیام assistant.
|
||
|
||
### CHAT-13 — پیام pause تأیید نباید بهعنوان پاسخ نهایی تاریخچه بماند
|
||
- وضعیت: انجامشده · اولویت: P2 · مالک: backend
|
||
- `build_approval_pause_content` اگر `accumulated_content` خالی باشد همان متن pause persist میشود. بعد از approve موفق، آن حباب باید با نتیجهٔ واقعی جایگزین یا علامت «منتظر تأیید» بخورد.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — پرچم `_awaiting_approval`؛ persist بعدی همان ردیف را جایگزین میکند؛ UI حباب pause را قبل از استریم تأیید برمیدارد.
|
||
|
||
### CHAT-14 — مشاهدهپذیری خطا و زبان تفکر
|
||
- وضعیت: انجامشده · اولویت: P2 · مالک: backend
|
||
- `reasoning_language_mismatch` و `tool_error` را به متریک/داشبورد ببرید تا بدون خواندن جلسه بفهمیم نرخ انگلیسیبودن تفکر و نرخ شکست ابزار چقدر است.
|
||
- یادداشت اصلاح: ۱۴۰۵/۰۵/۳۰ — `log_ai_event` برای هر دو + GET `/admin/ai/ops-metrics`.
|
||
|
||
---
|
||
|
||
## نقشهٔ اتصال به ممیزی
|
||
|
||
| CHAT | آیتم ممیزی مرتبط | توضیح |
|
||
|------|------------------|--------|
|
||
| CHAT-01 | TOOL-01، AGT-08، TOOL-04 | کاتالوگ ۴۸تایی + قطع حلقه پس از شکست + خطای بدون schema |
|
||
| CHAT-02 | AGT-06 فاز ۴ | بکاند هست؛ UI نیست |
|
||
| CHAT-03 | TOOL-04 یادداشت «جدول از رکورد ابزار» | اثر جانبی همان فیکس |
|
||
| CHAT-04 | UX-02 / رندر پیام | نرمالسازی ناقص |
|
||
| CHAT-05 | PRM زبان + کانال reasoning | prompt هست؛ enforcement نیست |
|
||
| CHAT-06 | SEC-01، AGT-01 | approval_id هست؛ مسیر UI هنوز «پیام جدید» است |
|
||
|
||
---
|
||
|
||
## سناریوهای پذیرش دستی (قبل از بستن P0)
|
||
|
||
1. **جدول داخلی:** سوالی بپرسید که مدل چند ابزار بزند. انتهای پاسخ نباید جدول با ستون `trace_id`/`step_id`/`kind` باشد. اگر جدول فاکتور/کالا آمد، ستونها فارسی و معنادار باشند.
|
||
2. **بولد:** از مدل بخواهید چند عنوان را برجسته کند. در حباب پاسخ و در باکس تفکر نباید `**` خام دیده شود.
|
||
3. **تأیید نوشتن:** در حالت با تأیید، ایجاد یک موجودیت آزمایشی. پس از تأیید: بدون پیام کاربر اضافه در تاریخچه؛ لودینگ تمام شود؛ موجودیت واقعاً ساخته شود؛ مدل «ساخته شد» بدون tool نگوید.
|
||
4. **تفکر فارسی:** یک سوال حسابداری فارسی. باکس تفکر یا فارسی است یا بدون پاراگراف انگلیسی جمع شده.
|
||
5. **زیر-ایجنت (پس از CHAT-02):** سوال چنددامنهای. کارت فرزند دیده شود؛ قطع دستی کار کند؛ سوال «موجودی کالای X» کارت نسازد.
|
||
|
||
---
|
||
|
||
## تاریخچهٔ بهروزرسانی
|
||
|
||
| تاریخ | نسخه | چه تغییر کرد |
|
||
|--------|------|----------------|
|
||
| ۱۴۰۵/۰۵/۲۷ | 1.0 | سند اولیه از روی شش گزارش کاربر + بررسی سورس و سوابق ممیزی ۱۷–۱۸ اوت |
|
||
| ۱۴۰۵/۰۵/۲۸ | 1.1 | CHAT-01…06 و CHAT-09…11 انجام شد: قرارداد handler `(args, context)`، خطای ابزار ساختیافته، تأیید silent، فیلتر جدول داخلی، markdown مشترک، تفکر فارسی، پنل/قطع subagent |
|
||
| ۱۴۰۵/۰۵/۳۰ | 1.2 | CHAT-07/12/13/14: جدول envelope-only، persist زیر-ایجنت، جایگزینی pause تأیید، متریک خطا/زبان |
|
||
| ۱۴۰۵/۰۵/۳۰ | 1.3 | استریم CRM/تیکت (CHN-02) و replay بافر هنگام poll چند-ورکر |
|
||
|
||
<!-- الگو:
|
||
| ۱۴۰۵/۰۵/۲۸ | 1.1 | CHAT-03 انجامشده — skip `_reasoning_trace` و کلیدهای `_` |
|
||
-->
|