Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions .agent-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ opt-in `modernc.org/sqlite`(纯 Go 无 CGO)。

### 1. 🛠️ Ground Truth Verification Baseline
- **Primary Test Command**: `GOWORK=off go test -race ./... -count=1`(必须 GOWORK=off:仓库可能处于某 worktree,GOWORK 会让包路径解析漂移)
- **Baseline Test Result**: [PASS] 321 func Test / 498 RUN(含子测试),12 包全绿,0 data race(re-verified on 2026-10-27;代码规模 83 个 Go 文件 = 39 生产 / 44 测试,共 19,074 行)
- **Baseline Test Result**: [PASS] 360 func Test / 545 RUN(含子测试),12 包全绿,0 data race(re-verified on 2026-10-27;代码规模 99 个 Go 文件 = 44 生产 / 55 测试,共 20,851 行)
- **Build / Lint Command**: `GOWORK=off go build ./...` + `GOWORK=off go vet ./...`(干净无警告)
- **Architecture Gates**: `GOWORK=off go test -v -run TestArchitecture . -count=1`(全仓 AST DAG 白名单 + 生产 ≤ 400 行 / 测试 ≤ 800 行硬门禁,83 个 Go 文件全量受控)
- **Benchmark**: `go test -bench=. -benchmem ./worker/`
- **Architecture Gates**: `GOWORK=off go test -v -run TestArchitecture . -count=1`(全仓 AST DAG 白名单 + 生产 ≤ 400 行 / 测试 ≤ 800 行硬门禁,99 个 Go 文件全量受控)
- **Benchmark**: `go test -bench=. -benchmem ./worker/ ./api/`
- 若先跑失败,先排查 Pre-Existing Broken(对照本基线),别归因到后续改动。

### 2. 🗺️ Core Symbol & Architecture Map
Expand All @@ -24,10 +24,11 @@ opt-in `modernc.org/sqlite`(纯 Go 无 CGO)。
- `eval/`:检索评测 harness(ADR-0018);同包拆分 `run.go`(受控参数锁定与预检)、`collector.go`(全文收集与辅助)、`grader.go`(程序化 Span 覆盖率)、`aggregate.go`(分布指标)、`report.go`(Markdown+JSON 报表,支持 `llm-usage` API 真实 Token 统计)。
- `prompts/`:版本化系统提示词(`go:embed *.md`),提供 `Get(version)`;收录 `default-v1`、`eval-template-v1`(空对照)、`eval-template-v2`(Grounded Citation 铁律)。
- `store/`:`TaskStore` 与 `SessionStore` 接口;`store.go` 内存任务存储 + `session.go` 内存会话存储;`sql.go` SQLite WAL 任务持久化与原子 CAS 抢占 + `sql_session.go` SQLite 会话与历史消息持久化(复合索引优化);`RecoverTasks` 启动断电补偿。
- `worker/`:`Pool`(Push-Notify 事务性抢占并发池,`tasks.ClaimNext` 原子 CAS 抢占,零 channel 阻塞,零 retrieval 依赖,通过 `tool.TerminalClassifier` 脱敏终态);`session.go`(多轮历史组装拉取 + 压缩 + 成功后原子写回,杜绝 `pool.go` 膨胀);两阶段优雅停机 + 队列快速失败 503 + context 抢占式取消树。
- `llm/`:`Client`(OpenAI 兼容客户端,幂等 `joinEndpoint` 防 `/v1/v1` 404,支持本地免密 Ollama,透传 `Temperature`/`Seed`,解析并回传 `Usage`);`stream.go` 提供 `ChatWithToolsStream` 原生 SSE 流式解析与工具调用分块组装。
- `metrics/`:包级原子计数器,提供 Prometheus 文本格式导出。
- `config/`:`Config` 12 项配置扁平解析(增补 `worker_concurrency` 默认 3 与 `max_context_tokens` 默认 16000)。
- `worker/`:`Pool`(Push-Notify 事务性抢占并发池,`tasks.ClaimNext` 原子 CAS 抢占,零 channel 阻塞,零 retrieval 依赖,通过 `tool.TerminalClassifier` 脱敏终态);`cancel.go`(抢占取消句柄解耦);`usage.go`(跨步 Token 计量累加与持久化落盘);`session.go`(多轮历史组装拉取 + 压缩 + 成功后原子写回,杜绝 `pool.go` 膨胀);两阶段优雅停机 + 队列快速失败 503 + context 抢占式取消树。
- `llm/`:`Client`(OpenAI 兼容客户端,幂等 `joinEndpoint` 防 `/v1/v1` 404,支持本地免密 Ollama,透传 `Temperature`/`Seed`,解析并回传 `Usage`);`retry.go` 驱动 429/5xx 指数退避与 `Retry-After` 尊重,`OnRetry` 回调注入指标;`stream.go` 提供 `ChatWithToolsStream` 原生 SSE 流式解析与工具调用分块组装(流式首包前可重试、产出后禁重试)。
- `metrics/`:包级原子计数器,提供 Prometheus 文本格式导出(覆盖 `agent_tasks_*` 与 `agent_llm_*`)。
- `config/`:`Config` 14 项配置扁平解析(增补 `worker_concurrency`、`max_context_tokens`、`session_history_limit`、`pprof_addr`)。
- 根级 `pprof.go`:独立端口与 mux 提供 `/debug/pprof/*`,默认关闭。
- **Existing Wheels(复用层)**: `agent.Chatter` / `llm.Embedder` 接口使测试可注入假实现;`httptest` 集成测试端到端跑 `POST /run → 轮询 → done`;`go:embed` 单页 Demo;`TraceBuffer` 同时服务轮询快照与 SSE 订阅。

