feat(agent-chat): complete core workflow and strengthen auth rate limiting

This commit is contained in:
qzl
2026-02-25 16:51:12 +08:00
parent 53c72e48e6
commit cd40b2b4f4
62 changed files with 3441 additions and 3 deletions
@@ -0,0 +1,36 @@
# Agent Chat CrewAI + AG-UI Spike Notes
## Scope
- 验证 CrewAI 依赖可用性与版本探测方式。
- 验证 AG-UI 官方 CrewAI 集成在当前仓库中的落地路径。
- 验证 DashScope FunASR 响应中的 usage 字段可得性与兜底策略。
## Findings
### CrewAI
- `uv run python -m pip show crewai` 在当前虚拟环境不可用(无 pip 模块)。
- `uv pip show crewai` 返回未安装,说明当前工作树尚未安装 CrewAI 依赖。
- 若需启用真实编排,需在 `pyproject.toml` 中声明依赖并执行 `uv sync --extra dev`
### AG-UI 官方 CrewAI 集成
- 目标对齐官方标准事件语义(如 `message.delta``tool.started``tool.completed``run.completed``run.failed`)。
- 当前仓库采取“适配层隔离”策略:由 `agui_adapter.py` 进行请求与事件映射,避免协议细节扩散到业务层。
### DashScope FunASR
- 优先读取上游响应 usage 字段用于成本统计。
- 若 usage 缺失,落库时保持 `raw_usage` 与空标准字段,并标记 `metadata.usage_missing=true` 以便审计。
## Fallback Strategy
- 当官方集成能力或版本存在不确定性时,启用最小兜底事件映射:
- 仅输出标准 AG-UI 事件。
- 不扩展私有协议字段。
-`event_bridge.py` 中统一做字段校验与错误转换。
## Decision
- 继续按计划推进:先补齐编排与成本核心,再完善 AG-UI 适配、多模态与 E2E 闭环。
@@ -0,0 +1,49 @@
# Agent Chat Gap Closure Design
**Goal:** 在不重做已完成任务的前提下,按既定 Task 顺序补齐 Agent Chat Core 的缺口,实现可验证、可审计的端到端闭环。
## Current State
- 已完成:Task 2/3/4 的核心数据层、静态配置、模板加载;Task 6/7 的部分骨架(`event_bridge``v1/agent_chat``storage_adapter``asr_fun_asr`)。
- 未完成或缺口:Task 1 的 spike 结论文档;Task 5 编排与成本追踪;Task 6 `agui_adapter` 与缺失测试;Task 7 `multimodal`Task 8 会话审计与 recent 规则;Task 9 E2E 与运行文档闭环。
## Design Decisions
- 以“缺口优先”方式执行:仅新增/修改缺失能力,已稳定模块不重构。
- 严格遵循顺序:Task 1 -> 5 -> 6 -> 7 -> 8 -> 9。
- 每个 Task 均采用 TDD:先写失败测试,再做最小实现,通过后再小步重构。
- 统一事件与持久化顺序:以 `session.id + seq` 为唯一顺序锚点,避免流式输出与落库顺序漂移。
- 工具调用成本仍归集到 `messages(role=tool)`,会话总成本由增量聚合维护。
## Component Plan
- Task 1: 新增 spike notes,记录 CrewAI/AG-UI/FunASR 依赖可用性与兜底策略。
- Task 5: 新增 `orchestrator.py``cost_tracker.py``events.py`,完成三阶段执行与 usage/cost 归一。
- Task 6: 新增 `agui_adapter.py`,对接现有 `event_bridge.py``v1/agent_chat/service.py`
- Task 7: 新增 `multimodal.py`,衔接附件校验、存储元数据、ASR 文本提取。
- Task 8: 增强会话标题策略、recent session 查询、审计字段与限流保护。
- Task 9: 补齐 E2E 与 runbook,执行 bootstrap gate + 分层测试验证。
## Data Flow
1. 路由接收 AG-UI 请求并解析输入文本/附件。
2. `agui_adapter` 生成内部命令并触发编排器三阶段执行。
3. 每阶段产出内部事件,经 `event_bridge` 映射为 AG-UI 标准事件。
4. `service` 在事务内写入 `messages` 并更新 `sessions` 汇总字段。
5. 流式事件向外输出,顺序与 `messages.seq` 保持一致。
## Error Handling
- 配置/模板错误:启动前校验并快速失败,返回可追踪错误码。
- 第三方调用错误(LLM/ASR/Storage):记录标准化失败事件与审计元数据,不泄露敏感信息。
- 持久化冲突:对 `session_id + seq` 冲突执行有限重试并记录告警。
## Testing Strategy
- Unit`cost_tracker``orchestrator``agui_adapter``multimodal``title strategy`
- Integration`agent_chat` 路由、事件落库、recent session 选择、会话成本聚合。
- E2E:文本、图片+文本、音频+ASR、文档问答、首页最近会话默认选中。
## Approval Note
该设计基于用户确认的“仅按未完成 Task 顺序推进”执行策略。
@@ -0,0 +1,230 @@
# Agent Chat Gap Closure Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 按未完成 Task 顺序补齐 Agent Chat Core 缺口,形成可运行、可测试、可审计的后端链路。
**Architecture:** 复用已完成的数据层与路由骨架,在 `core/agent_chat` 补齐编排、成本与多模态能力,并通过 `v1/agent_chat/service.py` 统一持久化与事件顺序。全流程以 `session.id + messages.seq` 作为一致性锚点,保证事件输出与落库一致。
**Tech Stack:** FastAPI, SQLAlchemy, Pydantic, pytest, CrewAI, AG-UI adapter, DashScope SDK, Supabase Storage。
---
### Task 1: 补齐 Spike 结论文档
**Files:**
- Create: `docs/plans/2026-02-25-agent-chat-crewai-ag-ui-spike-notes.md`
**Step 1: 写失败校验(文档存在性)**
```bash
test -f docs/plans/2026-02-25-agent-chat-crewai-ag-ui-spike-notes.md
```
**Step 2: 运行并确认失败**
Run: `test -f docs/plans/2026-02-25-agent-chat-crewai-ag-ui-spike-notes.md`
Expected: non-zero exit code。
**Step 3: 写最小文档实现**
```markdown
- CrewAI 版本探测结论
- AG-UI 官方 CrewAI 集成可用性结论
- DashScope FunASR usage 字段策略
- 不可用时的最小兜底映射策略
```
**Step 4: 运行并确认通过**
Run: `test -f docs/plans/2026-02-25-agent-chat-crewai-ag-ui-spike-notes.md`
Expected: zero exit code。
### Task 5: 补齐编排与成本追踪
**Files:**
- Create: `backend/src/core/agent_chat/events.py`
- Create: `backend/src/core/agent_chat/cost_tracker.py`
- Create: `backend/src/core/agent_chat/orchestrator.py`
- Test: `backend/tests/unit/core/agent_chat/test_cost_tracker.py`
- Test: `backend/tests/unit/core/agent_chat/test_orchestrator_pipeline.py`
**Step 1: 写失败测试**
```python
def test_normalize_usage_and_cost_aggregation():
assert False
def test_orchestrator_runs_three_stages_in_order():
assert False
```
**Step 2: 运行并确认失败**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_cost_tracker.py backend/tests/unit/core/agent_chat/test_orchestrator_pipeline.py -v`
Expected: FAIL。
**Step 3: 写最小实现**
```python
class CostTracker:
def add_usage(self, usage: dict) -> None: ...
def total(self) -> dict: ...
class AgentChatOrchestrator:
async def run(self, command):
# intent -> execution -> organization
...
```
**Step 4: 运行并确认通过**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_cost_tracker.py backend/tests/unit/core/agent_chat/test_orchestrator_pipeline.py -v`
Expected: PASS。
### Task 6: 补齐 AG-UI 适配层缺口
**Files:**
- Create: `backend/src/core/agent_chat/agui_adapter.py`
- Modify: `backend/src/core/agent_chat/event_bridge.py`
- Modify: `backend/src/v1/agent_chat/service.py`
- Test: `backend/tests/unit/core/agent_chat/test_agui_adapter.py`
- Test: `backend/tests/integration/test_agent_chat_event_persistence.py`
**Step 1: 写失败测试**
```python
def test_agui_adapter_maps_internal_events_to_protocol_events():
assert False
```
**Step 2: 运行并确认失败**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_agui_adapter.py backend/tests/integration/test_agent_chat_event_persistence.py -v`
Expected: FAIL。
**Step 3: 写最小实现**
```python
class AguiAdapter:
def to_command(self, request): ...
def to_protocol_event(self, event): ...
```
**Step 4: 运行并确认通过**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_agui_adapter.py backend/tests/integration/test_agent_chat_event_persistence.py -v`
Expected: PASS。
### Task 7: 补齐多模态输入编排
**Files:**
- Create: `backend/src/core/agent_chat/multimodal.py`
- Modify: `backend/src/core/agent_chat/storage_adapter.py`
- Modify: `backend/src/core/agent_chat/tools/asr_fun_asr.py`
- Test: `backend/tests/unit/core/agent_chat/test_multimodal.py`
**Step 1: 写失败测试**
```python
def test_multimodal_validates_and_builds_attachment_context():
assert False
```
**Step 2: 运行并确认失败**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_multimodal.py -v`
Expected: FAIL。
**Step 3: 写最小实现**
```python
class MultimodalProcessor:
async def build_context(self, attachments): ...
```
**Step 4: 运行并确认通过**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_multimodal.py backend/tests/unit/core/agent_chat/test_storage_adapter.py backend/tests/unit/core/agent_chat/test_asr_fun_asr_tool.py -v`
Expected: PASS。
### Task 8: 补齐会话审计与 recent 规则
**Files:**
- Modify: `backend/src/v1/agent_chat/service.py`
- Modify: `backend/src/v1/agent_chat/router.py`
- Test: `backend/tests/unit/core/agent_chat/test_session_title_strategy.py`
- Test: `backend/tests/integration/test_agent_chat_session_recent_selection.py`
- Test: `backend/tests/integration/test_agent_chat_session_persistence.py`
**Step 1: 写失败测试**
```python
def test_title_generated_from_first_user_message():
assert False
def test_recent_session_selected_by_last_activity_at_desc():
assert False
```
**Step 2: 运行并确认失败**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_session_title_strategy.py backend/tests/integration/test_agent_chat_session_recent_selection.py backend/tests/integration/test_agent_chat_session_persistence.py -v`
Expected: FAIL。
**Step 3: 写最小实现**
```python
def build_session_title(first_message: str) -> str: ...
```
**Step 4: 运行并确认通过**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat/test_session_title_strategy.py backend/tests/integration/test_agent_chat_session_recent_selection.py backend/tests/integration/test_agent_chat_session_persistence.py -v`
Expected: PASS。
### Task 9: 补齐 E2E 与运行文档闭环
**Files:**
- Create: `backend/tests/e2e/test_agent_chat_flow.py`
- Create: `backend/tests/e2e/test_agent_chat_recent_session_home.py`
- Modify: `docs/runtime/runtime-runbook.md`
**Step 1: 写失败 E2E 用例**
```python
def test_agent_chat_text_image_audio_document_flow():
assert False
```
**Step 2: 运行并确认失败**
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_agent_chat_flow.py -v`
Expected: FAIL。
**Step 3: 写最小实现与文档补充**
```markdown
- bootstrap gate 执行顺序
- agent_chat 验证命令
```
**Step 4: 全量验证**
Run: `make runtime-bootstrap-gate`
Expected: bootstrap 通过。
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/unit/core/agent_chat -v`
Expected: PASS。
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/integration -k agent_chat -v`
Expected: PASS。
Run: `PYTHONPATH=backend/src uv run pytest backend/tests/e2e/test_agent_chat_flow.py backend/tests/e2e/test_agent_chat_recent_session_home.py -v`
Expected: PASS。
Run: `PYTHONPATH=backend/src uv run pip check`
Expected: no broken requirements。