Files
next-tjwater-agent/docs/history/legacy-harness-design.md
T
jiang db87323b69 feat(investigation): publish incremental reference graphs
Publish graph deltas using the Server-owned cumulative graph contract. Validate historical comparison chart publications and consolidate Agent documentation.
2026-11-11 19:10:41 +08:00

623 lines
26 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.
# 早期 Harness 架构资料
> 历史归档:由旧 `HARNESS_INTRODUCTION.md` 与 `AGENT_HARNESS_REPORT.md` 合并保存。文中 CLI、render_ref、独立结果引用存储、旧模型默认值和旧会话目录均不能作为当前实现或维护依据。当前架构见 [Agent 架构](../architecture.md),配置见 [仓库 README](../../README.md)。原文中的覆盖声明与外部参考未在本次文档整理中重新验证。
## 原文件:HARNESS_INTRODUCTION.md
# TJWaterAgent Harness 框架设计
> 如果把 AI 大模型比作"大脑",Harness 就是让大脑能**安全、可靠、有条理地**在真实水务业务中工作的整套 **"神经 + 手脚 + 记忆"系统**。
---
## 一张图看懂
```mermaid
sequenceDiagram
autonumber
actor 用户 as 👤 用户
participant 前端 as 🖥️ 前端界面<br/>(聊天 / 地图 / 图表)
participant 接口 as 🚪 接口层<br/>接收问题、返回结果
participant 会话 as 📋 会话层<br/>“你是谁?哪个项目?”
participant 上下文 as 📦 上下文层<br/>整理背景资料<br/>历史对话 · 偏好 · 技能
participant 适配 as 🔌 适配层<br/>接通AI大脑<br/>(嵌入/远程)
participant 工具 as 🔧 工具层<br/>AI的“手和脚”<br/>调CLI · 存渲染引用 · 画图
participant 水务 as 🏭 水务系统<br/>管网 / SCADA / 仿真
participant 治理 as 🛡️ 治理观测层<br/>日志 · 审计 · 超时 · 容错
用户->>前端: 💬 “帮我查A片区今天用水量”
前端->>接口: 📤 POST 请求
接口->>会话: 🔍 验证身份、绑定会话
会话->>上下文: 📋 拼装:历史对话+记忆+技能+身份
接口->>前端: 📡 建立实时通道 SSE(“电话接通”)
接口->>适配: 📤 问题和背景一起发给AI
适配->>适配: 🧠 AI思考:推理 → 规划 → 决定调工具
适配->>工具: 🔧 “调用 tjwater_cli 查用水数据”
工具->>会话: 🔐 回读身份令牌(令牌留在服务端)
工具->>水务: 🏭 带上身份去查真实数据
水务-->>工具: 📊 返回数据
opt 需要渲染大型 junction 分区
工具->>工具: 💾 store_render_ref 存 render_ref
前端->>接口: 🔎 按 render_ref 回读完整渲染 payload
end
工具-->>适配: 📦 给AI结果
适配-->>前端: 📡 实时推送:文字逐字显示+图表弹窗
前端-->>用户: 📲 看到回答和数据
适配->>治理: 📝 记录:谁调了什么、为什么、耗时多久
会话->>会话: 🧠 同步复盘:对话中实时沉淀记忆/技能
```
---
## 主流 Harness 能力覆盖
AI Agent 领域主流的 Harness 是指大模型外层的工程基础设施。对照这些标准能力项,当前设计全覆盖:
| 主流 Harness 能力 | 本项目落点 | 覆盖 |
|---|---|---|
| 运行时编排 | `OpencodeRuntimeAdapter` + `ChatSessionBridge` | ✅ |
| 上下文装配 | `buildPromptWithLearningContext` + `runtime context store` | ✅ |
| 工具执行与权限隔离 | `.opencode/tools` + `/internal/tools/*` + `x-agent-internal-token`,令牌不出工具 | ✅ |
| 状态持久化 | `session` / `UI state` / `transcript` / `runtime context` | ✅ |
| 记忆与技能沉淀 | `MemoryStore` + `SkillStore` + `LearningOrchestrator`(对话中同步复盘) | ✅ |
| 观测与审计 | `Pino` + `LLM request audit` + `learning audit` + `traceId` | ✅ |
| 可靠性 | `abort` / `timeout` / `fallback` / `render_ref TTL` / `cleanup` | ✅ |
| 前端动作桥接 | SSE `tool_call` + `UI tools`(地图 / 图表 / 面板) | ✅ |
---
**Harness = 大脑负责思考,外壳负责让思考能落地执行。**
## 原文件:AGENT_HARNESS_REPORT.md
# TJWaterAgent 后端 Harness Engineering 设计整理
## 1. 先明确概念:什么是 Agent Harness
在 Agent 系统里,LLM 只是推理核心。Harness engineering 关注的是模型外层的工程系统:它把用户请求、上下文、工具、状态、权限、观测、持久化和恢复机制组织起来,让模型能在真实业务环境里安全地执行多步任务。
结合近期资料,可以把 harness 概括为:
- **运行时外壳**:承接请求,驱动模型,多轮执行,判断何时继续、停止或失败。
- **上下文装配层**:把用户身份、项目、历史、记忆、技能、业务约束注入到模型可用的上下文中。
- **工具执行层**:把模型意图转成受控的 CLI、渲染引用迁移和 UI 动作,并把结果反馈给模型。
- **权限与治理层**:隔离用户 token、项目权限、内部工具调用权限和渲染引用回读权限。
- **状态与记忆层**:保存 session、transcript、UI state、memory、skills、render refs。
- **观测与审计层**:记录工具调用、技能调用、学习决策、trace 和错误。
- **可靠性层**:处理 abort、timeout、fallback、cleanup 和渲染引用 TTL。
因此,TJWaterAgent 的 harness 不是某一个单独文件,而是 `src/` 服务代码、`.opencode/` Agent 资产、工具桥、持久化 store 和运行时适配器共同组成的 Agent 后端工程体系。
参考资料:
- TechTarget: [Harness engineering: Agent harnesses as critical infrastructure](https://www.techtarget.com/searchapparchitecture/tip/Harness-engineering-Agent-harnesses-as-critical-infrastructure)
- O'Reilly Radar: [Agent Harness Engineering](https://www.oreilly.com/radar/agent-harness-engineering/)
- MongoDB: [The Agent Harness: Why the LLM Is the Smallest Part of Your Agent System](https://www.mongodb.com/company/blog/technical/agent-harness-why-llm-is-smallest-part-of-your-agent-system)
- LLM Reference: [Harness](https://www.llmreference.com/concept/harness)
## 2. 项目总体框架
`TJWaterAgent` 是面向 TJWater 前端和水务后端能力的 Agent 服务层。它对外暴露 HTTP/SSE API,对内启动或连接 opencode runtime,并通过 `.opencode` 下的 agent、tools、skills 资产完成业务推理和工具执行。
```text
TJWaterAgent/
src/ 服务宿主、路由、会话、runtime、工具桥、持久化
.opencode/ opencode agent 资产
agents/instruction.md Agent 角色、行为规则、工具策略
tools/*.ts opencode 可调用工具
skills/ 可复用 workflow、CLI 使用说明、案例
data/ session、memory、render_ref 等运行时数据
logs/ LLM/tool/learning 审计日志
cli/tjwater-cli 业务 CLI 能力入口
opencode.json opencode provider、model、server、default_agent
```
核心技术栈:
| 类别 | 技术 |
| --- | --- |
| 服务运行 | Bun、Node.js、TypeScript ESM |
| HTTP 层 | Express、CORS、SSE |
| 参数校验 | Zod |
| Agent runtime | `@opencode-ai/sdk/v2`、opencode embedded/client 两种模式 |
| LLM provider | DeepSeek,默认 `deepseek/deepseek-v4-pro` |
| 工具扩展 | `@opencode-ai/plugin`、`.opencode/tools/*.ts` |
| 持久化 | JSON file store、atomic write、TTL cleanup |
| 观测 | Pino、LLM request audit、learning audit |
| 后端能力 | `tjwater-cli --auth-stdin` |
## 3. Harness Engineering 一图总览
下面这张图把现有后端设计收束成一张 Harness Engineering 视角的总图。重点不是“LLM 调用链”,而是模型外层的工程外壳如何完成请求接入、上下文装配、runtime 编排、工具治理、状态持久化、结果裁剪、审计和恢复。
```mermaid
flowchart LR
subgraph Client["Client / Frontend"]
Chat["Agent Chat UI"]
UIAction["Map / Chart / Panel Actions"]
end
subgraph Harness["TJWaterAgent Backend Harness Engineering"]
direction TB
subgraph Entry["1. 接入与协议层"]
API["Express REST API<br/>/api/v1/agent/chat/*"]
SSE["SSE Contract<br/>progress / token / tool_call / done / error"]
end
subgraph Control["2. 会话与上下文控制面"]
Session["ChatSessionBridge<br/>clientSessionId -> opencode sessionId"]
ActiveRun["activeRuns + AbortController<br/>并发控制 / 中断 / 重连"]
Context["SessionRuntimeContextStore<br/>actor / project / trace / token"]
PromptCtx["Learning Context Assembly<br/>recent turns / memory / skills"]
end
subgraph RuntimeLayer["3. Runtime 编排层"]
Adapter["OpencodeRuntimeAdapter"]
Mode["embedded / client mode"]
EventAdapter["Raw Event Adapter<br/>opencode events -> frontend SSE"]
end
subgraph ToolPlane["4. 工具执行与权限边界"]
ToolBridge["Internal Tool Bridge<br/>/internal/tools/*"]
InternalAuth["x-agent-internal-token"]
TokenInject["Server-side Auth Injection<br/>token / project / trace"]
RenderRefPolicy["Render Ref Policy<br/>store_render_ref + render_ref"]
end
subgraph State["5. 状态、记忆、沉淀"]
SessionStore["Session / UI State / Transcript Store"]
ResultStore["ResultReferenceStore<br/>TTL / actor-project-session auth"]
MemoryStore["MemoryStore"]
SkillStore["SkillStore"]
Learning["LearningOrchestrator<br/>gate / review / persistence policy"]
end
subgraph Governance["6. 治理、观测、可靠性"]
Audit["LLM Tool Audit / Learning Audit"]
Logs["Pino Logs + traceId"]
Reliability["timeout / fallback / cleanup / health"]
end
end
subgraph Runtime["opencode Runtime Assets"]
Agent[".opencode/agents/instruction.md"]
OCTools[".opencode/tools/*.ts"]
OCSkills[".opencode/skills/*"]
LLM["DeepSeek Model"]
end
subgraph Business["TJWater Business Capability"]
CLI["tjwater-cli --auth-stdin"]
Data["管网 / SCADA / 仿真 / 分析数据"]
end
Chat -->|"POST /stream"| API
API --> Session
API --> ActiveRun
Session --> Context
Session --> SessionStore
Session --> PromptCtx
MemoryStore --> PromptCtx
SkillStore --> PromptCtx
PromptCtx --> Adapter
Adapter --> Mode
Mode --> LLM
LLM --> Agent
LLM --> OCTools
LLM --> OCSkills
Adapter --> EventAdapter
EventAdapter --> SSE
SSE -->|"stream events"| Chat
SSE -->|"tool_call"| UIAction
OCTools -->|"sessionID + args + reason"| ToolBridge
ToolBridge --> InternalAuth
InternalAuth --> Context
Context --> TokenInject
TokenInject --> CLI
CLI --> Data
OCTools --> RenderRefPolicy
RenderRefPolicy --> ResultStore
SessionStore --> Learning
Learning --> MemoryStore
Learning --> SkillStore
EventAdapter --> Audit
ToolBridge --> Audit
Learning --> Audit
Audit --> Logs
ActiveRun --> Reliability
ResultStore --> Reliability
Adapter --> Reliability
```
图中可以看出,本项目 Harness Engineering 的核心设计是:
| 设计域 | 关键职责 | 项目落点 |
| --- | --- | --- |
| 接入协议 | 把前端请求和流式响应稳定化 | Express routes、SSE event contract |
| 会话控制 | 绑定前端会话和 runtime 会话,支持 abort、reconnect、active run 管理 | `ChatSessionBridge`、`activeRuns` |
| 上下文装配 | 把用户、项目、trace、token、历史、记忆、技能装配到一次运行中 | `SessionRuntimeContextStore`、learning context |
| Runtime 编排 | 屏蔽 opencode embedded/client 差异,统一 prompt、event、messages、abort | `OpencodeRuntimeAdapter` |
| 事件适配 | 把 opencode raw events 转成前端稳定协议 | `streamPromptResponse()` |
| 工具治理 | 通过内部桥执行真实业务能力,隔离模型和用户 token | `.opencode/tools`、`/internal/tools/*` |
| 渲染引用管理 | 大型 junction 渲染 payload 引用化,避免模型读取完整 `node_area_map` | `ResultReferenceStore`、`render_ref` |
| 记忆沉淀 | 从对话中异步提取 memory 和 reusable skill | `LearningOrchestrator`、`MemoryStore`、`SkillStore` |
| 治理可靠性 | 观测、审计、超时、中断、fallback、TTL cleanup | Pino、audit logs、health、cleanup |
## 4. Harness 总体架构图
```mermaid
flowchart LR
subgraph FE["TJWater 前端"]
ChatUI["聊天 UI / AgentWorkspace"]
MapUI["地图 / 图表 / 面板"]
end
subgraph Harness["TJWaterAgent Backend Harness"]
Server["Express Server"]
ChatRouter["Chat Router<br/>/api/v1/agent/chat/*"]
SessionBridge["ChatSessionBridge"]
RuntimeAdapter["OpencodeRuntimeAdapter"]
StreamAdapter["SSE Stream Adapter"]
InternalTools["Internal Tool Bridge<br/>/internal/tools/*"]
Stores["Persistent Stores<br/>session / memory / transcript / render_ref"]
Learning["LearningOrchestrator"]
Audit["Audit Logs"]
end
subgraph Runtime["opencode Runtime"]
OCServer["opencode server"]
AgentPrompt["agents/instruction.md"]
Tools["tools/*.ts"]
Skills["skills/workflow/*"]
end
subgraph Business["TJWater 业务能力"]
CLI["tjwater-cli"]
Data["管网 / SCADA / 仿真 / 分析数据"]
end
ChatUI -->|"POST /stream 或 GET /session/:id/stream"| Server
Server --> ChatRouter
ChatRouter --> SessionBridge
ChatRouter --> Stores
SessionBridge --> RuntimeAdapter
RuntimeAdapter --> OCServer
OCServer --> AgentPrompt
OCServer --> Tools
OCServer --> Skills
Tools -->|"internal callback + sessionID"| InternalTools
InternalTools --> Stores
InternalTools --> CLI
CLI --> Data
OCServer -->|"raw events"| StreamAdapter
StreamAdapter -->|"progress / token / tool_call / done / error"| ChatUI
StreamAdapter --> Audit
ChatRouter --> Learning
Learning --> Stores
ChatUI -->|"tool_call action"| MapUI
```
## 5. Harness 工程分层
```mermaid
flowchart TB
L1["1. 接口层<br/>Express + REST + SSE"]
L2["2. 会话层<br/>ChatSessionBridge + activeRuns + abort"]
L3["3. 上下文层<br/>user / project / trace / token 绑定"]
L4["4. Runtime 适配层<br/>opencode embedded/client"]
L5["5. 事件适配层<br/>opencode raw events -> 前端 SSE 协议"]
L6["6. 工具执行层<br/>tjwater-cli / store_render_ref / UI tools"]
L7["7. 渲染引用层<br/>render_ref / TTL"]
L8["8. 记忆学习层<br/>memory / transcript / skill / learning gate"]
L9["9. 治理观测层<br/>auth / audit / logs / timeout / cleanup"]
L1 --> L2 --> L3 --> L4 --> L5
L3 --> L6 --> L7
L2 --> L8
L6 --> L9
L8 --> L9
```
### 5.1 接口层
主要入口在 `src/server.ts` 和 `src/routes/chat.ts`:
- `GET /health`:检查服务和 opencode runtime 健康状态。
- `POST /api/v1/agent/chat/session`:创建或确保 session metadata。
- `GET /api/v1/agent/chat/sessions`:列出用户/项目维度的会话。
- `GET /api/v1/agent/chat/session/:sessionId`:读取会话 UI state。
- `POST /api/v1/agent/chat/stream`:核心对话入口,返回 SSE。
- `GET /api/v1/agent/chat/session/:sessionId/stream`:重新订阅正在运行的 stream。
- `POST /api/v1/agent/chat/abort`:中断当前会话运行。
- `POST /api/v1/agent/chat/fork`:基于历史 session 分叉。
- `GET /api/v1/agent/chat/render-ref/:renderRef`:授权读取渲染结果引用。
接口层的 harness 价值是给前端一个稳定协议,把复杂的 Agent runtime 行为收敛成会话、消息、状态、流式事件。
### 5.2 会话与上下文层
`ChatSessionBridge` 负责把前端 session 和 opencode session 绑定起来,并维护请求级上下文:
- `clientSessionId`:前端可见的会话 ID。
- `sessionId`:opencode runtime session ID。
- `actorKey`:由 `x-user-id` 归一化得到的用户隔离键。
- `projectKey`:由 `x-project-id` 归一化得到的项目隔离键。
- `traceId`:链路追踪 ID。
- `accessToken`:来自 `Authorization`,只存入服务端 runtime context,不暴露给模型工具代码。
每次 `POST /stream` 会:
1. 解析 headers 和 payload。
2. 查询或创建 session metadata。
3. 调用 `sessionBridge.resolve()` 创建或复用 runtime session。
4. 写入 `SessionRuntimeContextStore`,供内部工具桥回读。
5. 为该 session 注册 `AbortController`,避免同一会话并发运行。
### 5.3 Runtime 适配层
`OpencodeRuntimeAdapter` 屏蔽 opencode SDK 细节,提供统一方法:
- `ensureClient()`:懒加载 opencode client。
- `health()`:runtime 健康检查。
- `createSession()`:创建 runtime session。
- `prompt()` / `sendPrompt()`:发送用户消息。
- `messages()`:回读消息。
- `abortSession()` / `waitForSessionIdle()`:中断和等待空闲。
- `subscribeEvents()`:订阅 opencode 事件流。
- `dispose()`:关闭 embedded runtime。
支持两种部署模式:
```mermaid
flowchart LR
Mode["OPENCODE_MODE"]
Embedded["embedded"]
Client["client"]
SDKCreate["createOpencode()"]
SDKClient["createOpencodeClient()"]
Local["本地 opencode CLI 子进程"]
Remote["外部 opencode server"]
Mode --> Embedded --> SDKCreate --> Local
Mode --> Client --> SDKClient --> Remote
```
- `embedded`:服务启动本地 opencode server,同时注入 `TJWATER_AGENT_INTERNAL_BASE_URL` 和 `TJWATER_AGENT_INTERNAL_TOKEN` 给 `.opencode/tools`。
- `client`:服务连接外部 opencode server,适合 runtime 与 API 服务分离。
### 5.4 事件适配层
`streamPromptResponse()` 是前端体验的关键 harness。它订阅 opencode raw events,把内部事件转成稳定 SSE:
| opencode 事件 | SSE 事件 | 用途 |
| --- | --- | --- |
| `session.status` | `progress` | 展示 busy/retry/idle 等状态 |
| `message.part.delta` + text | `token` | 流式输出最终回答 |
| `message.part.updated` + reasoning | `progress` | 展示规划和推理状态 |
| `message.part.updated` + tool | `progress` / `tool_call` | 展示工具状态,并通知前端执行 UI 动作 |
| `todo.updated` | `progress` | 展示计划进度 |
| `session.error` | `error` | 返回错误 |
| `session.idle` | `done` | 结束本轮 |
```mermaid
flowchart TD
Raw["opencode raw event stream"]
Status["session.status"]
Reasoning["reasoning part"]
TextDelta["text delta"]
ToolPart["tool part"]
Todo["todo.updated"]
Error["session.error"]
Idle["session.idle"]
Progress["SSE progress"]
Token["SSE token"]
ToolCall["SSE tool_call"]
SSEError["SSE error"]
Done["SSE done"]
Raw --> Status --> Progress
Raw --> Reasoning --> Progress
Raw --> TextDelta --> Token
Raw --> ToolPart --> Progress
ToolPart --> ToolCall
Raw --> Todo --> Progress
Raw --> Error --> SSEError
Raw --> Idle --> Done
```
适配层还提供:
- 缺失流式文本时,通过 `runtime.messages()` 兜底补发最终回答。
- 工具调用必须提取 `reason`,并写入 LLM request audit。
- 对 running/completed/error 做统一归一化,前端不依赖 opencode 内部状态结构。
### 5.5 工具执行层
`.opencode/tools/*.ts` 是模型能调用的工具,分为三类:
| 类别 | 工具 | 作用 |
| --- | --- | --- |
| 业务数据工具 | `tjwater_cli` | 查询或计算真实后端数据 |
| 上下文工具 | `memory_manager`、`session_search`、`skill_manager` | 管理记忆、历史、技能 |
| 前端动作工具 | `locate_features`、`view_scada`、`view_history`、`show_chart`、`render_junctions`、`apply_layer_style` | 触发地图、图表、面板展示 |
工具桥设计重点:
```mermaid
sequenceDiagram
autonumber
participant M as Model / opencode Tool
participant Tool as .opencode/tools/*.ts
participant Bridge as /internal/tools/*
participant Ctx as SessionRuntimeContextStore
participant API as TJWater API
participant CLI as tjwater-cli
participant Store as ResultReferenceStore
M->>Tool: tool call(args, context.sessionID)
Tool->>Bridge: POST internal endpoint + x-agent-internal-token
Bridge->>Bridge: 校验内部 token
Bridge->>Ctx: 用 session_id 回读用户/项目/trace/token
Bridge->>CLI: --auth-stdin 写入 server/token/project
CLI-->>Bridge: JSON 或 raw stdout
opt 大型 junction 渲染 payload
Bridge->>Store: store_render_ref 写入 render_ref
Bridge-->>Tool: render_ref + preview
end
Tool-->>M: tool result
```
这个设计避免了两个常见问题:
- 模型工具代码不直接持有用户 token。
- 大型 junction 渲染 payload 不直接塞进模型上下文,而是存为 `render_ref`,由前端授权回读。
### 5.6 结果引用层
渲染引用会估算结果大小:
- 节点渲染 payload 存入 `ResultReferenceStore`,返回 `render_ref` 和 `preview`。
- 前端渲染工具通过 `render_ref` 回读完整 junctions 映射。
`ResultReferenceStore` 的权限校验维度:
- `actorKey`
- `projectId`
- 可选 `clientSessionId`
并提供:
- `preview`:列表、对象或标量的摘要。
- TTL 清理:`RESULT_REF_TTL_HOURS` 和 `RESULT_REF_CLEANUP_INTERVAL_MS`。
- legacy render payload 兼容。
### 5.7 记忆、历史与技能沉淀
这部分体现了 harness engineering 的“外部化记忆”和“可复用工作流”:
- `SessionTranscriptStore`:保存最近对话 turn,支持 `session_search`。
- `MemoryStore`:保存用户偏好和 workspace 事实。
- `SkillStore`:保存 workflow skill 的模式和参考资料。
- `LearningOrchestrator`:在 turn 完成后异步运行 gate/review,判断是否沉淀 memory 或 skill。
学习链路:
```mermaid
flowchart LR
Turn["对话 turn 完成"]
Transcript["append transcript"]
Cooldown["检查 cooldown"]
Gate["learning gate<br/>是否值得复盘"]
Review["learning review<br/>生成 memory/skill proposal"]
Policy["persistence policy<br/>脱敏与置信度阈值"]
Memory["MemoryStore"]
Skill["SkillStore"]
Audit["Learning Audit"]
Turn --> Transcript --> Cooldown --> Gate
Gate -->|"skip"| Audit
Gate -->|"accept"| Review --> Policy
Policy --> Memory
Policy --> Skill
Policy --> Audit
```
Agent 指令中明确区分:
- `memory_manager`:长期有效的用户偏好或项目事实。
- `skill_manager`:可复用操作流程。
- `session_search`:历史案例检索,只读。
- `tjwater_cli`:真实业务数据源和分析能力。
## 6. 一次 `/stream` 请求的完整时序
```mermaid
sequenceDiagram
autonumber
participant U as User
participant FE as Frontend
participant API as Express Chat Router
participant SB as ChatSessionBridge
participant Store as Session Stores
participant RT as OpencodeRuntimeAdapter
participant OC as opencode Runtime
participant SSE as Stream Adapter
participant Tool as opencode Tool
participant Bridge as Internal Tool Bridge
participant BE as TJWater API / CLI
U->>FE: 输入问题
FE->>API: POST /api/v1/agent/chat/stream
API->>API: Zod 校验 message/session/model
API->>Store: 读取或创建 session metadata/ui state/transcript
API->>SB: resolve(session, token, user, project, trace)
SB->>RT: createSession 或复用 session
SB->>Store: 写入 runtime context
API->>FE: 建立 SSE
API->>Store: 写入初始 user/assistant streaming messages
API->>Store: 读取 recent turns + memory
API->>SSE: streamPromptResponse(preparedMessage)
SSE->>RT: subscribeEvents()
SSE->>RT: prompt(sessionId, message, model)
RT->>OC: session.prompt
OC-->>SSE: status/reasoning/todo events
SSE-->>FE: progress
OC->>Tool: tool call
Tool->>Bridge: internal callback(sessionID, args, reason)
Bridge->>Store: 回读 runtime context
Bridge->>BE: 注入鉴权上下文后执行 CLI 或存储 render_ref
BE-->>Bridge: CLI 结果或 render_ref
Bridge-->>Tool: CLI 结果或 render_ref
Tool-->>OC: tool result
OC-->>SSE: tool/text/session events
SSE-->>FE: tool_call/token/done
API->>Store: 持久化 UI state、title、transcript
API->>Store: 触发异步 learning gate/review
```
## 7. 与 Harness Engineering 能力项的映射
| Harness 能力项 | 本项目落点 | 说明 |
| --- | --- | --- |
| Runtime orchestration | `OpencodeRuntimeAdapter`、`ChatSessionBridge` | 启动/连接 opencode,创建 session,发送 prompt,等待 idle,abort |
| Context assembly | `buildPromptWithLearningContext()`、runtime context store | 拼接历史、记忆、用户/项目/trace/token |
| Tool dispatch | `.opencode/tools/*.ts`、`/internal/tools/*` | 模型工具经内部桥执行真实能力 |
| Permission boundary | `x-agent-internal-token`、actor/project/session 授权 | token 不进工具代码,render_ref 按用户和项目授权 |
| State persistence | metadata、UI state、transcript、runtime context | 支持会话列表、恢复、重连、分叉和历史检索 |
| Memory | `MemoryStore`、`memory_manager`、learning review | 用户偏好、项目事实、prompt 注入 |
| Skill externalization | `.opencode/skills/workflow`、`skill_manager` | 把验证过的流程沉淀成可复用 workflow |
| Observability | Pino、LLM request audit、learning audit、traceId | 记录工具/技能调用理由、耗时、结果和学习决策 |
| Reliability | abort、timeout、fallback messages、render_ref TTL | 管控长任务、中断、超时、渲染引用和清理 |
| Frontend action bridge | SSE `tool_call` + UI tools | 把 Agent 决策映射为地图、图表、面板动作 |
## 8. 当前设计亮点
1. **模型与权限解耦**:用户 token 由服务端 session context 管理,工具只拿 `sessionID` 回调内部接口。
2. **前端协议稳定**:opencode 原始事件被统一成 `progress/token/tool_call/done/error`。
3. **支持运行时部署弹性**:embedded 和 client 模式兼容本地一体化和外部 runtime。
4. **大型渲染上下文友好**:使用 `render_ref`,避免模型读取完整 `node_area_map`。
5. **可持续沉淀工作流**:Agent 指令、`skill_manager`、`LearningOrchestrator` 共同支持 workflow 生长。
6. **恢复与重连能力**:active run、session UI state、`GET /session/:id/stream` 支持前端重新订阅。
7. **审计意识明确**:工具调用 reason、skill event、learning proposal 均有日志记录。
## 9. 可继续加强的点
| 方向 | 建议 |
| --- | --- |
| 工具治理 | 给工具增加风险等级、只读/写入分类、危险动作二次确认 |
| 幂等与重试 | 对写操作 API/CLI 增加 idempotency key,区分可重试和不可重试错误 |
| Eval harness | 为典型水务任务建立 golden traces,回归验证工具链和 prompt 改动 |
| 结构化事件 | 对 `tool_call` 参数增加 schema/version,便于前端兼容升级 |
| 结果生命周期 | render_ref 可增加按 session 删除、按项目统计和手动清理接口 |
| 安全审计 | 对内部工具桥增加 IP/来源限制、日志脱敏覆盖率检查 |
| Runtime 隔离 | client 模式下明确多租户 runtime session 隔离策略 |
## 10. 一句话结论
TJWaterAgent 的后端 harness 是一套围绕 opencode runtime 构建的 Agent 工程外壳:它把前端交互、LLM 推理、业务工具、用户权限、会话状态、记忆学习和审计观测组织成可运行、可恢复、可治理的生产级 Agent 服务。