### 3. 🚨 Local Engineering Red Lines & Gotchas
Expand All @@ -41,7 +42,9 @@ opt-in `modernc.org/sqlite`(纯 Go 无 CGO)。
- **SSE 必须清写截止时间**:`http.Server.WriteTimeout` 同样作用于流式响应,30s 被掐 → handler 内 `http.NewResponseController(w).SetWriteDeadline(time.Time{})`(不支持时忽略 ErrNotSupported);`TraceBuffer.Append` 对订阅通道 select+default 非阻塞投递,慢消费者只丢自己增量,终态用快照对账补齐(`sent < len(snapshot)` 续发)。
- **Trace 有界**:`DefaultMaxTraces = 1000` FIFO 驱逐防 OOM;detail 512B 截断用 `unicode/utf8.RuneStart` 回退到字符边界,杜绝 `\ufffd` 乱码。
- **SQLite 写吞吐**:`id INTEGER PRIMARY KEY AUTOINCREMENT` + `res.LastInsertId()`,禁止 `SELECT MAX(CAST(id AS INTEGER))`(全表扫描裹在排他写锁里,曾劣化到 <480 QPS);`RecoverTasks` 全程事务。
- **config.yaml 只接受扁平子集**:合法 key 包含 `deepseek_api_key`、`api_auth_key`、`model`、`db_path`、`task_timeout_seconds`、`max_queue_size`、`worker_concurrency`、`max_context_tokens`、`embed_base_url`、`embed_api_key`、`embed_model`、`embed_dim`(12 项);嵌套/未知 key 一律启动失败不静默。文件 gitignored(含密钥),示例是 `config.yaml.example`。同名环境变量优先级更高。服务模式缺 `DEEPSEEK_API_KEY` 以退出码 1 失败(`-index` 与 `-h` 短路不校验)。
- **config.yaml 只接受扁平子集**:合法 key 包含 `deepseek_api_key`、`api_auth_key`、`model`、`db_path`、`task_timeout_seconds`、`max_queue_size`、`worker_concurrency`、`max_context_tokens`、`session_history_limit`、`pprof_addr`、`embed_base_url`、`embed_api_key`、`embed_model`、`embed_dim`(14 项);嵌套/未知 key 一律启动失败不静默。文件 gitignored(含密钥),示例是 `config.yaml.example`。同名环境变量优先级更高。服务模式缺 `DEEPSEEK_API_KEY` 以退出码 1 失败(`-index` 与 `-h` 短路不校验)。
- **上游重试与流式不变式**:`llm.Client` 仅对 429 与 5xx 状态码退避重试,严禁重试 400/401/403/404/422;`Retry-After` 头受 `MaxDelay` 封顶;流式仅在首包前可重试,产出 delta 后断流坚决不重试以防打字机重复打印。
- **计量与状态机解耦**:`store.TaskStore.RecordUsage` 与 `Complete` 关注点分离;失败任务亦需计量(失败调用同样计费);计量落盘失败仅打日志,绝不把成功任务改写为失败。
- **会话存储与上下文防爆纪律**:多轮会话接入 `SessionStore`,创建任务通过 `CreateInSession` 记录会话绑定;`worker.process` 严禁在 `worker/pool.go` 直接堆砌多轮会话代码(硬限 400 行),必须在 `worker/session.go` 中通过 `assembleSessionMessages` 驱动 `agent.CompactMessages` 进行滑动窗口折半压缩;`recordSessionTurn` 必须严格检验并包装 `AppendSessionMessage` 错误,禁止使用 `_ =` 静默吞错。
- **并发取消在飞时序(TOCTOU 防护)**:在 `worker/pool.go:process` 中,必须先登记 `inFlight.Store(id, cancelCause)` 再更新数据库 `tasks.Update(id, StatusRunning)`。严禁先置 running 再存 handle,否则外部轮询方察觉 running 后立即调 cancel 会因找不到 handle 而报 `task is not running`。
- **请求/响应体积护栏**:`/run` body `MaxBytesReader` 32KB;LLM 响应 `io.LimitReader` 1MB。
Expand All @@ -58,5 +61,5 @@ opt-in `modernc.org/sqlite`(纯 Go 无 CGO)。
- Global Standards: `{vault_root}/AGENTS.md`(按 `$WIKI_PATH` → `$OBSIDIAN_VAULT_PATH` → 向上查找 `AGENTS.md` 解析,契约见 `dfs/references/vault-root-resolution.md`)
- Vault Search: 调用 `search_vault` MCP 或 `python {vault_root}/scripts/search-vault.py "<query>"`
- 沉淀新坑:写草稿至 `{vault_root}/99-Inbox/YYYY-MM-DD-{topic}.md`
- 项目文档:`docs/GO-STANDARDS.md`、`docs/GO-CHEATSHEET.md`、`docs/adr/0001..0020`(ADR-0019 事务性队列 + 打字机流式、ADR-0020 会话状态机 + 上下文压缩均已实施);`ARCHITECTURE.md`(根级架构总览:What Agent / What Architecture / What Borrowed / 设计权衡)
- 项目文档:`docs/GO-STANDARDS.md`、`docs/GO-CHEATSHEET.md`、`docs/adr/0001..0021`(ADR-0019 事务性队列 + 打字机流式、ADR-0020 会话状态机 + 上下文压缩、ADR-0021 上游退避重试 + Token 成本可观测 + 诊断端口均已实施);`ARCHITECTURE.md`(根级架构总览:What Agent / What Architecture / What Borrowed / 设计权衡)
- 工作记忆:`WORKMEMORY/`(INDEX → PROJECT_OVERVIEW → work.log 尾部);决策/踩坑/交接 MUST ≤4KB 事件追加 work.log
9 changes: 4 additions & 5 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 架构总览文档。回答三个核心问题:**实现了什么 Agent**、**基于什么架构**、**借鉴了什么**。
> 维护规则:随架构演进更新;重大变更须同步对应 ADR 与 `README.md`。
> 适用范围:当前主线(`master`,P1–P8 全部交付)。
> 适用范围:当前主线(`master`,P1–P10 全部交付)。

