Files
social-app/docs/plans/2026-03-05-agent-runtime-closed-loop-e2e-plan.md
T

231 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Agent Runtime Closed Loop E2E Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 让 agent 闭环在真实本地环境中可验证:`runs` 支持首聊自动建会话,并通过真实异步任务、真实 LLM、真实落库与真实 SSE 证明端到端可用。
**Architecture:**`v1/agent` 服务层引入“可选 session_id + 自动建会话”语义;保持已有 owner 鉴权路径。重构诊断脚本并新增 live E2E 用例,统一验证 run 入队、事件流、数据库状态、成本统计与删除语义。通过最小侵入改造现有 run/resume 流程,确保兼容已存在调用。
**Tech Stack:** FastAPI, SQLAlchemy async, Celery, Redis Stream, LiteLLM, PyJWT, pytest, httpx
---
### Task 1: 扩展 API 契约(session_id 可选)
**Files:**
- Modify: `backend/src/v1/agent/schemas.py`
- Modify: `backend/src/v1/agent/router.py`
- Test: `backend/tests/integration/v1/agent/test_routes.py`
**Step 1: Write the failing test**
`test_routes.py` 新增用例:请求体不传 `session_id` 仍返回 202,且响应含 `session_id`
**Step 2: Run test to verify it fails**
Run: `uv run pytest backend/tests/integration/v1/agent/test_routes.py -k "runs and session" -v`
Expected: FAIL,提示 `session_id` 缺失导致 422 或 mock 接口签名不匹配。
**Step 3: Write minimal implementation**
- `RunRequest.session_id` 改为可选。
- `enqueue_run` 调用 service 时传可选值。
- `TaskAcceptedResponse` 增加 `created: bool` 字段。
**Step 4: Run test to verify it passes**
Run: `uv run pytest backend/tests/integration/v1/agent/test_routes.py -v`
Expected: PASS。
**Step 5: Commit**
```bash
git add backend/src/v1/agent/schemas.py backend/src/v1/agent/router.py backend/tests/integration/v1/agent/test_routes.py
git commit -m "feat: allow agent runs without pre-created session"
```
### Task 2: 服务层支持自动建会话并保持鉴权
**Files:**
- Modify: `backend/src/v1/agent/service.py`
- Modify: `backend/src/v1/agent/repository.py`
- Modify: `backend/src/v1/agent/dependencies.py`
- Test: `backend/tests/unit/v1/agent/test_service.py` (new)
**Step 1: Write the failing test**
新增单测覆盖:
- `session_id is None` 时调用 `create_session_for_user` 并返回 `created=True`
- `session_id 有值` 时复用并校验 owner
**Step 2: Run test to verify it fails**
Run: `uv run pytest backend/tests/unit/v1/agent/test_service.py -v`
Expected: FAIL,当前 service 无自动建会话能力。
**Step 3: Write minimal implementation**
- repository 增加 `create_session_for_user(user_id)`
- service `enqueue_run` 处理两条路径:
-`session_id`:先创建 session。
-`session_id`:校验 owner。
- 返回 `TaskAccepted(task_id, session_id, created)`
**Step 4: Run test to verify it passes**
Run: `uv run pytest backend/tests/unit/v1/agent/test_service.py -v`
Expected: PASS。
**Step 5: Commit**
```bash
git add backend/src/v1/agent/service.py backend/src/v1/agent/repository.py backend/src/v1/agent/dependencies.py backend/tests/unit/v1/agent/test_service.py
git commit -m "feat: auto-create chat session on first agent run"
```
### Task 3: 对齐 runtime 闭环数据断言(messages/sessions/cost
**Files:**
- Modify: `backend/src/core/agent/application/run_service.py`
- Modify: `backend/src/core/agent/application/resume_service.py`
- Modify: `backend/src/core/agent/infrastructure/persistence/message_repository.py`
- Modify: `backend/src/core/agent/infrastructure/persistence/session_repository.py`
- Test: `backend/tests/integration/core/agent/test_queue_run_resume.py`
**Step 1: Write the failing test**
在集成测试增加断言:
- `sessions.total_tokens``sessions.total_cost` 有更新
- `messages` 的 token/cost 字段与 session 聚合一致
**Step 2: Run test to verify it fails**
Run: `uv run pytest backend/tests/integration/core/agent/test_queue_run_resume.py -v`
Expected: FAIL,当前默认 token/cost 为 0,未做聚合更新。
**Step 3: Write minimal implementation**
- run/resume 流程接入 usage/cost 结果(来自 litellm 返回或 fallback 规则)。
- message 写入时填充 input/output tokens 与 cost。
- session 更新时累加 total_tokens/total_cost。
**Step 4: Run test to verify it passes**
Run: `uv run pytest backend/tests/integration/core/agent/test_queue_run_resume.py -v`
Expected: PASS。
**Step 5: Commit**
```bash
git add backend/src/core/agent/application/run_service.py backend/src/core/agent/application/resume_service.py backend/src/core/agent/infrastructure/persistence/message_repository.py backend/src/core/agent/infrastructure/persistence/session_repository.py backend/tests/integration/core/agent/test_queue_run_resume.py
git commit -m "feat: persist runtime token and cost aggregates"
```
### Task 4: 补齐软删除级联(session -> messages
**Files:**
- Modify: `backend/src/core/agent/infrastructure/persistence/session_repository.py`
- Modify: `backend/src/v1/agent/service.py`
- Test: `backend/tests/integration/core/agent/test_queue_run_resume.py`
**Step 1: Write the failing test**
新增用例:软删 session 后,同会话 messages 的 `deleted_at` 同步写入。
**Step 2: Run test to verify it fails**
Run: `uv run pytest backend/tests/integration/core/agent/test_queue_run_resume.py -k soft_delete -v`
Expected: FAIL,当前无软删级联。
**Step 3: Write minimal implementation**
- repository 增加 `soft_delete_session_with_messages(session_id)`
- service 调用时使用同事务批量更新 messages。
**Step 4: Run test to verify it passes**
Run: `uv run pytest backend/tests/integration/core/agent/test_queue_run_resume.py -k soft_delete -v`
Expected: PASS。
**Step 5: Commit**
```bash
git add backend/src/core/agent/infrastructure/persistence/session_repository.py backend/src/v1/agent/service.py backend/tests/integration/core/agent/test_queue_run_resume.py
git commit -m "fix: cascade soft delete from sessions to messages"
```
### Task 5: 重构诊断脚本并新增 live E2E
**Files:**
- Modify: `test_agent_sse_flow.py`
- Create: `backend/tests/e2e/test_agent_closed_loop_live.py`
- Modify: `docs/bugs/2026-03-05-agent-runtime-bugs.md`
**Step 1: Write the failing test**
新增 live E2E 用例(`@pytest.mark.live`):
- 首聊不传 `session_id` 返回 202
- 订阅 SSE 收到关键事件
- DB 断言 session/messages/tokens/cost
**Step 2: Run test to verify it fails**
Run: `uv run pytest backend/tests/e2e/test_agent_closed_loop_live.py -m live -v`
Expected: FAIL,当前契约或脚本未对齐。
**Step 3: Write minimal implementation**
- 清理脚本重复/不可达逻辑。
- 增加健康检查、阶段化日志、超时和错误根因输出。
- E2E 用例复用脚本中的 helperJWT、SSE 解析、DB 断言)。
**Step 4: Run test to verify it passes**
Run:
- `uv run python test_agent_sse_flow.py --new-session`
- `uv run pytest backend/tests/e2e/test_agent_closed_loop_live.py -m live -v`
Expected: PASS。
**Step 5: Commit**
```bash
git add test_agent_sse_flow.py backend/tests/e2e/test_agent_closed_loop_live.py docs/bugs/2026-03-05-agent-runtime-bugs.md
git commit -m "test: add live closed-loop agent e2e verification"
```
### Task 6: 全量验证与文档同步
**Files:**
- Modify: `docs/runtime/runtime-runbook.md`
- Modify: `docs/runtime/runtime-route.md`
**Step 1: Run targeted checks**
Run:
- `uv run pytest backend/tests/unit/v1/agent/test_service.py -v`
- `uv run pytest backend/tests/integration/v1/agent/test_routes.py -v`
- `uv run pytest backend/tests/integration/core/agent/test_queue_run_resume.py -v`
- `uv run pytest backend/tests/e2e/test_agent_closed_loop_live.py -m live -v`
Expected: PASS。
**Step 2: Run quality gates**
Run:
- `uv run ruff check backend/src backend/tests`
- `uv run basedpyright`
Expected: PASS。
**Step 3: Update docs**
记录本地启动流程、真实 LLM 前置配置、live E2E 执行方式和故障排查。
**Step 4: Commit**
```bash
git add docs/runtime/runtime-runbook.md docs/runtime/runtime-route.md
git commit -m "docs: document live agent closed-loop e2e workflow"
```