init: 敲定开发文档
This commit is contained in:
commit
273750cd0d
138
.agents/skills/idea-to-product/SKILL.md
Normal file
138
.agents/skills/idea-to-product/SKILL.md
Normal file
@ -0,0 +1,138 @@
|
||||
---
|
||||
name: idea-to-product
|
||||
description: 将已经通过的软件点子依次推进为固化需求、实施方案、项目骨架、纵向功能、功能验收和发布候选版本。适用于用户提出应用、网站、服务、工具或其他软件项目,并希望 Agent 不进行市场、竞品或价值分析而直接落地的场景;也适用于继续执行已经由本流程管理的项目。开始开发前的每个阶段都必须获得明确的人工确认。
|
||||
---
|
||||
|
||||
# 从点子到产品
|
||||
|
||||
通过一套由项目文件持续记录的流程,将已经通过的软件点子落地为可验收产品。默认点子已经立项,只关注交付。
|
||||
|
||||
## 不可违反的规则
|
||||
|
||||
- 不进行市场、竞品、需求价值或商业价值分析。
|
||||
- 对不影响方向的歧义采用合理默认值。
|
||||
- 只有当选择会改变产品方向、产生明显成本差异、涉及敏感数据、缺少必要权限或造成需求冲突时才询问用户。
|
||||
- 当前版本保持精简,但核心流程必须端到端可用。
|
||||
- 把决策和进度写入项目文件,不依赖聊天记录。
|
||||
- 三个开发前阶段未全部获得明确人工确认时,绝不进入纵向功能开发。
|
||||
- 不得把沉默、话题切换或要求解释理解为确认。
|
||||
- 不得代替用户批准阶段门。
|
||||
|
||||
## 项目控制文件
|
||||
|
||||
新项目应从 `assets/` 复制模板,结合项目内容生成以下文件:
|
||||
|
||||
```text
|
||||
AGENTS.md
|
||||
.ai-project/state.yaml
|
||||
docs/REQUIREMENTS.md
|
||||
docs/IMPLEMENTATION.md
|
||||
docs/FEATURES.md
|
||||
docs/ACCEPTANCE.md
|
||||
```
|
||||
|
||||
如果已有 `AGENTS.md`,保留原有内容,只合并本项目需要的流程规则,不得删除用户指令。
|
||||
|
||||
继续已有项目时,先读取 `AGENTS.md`、`.ai-project/state.yaml`、相关 `docs/` 文件、仓库状态和已有实现,再从记录的阶段继续。如果状态文件与实际产物不一致,停止执行并报告差异,不得自行猜测。
|
||||
|
||||
开始或继续流程前,读取 [references/stage-gates.md](references/stage-gates.md)。
|
||||
|
||||
## 状态流转
|
||||
|
||||
在 `.ai-project/state.yaml` 中使用以下阶段值:
|
||||
|
||||
```text
|
||||
需求起草
|
||||
需求待确认
|
||||
实施方案起草
|
||||
实施方案待确认
|
||||
骨架构建中
|
||||
骨架待确认
|
||||
纵向功能开发
|
||||
功能验收中
|
||||
验收待确认
|
||||
发布候选
|
||||
```
|
||||
|
||||
阶段开始、产物变化、阶段门确认或出现阻塞时,都要更新状态文件。
|
||||
|
||||
## 执行流程
|
||||
|
||||
### 1. 记录点子
|
||||
|
||||
把用户的点子整理成简短的项目身份信息:暂定名称、一句话说明、目标用户、核心流程、交付形态和采用的默认值。不要评估这个点子是否值得做。
|
||||
|
||||
除非存在会改变产品方向的歧义,否则立即基于这份理解起草需求。
|
||||
|
||||
### 2. 固化需求——人工确认门 1
|
||||
|
||||
根据 `assets/REQUIREMENTS.md.template` 创建或更新 `docs/REQUIREMENTS.md`。
|
||||
|
||||
让每条规则都能被开发和测试。包含用户角色、用户流程、页面或接口、功能、业务规则、数据、权限、正常和异常流程、非目标以及验收标准。
|
||||
|
||||
把阶段设为“需求待确认”,展示精简的范围摘要和变更文件,然后停止。请用户确认或提出修改。
|
||||
|
||||
只有用户明确说出“需求确认”“通过,进入下一阶段”或同等明确的话语后才能继续。把确认记录到需求文档和状态文件中,并冻结当前版本范围。
|
||||
|
||||
### 3. 生成实施方案——人工确认门 2
|
||||
|
||||
根据 `assets/IMPLEMENTATION.md.template` 创建或更新 `docs/IMPLEMENTATION.md`。
|
||||
|
||||
只依据已经冻结的需求和仓库约束制定方案。明确架构、技术栈、目录结构、路由、数据模型、接口、身份认证、存储、外部服务、状态流转、失败处理、安全、可观测性、环境、测试、验证命令、部署形态和有序的纵向功能切片。
|
||||
|
||||
把阶段设为“实施方案待确认”,展示关键技术决策和变更文件,然后停止。不得创建项目骨架或编写产品代码。
|
||||
|
||||
只有用户明确确认实施方案后才能继续。记录确认人和确认时间。
|
||||
|
||||
### 4. 生成并验证项目骨架——人工确认门 3
|
||||
|
||||
把阶段设为“骨架构建中”。只构建已确认方案中定义的基础工程:项目初始化、目录、依赖、配置示例、质量工具、必要的数据库与迁移机制、基础布局、健康检查、错误与日志基础以及最小冒烟测试。
|
||||
|
||||
不得提前实现计划中的产品功能。实际运行文档中规定的安装、格式或静态检查、类型检查、测试和生产构建命令,并把准确命令和结果记录到 `docs/IMPLEMENTATION.md`。
|
||||
|
||||
把阶段设为“骨架待确认”,总结项目结构、验证结果、尚未配置的外部服务和建议的第一个纵向功能,然后停止。
|
||||
|
||||
只有用户明确确认项目骨架后才能开始产品功能开发。确认后记录结果,并把阶段设为“纵向功能开发”。
|
||||
|
||||
### 5. 按纵向功能开发
|
||||
|
||||
根据 `assets/FEATURES.md.template` 创建或更新 `docs/FEATURES.md`,从已确认的实施方案生成有序的功能切片清单。
|
||||
|
||||
每次只完成一个切片。每个切片必须覆盖所有适用的界面、服务或接口、数据持久化、身份与权限、输入校验、加载/空白/成功/失败状态、重试与幂等、日志、自动化测试和人工验证步骤。
|
||||
|
||||
每个切片按以下步骤执行:
|
||||
|
||||
1. 标记为“进行中”。
|
||||
2. 修改前先检查现有代码。
|
||||
3. 只实现当前切片及其直接前置条件。
|
||||
4. 运行相关检查,并在风险相称时运行完整检查套件。
|
||||
5. 工具允许时,人工操作验证核心流程。
|
||||
6. 记录证据并标记为“已完成”,不得标记为已经获得人工验收。
|
||||
|
||||
除非遇到阻塞或用户要求暂停,否则持续完成已确认的切片清单。新功能想法只记录到后续版本,不得加入当前版本。
|
||||
|
||||
### 6. 执行功能验收——人工确认门 4
|
||||
|
||||
把阶段设为“功能验收中”。根据 `assets/ACCEPTANCE.md.template` 创建或更新 `docs/ACCEPTANCE.md`。
|
||||
|
||||
把每条冻结需求和验收标准映射到具体实现与验证证据。运行全部必要的静态检查、测试、生产构建、迁移验证、权限与数据隔离检查、密钥检查、失败恢复检查和可执行的端到端流程。
|
||||
|
||||
修复冻结范围内能够明确判断的实现缺陷,增加回归测试,并重新运行受影响的检查。把结果分为已通过、未通过、仅能人工验证、已知限制、发布阻塞项和非阻塞项。
|
||||
|
||||
自动验收不存在发布阻塞项后,把阶段设为“验收待确认”,提供准确的人工测试步骤,然后停止。必须由用户明确报告验收通过,不能只凭 AI 的验证结果标记为通过。
|
||||
|
||||
用户明确验收通过后,记录结果并把阶段设为“发布候选”。除非用户另外要求部署,否则不得自行部署。
|
||||
|
||||
## 阶段门回复格式
|
||||
|
||||
每个人工确认门都只使用以下栏目回复:
|
||||
|
||||
```text
|
||||
阶段结果
|
||||
关键内容
|
||||
验证证据
|
||||
需要你确认
|
||||
确认后下一步
|
||||
```
|
||||
|
||||
保持回复简洁,并链接相关项目文件。明确说明尚未开始下一阶段。
|
||||
4
.agents/skills/idea-to-product/agents/openai.yaml
Normal file
4
.agents/skills/idea-to-product/agents/openai.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "点子落地"
|
||||
short_description: "将软件点子按四个人工确认阶段推进到功能验收与发布候选版本"
|
||||
default_prompt: "使用 $idea-to-product 将这个已通过的软件点子推进到功能验收,并在每个开发前阶段等待我的明确确认。"
|
||||
34
.agents/skills/idea-to-product/assets/ACCEPTANCE.md.template
Normal file
34
.agents/skills/idea-to-product/assets/ACCEPTANCE.md.template
Normal file
@ -0,0 +1,34 @@
|
||||
# 功能验收
|
||||
|
||||
状态:草稿
|
||||
版本:0.1.0
|
||||
验收人:
|
||||
验收时间:
|
||||
|
||||
## 需求追踪
|
||||
|
||||
| 验收标准 | 具体实现 | 自动验证证据 | 人工验证证据 | 结果 |
|
||||
|---|---|---|---|---|
|
||||
|
||||
## 自动化检查
|
||||
|
||||
## 端到端流程
|
||||
|
||||
## 安全与数据隔离检查
|
||||
|
||||
## 迁移与生产构建检查
|
||||
|
||||
## 已通过
|
||||
|
||||
## 未通过
|
||||
|
||||
## 仅能人工验证
|
||||
|
||||
## 已知限制
|
||||
|
||||
## 发布阻塞项
|
||||
|
||||
## 非阻塞项
|
||||
|
||||
## 人工验收步骤
|
||||
|
||||
31
.agents/skills/idea-to-product/assets/AGENTS.md.template
Normal file
31
.agents/skills/idea-to-product/assets/AGENTS.md.template
Normal file
@ -0,0 +1,31 @@
|
||||
# 从点子到产品工作流
|
||||
|
||||
## 唯一事实来源
|
||||
|
||||
- `docs/REQUIREMENTS.md` 是当前版本产品范围的唯一来源。
|
||||
- `docs/IMPLEMENTATION.md` 保存已经确认的技术实施方案。
|
||||
- `.ai-project/state.yaml` 记录当前阶段和人工确认结果。
|
||||
- `docs/FEATURES.md` 记录纵向功能切片进度。
|
||||
- `docs/ACCEPTANCE.md` 记录验收证据。
|
||||
|
||||
## 人工确认门
|
||||
|
||||
- 完成需求草案后停止,等待明确人工确认。
|
||||
- 完成实施方案后停止,等待明确人工确认。
|
||||
- 生成并验证项目骨架后停止,等待明确人工确认。
|
||||
- 三个阶段门全部通过前,不得开始纵向功能开发。
|
||||
- 完成功能验收后停止,等待明确人工确认。
|
||||
|
||||
## 开发规则
|
||||
|
||||
- 默认项目已经立项,不进行市场、竞品、需求价值或商业价值分析。
|
||||
- 不得扩大已经冻结的当前版本范围。
|
||||
- 新想法记录到后续版本。
|
||||
- 每次只开发一个完整的纵向功能切片。
|
||||
- 每个切片覆盖所有适用的界面、接口或服务、数据持久化、权限、校验、异常状态、日志和测试。
|
||||
- 修改前先检查现有代码。
|
||||
- 实际运行项目规定的格式或静态检查、类型检查、测试和生产构建。
|
||||
- 不得通过删除或跳过测试获得通过结果。
|
||||
- 绝不提交真实密钥。
|
||||
- 保留与当前任务无关的用户修改。
|
||||
|
||||
23
.agents/skills/idea-to-product/assets/FEATURES.md.template
Normal file
23
.agents/skills/idea-to-product/assets/FEATURES.md.template
Normal file
@ -0,0 +1,23 @@
|
||||
# 纵向功能
|
||||
|
||||
需求版本:0.1.0
|
||||
|
||||
允许的状态:“待开始”“进行中”“已完成”“已阻塞”。
|
||||
|
||||
## 当前版本功能切片
|
||||
|
||||
### F-001——功能名称
|
||||
|
||||
- 状态:待开始
|
||||
- 用户可见结果:
|
||||
- 页面与交互:
|
||||
- 服务或接口:
|
||||
- 数据持久化:
|
||||
- 权限与校验:
|
||||
- 异常状态:
|
||||
- 自动化测试:
|
||||
- 验证命令与结果:
|
||||
- 人工验证步骤:
|
||||
- 已知限制:
|
||||
|
||||
## 后续版本想法
|
||||
@ -0,0 +1,41 @@
|
||||
# 实施方案
|
||||
|
||||
状态:草稿
|
||||
需求版本:0.1.0
|
||||
确认人:
|
||||
确认时间:
|
||||
|
||||
## 约束与默认值
|
||||
|
||||
## 技术栈
|
||||
|
||||
## 系统架构
|
||||
|
||||
## 目录结构
|
||||
|
||||
## 路由与接口
|
||||
|
||||
## 数据模型与迁移
|
||||
|
||||
## 身份认证与权限
|
||||
|
||||
## 外部服务与存储
|
||||
|
||||
## 状态流转
|
||||
|
||||
## 校验、失败、重试与幂等
|
||||
|
||||
## 安全、日志、监控与密钥
|
||||
|
||||
## 本地、测试与生产环境
|
||||
|
||||
## 自动化测试方案
|
||||
|
||||
## 验证命令
|
||||
|
||||
## 有序的纵向功能切片
|
||||
|
||||
## 项目骨架验证证据
|
||||
|
||||
记录命令、日期、退出状态和简要结果。
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
# 产品需求
|
||||
|
||||
状态:草稿
|
||||
版本:0.1.0
|
||||
确认人:
|
||||
确认时间:
|
||||
|
||||
## 项目身份
|
||||
|
||||
- 项目名称:
|
||||
- 一句话说明:
|
||||
- 目标用户:
|
||||
- 交付形态:
|
||||
- 采用的默认值:
|
||||
|
||||
## 当前版本范围
|
||||
|
||||
## 用户角色与权限
|
||||
|
||||
## 核心用户流程
|
||||
|
||||
## 页面或接口
|
||||
|
||||
## 功能需求
|
||||
|
||||
## 业务规则
|
||||
|
||||
## 数据与状态
|
||||
|
||||
## 正常、异常和边界流程
|
||||
|
||||
## 本版本不做
|
||||
|
||||
## 验收标准
|
||||
|
||||
每条标准使用 `AC-001` 这样的稳定编号。
|
||||
|
||||
## 后续版本想法
|
||||
|
||||
26
.agents/skills/idea-to-product/assets/state.yaml.template
Normal file
26
.agents/skills/idea-to-product/assets/state.yaml.template
Normal file
@ -0,0 +1,26 @@
|
||||
工作流: "idea-to-product"
|
||||
项目: ""
|
||||
版本: "0.1.0"
|
||||
当前阶段: "需求起草"
|
||||
更新时间: ""
|
||||
阻塞: null
|
||||
|
||||
阶段门:
|
||||
需求:
|
||||
状态: "草稿"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
实施方案:
|
||||
状态: "未开始"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
项目骨架:
|
||||
状态: "未开始"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
功能验收:
|
||||
状态: "未开始"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
|
||||
功能: []
|
||||
65
.agents/skills/idea-to-product/references/stage-gates.md
Normal file
65
.agents/skills/idea-to-product/references/stage-gates.md
Normal file
@ -0,0 +1,65 @@
|
||||
# 阶段门
|
||||
|
||||
使用以下检查表判断某个阶段是否已经具备提交人工确认的条件。“可以提交确认”不等于“已经获得确认”。
|
||||
|
||||
## 1. 需求阶段门
|
||||
|
||||
- 项目点子已经被完整表达,没有市场或价值分析。
|
||||
- 当前版本范围和明确不做的内容清晰。
|
||||
- 用户角色、核心流程、页面或接口、数据、权限和业务规则具体。
|
||||
- 正常、异常、边界和未授权流程已经覆盖。
|
||||
- 验收标准可观察、可测试。
|
||||
- 会改变产品方向的未决问题已经列出。
|
||||
- `docs/REQUIREMENTS.md` 标记为“待确认”。
|
||||
|
||||
获得明确确认后,先标记为“已确认”和“已冻结”,然后才能制定实施方案。
|
||||
|
||||
## 2. 实施方案阶段门
|
||||
|
||||
- 每条冻结需求都有明确的实现位置。
|
||||
- 技术选择和关键默认值清晰。
|
||||
- 架构和目录结构符合小工作室的规模。
|
||||
- 数据模型、接口、身份认证、权限、外部服务和失败处理已经定义。
|
||||
- 验证命令和部署假设已经列出。
|
||||
- 纵向功能切片有明确顺序,每个切片都会产生用户可见结果。
|
||||
- 本阶段没有创建产品代码或项目骨架。
|
||||
- `docs/IMPLEMENTATION.md` 标记为“待确认”。
|
||||
|
||||
获得明确确认后,先标记为“已确认”,然后才能生成项目骨架。
|
||||
|
||||
## 3. 项目骨架阶段门
|
||||
|
||||
- 项目能在文档规定的开发环境中启动。
|
||||
- 已配置必要的质量、类型、测试和构建命令。
|
||||
- 文档规定的验证命令都已经实际运行。
|
||||
- 环境变量已经记录,但没有写入真实密钥。
|
||||
- 必要时已经建立数据库迁移、日志与错误处理基础和健康检查。
|
||||
- 没有提前实现计划中的产品功能。
|
||||
- 准确命令和结果已经记录。
|
||||
- 已明确第一个纵向功能切片。
|
||||
|
||||
获得明确确认后才能进入“纵向功能开发”,不得提前进入。
|
||||
|
||||
## 4. 功能验收阶段门
|
||||
|
||||
- 每条冻结验收标准都映射到代码和证据。
|
||||
- 全部必要的自动化检查和生产构建通过。
|
||||
- 已检查权限和数据隔离。
|
||||
- 适用时,失败、超时、重试和重复提交场景都有证据。
|
||||
- 适用时,数据库迁移安全且可复现。
|
||||
- 没有密钥被提交或暴露给客户端。
|
||||
- 发布阻塞项为空。
|
||||
- 仅能人工执行的步骤准确且可复现。
|
||||
|
||||
只有用户可以确认功能验收通过。
|
||||
|
||||
## 确认处理规则
|
||||
|
||||
有效确认必须明确指向当前等待确认的阶段,并授权进入下一阶段。例如:
|
||||
|
||||
- “需求确认,进入实施方案。”
|
||||
- “实施方案通过。”
|
||||
- “骨架确认,可以开始开发。”
|
||||
- “功能验收通过。”
|
||||
|
||||
要求解释、部分认可、保持沉默或只批准其中一小部分,都不能视为阶段确认。如果用户要求修改,保持阶段门为等待确认状态;修改完成后重新提交确认。
|
||||
26
.ai-project/state.yaml
Normal file
26
.ai-project/state.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
工作流: "idea-to-product"
|
||||
项目: "Great Agent 2"
|
||||
版本: "0.3.0"
|
||||
当前阶段: "实施方案待确认"
|
||||
更新时间: "2026-08-11"
|
||||
阻塞: null
|
||||
|
||||
阶段门:
|
||||
需求:
|
||||
状态: "已确认、已冻结"
|
||||
确认人: "用户"
|
||||
确认时间: "2026-08-11"
|
||||
实施方案:
|
||||
状态: "待确认"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
项目骨架:
|
||||
状态: "未开始"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
功能验收:
|
||||
状态: "未开始"
|
||||
确认人: null
|
||||
确认时间: null
|
||||
|
||||
功能: []
|
||||
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
.DS_Store
|
||||
|
||||
dist
|
||||
node_modules
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
.temp
|
||||
.cache
|
||||
38
AGENTS.md
Normal file
38
AGENTS.md
Normal file
@ -0,0 +1,38 @@
|
||||
# 从点子到产品工作流
|
||||
|
||||
## 唯一事实来源
|
||||
|
||||
- `docs/REQUIREMENTS.md` 是当前版本产品范围的唯一来源。
|
||||
- `docs/IMPLEMENTATION.md` 保存已经确认的技术实施方案。
|
||||
- `.ai-project/state.yaml` 记录当前阶段和人工确认结果。
|
||||
- `docs/FEATURES.md` 记录纵向功能切片进度。
|
||||
- `docs/ACCEPTANCE.md` 记录验收证据。
|
||||
|
||||
## 人工确认门
|
||||
|
||||
- 完成需求草案后停止,等待明确人工确认。
|
||||
- 完成实施方案后停止,等待明确人工确认。
|
||||
- 生成并验证项目骨架后停止,等待明确人工确认。
|
||||
- 三个阶段门全部通过前,不得开始纵向功能开发。
|
||||
- 完成功能验收后停止,等待明确人工确认。
|
||||
|
||||
## 开发规则
|
||||
|
||||
- 默认项目已经立项,不进行市场、竞品、需求价值或商业价值分析。
|
||||
- 不得扩大已经冻结的当前版本范围。
|
||||
- 新想法记录到后续版本。
|
||||
- 每次只开发一个完整的纵向功能切片。
|
||||
- 每个切片覆盖所有适用的界面、接口或服务、数据持久化、权限、校验、异常状态、日志和测试。
|
||||
- 修改前先检查现有代码。
|
||||
- 实际运行项目规定的格式或静态检查、类型检查、测试和生产构建。
|
||||
- 不得通过删除或跳过测试获得通过结果。
|
||||
- 绝不提交真实密钥。
|
||||
- 保留与当前任务无关的用户修改。
|
||||
|
||||
## 项目专项规则
|
||||
|
||||
- 保持 `local file -> agent core -> web serve -> web` 的依赖方向。
|
||||
- Agent Core 不得依赖 Web 层,为后续 `local file -> agent core -> cli` 保留扩展边界。
|
||||
- 避免大文件;模块按单一职责拆分。出现同时承担协议、业务和存储职责的文件时必须拆分。
|
||||
- 当前版本为单人使用,不引入多租户、多用户或分布式并发设计。
|
||||
- 访问保护由部署环境中的外部反向代理承担;应用内不得实现登录页面、身份校验中间件、用户会话或访问凭据配置。
|
||||
9
docs/ACCEPTANCE.md
Normal file
9
docs/ACCEPTANCE.md
Normal file
@ -0,0 +1,9 @@
|
||||
# 功能验收
|
||||
|
||||
状态:未开始
|
||||
版本:0.1.0(待确认)
|
||||
验收人:
|
||||
验收时间:
|
||||
|
||||
项目尚未进入功能验收阶段。
|
||||
|
||||
7
docs/FEATURES.md
Normal file
7
docs/FEATURES.md
Normal file
@ -0,0 +1,7 @@
|
||||
# 纵向功能
|
||||
|
||||
状态:未开始
|
||||
需求版本:0.1.0(待确认)
|
||||
|
||||
实施方案和项目骨架获得人工确认前,不生成纵向功能开发清单。
|
||||
|
||||
949
docs/IMPLEMENTATION.md
Normal file
949
docs/IMPLEMENTATION.md
Normal file
@ -0,0 +1,949 @@
|
||||
# 实施方案
|
||||
|
||||
状态:待确认
|
||||
方案版本:0.4.0
|
||||
需求版本:0.3.0(已确认、已冻结)
|
||||
确认人:
|
||||
确认时间:
|
||||
|
||||
## 1. 约束与关键默认值
|
||||
|
||||
- 产品只面向单人、单实例,不设计多用户、多租户、分布式任务或跨实例协调。
|
||||
- 应用不实现登录、身份校验、用户会话或访问凭据管理;访问保护完全属于外部反向代理职责。
|
||||
- 当前版本只交付 Web 链路;CLI 不进入构建产物,但 Agent Core 必须能被无 Web 进程直接调用。
|
||||
- 普通会话使用 `DEFAULT_WORKSPACE_ROOT`;项目会话使用所属 Project 保存的 `workspaceRoot`。每次 Run 固化解析后的工作区,运行中不得切换。
|
||||
- 同一时刻只允许一个 Agent Run 处于活动状态;“等待用户”仍属于活动状态。
|
||||
- 首个模型适配器采用 DeepSeek OpenAI 兼容接口;Agent Core 只依赖自有 `ModelPort`,后续可以增加其他模型适配器。
|
||||
- 运行时和包管理统一使用 Bun;应用代码统一使用 TypeScript 严格模式。
|
||||
- 项目、会话、消息、运行事件与设置全部使用真实本地文件系统存储,不引入数据库;业务数据目录与各工作区使用不同根目录和权限边界。
|
||||
- UI 使用 VanJS 单页应用,视觉实现以 CSS Modules 和设计令牌为主,避免组件库默认样式妨碍 Claude Desktop 还原。
|
||||
- 主要目标环境为 macOS/Linux;Windows 不是 v0.1.0 验收平台。
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
| 层级 | 选择 | 用途与理由 |
|
||||
|---|---|---|
|
||||
| 运行时/包管理 | Bun Workspaces | 单一工具完成安装、脚本、测试和服务运行;适合单实例应用 |
|
||||
| 语言 | TypeScript strict | 为跨层接口、事件和未来 CLI 提供稳定类型边界 |
|
||||
| Web UI | VanJS + Vite | 使用接近原生 DOM 的函数组件和细粒度 State 绑定,运行时极轻;Vite 负责编译 TypeScript、CSS Modules 和生产构建 |
|
||||
| 样式 | CSS Modules + CSS Variables | 精确控制尺寸、间距和状态,避免大而统一的全局样式文件 |
|
||||
| Web Serve | Hono | 轻量路由、流式响应和 Bun 运行时支持 |
|
||||
| 数据校验 | Zod | 在 HTTP 边界、环境配置和模型工具输入处执行运行时校验 |
|
||||
| 本地数据 | Bun 文件 API + 原子替换 + NDJSON | 会话与运行数据直接落在可查看、可备份的真实目录中;按实体拆分,避免单个巨型 JSON 文件 |
|
||||
| 模型接入 | DeepSeek OpenAI 兼容 API + `openai` SDK | 首版实现 DeepSeek 流式回复和工具调用;SDK 仅存在于独立适配包中 |
|
||||
| Markdown | `markdown-it` + DOMPurify | 与前端框架解耦,渲染常用 Markdown,并在插入 DOM 前执行白名单净化 |
|
||||
| 代码高亮 | Shiki | 输出稳定、主题可控,便于贴近目标视觉 |
|
||||
| 日志 | Pino | 结构化日志、字段脱敏和运行标识关联 |
|
||||
| 静态检查 | Biome + TypeScript | 格式、常见质量问题和类型检查 |
|
||||
| 单元/集成测试 | Bun Test | 与运行时一致,覆盖 Core、存储、文件和服务接口 |
|
||||
| 浏览器验收 | Playwright | 端到端流程、固定视口截图和视觉回归 |
|
||||
|
||||
不引入 React/Preact、JSX、Redux、Zustand、Tailwind、大型 UI 组件库、ORM、消息队列或独立数据库服务。Web 数据获取、SSE 生命周期和局部交互状态使用项目内的明确模块与 VanJS State 管理。
|
||||
|
||||
### 前端选型结论
|
||||
|
||||
- **采用 VanJS。** 当前 UI 是单页、单用户桌面式界面,不依赖大型组件生态;核心交互可用 DOM 函数组件、`van.state` 和 `van.derive` 表达。
|
||||
- 使用 `vanjs-core` 的 NPM 包并通过 Vite 构建,不从 CDN 加载运行时代码。
|
||||
- 默认只使用 VanJS Core。只有骨架或 F-001 的消息/会话列表验证证明细粒度数组操作明显更清晰时,才允许增加官方 VanX;增加前必须记录具体用途,不把它当作通用全局状态容器。
|
||||
- 不启用社区 JSX 转换、社区路由或 UI 组件库。首版仅有一个应用入口,设置使用面板或弹窗,不需要前端路由。
|
||||
- Markdown、代码高亮和内容净化继续使用框架无关的 `markdown-it`、Shiki 和 DOMPurify。
|
||||
- 采用 VanJS 后必须显式约束状态粒度和资源释放,避免因缺少框架生命周期而产生重复订阅或泄漏。
|
||||
|
||||
## 3. 总体架构
|
||||
|
||||
```text
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ apps/web │
|
||||
│ VanJS UI、页面状态、流式事件消费、视觉呈现 │
|
||||
└──────────────────────────┬───────────────────────────┘
|
||||
│ HTTP + SSE
|
||||
┌──────────────────────────▼───────────────────────────┐
|
||||
│ apps/web-server │
|
||||
│ Hono 路由、DTO 转换、SSE、进程组合、静态资源 │
|
||||
└─────────────┬──────────────┬──────────────┬──────────┘
|
||||
│ │ │
|
||||
┌─────────────▼──────┐ ┌─────▼────────┐ ┌───▼─────────────┐
|
||||
│ packages/agent-core│ │ local-files │ │ local-data │
|
||||
│ 领域、用例、Ports │ │ 工作区工具 │ │ 运行数据文件 │
|
||||
└─────────────▲──────┘ └─────┬────────┘ └───┬─────────────┘
|
||||
│ │ │
|
||||
│ 实现 Core Ports │
|
||||
┌─────────────┴──────────────┴──────────────┴──────────┐
|
||||
│ packages/model-deepseek │
|
||||
│ ModelPort 的 DeepSeek 适配器 │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
|
||||
未来:apps/cli -> agent-core + local-files + local-data + model adapter
|
||||
```
|
||||
|
||||
代码依赖规则:
|
||||
|
||||
- `agent-core` 不依赖 Hono、VanJS、DeepSeek/OpenAI SDK 或 Node/Bun 文件 API。
|
||||
- `local-files`、`local-data`、`model-deepseek` 实现 Agent Core 定义的 Ports。
|
||||
- `web-server` 是组合根,负责创建适配器并注入 Agent Core。
|
||||
- `web` 只依赖 Web DTO 和事件契约,不导入服务端包。
|
||||
- 未来 CLI 直接组合 Agent Core 与相同适配器,不通过 HTTP 调用本机 Web Server。
|
||||
|
||||
## 4. 目录结构
|
||||
|
||||
```text
|
||||
great-agent2/
|
||||
├── apps/
|
||||
│ ├── web/
|
||||
│ │ └── src/
|
||||
│ │ ├── app/
|
||||
│ │ ├── features/
|
||||
│ │ │ ├── onboarding/
|
||||
│ │ │ ├── projects/
|
||||
│ │ │ ├── conversations/
|
||||
│ │ │ ├── messages/
|
||||
│ │ │ ├── interactions/
|
||||
│ │ │ ├── composer/
|
||||
│ │ │ ├── files/
|
||||
│ │ │ └── settings/
|
||||
│ │ ├── components/
|
||||
│ │ ├── api/
|
||||
│ │ └── styles/
|
||||
│ └── web-server/
|
||||
│ └── src/
|
||||
│ ├── routes/
|
||||
│ ├── streaming/
|
||||
│ ├── http/
|
||||
│ ├── config/
|
||||
│ └── composition/
|
||||
├── packages/
|
||||
│ ├── agent-core/
|
||||
│ │ └── src/
|
||||
│ │ ├── domain/
|
||||
│ │ ├── ports/
|
||||
│ │ ├── use-cases/
|
||||
│ │ ├── events/
|
||||
│ │ └── errors/
|
||||
│ ├── local-files/
|
||||
│ │ └── src/
|
||||
│ │ ├── paths/
|
||||
│ │ ├── readers/
|
||||
│ │ ├── search/
|
||||
│ │ └── writers/
|
||||
│ ├── local-data/
|
||||
│ │ └── src/
|
||||
│ │ ├── layout/
|
||||
│ │ ├── atomic-writes/
|
||||
│ │ ├── recovery/
|
||||
│ │ ├── repositories/
|
||||
│ │ └── indexing/
|
||||
│ ├── model-deepseek/
|
||||
│ │ └── src/
|
||||
│ │ ├── adapter/
|
||||
│ │ ├── streaming/
|
||||
│ │ ├── tool-mapping/
|
||||
│ │ └── interaction-mapping/
|
||||
│ └── web-contracts/
|
||||
│ └── src/
|
||||
│ ├── requests/
|
||||
│ ├── responses/
|
||||
│ └── events/
|
||||
├── tests/
|
||||
│ ├── e2e/
|
||||
│ ├── visual/
|
||||
│ └── fixtures/
|
||||
├── scripts/
|
||||
│ ├── check-architecture.ts
|
||||
│ └── check-file-size.ts
|
||||
├── data/ # 运行时生成,Git 忽略
|
||||
├── docs/
|
||||
├── package.json
|
||||
├── bunfig.toml
|
||||
├── tsconfig.base.json
|
||||
└── biome.json
|
||||
```
|
||||
|
||||
不创建含糊的 `shared/`、`helpers/` 或单一巨型 `utils.ts`。跨包内容必须有明确领域名称和使用方向。
|
||||
|
||||
## 5. 文件规模与模块拆分规则
|
||||
|
||||
- 业务源码目标不超过 250 行;超过 300 行必须拆分或在代码评审中记录明确理由。
|
||||
- 非生成的 TypeScript 业务文件超过 400 行时,`check:file-size` 直接失败。
|
||||
- 生成文件、格式迁移固定数据、测试固定数据和纯类型映射可豁免,但必须在检查脚本中显式列出。
|
||||
- VanJS 应用外壳只负责组合 feature 组件,不直接包含 API、持久化或 Agent 规则。
|
||||
- 路由处理器只做校验、调用用例、转换响应,不实现领域逻辑。
|
||||
- 每个 Port、Repository、Use Case 和工具处理器独立成文件或小型同职责目录。
|
||||
- 使用包导出控制依赖边界;`check:architecture` 禁止 Core 导入外层包和 Web 导入服务端实现。
|
||||
|
||||
## 6. Agent Core 设计
|
||||
|
||||
### 领域对象
|
||||
|
||||
- `Project`:项目标识、名称、绑定工作区、时间和项目会话摘要。
|
||||
- `Conversation`:会话标识、可空 `projectId`、标题、时间和消息顺序。
|
||||
- `Message`:角色、内容块、附件引用、运行标识和时间。
|
||||
- `AgentRun`:等待、运行中、调用工具、等待用户、已完成、失败、已取消。
|
||||
- `ToolCall`:工具名称、已校验输入、状态、结果摘要和错误。
|
||||
- `UserInteraction`:所属 Run、消息位置、交互类型、问题、选项、限制、回答和状态。
|
||||
- `AttachmentRef`:工作区相对路径、类型、可用状态和最近确认时间。
|
||||
|
||||
### Ports
|
||||
|
||||
- `ModelPort`:接收项目自有的模型请求,返回项目自有的异步事件流,并支持取消;它不是 TCP/HTTP 端口。
|
||||
- `ProjectRepository`:项目实体与项目索引的一致性读写。
|
||||
- `ConversationRepository`:会话与消息的一致性读写。
|
||||
- `RunRepository`:运行状态、工具调用和流式草稿持久化。
|
||||
- `InteractionRepository`:等待回答、已回答和已取消交互的一致性读写。
|
||||
- `SettingsRepository`:非敏感配置。
|
||||
- `WorkspacePort`:列出、搜索、读取、创建和修改文件。
|
||||
- `WorkspaceResolverPort`:按普通会话或项目会话解析并校验当前工作区,不允许失败时跨边界回退。
|
||||
- `ClockPort`、`IdPort`:保证测试可控。
|
||||
|
||||
### 核心用例
|
||||
|
||||
- `CreateProject`
|
||||
- `ListProjects`
|
||||
- `GetProject`
|
||||
- `ListProjectConversations`
|
||||
- `CreateConversationWithFirstRun`
|
||||
- `ListRecentConversations`
|
||||
- `RenameConversation`
|
||||
- `DeleteConversation`
|
||||
- `GetConversation`
|
||||
- `StartAgentRun`
|
||||
- `CancelAgentRun`
|
||||
- `RetryAgentRun`
|
||||
- `RespondToInteraction`
|
||||
- `ListWorkspaceFiles`
|
||||
- `ReadAttachment`
|
||||
- `GetSettings` / `UpdateSettings`
|
||||
|
||||
### 单任务限制
|
||||
|
||||
- Core 内维护全局活动 Run 约束,而不是由按钮禁用单独保证。
|
||||
- Core 的单进程运行协调器执行原子检查;`local-data` 同时维护活动 Run 指针,供重启恢复。
|
||||
- “新任务”和项目内“新对话”只是 Web UI 草稿状态,不调用 Repository;第一条有效消息提交时,Core 才创建会话与首个 Run。
|
||||
- 首次创建时先校验 `projectId` 与工作区,再写入会话、用户消息、Run 事件日志和活动 Run 指针;失败时不得在索引中留下可见空会话。
|
||||
- 已有会话创建 Run 前再次校验其 Project 与工作区绑定,绝不接受客户端直接传入任意工作区路径。
|
||||
- 第二个 Run 请求返回稳定错误码 `RUN_ALREADY_ACTIVE`。
|
||||
- 等待用户回答的 Run 同样占用全局活动位置;回答会恢复原 Run,停止会取消其全部未回答交互。
|
||||
|
||||
## 7. ModelPort 与 DeepSeek 适配器
|
||||
|
||||
`ModelPort` 是 Agent Core 自己定义的一份 TypeScript 接口,名称中的 Port 表示“架构边界”,不是网络端口。调用方向如下:
|
||||
|
||||
```text
|
||||
Agent Core -> ModelPort.stream(项目领域请求) -> DeepSeekModelAdapter
|
||||
Agent Core <- AsyncIterable<项目领域事件> <- DeepSeek SSE/SDK 事件
|
||||
```
|
||||
|
||||
它解决四个具体问题:
|
||||
|
||||
1. Core 不认识 DeepSeek 的请求、响应或 SDK 类型,只认识 `ModelRequest`、`ModelEvent`、`ToolDefinition` 等项目类型。
|
||||
2. `DeepSeekModelAdapter` 负责翻译角色、内容块、工具定义、增量文本、工具调用、结束原因和错误。
|
||||
3. 单元测试可以注入 `FakeModelAdapter`,不联网也能确定性验证工具循环、取消和失败。
|
||||
4. 未来增加其他模型或 CLI 时复用 Core,不需要修改业务用例和 Web 协议。
|
||||
|
||||
概念接口如下,具体字段在骨架阶段再固化:
|
||||
|
||||
```ts
|
||||
interface ModelPort {
|
||||
stream(request: ModelRequest, signal: AbortSignal): AsyncIterable<ModelEvent>;
|
||||
}
|
||||
```
|
||||
|
||||
- `model-deepseek` 把领域消息映射为 DeepSeek 的 OpenAI 兼容 Chat Completions 请求,把流式 SSE/SDK 响应映射为 Core 事件。
|
||||
- SDK 对象和响应类型不得穿透 `ModelPort`。
|
||||
- 工具定义由 Core 提供,适配器只负责协议映射。
|
||||
- 取消操作通过 `AbortSignal` 传递。
|
||||
- 默认模型为当前 DeepSeek API 提供的 `deepseek-v4-pro`,但模型名、Base URL、思考模式、最大输出和超时均由环境配置提供;密钥只在服务端进程读取。
|
||||
- 默认不把完整提示词、消息正文、文件内容或密钥写入日志。
|
||||
- 模型错误统一映射为 `MODEL_CONFIG_MISSING`、`MODEL_TIMEOUT`、`MODEL_RATE_LIMITED`、`MODEL_UNAVAILABLE` 或 `MODEL_RESPONSE_INVALID`。
|
||||
|
||||
### 内置用户交互工具
|
||||
|
||||
Core 向模型提供名为 `request_user_interaction` 的内置工具,支持 `single_choice`、`multiple_choice`、`confirmation` 和 `free_text`。它与文件工具使用相同的模型工具调用入口,但执行方式不同:
|
||||
|
||||
1. `model-deepseek` 只把 DeepSeek 工具调用转换成项目自有 `ToolRequest`,不决定界面行为。
|
||||
2. Core 识别 `request_user_interaction`,校验问题、选项、选择数量和文本上限。
|
||||
3. 校验成功后保存 `UserInteraction`,把 Run 设为“等待用户”,发送 `interaction.requested`;不发送 `tool.completed`。
|
||||
4. 当前 DeepSeek HTTP 流在工具调用结束后正常关闭;这里暂停的是项目内的 Run,不是长期占用一个模型连接。
|
||||
5. 用户回答后,Core 原子保存答案并发送 `interaction.resolved`,再以同一 `toolCallId` 构造工具结果,发起下一次 DeepSeek 请求。
|
||||
6. 后续模型请求、消息和工具调用继续归入原 `runId`,因此对用户仍是同一次任务。
|
||||
7. 用户停止任务时,未回答交互变为已取消并发送 `interaction.cancelled`。
|
||||
|
||||
无效的交互参数作为工具错误返回模型,不创建前端卡片。首版每个 Run 同一时刻最多有一个等待回答的交互;若模型并行请求多个用户交互,只接受事件顺序中的第一个,其余返回工具冲突错误。
|
||||
|
||||
如果用户在本阶段改选其他模型提供方,只替换模型适配包与环境配置,不修改 Core、Web Serve 或 Web UI 契约。
|
||||
|
||||
## 8. 本地文件层
|
||||
|
||||
### 工具集合
|
||||
|
||||
- `list_directory`:列出目录内容。
|
||||
- `search_files`:按文件名和文本内容搜索。
|
||||
- `read_text_file`:读取 UTF-8 文本。
|
||||
- `create_text_file`:只创建不存在的文本文件。
|
||||
- `apply_text_patch`:基于预期内容哈希修改已有文本文件。
|
||||
|
||||
当前版本不提供删除、移动、目录递归覆盖和任意 Shell 工具。
|
||||
|
||||
### 路径保护
|
||||
|
||||
每次操作依次执行:
|
||||
|
||||
1. Core 根据 `conversationId` 读取可信的 `projectId`,由 `WorkspaceResolverPort` 解析默认工作区或项目工作区;浏览器和模型都不能直接指定根目录。
|
||||
2. 项目工作区不存在或不可访问时返回 `PROJECT_WORKSPACE_UNAVAILABLE`,不得回退到默认工作区。
|
||||
3. 拒绝工具输入中的空字节、绝对路径和显式父目录逃逸。
|
||||
4. 将工具输入解析为当前工作区内相对路径。
|
||||
5. 对已存在目标执行 `realpath`,确认仍位于当前工作区真实路径下。
|
||||
6. 对新文件检查最近的已存在父目录,阻止符号链接逃逸。
|
||||
7. 检查文件类型、大小、编码和操作权限。
|
||||
|
||||
### 默认限制
|
||||
|
||||
- 单条用户文本最大 32 KiB。
|
||||
- 单次最多附加 10 个文件。
|
||||
- 单个可读附件最大 2 MiB。
|
||||
- 单次 API 请求体最大 5 MiB。
|
||||
- 单次文本搜索最多返回 200 个匹配项,每个文件最多返回 20 个片段。
|
||||
- 超过限制时返回明确错误,不静默截断用户文件。
|
||||
|
||||
### 写入策略
|
||||
|
||||
- 新建文件使用排他创建,已存在时失败。
|
||||
- 修改文件要求传入读取时获得的内容哈希,避免覆盖已变化内容。
|
||||
- 在同目录写临时文件后执行原子替换,并尽可能保留原文件权限。
|
||||
- 写入成功后返回新哈希和简洁 diff 摘要。
|
||||
|
||||
## 9. 真实本地文件持久化
|
||||
|
||||
所有项目、会话与运行数据默认位于 `${DATA_DIR}`。不使用 SQLite,不把全部数据塞进单个 JSON;每个 Project、Conversation 和 Run 独立成目录,事件采用可追加、可重放的 NDJSON。
|
||||
|
||||
```text
|
||||
${DATA_DIR}/
|
||||
├── version.json
|
||||
├── settings.json
|
||||
├── projects/
|
||||
│ ├── index.json
|
||||
│ └── <project-id>/
|
||||
│ └── project.json
|
||||
├── conversations/
|
||||
│ ├── index.json
|
||||
│ └── <conversation-id>/
|
||||
│ ├── conversation.json
|
||||
│ ├── messages/
|
||||
│ │ └── <sequence>-<message-id>.json
|
||||
│ └── runs.json
|
||||
├── runs/
|
||||
│ └── <run-id>/
|
||||
│ ├── run.json
|
||||
│ ├── events.ndjson
|
||||
│ └── interactions/
|
||||
│ └── <interaction-id>.json
|
||||
├── runtime/
|
||||
│ ├── active-run.json
|
||||
│ └── intents/
|
||||
│ └── <operation-id>.json
|
||||
└── recovery/
|
||||
└── quarantined/
|
||||
```
|
||||
|
||||
- `project.json`、`conversation.json`、消息文件、`run.json`、交互文件和 `settings.json` 均包含 `schemaVersion`。
|
||||
- `project.json` 保存名称和规范化后的绝对 `workspaceRoot`;`conversation.json` 保存可空 `projectId`。会话所属关系只以 `conversation.json` 为事实来源。
|
||||
- `events.ndjson` 是单 Run 的追加日志,每行一个带 `sequence` 的完整 JSON 事件;终态后不再修改。
|
||||
- Projects 与 Conversations 下的 `index.json` 以及 `runs.json` 只是可重建索引,不是事实来源;损坏或缺失时从实体文件重建。
|
||||
- 消息正文、工具输入和文件引用分别落到所属实体,不产生跨会话的巨型文件;模型密钥永不落盘。
|
||||
- 交互文件保存问题、选项、约束、状态和答案;模型提供的文字按纯文本存储,前端不得直接当作 HTML 插入。
|
||||
|
||||
### 一致性与恢复策略
|
||||
|
||||
- 单实例内使用串行写队列;每个实体更新都在同目录写临时文件、刷新后原子 `rename` 替换。
|
||||
- 创建 Project、首次创建 Conversation+Run 等跨文件操作先写入带阶段标记的 intent;实体可靠落盘后才更新可见索引,全部完成后删除 intent。
|
||||
- 用户回答使用同一个串行写队列:先原子更新交互文件,再追加 `interaction.resolved`,最后恢复 Run,防止答案已经送给模型但本地仍显示未回答。
|
||||
- 删除项目使用 intent 分批移除项目实体、所属会话和运行数据;完成前项目继续可见,失败时按 intent 恢复或重试。删除流程从不操作 `workspaceRoot` 下的文件。
|
||||
- 启动时按 intent 阶段幂等继续或回滚未完成操作;未进入可见索引的半成品实体不会出现在 UI,无法自动处理时移入隔离目录。
|
||||
- 运行事件先追加并刷新 `events.ndjson`,再更新可重建的摘要文件;服务崩溃后以事件日志恢复 Run。
|
||||
- 启动时清理明确可识别的临时文件并检查事件序列:模型请求或普通工具执行中断的 Run 标记为 `RUN_INTERRUPTED`;具有有效待回答交互的 Run 恢复为“等待用户”,允许继续回答。
|
||||
- 文件损坏不静默覆盖:原文件移入 `recovery/quarantined`,记录结构化错误,再从事件或实体重建;无法重建时向 UI 报告。
|
||||
- 数据格式升级先生成 `${DATA_DIR}.backup-<timestamp>` 同级备份,再逐实体迁移;迁移必须可重复执行。
|
||||
- Repository 层屏蔽目录布局、原子写入和恢复细节,路由和 UI 不直接读写运行数据文件。
|
||||
- 因为仅支持单人单进程,不实现跨进程事务或并发锁服务;启动时若发现另一个有效进程锁则拒绝启动,避免两个实例同时写同一 `DATA_DIR`。
|
||||
|
||||
## 10. Web Serve 接口
|
||||
|
||||
所有路径以 `/api` 为业务前缀。应用内部不设置访问身份相关端点或中间件。
|
||||
|
||||
### 状态与设置
|
||||
|
||||
- `GET /api/health`:进程、数据目录和默认工作区可用状态,不因某个历史项目目录离线而使整个进程不健康。
|
||||
- `GET /api/status`:模型是否已配置、默认工作区摘要、不可用项目数量、活动 Run 和版本。
|
||||
- `GET /api/settings`
|
||||
- `PATCH /api/settings`
|
||||
|
||||
### 项目
|
||||
|
||||
- `GET /api/projects?cursor=`:项目列表和工作区可用状态。
|
||||
- `POST /api/projects`:提交名称和绝对 `workspaceRoot`;服务端规范化、`realpath` 并验证目标为可读写目录后创建。
|
||||
- `GET /api/projects/:projectId`
|
||||
- `PATCH /api/projects/:projectId`:只允许修改非空名称,不允许修改 `workspaceRoot`。
|
||||
- `DELETE /api/projects/:projectId`:请求体携带项目名称作二次确认;有活动 Run 时拒绝。删除应用内项目及所属聊天数据,绝不访问工作区内容。
|
||||
- `GET /api/projects/:projectId/conversations?cursor=`
|
||||
|
||||
### 会话
|
||||
|
||||
- `GET /api/conversations?scope=recent&cursor=`:只返回普通会话。
|
||||
- `GET /api/conversations/:conversationId`
|
||||
- `PATCH /api/conversations/:conversationId`
|
||||
- `DELETE /api/conversations/:conversationId`
|
||||
|
||||
不提供创建空会话接口。新任务在浏览器内保持草稿状态,第一条消息通过创建 Run 接口原子生成会话。
|
||||
|
||||
### Agent 运行
|
||||
|
||||
- `POST /api/runs`:提交以下互斥形态之一:
|
||||
- 已有会话:`conversationId + message + attachments`。
|
||||
- 普通新对话:`kind=ordinary + message + attachments`。
|
||||
- 项目新对话:`kind=project + projectId + message + attachments`。
|
||||
- 新对话请求必须在同一 Core 用例中创建 Conversation、首条消息和 Run;响应返回 `conversationId` 与 `runId`。
|
||||
- `GET /api/runs/:runId`
|
||||
- `GET /api/runs/:runId/events`:SSE 事件流。
|
||||
- `POST /api/runs/:runId/cancel`
|
||||
- `POST /api/runs/:runId/retry`
|
||||
|
||||
### 用户交互
|
||||
|
||||
- `GET /api/interactions/:interactionId`:刷新后读取等待、已回答或已取消状态。
|
||||
- `POST /api/interactions/:interactionId/response`:提交单选、多选、确认或自由文本答案。
|
||||
- 回答成功后恢复原 Run;相同答案重复提交返回当前结果,不同答案重复提交返回 `INTERACTION_ALREADY_RESOLVED`。
|
||||
- Run 取消后提交返回 `INTERACTION_CANCELLED`。
|
||||
|
||||
### 工作区
|
||||
|
||||
- `GET /api/workspace/tree?conversationId=&projectId=&path=&cursor=`
|
||||
- `GET /api/workspace/search?conversationId=&projectId=&query=&cursor=`
|
||||
- `GET /api/workspace/file?conversationId=&projectId=&path=`:仅为附件选择和预览提供受限文本响应。
|
||||
|
||||
`conversationId`、`projectId` 和普通草稿上下文必须满足服务端定义的互斥校验。已有会话始终从持久化关系解析工作区;项目草稿使用已存在的 `projectId`;普通草稿使用默认工作区。
|
||||
|
||||
文件创建和修改不直接暴露为通用浏览器 API,由 Agent 工具通过 Core 调用,降低页面误操作面。
|
||||
|
||||
### 响应约定
|
||||
|
||||
成功响应直接使用有业务含义的字段,不统一套一层 `data/meta`。`requestId` 通过 `X-Request-ID` 响应头返回。
|
||||
|
||||
创建项目成功(`201 Created`):
|
||||
|
||||
```json
|
||||
{
|
||||
"project": {
|
||||
"id": "project_01",
|
||||
"name": "Great Agent 2",
|
||||
"workspaceRoot": "/workspace/great-agent2",
|
||||
"workspaceAvailable": true,
|
||||
"conversationCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
列表成功(`200 OK`):
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [],
|
||||
"nextCursor": null
|
||||
}
|
||||
```
|
||||
|
||||
首条消息创建会话和 Run(`202 Accepted`):
|
||||
|
||||
```json
|
||||
{
|
||||
"conversationId": "conversation_01",
|
||||
"runId": "run_01",
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
回答交互成功(`200 OK`):
|
||||
|
||||
```json
|
||||
{
|
||||
"interactionId": "interaction_01",
|
||||
"runId": "run_01",
|
||||
"status": "resolved",
|
||||
"answer": {
|
||||
"selectedOptionIds": ["minimal"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
错误统一使用:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "RUN_ALREADY_ACTIVE",
|
||||
"message": "当前已有 Agent 任务正在运行",
|
||||
"requestId": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
DTO 全部在 `web-contracts` 中定义并用 Zod 校验,领域错误由 Web Serve 映射为 HTTP 状态。
|
||||
|
||||
## 11. 流式事件协议
|
||||
|
||||
使用 SSE。每个事件都包含 `runId`、单调递增的 `sequence`、`timestamp` 和类型明确的 `payload`。
|
||||
|
||||
事件类型:
|
||||
|
||||
- `run.started`
|
||||
- `message.started`
|
||||
- `message.delta`
|
||||
- `message.completed`
|
||||
- `tool.started`
|
||||
- `tool.completed`
|
||||
- `tool.failed`
|
||||
- `interaction.requested`
|
||||
- `interaction.resolved`
|
||||
- `interaction.cancelled`
|
||||
- `conversation.title.updated`
|
||||
- `run.completed`
|
||||
- `run.failed`
|
||||
- `run.cancelled`
|
||||
- `stream.heartbeat`
|
||||
|
||||
### 三类内容事件
|
||||
|
||||
- `message.*` 表示助手主要回复,必须带 `messageId`。`message.started` 先建立消息位置,`message.delta` 只追加该消息文本,`message.completed` 固化完整内容。
|
||||
- `tool.*` 表示文件读取、搜索、创建、修改等普通工具调用,必须带 `messageId` 和 `toolCallId`。工具卡片插在对应助手消息的时间线位置。
|
||||
- `interaction.*` 表示需要用户操作的卡片,必须带 `messageId`、`toolCallId` 和 `interactionId`。它不显示为普通工具完成卡片。
|
||||
|
||||
`conversation.title.updated` 带 `conversationId` 和新标题,用于首条消息后刷新左侧列表。服务端不发送 `render_component`、`open_dialog` 等前端组件命令;Web UI 根据事件类型和交互 `kind` 自行选择 VanJS 组件。
|
||||
|
||||
交互请求示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "interaction.requested",
|
||||
"runId": "run_01",
|
||||
"messageId": "message_02",
|
||||
"toolCallId": "tool_01",
|
||||
"interactionId": "interaction_01",
|
||||
"sequence": 8,
|
||||
"timestamp": "2026-08-11T10:00:00Z",
|
||||
"payload": {
|
||||
"kind": "single_choice",
|
||||
"question": "这次修改采用哪种方式?",
|
||||
"options": [
|
||||
{ "id": "minimal", "label": "最小修改" },
|
||||
{ "id": "refactor", "label": "同时重构" }
|
||||
],
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
断线恢复:
|
||||
|
||||
- Web 保存最后收到的 `sequence`。
|
||||
- 重新连接时通过 `Last-Event-ID` 请求缺失事件。
|
||||
- 服务端先从持久化记录补发,再接入当前内存流。
|
||||
- 已完成 Run 的事件端点返回可重放的终态序列,不创建新 Run。
|
||||
- 等待用户的 Run 重连后先补发 `interaction.requested`;若交互已经回答或取消,则按顺序补发对应终态事件。
|
||||
- 页面刷新只读取原 Run,不自动重试模型请求。
|
||||
|
||||
## 12. Web UI 设计
|
||||
|
||||
### 页面状态
|
||||
|
||||
- 首次空状态:最近为空、项目为空、右侧对话引导
|
||||
- 未选择状态:已有数据但右侧仍显示对话引导
|
||||
- 普通新对话草稿状态
|
||||
- 项目创建面板状态
|
||||
- 项目重命名状态
|
||||
- 项目删除确认和删除失败状态
|
||||
- 空项目状态:项目已创建但还没有会话
|
||||
- 项目新对话草稿状态
|
||||
- 已选普通会话状态
|
||||
- 已选项目会话状态
|
||||
- 流式生成状态
|
||||
- 工具执行状态
|
||||
- 等待用户回答状态
|
||||
- 交互已回答和已取消状态
|
||||
- 失败状态
|
||||
- 已取消状态
|
||||
- 设置面板
|
||||
- 会话重命名/删除菜单
|
||||
|
||||
### 组件拆分
|
||||
|
||||
- `AppShell`
|
||||
- `NewTaskButton`
|
||||
- `ConversationSidebar`
|
||||
- `RecentSection`
|
||||
- `ConversationList`
|
||||
- `ConversationMenu`
|
||||
- `ProjectsSection`
|
||||
- `ProjectList`
|
||||
- `ProjectItem`
|
||||
- `ProjectMenu`
|
||||
- `ProjectConversationList`
|
||||
- `ProjectCreatePanel`
|
||||
- `ProjectRenameDialog`
|
||||
- `ProjectDeleteDialog`
|
||||
- `ConversationGuide`
|
||||
- `ChatHeader`
|
||||
- `MessageTimeline`
|
||||
- `UserMessage`
|
||||
- `AssistantMessage`
|
||||
- `ToolActivity`
|
||||
- `InteractionBlock`
|
||||
- `SingleChoiceCard`
|
||||
- `MultipleChoiceCard`
|
||||
- `ConfirmationCard`
|
||||
- `FeedbackInputCard`
|
||||
- `MarkdownContent`
|
||||
- `CodeBlock`
|
||||
- `Composer`
|
||||
- `AttachmentPicker`
|
||||
- `SettingsPanel`
|
||||
|
||||
组件只接收视图模型、VanJS State 和回调。请求、SSE、资源释放和领域状态分别放在 feature controller、stream subscription 与 API client 中。项目目录输入属于创建项目配置,只提交到服务端验证,不传入文件工具接口。
|
||||
|
||||
交互组件由前端渲染表选择,不允许服务端传组件名称:
|
||||
|
||||
```text
|
||||
single_choice -> SingleChoiceCard
|
||||
multiple_choice -> MultipleChoiceCard
|
||||
confirmation -> ConfirmationCard
|
||||
free_text -> FeedbackInputCard
|
||||
```
|
||||
|
||||
提交期间卡片进入只读加载状态;成功后显示只读答案,失败后恢复可编辑并展示明确错误。等待回答时普通输入框禁用,但停止任务仍可用。
|
||||
|
||||
### 页面选择状态机
|
||||
|
||||
Web 使用显式联合状态,不用多个可能互相冲突的布尔值表示当前右侧内容:
|
||||
|
||||
```text
|
||||
selection =
|
||||
| { kind: "none" }
|
||||
| { kind: "ordinary-draft" }
|
||||
| { kind: "project-draft"; projectId: string }
|
||||
| { kind: "conversation"; conversationId: string }
|
||||
| { kind: "project-create" }
|
||||
| { kind: "project-rename"; projectId: string }
|
||||
| { kind: "project-delete"; projectId: string }
|
||||
```
|
||||
|
||||
- 应用启动总是进入 `none`;加载列表不会自动选择第一项。
|
||||
- 点击“新任务”进入 `ordinary-draft`,不会发起创建会话请求。
|
||||
- 创建项目成功后进入该项目的 `project-draft`;项目仍可保持零会话。
|
||||
- 项目重命名成功后保留当前选择并刷新项目列表;删除当前项目成功后回到 `none`,不自动选择其他项目。
|
||||
- 普通或项目草稿首次发送成功后,使用服务端返回的 `conversationId` 切换为 `conversation`。
|
||||
- 点击任意历史会话直接进入 `conversation`,加载完成后恢复消息并可续聊。
|
||||
- 切换 selection 前先释放旧 SSE、Observer、全局事件和定时器。
|
||||
|
||||
### 视觉还原流程
|
||||
|
||||
在进入 UI 功能切片前建立参考包,至少包含 `1440 × 900` 下的首次空状态、普通新任务、项目创建/重命名/删除、空项目、普通历史会话、项目历史会话、流式回复、工具状态、四类用户交互、错误状态、侧栏菜单和设置面板截图。
|
||||
|
||||
实现顺序:
|
||||
|
||||
1. 固定字体、颜色、间距、圆角、阴影和层级令牌。
|
||||
2. 对齐整体布局和主要区域尺寸。
|
||||
3. 对齐消息、输入框、菜单和交互状态。
|
||||
4. 使用 Playwright 在固定数据和固定视口下生成截图。
|
||||
5. 对参考截图进行人工并排检查,并为已确认的本项目截图建立回归基线。
|
||||
|
||||
不复制 Claude 商标、账号入口或当前版本不支持的小组件。没有实现能力的组件不渲染。
|
||||
|
||||
## 13. 状态与滚动行为
|
||||
|
||||
- 服务端会话数据是事实来源,Web 本地只保存正在编辑文本、侧栏折叠和滚动跟随状态。
|
||||
- 项目、普通最近会话和项目会话列表由服务端数据驱动;当前 `selection` 和尚未发送的草稿只存在浏览器内存中。
|
||||
- 应用状态按 feature 拆分为小型 `van.state`,禁止创建一个包含全部会话、消息、设置和 UI 状态的巨型 Store。
|
||||
- 会话和消息集合按不可变方式替换;正在流式生成的助手消息使用独立文本 State,收到 delta 时只更新该消息,不重建完整消息数组或时间线 DOM。
|
||||
- `van.derive` 只用于纯派生值或有明确释放边界的副作用,不在渲染函数中隐式创建长期订阅。
|
||||
- 每个会创建 SSE、全局事件、Observer 或定时器的 feature controller 都必须返回 `dispose()`;切换会话、关闭面板和卸载应用时显式调用。
|
||||
- 发送成功前保留输入草稿;请求确认创建 Run 后再清空。
|
||||
- 当用户距离底部小于阈值时自动跟随流式内容。
|
||||
- 用户主动向上滚动后暂停自动跟随,并显示“回到底部”按钮。
|
||||
- 切换会话或项目时关闭旧 SSE 订阅,根据 Run 状态决定是否订阅新会话活动流。
|
||||
- 删除当前会话后回到 `none`,不自动选择最近会话。
|
||||
- 项目工作区不可用时仍加载历史记录,但隐藏或禁用附件入口;Agent 文件工具返回稳定错误,不回退到普通默认工作区。
|
||||
- 收到 `interaction.requested` 后把对应 Run 标记为等待用户,禁用普通输入框并显示交互卡片。
|
||||
- 回答成功以前不做乐观完成;只有收到成功响应或 `interaction.resolved` 后才把卡片变为只读。
|
||||
- 刷新页面时从会话历史和 Run 状态恢复交互卡片;不依赖浏览器内存保存待回答问题。
|
||||
|
||||
## 14. 错误、取消与重试
|
||||
|
||||
- 所有可预期错误使用稳定错误码,UI 不依据文本判断类型。
|
||||
- 取消请求必须幂等;重复取消已结束 Run 返回其当前终态。
|
||||
- 重试创建新 Run,并通过 `retryOfRunId` 指向原 Run;不覆盖原始失败记录。
|
||||
- 回答交互不属于重试,不创建新 Run;相同答案重复提交幂等,不同答案返回冲突。
|
||||
- 停止等待用户的 Run 时,先把交互标记为已取消,再结束 Run;后续回答返回稳定错误。
|
||||
- 模型失败时保留用户消息和已落盘的助手草稿,明确显示失败。
|
||||
- 本地持久化失败时优先停止运行并提示数据未可靠保存。
|
||||
- 文件工具失败只结束当前工具调用;是否继续由 Core 和模型响应决定。
|
||||
- 交互参数无效时向模型返回工具错误,不渲染半成品卡片;答案保存失败时保持等待状态,不能恢复模型调用。
|
||||
|
||||
## 15. 配置与环境变量
|
||||
|
||||
```text
|
||||
HOST=127.0.0.1
|
||||
PORT=3000
|
||||
DATA_DIR=./data
|
||||
DEFAULT_WORKSPACE_ROOT=/absolute/path/to/default-workspace
|
||||
DEEPSEEK_API_KEY=
|
||||
DEEPSEEK_BASE_URL=https://api.deepseek.com
|
||||
DEEPSEEK_MODEL=deepseek-v4-pro
|
||||
DEEPSEEK_THINKING=enabled
|
||||
MODEL_TIMEOUT_MS=120000
|
||||
LOG_LEVEL=info
|
||||
```
|
||||
|
||||
- 使用 Zod 在进程启动时校验配置。
|
||||
- 本地开发允许模型密钥缺失,但 `/api/status` 必须报告“未配置”,发送请求返回稳定错误。
|
||||
- 生产启动要求 `DATA_DIR` 和 `DEFAULT_WORKSPACE_ROOT` 为可读写的明确路径;Project 工作区在创建和每次使用前单独校验。
|
||||
- 仓库只提供 `.env.example`,绝不提供真实 `.env`。
|
||||
- 不定义反向代理或访问凭据相关环境变量。
|
||||
|
||||
## 16. 日志与可观测性
|
||||
|
||||
- 每个 HTTP 请求生成 `requestId`,每次运行携带 `runId` 和 `conversationId`。
|
||||
- 默认记录状态、耗时、错误码、模型名称、工具名称和交互类型,不记录完整消息、交互问题/答案、文件内容或模型密钥。
|
||||
- 本地开发使用可读日志,生产默认输出 JSON。
|
||||
- `/api/health` 检查进程、数据目录布局、写入能力和默认工作区可访问性;不执行模型请求,也不因单个历史项目工作区离线失败。
|
||||
- 错误堆栈仅写服务端日志,客户端返回安全摘要。
|
||||
- v0.1.0 不接入外部指标平台;结构化日志为后续监控保留基础。
|
||||
|
||||
## 17. 测试方案
|
||||
|
||||
### Agent Core 单元测试
|
||||
|
||||
- Project 创建、项目会话所属关系和工作区解析。
|
||||
- 普通草稿与项目草稿在首条消息前不持久化,首个 Run 创建后会话可见。
|
||||
- 会话与消息状态流转。
|
||||
- 单活动 Run 约束。
|
||||
- 模型事件到领域事件的处理。
|
||||
- 工具调用、取消、失败和重试。
|
||||
- 四类交互请求校验、等待用户、回答后恢复同一 Run、取消和重复回答。
|
||||
- DeepSeek 的交互工具调用被转换为 `interaction.*`,不错误地产生 `tool.completed`。
|
||||
- 无 Web Server 的 Core 初始化与运行。
|
||||
|
||||
### 本地文件测试
|
||||
|
||||
- 普通会话解析默认工作区,项目会话解析项目工作区。
|
||||
- 项目工作区失效时明确失败且绝不回退到默认工作区。
|
||||
- 正常列出、搜索、读取、创建和修改。
|
||||
- `..`、绝对路径、编码路径和空字节。
|
||||
- 文件与父目录符号链接逃逸。
|
||||
- 文件大小、编码和权限错误。
|
||||
- 内容哈希冲突与原子写入失败。
|
||||
|
||||
### 持久化测试
|
||||
|
||||
- Project 创建/读取、项目索引重建以及 Conversation `projectId` 关系恢复。
|
||||
- Repository CRUD、串行写入和原子替换失败。
|
||||
- schemaVersion 迁移、备份、索引重建、损坏隔离和 NDJSON 尾部残缺恢复。
|
||||
- 服务重启后的恢复。
|
||||
- 模型请求中的遗留 Run 转换为 `RUN_INTERRUPTED`;带有效待回答交互的 Run 保持“等待用户”。
|
||||
- 等待交互、回答、取消和答案写入失败的恢复;答案不得先送给模型后丢失。
|
||||
- 项目重命名和删除 intent;删除应用数据后工作区文件保持原样。
|
||||
|
||||
### Web Serve 集成测试
|
||||
|
||||
- DTO 校验、错误映射和请求体限制。
|
||||
- 项目创建/列表、普通最近会话、项目会话与三种 Run 创建形态。
|
||||
- 第一条消息创建会话失败时没有可见空会话残留。
|
||||
- 项目重命名、删除确认、活动 Run 删除拒绝和重复删除终态。
|
||||
- 交互读取与回答接口、答案校验、幂等提交和冲突提交。
|
||||
- SSE 顺序、心跳、补发、终态和断线重连。
|
||||
- 应用内部不存在访问身份相关路由和中间件。
|
||||
|
||||
### Web UI 测试
|
||||
|
||||
- 首次进入、无自动选择、普通草稿、项目创建、空项目和项目草稿状态。
|
||||
- 项目与普通历史会话选择后分别还原记录并续聊。
|
||||
- 项目重命名、删除确认文案、删除失败和当前项目删除后的返回状态。
|
||||
- 单选、多选、确认和意见输入卡片;提交加载、成功只读、失败恢复、取消与刷新恢复。
|
||||
- 会话切换、输入、停止和重试。
|
||||
- 仅附件消息与空消息。
|
||||
- 流式消息、工具状态和错误状态。
|
||||
- 高频 delta 只更新活动消息节点,不重建整个消息时间线。
|
||||
- 切换会话和关闭面板后,SSE、全局事件、Observer 与定时器均被释放,重复进入不会产生重复回调。
|
||||
- 对 `van.derive` 的异步传播使用显式等待,不依赖立即同步更新的错误假设。
|
||||
- 滚动跟随暂停与恢复。
|
||||
- 固定视口视觉截图。
|
||||
|
||||
### 端到端测试
|
||||
|
||||
- 新任务首条消息后创建普通会话并完成一次真实适配器的可替换测试流。
|
||||
- 创建绑定临时目录的项目,在项目内创建两个独立会话,重启后恢复所属关系和历史。
|
||||
- Fake Model 发起四类用户交互,回答后继续同一 Run;等待期间刷新仍可回答。
|
||||
- 删除项目后项目聊天数据消失,但临时工作区内的校验文件仍存在。
|
||||
- 使用确定性 Fake Model 完成工具调用全链路。
|
||||
- 刷新与服务重启恢复。
|
||||
- 模型失败、取消、文件消失和持久化失败。
|
||||
- 工作区外文件访问被拒绝。
|
||||
|
||||
## 18. 验证命令
|
||||
|
||||
项目骨架阶段必须创建并实际运行以下命令:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
bun run format:check
|
||||
bun run lint
|
||||
bun run typecheck
|
||||
bun run check:file-size
|
||||
bun run check:architecture
|
||||
bun test
|
||||
bun run build
|
||||
```
|
||||
|
||||
功能开发阶段增加:
|
||||
|
||||
```bash
|
||||
bun run test:e2e
|
||||
bun run test:visual
|
||||
```
|
||||
|
||||
不得用跳过测试、删除测试或放宽检查阈值的方式获得通过结果。
|
||||
|
||||
## 19. 部署形态
|
||||
|
||||
- 生产构建生成 Web 静态资源,由同一个 Hono/Bun 进程提供。
|
||||
- 默认本机运行绑定 `127.0.0.1`;容器运行时可显式设置 `0.0.0.0`,但只暴露到受控网络。
|
||||
- 提供单进程启动命令和多阶段 Dockerfile。
|
||||
- 数据目录、默认工作区和所有项目工作区通过宿主路径或容器卷挂载,不打包进镜像;容器内创建项目时填写容器可见路径。
|
||||
- 进程接收终止信号后停止新 Run、取消活动模型请求、刷新写入队列并安全关闭文件句柄。
|
||||
- 外部反向代理、TLS 和访问策略由用户在部署环境统一配置,不进入本仓库。
|
||||
|
||||
## 20. 项目骨架阶段范围
|
||||
|
||||
需求和实施方案确认后,项目骨架阶段只完成:
|
||||
|
||||
1. Bun Workspaces 与上述目录边界。
|
||||
2. 各包最小入口、类型检查和受控导出。
|
||||
3. VanJS/Vite 可启动空页面,不实现 Claude Desktop 业务界面。
|
||||
4. Hono 健康检查与静态资源基础,不实现业务路由。
|
||||
5. `local-data` 的目录布局、原子 JSON 写入、NDJSON 追加和格式版本框架,不创建完整业务 Repository。
|
||||
6. 环境配置校验、日志和错误基础。
|
||||
7. 文件规模与依赖方向检查脚本。
|
||||
8. 最小单元测试、构建和 Dockerfile。
|
||||
|
||||
骨架阶段不得提前实现会话、模型调用、本地文件工具或完整 UI。
|
||||
|
||||
## 21. 有序纵向功能切片
|
||||
|
||||
### F-001 应用外壳、首次状态与普通会话
|
||||
|
||||
- 用户可见结果:首次进入看到“最近/项目”空状态和右侧引导;点击“新任务”不会产生空记录,首条消息后普通会话出现并可恢复。
|
||||
- 覆盖:VanJS 外壳、selection 状态机、普通会话 API、Conversation Repository、延迟创建、会话文件与索引、基础视觉截图。
|
||||
- 主要验收:AC-001、AC-003、AC-006、AC-024、AC-025。
|
||||
|
||||
### F-002 Agent Core 与 DeepSeek 流式回复
|
||||
|
||||
- 用户可见结果:普通会话发送消息后看到真实 DeepSeek 回复流式出现,并可继续聊天。
|
||||
- 覆盖:Core Run 用例、ModelPort、DeepSeek Adapter、SSE、消息渲染与持久化。
|
||||
- 主要验收:AC-004、AC-010、AC-014、AC-016。
|
||||
|
||||
### F-003 项目管理与项目聊天
|
||||
|
||||
- 用户可见结果:创建绑定本地目录的项目,在项目中创建多个独立聊天,选择历史后还原并续聊;项目可以重命名和删除,删除项目不会删除绑定目录中的文件。
|
||||
- 覆盖:Project 领域/Repository/API、项目列表和创建面板、项目草稿、重命名、删除确认与删除 intent、`projectId` 关系、WorkspaceResolver、项目索引与恢复。
|
||||
- 主要验收:AC-026 至 AC-033。
|
||||
|
||||
### F-004 用户交互卡片
|
||||
|
||||
- 用户可见结果:Agent 可以在回复中请求单选、多选、确认或意见输入;用户回答后,同一个 Run 继续执行并生成后续回复,刷新后仍可继续回答。
|
||||
- 覆盖:内置 `request_user_interaction` 工具、交互参数校验、Interaction Repository/API、`interaction.*` SSE、等待用户状态、VanJS 交互卡片、答案幂等、取消、持久化与恢复。
|
||||
- 主要验收:AC-034 至 AC-038。
|
||||
|
||||
### F-005 停止、失败与重试
|
||||
|
||||
- 用户可见结果:能够停止生成,并从普通或项目聊天的失败状态重新发送。
|
||||
- 覆盖:AbortSignal、终态、错误映射、草稿保留、断线补发和单活动 Run。
|
||||
- 主要验收:AC-005、AC-010、AC-011。
|
||||
|
||||
### F-006 附件、文件列表、读取与搜索
|
||||
|
||||
- 用户可见结果:从当前聊天对应工作区选择附件,Agent 可以读取和搜索且不会跨工作区。
|
||||
- 覆盖:上下文工作区浏览 API、附件元数据、路径保护、读取/搜索工具和工具状态 UI。
|
||||
- 主要验收:AC-007、AC-008、AC-009、AC-021、AC-022、AC-028、AC-030。
|
||||
|
||||
### F-007 文件创建与安全修改
|
||||
|
||||
- 用户可见结果:Agent 可以在普通默认工作区或当前项目工作区创建文件并通过补丁安全修改。
|
||||
- 覆盖:可信工作区解析、排他创建、内容哈希、原子写入、diff 摘要和错误状态。
|
||||
- 主要验收:AC-008、AC-009、AC-023、AC-028。
|
||||
|
||||
### F-008 会话管理与个人设置
|
||||
|
||||
- 用户可见结果:重命名、删除普通或项目会话,查看并修改默认工作区等非敏感设置。
|
||||
- 覆盖:菜单交互、设置 API、模型/默认工作区摘要和长列表边界状态。
|
||||
- 主要验收:AC-003、AC-018。
|
||||
|
||||
### F-009 Claude Desktop 视觉与交互收口
|
||||
|
||||
- 用户可见结果:首次引导、普通聊天、项目、消息和设置等全部支持状态在目标视口下尽量贴近参考界面。
|
||||
- 覆盖:设计令牌、项目侧栏、消息排版、代码块、菜单、输入框、滚动行为和截图回归。
|
||||
- 主要验收:AC-001、AC-002、AC-012、AC-013、AC-020、AC-024。
|
||||
|
||||
### F-010 恢复、边界与发布前加固
|
||||
|
||||
- 用户可见结果:刷新、重启、项目目录离线、数据损坏和其他边界情况下仍有明确可恢复行为。
|
||||
- 覆盖:格式迁移备份、项目/会话/交互索引重建、启动恢复、等待交互恢复、工作区失效、配置缺失、日志脱敏、E2E 和生产构建。
|
||||
- 主要验收:AC-006、AC-017、AC-018、AC-019、AC-023、AC-029、AC-030、AC-036、AC-037。
|
||||
|
||||
## 22. 需求追踪摘要
|
||||
|
||||
| 需求 | 主要实现位置 | 主要切片 |
|
||||
|---|---|---|
|
||||
| FR-001 会话管理 | Core 用例、local-data、conversation UI | F-001、F-008 |
|
||||
| FR-002 消息与流式回复 | Core Run、model adapter、SSE、message UI | F-002、F-005 |
|
||||
| FR-003 Agent Core | agent-core ports/use-cases/events | F-002 至 F-005 |
|
||||
| FR-004 本地文件 | WorkspaceResolver、local-files、Core tools | F-003、F-006、F-007 |
|
||||
| FR-005 文件附件 | local-files、attachments、composer | F-006 |
|
||||
| FR-006 本地持久化 | local-data、layout/recovery/repositories | F-001 至 F-010 |
|
||||
| FR-007 视觉还原 | web styles/components、Playwright | F-001、F-003、F-004、F-009 |
|
||||
| FR-008 模块拆分 | Workspaces、导出边界、检查脚本 | 骨架、全部切片 |
|
||||
| FR-009 CLI 扩展准备 | Core Ports、composition boundary | 骨架、F-002、F-003 |
|
||||
| FR-010 项目管理与项目聊天 | Project Core/API/Repository/UI、WorkspaceResolver | F-003、F-010 |
|
||||
| FR-011 用户交互请求 | Core 内置工具、Interaction Repository/API、SSE、VanJS 交互卡片 | F-004、F-010 |
|
||||
|
||||
## 23. 已知风险与处理
|
||||
|
||||
- Claude Desktop 视觉可能随版本变化:以开发开始前确认的截图包为唯一视觉基线,不追随之后的界面更新。
|
||||
- 字体和系统渲染存在平台差异:视觉回归固定在同一浏览器、操作系统字体和视口。
|
||||
- 模型流式工具事件复杂:模型协议封装在独立适配器,Core 只接收标准事件。
|
||||
- 内置用户交互工具容易被误当成普通工具:Core 保留精确工具名 `request_user_interaction`,校验后只映射为 `interaction.*`,不产生普通 `tool.completed`。
|
||||
- 等待用户可能长期占用模型连接:收到有效交互请求后结束本次 DeepSeek HTTP 流;用户回答后使用同一 `runId` 和 `toolCallId` 发起后续模型请求,不保持悬空连接。
|
||||
- 交互答案可能在恢复模型后丢失:必须先原子写入答案并标记交互已回答,再恢复模型调用;写入失败时继续保持等待状态。
|
||||
- 用户可能重复或并发提交答案:相同答案返回已有结果,不同答案返回冲突;一个 Run 同时只允许一个待回答交互。
|
||||
- Project 工作区属于服务端文件系统路径:UI 明确显示当前运行环境可见路径;容器部署时必须先挂载目录,再用容器内路径创建项目。
|
||||
- 项目目录可能后来离线:历史数据照常读取,WorkspaceResolver 返回 `PROJECT_WORKSPACE_UNAVAILABLE`,任何代码路径都不得回退到默认工作区。
|
||||
- 普通与项目会话可能被错误混列:`projectId` 是实体事实来源,普通“最近”查询强制筛选空 `projectId`,项目列表按确定关系查询。
|
||||
- 首条消息与会话创建跨多个文件:用单一 Core 用例、串行写队列和恢复记录保证失败后不暴露空会话,索引只在实体可靠落盘后更新。
|
||||
- 项目重命名和删除会跨越多个实体:重命名使用原子替换;删除先写 intent,再删除本应用内的项目、会话、消息和 Run 数据,恢复流程可继续未完成删除,任何步骤都不得操作项目绑定的工作区。
|
||||
- VanJS 生态和约定少于主流框架:不引入社区 JSX、路由或状态框架;项目自行固定组件签名、feature controller 和 `dispose()` 资源释放约定,并用架构检查与浏览器测试守住边界。
|
||||
- 流式更新可能误触发大范围 DOM 重建:活动助手消息使用独立文本 State,列表更新不得绑定到每个 token;用自动化测试记录时间线节点身份保持不变。
|
||||
- 本地文件符号链接可能逃逸:对目标和最近存在父目录执行真实路径校验,并使用专门安全测试。
|
||||
- 文件系统无法提供跨文件数据库事务:以单 Run 事件日志作为恢复依据,摘要和索引均可重建,实体更新使用同目录原子替换。
|
||||
- NDJSON 末行可能在进程中断时残缺:启动恢复只截断无法解析的最后一行,保留原文件副本并检查事件序列。
|
||||
- 单任务运行在刷新后可能遗留状态:启动恢复和 SSE 重连共同处理,不自动创建重复 Run。
|
||||
|
||||
## 24. 需要人工确认的技术决策
|
||||
|
||||
1. 接受 Bun + TypeScript + VanJS/Vite + Hono 的单仓库工作区方案,不使用 JSX,不引入大型 UI 组件库。
|
||||
2. 接受首个模型适配器使用 DeepSeek OpenAI 兼容接口,默认 `deepseek-v4-pro`;Core 保持模型无关。
|
||||
3. 接受 Project、Conversation、Message、Run 和设置全部保存到真实本地文件系统,并采用“实体 JSON + Run NDJSON + 可重建索引”的布局。
|
||||
4. 接受普通会话使用 `DEFAULT_WORKSPACE_ROOT`,项目会话使用 Project 的 `workspaceRoot`;项目目录失效时禁止回退。
|
||||
5. 接受新任务与项目新对话在首条有效消息前只存在于浏览器内存,首次创建 Conversation 与 Run 使用一个 Core 用例。
|
||||
6. 接受项目首版包含创建、列表、选择、重命名、删除和项目内多会话;删除只清理应用数据,绝不删除绑定工作区,不包含共享或云同步。
|
||||
7. 接受将流式事件分成三类:`message.*` 表示主要回复,`tool.*` 表示普通工具活动,`interaction.*` 表示需要用户操作的卡片。
|
||||
8. 接受首版交互类型为单选、多选、确认和意见输入;回答后使用同一 `runId` 继续执行,不为回答新建 Run。
|
||||
9. 接受 SSE 作为浏览器流式协议。
|
||||
10. 接受 Bun Workspaces 的多包结构,并保留 `WorkspaceResolverPort`、`ClockPort`、`IdPort` 和 Pino 日志边界。
|
||||
11. 接受单文件 300 行拆分提醒、400 行硬限制。
|
||||
12. 接受首版 CLI 只保留复用边界,不创建 CLI 应用。
|
||||
13. 接受视觉基线在 UI 开发前通过固定截图包确定。
|
||||
532
docs/REQUIREMENTS.md
Normal file
532
docs/REQUIREMENTS.md
Normal file
@ -0,0 +1,532 @@
|
||||
# 产品需求
|
||||
|
||||
状态:已确认、已冻结
|
||||
版本:0.3.0
|
||||
上一确认版本:0.2.0
|
||||
确认人:用户
|
||||
确认时间:2026-08-11
|
||||
|
||||
本次变更:项目首版增加重命名和删除;增加 Agent 请求用户选择、确认和填写意见的交互组件能力。
|
||||
|
||||
## 项目身份
|
||||
|
||||
- 项目名称:Great Agent 2
|
||||
- 一句话说明:一个供个人使用、界面尽量一比一还原 Claude Desktop、以本地文件和可复用 Agent Core 为基础的自托管 Web Agent。
|
||||
- 目标用户:项目所有者本人。
|
||||
- 交付形态:本地或服务器运行的单用户 Web 应用;访问保护由部署环境中的外部反向代理承担;架构预留未来 CLI 入口。
|
||||
- 核心依赖方向:`local file -> agent core -> web serve -> web`。
|
||||
- 后续扩展方向:`local file -> agent core -> cli`。
|
||||
|
||||
## 采用的默认值
|
||||
|
||||
- 默认视觉基准为当前 macOS Claude Desktop 的浅色桌面布局,主要验收视口为 `1440 × 900`。
|
||||
- 当前版本只实现 Web 使用链路,不实现完整 CLI 命令;但 Agent Core 的公开边界不得依赖 Web 类型、HTTP 请求或浏览器状态。
|
||||
- 当前版本只面向单人、单实例使用,不设计注册、用户表、多租户、角色系统、共享会话或分布式并发。
|
||||
- 同一实例同一时间只支持一个正在生成的 Agent 任务;不处理多个用户或多个任务并发执行。
|
||||
- 业务数据、项目、会话记录和文件索引保存在本地;具体文件格式在实施方案阶段确定。
|
||||
- 普通聊天使用应用配置的默认工作区;项目聊天使用所属项目绑定的工作区目录。
|
||||
- 本地文件能力只允许访问当前聊天对应的工作区目录,禁止通过路径穿越访问工作区之外的路径。
|
||||
- 应用默认运行在可信上游之后,不实现登录页面、身份校验中间件、用户会话或访问凭据配置。
|
||||
- 外部反向代理的配置、凭据和访问策略不属于本项目开发范围。
|
||||
- Claude Desktop 中当前版本不支持的小组件直接隐藏,不显示不可用按钮或假入口。
|
||||
|
||||
## 当前版本范围
|
||||
|
||||
1. Claude Desktop 风格的桌面 Web 外壳。
|
||||
2. 普通会话的新建、列表、切换、重命名和删除。
|
||||
3. 项目的创建、列表、选择、重命名和删除;每个项目绑定一个本地工作区目录并可包含多个独立会话。
|
||||
4. 项目会话的新建、列表、切换和持续聊天。
|
||||
5. 用户消息、助手消息、工具过程和错误消息的展示。
|
||||
6. Agent 回复的流式输出、停止生成、失败提示和重新发送。
|
||||
7. 本地项目、会话和消息持久化,服务重启后可恢复。
|
||||
8. 在当前聊天对应工作区内读取、搜索、创建和修改本地文件。
|
||||
9. 文件附件的选择、提交、显示和 Agent 读取。
|
||||
10. Agent Core 对模型调用、消息上下文、工具调用、运行状态和取消操作的统一编排。
|
||||
11. Web Serve 对 Web 静态资源、业务接口和流式事件的统一提供。
|
||||
12. 简单的个人配置界面,显示默认工作区、模型和运行信息;敏感配置不回显完整值。
|
||||
13. 清晰的分层和模块拆分,避免页面、协议、业务逻辑和文件操作堆积在大文件中。
|
||||
14. 为未来 CLI 暴露与 Web 无关的 Agent Core 调用能力,但当前版本不交付完整 CLI 产品体验。
|
||||
15. Agent 可以在回复过程中请求用户做单选、多选、确认或填写意见,用户提交后继续同一次 Agent 任务。
|
||||
|
||||
## 用户角色与权限
|
||||
|
||||
### 项目所有者
|
||||
|
||||
- 使用全部会话、Agent 和配置能力。
|
||||
- 访问普通聊天的默认工作区以及项目聊天所属项目的工作区。
|
||||
|
||||
应用内部不区分用户身份。系统不包含登录、注册、找回密码、邀请成员、用户管理、角色管理或权限分组。
|
||||
|
||||
## 核心用户流程
|
||||
|
||||
### 首次进入
|
||||
|
||||
1. 用户打开 Web 地址。
|
||||
2. 应用直接进入 Claude Desktop 风格的主界面。
|
||||
3. 左侧“最近”列表为空,左侧“项目”列表为空并显示创建项目入口。
|
||||
4. 当前不自动创建或选中任何会话。
|
||||
5. 右侧显示对话引导组件和可用输入区。
|
||||
|
||||
### 普通对话
|
||||
|
||||
1. 用户点击左侧“新任务”,进入未持久化的普通新对话状态。
|
||||
2. 在用户发送第一条有效消息前,不创建空会话记录。
|
||||
3. 用户在输入框中输入消息,可选择附加默认工作区内的本地文件。
|
||||
4. 第一条消息提交成功时创建普通会话,此后显示在左侧“最近”列表。
|
||||
5. 系统立即显示用户消息并创建 Agent 运行。
|
||||
6. Agent Core 组织上下文、调用模型并按需调用默认工作区文件工具。
|
||||
7. Web 界面流式显示助手内容和工具执行状态。
|
||||
8. 运行结束后保存完整消息和运行结果,用户可以在同一会话继续聊天。
|
||||
|
||||
### 创建项目与项目对话
|
||||
|
||||
1. 用户点击左侧“项目”区域的创建入口。
|
||||
2. 系统显示项目创建界面,要求填写项目名称并选择一个可访问的本地工作区目录。
|
||||
3. 校验通过后创建并持久化项目;项目出现在左侧“项目”列表。
|
||||
4. 用户进入项目后,可以开始该项目下的新对话或选择该项目已有会话。
|
||||
5. 项目新对话同样在第一条有效消息提交时才持久化。
|
||||
6. 项目会话的文件附件和 Agent 文件工具只访问该项目绑定的工作区。
|
||||
7. 一个项目可以包含多个相互独立、分别保存历史记录的会话。
|
||||
8. 用户可在项目会话中持续发送消息,助手回复和工具过程正常追加。
|
||||
|
||||
### 管理项目
|
||||
|
||||
1. 用户从项目菜单发起重命名,输入非空新名称后立即持久化。
|
||||
2. 用户从项目菜单发起删除,系统显示项目名称和所含会话数量并要求明确确认。
|
||||
3. 项目中有正在运行的任务时禁止删除,用户需要先停止任务。
|
||||
4. 确认删除后,项目及其全部项目会话、消息、附件元数据和运行记录不再出现在应用中。
|
||||
5. 删除项目不得删除、移动或修改项目绑定的真实工作区及其中任何文件。
|
||||
|
||||
### 本地文件操作
|
||||
|
||||
1. 用户在消息中提出与文件有关的任务,或主动附加文件。
|
||||
2. Agent Core 根据任务调用工作区文件工具。
|
||||
3. 工具校验目标路径位于允许的工作区内。
|
||||
4. 系统读取、搜索、创建或修改文件。
|
||||
5. 界面展示简洁的工具状态和操作结果。
|
||||
6. 文件操作结果进入当前会话上下文。
|
||||
|
||||
### 回答 Agent 的交互请求
|
||||
|
||||
1. Agent 在需要用户决定或补充信息时发起交互请求,而不是用普通文本假装按钮。
|
||||
2. 支持四种首版交互:单选、多选、确认、自由文本意见。
|
||||
3. 系统暂停当前 Agent 任务并保存交互请求,状态显示为“等待用户”。
|
||||
4. 右侧消息时间线在对应助手回复位置显示交互卡片。
|
||||
5. 用户填写并提交答案;系统校验成功后保存答案,并恢复同一次 Agent 任务。
|
||||
6. Agent 收到结构化答案后继续回复或继续调用工具。
|
||||
7. 页面刷新或重新打开会话时,尚未回答的交互卡片仍可继续操作;已经回答的卡片显示已提交结果,不可重复修改。
|
||||
|
||||
### 恢复历史会话
|
||||
|
||||
1. 用户刷新页面或重新启动服务。
|
||||
2. 系统从本地存储读取普通会话、项目以及项目下的会话。
|
||||
3. 当前没有选中项时,右侧显示对话引导组件,不自动进入任意历史会话。
|
||||
4. 用户选择普通会话后,恢复其消息、附件和已完成的工具记录,并使用默认工作区继续聊天。
|
||||
5. 用户选择项目会话后,恢复相同历史内容,并使用所属项目工作区继续聊天。
|
||||
|
||||
## 页面流转
|
||||
|
||||
```text
|
||||
进入系统
|
||||
├── 加载最近普通聊天
|
||||
├── 加载项目及其聊天摘要
|
||||
└── 当前不自动选择会话
|
||||
└── 右侧显示对话引导组件
|
||||
|
||||
点击“新任务”
|
||||
└── 普通新对话(未持久化)
|
||||
└── 第一条有效消息
|
||||
├── 创建普通会话
|
||||
├── 加入“最近”
|
||||
└── 持续聊天
|
||||
|
||||
点击“创建项目”
|
||||
└── 输入名称并选择本地目录
|
||||
└── 创建项目
|
||||
└── 项目新对话(未持久化)
|
||||
└── 第一条有效消息
|
||||
├── 创建项目会话
|
||||
└── 持续聊天
|
||||
|
||||
选择普通历史会话
|
||||
└── 还原历史记录并继续聊天
|
||||
|
||||
选择项目历史会话
|
||||
└── 还原历史记录、恢复项目工作区并继续聊天
|
||||
```
|
||||
|
||||
## 页面或接口
|
||||
|
||||
### 主应用外壳
|
||||
|
||||
- 整体布局、留白、颜色、圆角、阴影、字体层级和控件尺寸尽量贴近 Claude Desktop。
|
||||
- 主要区域由左侧会话栏、顶部当前会话区域、中央消息区和底部输入区组成。
|
||||
- 桌面视口下不得出现明显错位、溢出或与参考界面风格冲突的组件。
|
||||
|
||||
### 左侧会话栏
|
||||
|
||||
- 顶部提供“新任务”入口。
|
||||
- “最近”区域按最近更新时间展示普通会话;为空时显示明确空状态,不创建占位会话。
|
||||
- “项目”区域展示项目列表和创建项目入口;为空时显示创建引导。
|
||||
- 项目项可展开或进入,以展示并选择该项目下的会话。
|
||||
- 项目菜单提供重命名和删除;删除必须二次确认。
|
||||
- 展示当前选中状态。
|
||||
- 支持重命名和删除。
|
||||
- 支持折叠或展开,行为尽量贴近 Claude Desktop。
|
||||
|
||||
### 右侧主区域
|
||||
|
||||
- 未选择会话时显示对话引导组件和输入区。
|
||||
- 普通新对话与项目新对话在首条消息前都属于临时 UI 状态。
|
||||
- 选择已有普通会话或项目会话时,完整还原历史消息、附件和工具记录。
|
||||
- 恢复完成后沿用原会话上下文继续聊天,不创建替代会话。
|
||||
|
||||
### 项目创建与管理界面
|
||||
|
||||
- 必填项目名称和本地工作区目录。
|
||||
- 工作区必须是存在、可访问的目录;校验失败时不得创建项目。
|
||||
- 创建成功后进入项目,并提供开始项目新对话的入口。
|
||||
- 重命名要求非空名称,成功后立即更新左侧列表和本地数据。
|
||||
- 删除确认必须显示项目名称和会话数量,并明确说明不会删除工作区文件。
|
||||
- 当前版本不提供项目成员、共享、云同步、远程知识库或 Claude 账号能力。
|
||||
|
||||
### 消息区
|
||||
|
||||
- 区分用户、助手和工具过程。
|
||||
- 支持 Markdown、列表、链接、引用、表格和代码块。
|
||||
- 代码块支持语言标识和复制。
|
||||
- 支持流式内容逐步出现。
|
||||
- 长内容可滚动,新增内容默认跟随到底部;用户主动上滚后不得强制抢回滚动位置。
|
||||
- 错误和取消状态有明确但不过度突出的视觉提示。
|
||||
- 在消息时间线中显示单选、多选、确认和意见输入卡片,卡片属于触发它的 Agent 运行。
|
||||
- 交互卡片提交后保留问题和答案的只读历史展示。
|
||||
|
||||
### 输入区
|
||||
|
||||
- 支持多行输入、发送、停止生成和附加文件。
|
||||
- 空输入不能发送。
|
||||
- 生成过程中发送按钮切换为停止操作。
|
||||
- 输入内容在发送失败时不得无提示丢失。
|
||||
- 不支持的 Claude 小组件直接隐藏。
|
||||
- 当前任务等待交互卡片回答时,普通消息输入保持禁用,用户可以回答卡片或停止任务。
|
||||
|
||||
### 设置界面
|
||||
|
||||
- 显示当前工作区路径、模型配置摘要和版本信息。
|
||||
- 允许修改非敏感个人配置。
|
||||
- 模型密钥等敏感值不以明文回显。
|
||||
|
||||
### Web Serve 接口
|
||||
|
||||
- 为项目、会话、消息、Agent 运行、用户交互回答、取消、文件和配置提供内部接口。
|
||||
- 为 Agent 流式输出和工具状态提供流式通道。
|
||||
- Web 层只负责协议转换和传输,不承载 Agent 核心业务规则。
|
||||
- Web Serve 不包含登录、身份校验、用户会话或访问控制逻辑;这些职责由部署环境中的外部反向代理承担。
|
||||
|
||||
### Agent Core 接口
|
||||
|
||||
- 接受与传输协议无关的运行请求。
|
||||
- 提供项目与会话操作、消息提交、用户交互请求与回答、流式事件、取消操作和文件工具能力。
|
||||
- 返回领域对象或领域事件,不返回绑定具体 Web 框架的响应对象。
|
||||
- 可被未来 CLI 在不启动 Web Server 的情况下调用。
|
||||
|
||||
## 功能需求
|
||||
|
||||
### FR-001 会话管理
|
||||
|
||||
- 新建会话时生成稳定标识和默认标题。
|
||||
- 会话通过可空 `projectId` 区分普通会话和项目会话;创建后不得在普通与项目类型之间移动。
|
||||
- 点击“新任务”或项目内“新对话”只创建临时 UI 状态,第一条有效消息提交时才持久化会话。
|
||||
- 首次有效消息后可生成或更新标题。
|
||||
- 重命名后立即持久化。
|
||||
- 删除会话前需要明确确认,删除后不再出现在列表中。
|
||||
- 切换会话不得混淆消息或正在展示的状态。
|
||||
|
||||
### FR-010 项目管理与项目聊天
|
||||
|
||||
- 创建项目时生成稳定标识,保存名称、工作区目录、创建时间和更新时间。
|
||||
- 项目名称不能为空;工作区必须是存在且可访问的本地目录。
|
||||
- 左侧项目列表可展示并选择项目,项目下可包含多个独立会话。
|
||||
- 项目可以重命名;新名称不能为空,修改后立即持久化。
|
||||
- 删除项目必须明确确认,并同时删除应用内的项目实体及其全部项目会话数据。
|
||||
- 删除项目不得删除、移动或修改项目绑定的真实工作区或其中的文件。
|
||||
- 项目中有正在运行的任务时拒绝删除,并说明需要先停止任务。
|
||||
- 项目会话必须持有所属 `projectId`,并使用项目绑定的工作区执行附件和文件工具操作。
|
||||
- 普通会话不属于任何项目,使用应用默认工作区。
|
||||
- 项目或其工作区暂时不可用时,历史会话仍可打开;文件相关能力明确禁用并显示原因。
|
||||
- 当前版本不提供项目共享、项目成员、云同步、跨项目统一知识库或项目级模型密钥。
|
||||
|
||||
### FR-002 消息与流式回复
|
||||
|
||||
- 用户消息提交后立即进入当前会话。
|
||||
- 助手回复以流式方式展示。
|
||||
- 支持文本、Markdown、代码块、工具状态和错误块。
|
||||
- 用户可以停止当前生成。
|
||||
- 完成、失败和取消都必须形成明确的终态。
|
||||
|
||||
### FR-003 Agent Core
|
||||
|
||||
- 统一管理系统提示、会话上下文、模型调用和工具调用。
|
||||
- 模型提供方通过适配边界接入,不把具体 SDK 类型泄漏到领域层。
|
||||
- Web 和未来 CLI 使用同一套 Agent Core 能力。
|
||||
- Agent Core 不直接依赖 DOM、浏览器 API、HTTP 请求对象或 Web 路由。
|
||||
|
||||
### FR-011 用户交互请求
|
||||
|
||||
- Agent Core 提供内置的用户交互能力,模型可以请求单选、多选、确认或自由文本意见。
|
||||
- 交互请求包含稳定标识、所属 Run、问题、类型、选项、是否必填和创建时间。
|
||||
- 单选和多选必须提供 2 至 10 个非空选项;多选可限制最少和最多选择数。
|
||||
- 自由文本意见最大 8 KiB;所有模型提供的标题、说明和选项按纯文本显示,不解释为 HTML。
|
||||
- 有效交互请求使当前 Run 进入“等待用户”,不结束 Run,也不创建新的 Run。
|
||||
- 前端根据交互类型显示对应卡片;用户回答通过明确接口提交,不通过普通聊天消息猜测匹配。
|
||||
- 提交答案时校验交互仍在等待、答案类型正确并满足选择数量限制。
|
||||
- 答案保存成功后转换为该内置交互工具的结果,再恢复同一次模型调用流程。
|
||||
- 同一个交互只能成功回答一次;重复提交相同答案返回当前结果,提交不同答案返回冲突错误。
|
||||
- 用户停止等待中的 Run 时,交互变为“已取消”,卡片不可继续提交。
|
||||
- 刷新和重启服务后,等待中的交互、已回答结果和所属消息位置都能恢复。
|
||||
- 普通 `tool.*` 用于展示文件等工具调用;用户交互使用独立语义,不混入普通工具完成状态。
|
||||
|
||||
### FR-004 本地文件
|
||||
|
||||
- 根据当前会话解析唯一有效工作区:普通会话使用默认工作区,项目会话使用项目工作区。
|
||||
- 列出当前工作区目录和文件。
|
||||
- 按文件名或文本内容搜索当前工作区文件。
|
||||
- 读取文本文件,并对不支持的二进制文件给出明确提示。
|
||||
- 创建新文件和修改已有文件。
|
||||
- 所有路径在执行前规范化并校验工作区边界。
|
||||
- 文件不存在、权限不足、编码错误或写入失败时返回可理解错误。
|
||||
- 当前版本不要求 Agent 删除、移动或批量覆盖文件。
|
||||
|
||||
### FR-005 文件附件
|
||||
|
||||
- 用户只能从当前会话对应的工作区选择文件附加到消息。
|
||||
- 消息中显示附件名称、类型和可用状态。
|
||||
- Agent 能读取附件内容或获得不支持原因。
|
||||
- 文件在发送后被移动或删除时,历史记录仍保留附件元数据并显示文件不可用。
|
||||
|
||||
### FR-006 本地持久化
|
||||
|
||||
- 保存项目、会话及其所属关系、消息、附件元数据、Agent 运行终态和非敏感配置。
|
||||
- 数据写入失败时不得伪装为成功。
|
||||
- 服务重启后恢复已完成数据。
|
||||
- 写入过程不得因进程中断而轻易留下无法解析的半成品文件。
|
||||
- 不引入面向多用户的用户表、租户字段或共享权限模型。
|
||||
|
||||
### FR-007 Claude Desktop 风格还原
|
||||
|
||||
- 对齐主布局、侧栏、欢迎状态、消息排版、输入框、按钮、菜单和常见交互状态。
|
||||
- 优先保证整体比例、间距、层级、颜色、字体、圆角和交互反馈一致。
|
||||
- 不支持的入口、小组件和菜单项直接隐藏。
|
||||
- 不使用“即将推出”占位填充参考界面。
|
||||
- 实施阶段建立参考截图和对应视口的视觉对比基线。
|
||||
|
||||
### FR-008 模块拆分
|
||||
|
||||
- 本地文件层、Agent Core、Web Serve、Web UI 分别拥有明确目录和公开边界。
|
||||
- 领域规则不得散落到路由处理器或页面组件。
|
||||
- 页面组件不得直接读写本地业务数据文件。
|
||||
- 单个文件只承担一种主要职责;超出合理阅读和维护范围时按职责拆分。
|
||||
- 禁止创建同时包含大量 UI、网络协议、Agent 编排和文件操作的“总控文件”。
|
||||
|
||||
### FR-009 CLI 扩展准备
|
||||
|
||||
- Agent Core 可在没有 Web Server 的进程中初始化。
|
||||
- 核心输入、输出、事件和取消机制不绑定 Web 协议。
|
||||
- 文件存储和模型适配通过可替换边界提供。
|
||||
- 当前版本不要求交付交互式 CLI、命令补全、终端 UI 或 CLI 安装包。
|
||||
|
||||
## 业务规则
|
||||
|
||||
- BR-001:整个实例只有一个逻辑用户,不创建产品级用户身份。
|
||||
- BR-002:同一时间最多存在一个正在运行的 Agent 任务;新任务到来时应拒绝并提示,或由用户先停止当前任务。
|
||||
- BR-003:所有会话数据归项目所有者本地持有。
|
||||
- BR-004:工作区之外的路径一律不可访问,即使请求来自模型工具调用。
|
||||
- BR-005:模型生成内容和工具结果都属于同一次 Agent 运行,并具有可追踪的运行标识。
|
||||
- BR-006:失败或取消的运行不得显示为成功完成。
|
||||
- BR-007:不支持的 Claude Desktop 功能必须隐藏,而不是展示不可点击入口。
|
||||
- BR-008:Web 层不得成为核心业务能力的唯一入口。
|
||||
- BR-009:模型密钥等敏感配置不得出现在客户端资源、接口响应、日志正文或本地业务数据中。
|
||||
- BR-010:应用内不得实现访问身份逻辑,外部反向代理配置不得进入 Agent Core、Web Serve 或 Web UI。
|
||||
- BR-011:普通会话只能使用应用默认工作区;项目会话只能使用所属项目绑定的工作区。
|
||||
- BR-012:没有首条有效消息的临时新对话不进入本地持久化和“最近”列表。
|
||||
- BR-013:项目是会话容器和工作区边界,一个项目可以包含多个会话;会话最多属于一个项目。
|
||||
- BR-014:打开应用时不自动选择历史会话,也不自动创建新会话。
|
||||
- BR-015:删除项目时一并删除应用内的项目聊天数据,但绝不删除真实工作区及其中的文件。
|
||||
- BR-016:项目中有正在运行的任务时不得删除项目;当前版本不支持修改项目绑定的工作区,项目名称重命名不影响运行中的任务。
|
||||
- BR-017:等待用户回答的任务仍属于正在运行的全局任务,回答或停止前不得启动第二个任务。
|
||||
- BR-018:用户交互请求和答案必须归属于同一个 Run;提交答案只恢复原 Run,不新建会话或 Run。
|
||||
- BR-019:前端组件名称不进入领域协议;协议表达交互类型和数据,Web UI 自行选择对应组件。
|
||||
|
||||
## 数据与状态
|
||||
|
||||
### 项目
|
||||
|
||||
- 稳定标识
|
||||
- 名称
|
||||
- 绑定的本地工作区目录
|
||||
- 创建时间
|
||||
- 更新时间
|
||||
- 所含会话摘要
|
||||
|
||||
### 会话
|
||||
|
||||
- 稳定标识
|
||||
- 可空项目标识:为空表示普通会话,非空表示项目会话
|
||||
- 标题
|
||||
- 创建时间
|
||||
- 更新时间
|
||||
- 消息顺序
|
||||
|
||||
### 消息
|
||||
|
||||
- 稳定标识
|
||||
- 所属会话
|
||||
- 角色:用户、助手、工具、系统内部记录
|
||||
- 内容块
|
||||
- 附件元数据
|
||||
- 创建时间
|
||||
- 对应 Agent 运行标识
|
||||
|
||||
### Agent 运行
|
||||
|
||||
- 稳定标识
|
||||
- 所属会话
|
||||
- 状态:等待、运行中、调用工具、等待用户、已完成、失败、已取消
|
||||
- 开始与结束时间
|
||||
- 错误摘要
|
||||
- 工具过程摘要
|
||||
|
||||
### 用户交互
|
||||
|
||||
- 稳定标识
|
||||
- 所属 Run 和消息位置
|
||||
- 类型:单选、多选、确认、自由文本
|
||||
- 问题、说明和选项
|
||||
- 必填与选择数量限制
|
||||
- 状态:等待回答、已回答、已取消
|
||||
- 用户答案
|
||||
- 创建时间和回答时间
|
||||
|
||||
### 文件引用
|
||||
|
||||
- 显示名称
|
||||
- 工作区内相对路径
|
||||
- 文件类型
|
||||
- 可用状态
|
||||
- 最近确认时间
|
||||
|
||||
### 配置
|
||||
|
||||
- 普通聊天默认工作区路径
|
||||
- 模型配置摘要
|
||||
- 非敏感界面偏好
|
||||
- 应用版本
|
||||
|
||||
## 正常、异常和边界流程
|
||||
|
||||
### 正常流程
|
||||
|
||||
- 打开应用后新建会话并完成一次流式对话。
|
||||
- 创建绑定本地目录的项目,在项目内创建多个对话并分别持续聊天。
|
||||
- 重命名项目并在重启后看到新名称。
|
||||
- 确认删除项目后,项目和项目聊天从应用中消失,绑定工作区文件保持原样。
|
||||
- Agent 发起单选、多选、确认或意见输入,用户提交后同一次任务继续运行。
|
||||
- 从左侧选择普通聊天或项目聊天,恢复历史后继续发送消息。
|
||||
- 在历史会话中继续发送消息。
|
||||
- 附加工作区文件并让 Agent 读取。
|
||||
- Agent 搜索、创建或修改工作区文件。
|
||||
- 停止正在生成的回复。
|
||||
- 重启服务后恢复历史会话。
|
||||
|
||||
### 异常流程
|
||||
|
||||
- 模型配置缺失时界面提示不可运行,不产生伪造回复。
|
||||
- 模型请求失败或超时时,运行进入失败状态并可重新发送。
|
||||
- 流式连接中断时保留已经确认写入的内容,并将运行标记为中断或失败。
|
||||
- 文件不存在、超出工作区、权限不足、编码不支持或写入失败时,工具返回明确错误。
|
||||
- 本地持久化失败时向用户提示,并避免把未保存结果显示为已经可靠保存。
|
||||
- 生成过程中再次发送消息时阻止提交,并说明当前已有运行。
|
||||
- 历史附件消失时显示不可用状态,不导致整个会话无法打开。
|
||||
- 创建项目时名称为空、目录不存在、目录不可访问或不是目录,创建失败并指出具体字段。
|
||||
- 项目工作区在创建后被移动、删除或变得不可访问时,项目历史会话仍可查看,但附件选择和文件工具被禁用。
|
||||
- 删除项目前项目聊天仍有任务运行时,删除被拒绝并提示先停止任务。
|
||||
- 项目数据删除失败时保持项目可见并提示失败,不展示部分删除成功的状态。
|
||||
- 交互请求格式无效时不显示损坏卡片,Agent 收到可理解的交互请求错误。
|
||||
- 回答已经取消、已经回答或不属于当前 Run 的交互时,提交被拒绝并保持原状态。
|
||||
|
||||
### 边界流程
|
||||
|
||||
- 空消息不发送。
|
||||
- 仅有附件的消息允许发送。
|
||||
- 超长消息和超大文件必须在实施方案中定义上限并在界面提示。
|
||||
- 空会话、超长会话标题、超长代码块和大量历史会话不能破坏布局。
|
||||
- 刷新页面不得创建重复的 Agent 运行。
|
||||
- 反复点击“新任务”但未发送消息,不得产生空会话记录。
|
||||
- 一个项目没有会话时仍可正常打开并显示项目对话引导。
|
||||
- 同名项目允许存在,但必须通过稳定标识和工作区摘要区分。
|
||||
- 删除包含大量历史会话的项目时仍只执行一次确认后的删除操作;重复提交删除请求返回稳定终态,不触碰工作区。
|
||||
- 刷新页面后等待回答的卡片仍可提交,已回答卡片不能再次编辑。
|
||||
- 多选答案少于最少数量、超过最多数量或包含未知选项时不得提交。
|
||||
|
||||
## 本版本不做
|
||||
|
||||
- 多用户、注册、用户邀请、角色和权限管理。
|
||||
- 多租户、团队空间、会话分享和跨设备同步服务。
|
||||
- 应用层登录、身份校验、用户会话或访问凭据管理。
|
||||
- 外部反向代理的配置和访问策略。
|
||||
- 多实例协调、任务队列和分布式并发。
|
||||
- 完整 CLI 产品、终端 UI、CLI 安装包和命令补全。
|
||||
- Claude 账号体系、Artifacts、远程连接器、语音、浏览器控制等未明确支持的 Claude Desktop 功能。
|
||||
- 项目成员、共享、云同步、远程知识库和跨项目统一上下文。
|
||||
- 移动端一比一还原;移动端只要求不出现完全不可操作的页面。
|
||||
- Agent 对本地文件的删除、移动和批量覆盖。
|
||||
- 插件市场、第三方技能商店和多人共享工具配置。
|
||||
- 任意动态表单、文件上传式交互、日期选择、富文本编辑器和自定义脚本组件;首版只支持四种固定交互类型。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- AC-001:在 `1440 × 900` 视口下,主布局、侧栏、消息区和输入区与确认后的 Claude Desktop 参考截图没有明显结构差异。
|
||||
- AC-002:所有未实现的参考界面小组件均被隐藏,不存在无效按钮或“即将推出”占位。
|
||||
- AC-003:用户能够新建、切换、重命名和删除会话。
|
||||
- AC-004:用户发送消息后能够看到助手内容流式出现,并在完成后持久化。
|
||||
- AC-005:用户能够停止正在运行的回复,界面和存储状态均显示“已取消”而不是“已完成”。
|
||||
- AC-006:服务重启后,会话列表、消息、附件元数据和已完成运行仍可恢复。
|
||||
- AC-007:用户能够附加允许工作区内的文件,Agent 能读取其内容或给出明确的不支持原因。
|
||||
- AC-008:Agent 能在允许工作区内搜索、读取、创建和修改文本文件。
|
||||
- AC-009:任何指向工作区之外的文件访问都被拒绝,包括包含 `..`、绝对路径和符号链接逃逸的情况。
|
||||
- AC-010:模型失败、超时和流式连接中断都会产生清晰错误状态,不会无限加载或伪装成功。
|
||||
- AC-011:同一时间已有 Agent 任务运行时,第二次发送被阻止且用户得到明确提示。
|
||||
- AC-012:Markdown、表格、引用和带语言标识的代码块能够正确展示,代码块可复制。
|
||||
- AC-013:用户主动上滚阅读历史内容时,新流式内容不会强制把滚动位置拉到底部。
|
||||
- AC-014:Agent Core 的自动化测试可以在不启动 Web Server 和浏览器的情况下运行。
|
||||
- AC-015:Web 路由或页面组件中不存在直接实现模型编排或本地文件读写的代码路径。
|
||||
- AC-016:通过 Agent Core 的公开接口可以构造一次不依赖 HTTP 的测试运行,证明未来 CLI 可以复用。
|
||||
- AC-017:应用源码中不存在登录页面、身份校验中间件、用户会话或访问凭据配置。
|
||||
- AC-018:仓库和客户端构建产物中不存在模型密钥或其他真实敏感配置。
|
||||
- AC-019:格式检查、类型检查、自动化测试和生产构建全部通过。
|
||||
- AC-020:核心页面没有同时承担 UI、协议、Agent 编排和文件操作职责的大型总控文件。
|
||||
- AC-021:仅有附件而无文本的消息可以成功提交;空文本且无附件的消息被阻止。
|
||||
- AC-022:历史附件被移动或删除后,会话仍可打开并明确显示该附件不可用。
|
||||
- AC-023:本地数据写入失败时,系统显示保存失败,不将结果标记为可靠持久化。
|
||||
- AC-024:首次进入且没有数据时,左侧“最近”和“项目”均显示空状态,右侧显示对话引导组件,系统不自动创建或选中会话。
|
||||
- AC-025:点击“新任务”后,在发送第一条有效消息前本地没有新增会话;首条消息提交后会话出现在“最近”并可持续聊天。
|
||||
- AC-026:用户能够以名称和有效本地目录创建项目;无效名称或目录会被拒绝并显示明确原因。
|
||||
- AC-027:一个项目可以包含至少两个独立会话,切换时各自历史和后续上下文互不混淆。
|
||||
- AC-028:普通会话的附件和文件工具只使用默认工作区,项目会话只使用所属项目工作区,越界访问均被拒绝。
|
||||
- AC-029:刷新或重启服务后,普通会话、项目、项目会话及其所属关系均可恢复;选择任一历史会话都能还原消息并继续聊天。
|
||||
- AC-030:项目工作区不可用时,其历史会话仍能打开,文件相关入口和工具明确报告工作区不可用,不会回退到默认工作区。
|
||||
- AC-031:项目重命名后左侧立即显示新名称,刷新和重启服务后新名称仍然保留。
|
||||
- AC-032:删除确认显示项目名称、会话数量和“不删除工作区文件”的说明;确认后项目及项目聊天从应用消失,而工作区文件保持不变。
|
||||
- AC-033:项目中有任务正在运行时删除被拒绝;项目数据删除失败时不会显示成已删除或留下部分可见状态。
|
||||
- AC-034:Agent 发起单选、多选、确认和自由文本请求时,前端分别显示可操作卡片,而不是只显示普通文本或普通工具完成记录。
|
||||
- AC-035:用户提交有效答案后,原 Run 从“等待用户”恢复并继续生成;不会创建新的 Run 或重复用户消息。
|
||||
- AC-036:刷新或重启服务后,未回答交互仍可继续回答,已回答交互显示只读问题和答案。
|
||||
- AC-037:重复回答、非法选项、超出多选限制和过长文本均被稳定拒绝,不会让 Run 进入错误的完成状态。
|
||||
- AC-038:停止正在等待用户的 Run 后,交互卡片显示已取消且无法再提交,同时可以开始新的 Agent 任务。
|
||||
|
||||
## 后续版本想法
|
||||
|
||||
- 基于同一 Agent Core 提供 CLI。
|
||||
- 增加更丰富的本地工具和可配置系统提示。
|
||||
- 增加深色主题。
|
||||
- 在需要时再评估是否由应用承担访问身份能力。
|
||||
Loading…
x
Reference in New Issue
Block a user