design: §7.1 改 task-primary + dir 副视图心智模型

原"Folder-centric"标题误导,实际产品形态是 task list 扁平视图为主、
dir tree 为辅,两视图正交查同一份数据(dir 不是 task 的父容器)。

- §7.1 重写心智模型,加双视图对照表 + Mac Finder 类比
- §7.1 明写 task_dir 留空 vs 指定的产品语义(一次性对话 vs 项目化)
- §7.1 空 dir(只上传素材未开 task)行为
- §7.2 API 顺序调整,tasks 前置,加分组注释
- §7.0/§7.6 task_dir 行同步统一为"留空派生/指定路径"二分

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-05-14 09:15:25 +08:00
parent efe4a91c33
commit 55dc8eb99d
1 changed files with 32 additions and 13 deletions

View File

@ -188,7 +188,7 @@ SaaS 化不是"重写"也不是"取代 CLI",而是**给同一份 core 加一个
|---|---|---|
| 入口 | `cli.py chat` 直调 core | HTTP `/v1/...` + SSE |
| Storage | **PG**(`ZCBOT_DB_URL` 指 docker compose / 远端 dev PG) | **PG**(指生产 PG) |
| task_dir 根 | `workspace/tasks/<task_id>/`(派生,私有) | `<storage_root>/users/<user_id>/<task_dir>/`(用户给,可共享) |
| task_dir 默认值 | `workspace/tasks/<task_id>/`(留空时派生) | `<storage_root>/users/<user_id>/tasks/<task_id>/`(留空时派生);用户指定时走 `<storage_root>/users/<user_id>/<user-path>/` |
| Memory | `workspace/memory/`(FS) | `<storage_root>/users/<user_id>/memory/`(仍是 FS) |
| Sandbox | subprocess + env 过滤 | per-task docker exec |
| Auth | 无(`user_id='local'`) | OIDC + JWT |
@ -197,26 +197,45 @@ SaaS 化不是"重写"也不是"取代 CLI",而是**给同一份 core 加一个
`workspace/` 仅存 skill 产物,state / messages 全在 PG。本地 vs SaaS 差别只在 task_dir 根路径,不在 storage 形态。
### 7.1 心智模型:Folder-centric,task-as-DB-record
### 7.1 心智模型:Task 一等公民 + Dir 文件副视图
参考 Claude Code(cwd 是 anchor)+ OpenAI Assistants(stateful agent service)。
两个并列入口,正交不嵌套:
- **Folder** = 用户的"硬盘",路径 `users/<user_id>/<user-defined>/...`,**和本地文件管理器体感一致**。folder 无 ID,**path 即标识**;改名走 prefix cascade。
- **Task** = DB 一行,带 `task_dir` 指向 folder(相对 user root)。同 folder 允许多 task,但 task 之间**不嵌套**(no-subtask)。
- **Messages** = DB 表,append-only,`jsonb` 存 LiteLLM 原样 payload。
- **Skill 产物**全落 cwd,不引入 artifacts 表;SKILL.md 指示 agent 清中间件。
- **Skill 定义**是项目代码,跟部署走,所有用户共享。
| 视图 | 入口语义 | 适用场景 | API |
|---|---|---|---|
| **Task list**(主) | "我的对话历史" | 任务驱动:"继续昨天那个 bug fix" | `GET /v1/tasks?status=&task_dir=` |
| **Dir tree**(辅) | "我的文件资产" | 项目驱动:"看汇报项目里所有素材 + 关联对话" | `GET /v1/folders` |
state / messages 两形态都在 PG,FS 只承担 skill 产物。多 task 共享同 folder 时由 §7.8 文件级悲观锁兜底。
类比:macOS Finder + 最近使用 / Apple Notes 文件夹视图 + 全部备忘录。两个视图查同一份数据的不同切面,**dir 不是 task 的父容器**。
- **Task** = DB 一行,一等公民,自带 `task_dir text` 字段:
- **留空 → 默认派生路径**(`workspace/tasks/<task_id>/`),等价"一次性对话"(ChatGPT thread 体验)
- **指定 → 项目化 task**,同 task_dir 多 task 自动共享 `source/` / `sections/` / 终稿(无需建"项目"实体)
- **Dir** = FS 路径,**无 DB 实体,path 即标识**;无父子结构,改名走 prefix cascade(§7.4)
- **No-subtask**:同 task_dir 允许(同项目多对话),前缀嵌套拒
- **Messages** = DB 表,append-only,`jsonb` 存 LiteLLM 原样 payload
- **Skill 产物**全落 task_dir,不引入 artifacts 表;SKILL.md 指示 agent 清中间件
- **Skill 定义**是项目代码,跟部署走,所有用户共享
**空 dir**(用户上传素材但还没开 task)在 dir tree 视图正常展示 —— 上传本身是有效产品行为;UI 上跟"有 task 的 dir"做轻量区分(如 task 数 badge)。
state / messages 两形态都在 PG,FS 只承担 skill 产物。多 task 共享同 task_dir 时由 §7.8 文件级悲观锁兜底。
### 7.2 资源模型(/v1)
Task 是主视图,排在前面;folder 是文件副视图。
```
POST/GET/PATCH/DELETE /v1/folders[/{path}] 列树 / 创建 / 改名 / hard cascade
GET/POST/DELETE /v1/folders/{path}/files[/{name}] 列 / 上传 / 下载 / 删
CRUD /v1/tasks[/{id}] {task_dir, mode, desc, model}
# Tasks(主)
CRUD /v1/tasks[/{id}] {task_dir?, mode, desc, model};task_dir 留空默认派生
POST/GET /v1/tasks/{id}/messages 发消息 / 历史(?search= 走 jsonb GIN / tsvector)
GET/POST /v1/tasks/{id}/runs/{run_id}/{events,cancel} SSE
# Folders(文件副视图)
POST/GET/PATCH/DELETE /v1/folders[/{path}] 列树 / 创建 / 改名(cascade)/ hard cascade
GET/POST/DELETE /v1/folders/{path}/files[/{name}] 列 / 上传 / 下载 / 删
# 元数据
GET /v1/{skills,models,usage}
POST /v1/probe (admin)
```
@ -285,7 +304,7 @@ usage_events(id, user_id, task_id uuid, run_id uuid, kind, value, ts)
|---|---|---|
| 1 | ~~事件流化 `loop.py`~~(commit `375bb29`) | done |
| 2 | **Storage 落 PG**:`Session` / `TaskState` 改 SQLAlchemy 写 PG;alembic;`cli migrate-from-fs`;`docker-compose.yml` 起本地 PG | 3 天 |
| 3 | **task_dir 双形态**:`TaskState.task_dir` 可显式指定;`tools/fs.py::_resolve` 接 task_dir 注入;system prompt 注入两形态共用 | 1 天 |
| 3 | **task_dir 字段语义**:留空走默认派生(本地 `workspace/tasks/<task_id>/` / SaaS `<storage_root>/users/<uid>/tasks/<task_id>/`)或显式指定(走用户给路径);`tools/fs.py::_resolve` 接 task_dir 注入;system prompt 注入两形态共用 | 1 天 |
| 4 | **Folder API**:list / create / rename(cascade + 锁 running) / delete(hard cascade) / upload / download | 2 天 |
| 5 | **No-subtask 校验**:`create_task` 入口跑 §7.4 SQL | 0.5 天 |
| 6 | **Executor + sandbox**:`run_python`/`shell` → `Executor.run(...)`;本地保留 subprocess executor,SaaS 走 docker;`api_key_env` → `KeyProvider` 运行时注入 | 2-3 天 |