---

Expand All @@ -25,7 +25,7 @@
| **内置工具** | `calculate`(自研递归下降 AST 算术求值,**不用 eval**,防代码注入)、`current_time`(IANA 时区);P5 起增加 `search_docs`(混合检索即工具) |
| **执行形态** | 被 Worker Pool 并发调度的**后端服务**智能体,而非交互式 CLI / 本地 Agent |
| **对外契约** | 任务状态机 `pending → running → done/failed`;`POST /run` 提交、`GET /tasks/{id}` 轮询、`GET /tasks/{id}/events` SSE 流式 |
| **生产级能力** | 用户主动取消(context 物理中断上游)、掉电崩溃恢复、SSE 原生 token 级打字机、多轮会话状态机、滑动窗口上下文压缩 |
| **生产级能力** | 用户主动取消(context 物理中断上游)、掉电崩溃恢复、SSE 原生 token 级打字机、多轮会话状态机、滑动窗口上下文压缩、上游限流指数退避与 Retry-After 尊重、Token 成本计量持久化、独立诊断端口(pprof) |

**最小可信定义**:多步工具调用循环即 agent 的实质(ADR-0008 双镜论证)——区别于"LLM 聊天的异步封装",使 "agent" 名副其实。

Expand Down Expand Up @@ -97,8 +97,7 @@
`POST /run` 可绑定 `session_id`,打破单轮任务孤岛。
- **纯算法滑动窗口压缩**:`agent.CompactMessages` 无堆逃逸 Token 估算,首尾强锚定(System 提示 + 最新一轮),
中间轮次按 User 边界折半截断并插入系统折叠注记,**零 LLM 调用开销**根除 Context Window 爆炸。
- **可观测性**:`/metrics` 以 Prometheus 文本格式暴露 `agent_tasks_*`(`sync/atomic` 实现,零依赖);
`/healthz` 探活;指标仅暴露聚合计数,不含任务内容或上游响应体。
- **可观测性与诊断**:`/metrics` 以 Prometheus 文本格式暴露 `agent_tasks_*` 任务生命周期指标与 `agent_llm_*` 上游重试与 Token 成本指标(`sync/atomic` 实现,零依赖);`tasks` 表持久化单任务 `prompt_tokens`/`completion_tokens`;`/healthz` 存活探针;独立端口/mux 提供 `/debug/pprof/*` 性能分析;指标仅暴露聚合计数,不含任务内容或上游响应体。

---

Expand Down Expand Up @@ -132,7 +131,7 @@

- 决策记录:`docs/adr/0001`(项目定位)、`0002`(Worker Pool)、`0008`(Agent 工具循环)、
`0013`(分层解耦,Pi 哲学)、`0015`(崩溃恢复)、`0016`(SSE 流式)、`0017/0018`(检索与评测)、
`0019`(事务队列与流式推断)、`0020`(会话状态机与压缩)。
`0019`(事务队列与流式推断)、`0020`(会话状态机与压缩)、`0021`(上游限流退避、Token 成本可观测与诊断端口)。
- 实现计划:`docs/implementation_plan_p1.md` … `p8.md`。
- 评测实证:`docs/eval/2026-10-25-hybrid-r3.md` 等。
- 运行与 API 契约详见 `README.md`。
Loading
Loading