caoqianming
|
d1a2961bf4
|
api+ui(dev SPA): POST /v1/tasks/{id}/clear 清空对话 + 顶栏「清空对话」按钮
- 后端: 同事务 SELECT FOR UPDATE 锁 + active run 检查(running/cancelling → 409) +
DELETE messages + reset tasks.tokens_prompt/completion/cost_usd=0 + run_status='idle'
- usage_events 完全不动 — 用户级账单 source of truth 与对话清空解耦;
message_id FK 是 ondelete=SET NULL,task_id/units/cost_usd 全保留可重建累计
- dev SPA 顶栏在导出后插「清空对话」(紫色 hover,介于完成绿/废弃橙/删除红),
running||n_messages==0 → disabled,confirm 二次确认 + 同步刷新 chat-meta / 消息 / 任务列表
- FS 文件保留(沿用 task delete 的"FS 视图可重生"心智)
- RUN.md API 表 + 故障兜底加 409 case;DESIGN.md 不动(无架构 / schema 字段语义变化)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 14:19:08 +08:00 |
caoqianming
|
ecff1d7858
|
ui(dev SPA): tool_call/result 卡片下加 artifact chip — 点击复用文件预览 modal,免再去右栏找
PROGRESS.md 同步。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 14:08:15 +08:00 |
caoqianming
|
c4fac2428b
|
skills+core(命名约定): task 级宪法文件 <date>-<short_id>-<name>.spec.md + spec_lock → spec 简化
同 working_dir 多 task 共享中间产物是设计意图(素材跨本子复用),
但 spec 这种 task 1:1 宪法文件必须隔离 — 否则两本子 spec 直接撞。
文件名三段式:
- task_short_id (task_id.hex[:8],永不变) 主锚 → glob *-<short_id>-*.spec.md 字典序最大 = current
- date 让"重定调"写新文件而非 edit 覆盖,旧版自然成历史快照
- task_name 作建时元数据,改 task.name 不 cascade(由 short_id 兜底定位)
约定由 core/agent_builder.py::_build_system_prompt 单点注入
(task_id / today 实际值嵌入,所有 skill SKILL.md 引用同一份)。
proposal / ppt SKILL.md 阶段一加"glob 检测已有 spec → 询问沿用/重定调"分支。
模板 templates/spec_lock.md → spec.md (git mv 保历史),_lock 后缀无信息量去掉。
未动:DB schema / PATCH /v1/tasks/{id} 改 name 入口 / 其他中间产物扁平共享
/ quality_check.py (--spec 接路径)。反方案(cascade rename / spec 入 PG /
物理 task 子目录)及"何时升级到 DB 化"信号见 DESIGN §7.9。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 14:03:21 +08:00 |
caoqianming
|
775962d68a
|
ui(dev SPA): 任务行 meta 数字槽位等宽 + 折叠按钮挪 pane-head + rail 模式 + time-ago 锁宽完成跨行对齐
- meta 加 tabular-nums + .num 槽位 (min-width:44px + text-align:right) + fmtTokens (1.2k/123k/1.2M)
- .num.right-group 把 [N条][Ntok][time] 整组用 margin-left:auto 推右
- time-ago 加 min-width:64px 锁宽: 整组右锚点稳定后, 跨行"条/tok"后缀才真正垂直对齐
- 折叠按钮挪到 pane-head 紧贴 ↻ 刷新; 折叠态改 VS Code rail 模式 (40px 列 + 只留 toggle 一直可点)
- 删 header #hd-toggle-left 冗余按钮 + header .icon-btn CSS (rail 模式下不需要)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 11:30:14 +08:00 |
caoqianming
|
5b67d29f59
|
ui(dev SPA): 左 pane 280→320px + header 折叠 toggle + 任务行精简 meta 防 CJK 断行
- grid 左列 280→320px (从 chat 借 40px), 任务名 / 描述 / wd 更舒展
- header 最左 toggle 按钮: body.left-collapsed → 列归零 + #pane-left display:none, chevron 翻向, localStorage 持久化
- 任务行 meta 删 id8 (挪到 row title 仍可查) + 各 span white-space:nowrap + badge/time-ago flex-shrink:0
- wd/desc 副行恢复 inline overflow:hidden ellipsis (单文本带不是 flex 子元素)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 11:18:42 +08:00 |
caoqianming
|
afebf25d79
|
ui(dev SPA): 任务列表 pager bar → 滚动加载(IntersectionObserver sentinel)
- 删 #task-pager / renderPager / resetPageAndReload / btn-prev|next 三件套
- 加 #task-sentinel + IO root=#pane-left + rootMargin 200px 提前触发
- loadTaskList({append}) 双语义: reset 抢占(_taskLoadSeq 丢弃过期响应) / append 互斥
- renderTaskList(append=true) 不 clobber 已渲染行, 事件 handler 只挂新行
- 首 pane-head 加 "共 N 个" 总数小字补偿丢失的 pager-info
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 11:09:46 +08:00 |
caoqianming
|
97d838a9ec
|
ui(dev SPA): 任务列表行加最近操作时间(updated_at 相对显示) + 新建弹框工作目录改 <select> 下拉
- 列表行 meta 加 fmtTimeAgo helper(刚刚/N 分钟前/N 小时前/昨天 HH:MM/MM-DD/YYYY-MM-DD), title 出完整 locale 串
- 新建任务工作目录: input + datalist → <select> 既有目录列表 + "+ 新建目录..." 展开 text input(保留新名建目录能力)
- folders-datalist 保留供左 pane filter-wd 继续 autocomplete
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 10:57:16 +08:00 |
caoqianming
|
7fc9570ffe
|
model: 加 GLM 5.1 档案 (zai provider + 国内站 bigmodel.cn)
- config/models/glm.yaml: family=glm, variant=pro, model_id=zai/glm-5.1,
api_base 覆盖到 https://open.bigmodel.cn/api/paas/v4,env ZHIPUAI_API_KEY
- thinking_mode 暂不开:GLM 协议是 body {"type":"enabled"} 而非
reasoning_effort 等级,需 core/llm.py 加 family 分支才能透传,留 TODO
- requirements.txt: litellm 下限 1.50→1.83(zai provider PR #17307
merge 后才内置,旧版不识别 zai/ 前缀会炸)
- RUN.md: .env 例子加 ZHIPUAI_API_KEY,probe 命令加 glm.pro
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 10:32:15 +08:00 |
caoqianming
|
337b8896a6
|
files(dev SPA): UX 翻面 — 主区去 checkbox / 黄 bar,改 [选入到此处] 弹框 + 拖拽上传 + 修全局 input width bug
主区从 select-then-pick-dest 改 at-dest-pull-sources:用户切任务时主
区已自动跳 working_dir,destination-first 比 source-first 少一次心智
切换。pane-head 加 [选入…] → 弹框跨目录勾源(Set<rel> 切换路径保留)
→ 底部 [复制到此处] / [移动到此处] 落到主区当前 state.filesPath;弹
框浏览 == 主区路径时同目录 checkbox 灰禁(挡 409)。整个 pane-right
成 drop zone,Files 类型才响应 + dragenter/leave 计数防子元素冒泡闪
烁,落点用 state.filesPath 沿用 /v1/files/upload。
根因 bug:全局 input{ width: 100% } 把新加的行 checkbox 撑成全行宽,
.name(flex:1; flex-basis:0)被挤成 0 宽 — 用户报"看不到文字"的元
凶。修法 selector 排除 [type=checkbox]/[type=radio]/[type=file]。
按 CLAUDE.md 不留兼容:state.selectedFiles / syncBulkBar / dirPicker
/ files-selall / files-bulkbar / row-cb / .file-row.selected 整套删
干净。后端 /v1/files/copy /v1/files/move 一行没动,前端用同样的
{paths, dest_dir}。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 09:59:21 +08:00 |
caoqianming
|
0c5dd3b176
|
files(dev SPA): /v1/files/copy + /move 跨目录批量搬动 + 多选 + 目录选择弹框
后端两路由共用 _validate_transfer 预检 helper(批量原子校验:同名 409 不
覆盖、不自嵌套、不重名、target 已存);move 加闸"顶层目录是某 task
working_dir → 409"维持 working_dir = top-level invariant,copy 无此闸
(新副本无 task 关联)。dev SPA 文件行加 checkbox + 顶栏全选三态 + 黄底
toolbar(复制到/移动到/取消),目录选择弹框复用 /v1/files 浏览。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 09:29:59 +08:00 |
caoqianming
|
7925dcef54
|
files: working_dir 视为可重生 FS 视图(DELETE task 顺手清空孤儿 + delete_file 去 task-ref 闸)
DB 是 source of truth,FS working_dir 可独立删 / 用户手删 / 跨机器迁移丢失,
下次 build_agent 自动 mkdir 重建。三处改:
- core/agent_builder.py: working_dir.mkdir(exist_ok=True) 从 if not resume:
里挪出,resume 也兜底建目录
- web/app.py DELETE /v1/tasks/{id}: 删完后若同 user 无其他 task 引用 +
FS 空 + ROOT 内相对路径 → best-effort rmdir 清孤儿;外部 --working-dir
(DB 绝对串)静默跳过
- web/app.py POST /v1/files/delete: 顶层目录去掉"有 task 引用 → 409"闸,
允许独立删空目录,task.working_dir 字段不动
smoke case 4 改 200 + working_dir 不变;新增 case 8(空目录自动清)/
case 9(非空保留),全 9 pass。PROGRESS / RUN 跟着更。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-20 08:10:36 +08:00 |
caoqianming
|
781a216ca6
|
model: 同 task 内切模型(c 模式 task 级 / A 粒度)+ usage_events v2 表(0006); GET /v1/models; 前端顶栏下拉 + 历史 model 切换点小标
- DB(0006): messages 加 model_profile 列(assistant 行有值); 重建 usage_events 表 v2 形态(event_id/user_id/task_id/message_id/kind/model_profile/units jsonb/cost_usd + 三索引), 0004 删的旧 schema 字段不够多态; tasks.tokens_prompt/completion/cost_usd 保留作粗概览
- ModelCapabilities 加 display_name; deepseek_v4.yaml flash/pro 各填名
- GET /v1/models: 扫 config/models/*.yaml 列可选项(profile/display_name/family/thinking_mode/is_default); POST /v1/tasks + PATCH 接受 model_profile(不传 → cfg["default_model"]; 校验走 ModelCapabilities.load 失败 400)
- build_agent: resume 时优先 task.model_profile 而非 cfg default; AgentLoop 加 user_id 透传, 每轮 assistant 入库后调 record_chat_usage(litellm cost map 算钱, 失败吞掉 emit warn 不阻 loop)
- core/storage/usage.py 新文件: record_chat_usage(双写 messages.tokens_in/out + model_profile + insert usage_events 一行)
- session.append() 返回 message_id(供 usage 关联)
- 前端 dev.html: chat-meta 加模型下拉(切了 PATCH + running 中提示"跑完后生效"); 新建对话框 modal 加 nt-model select; renderMessages 按 model_profile 切换点画小标 "── DeepSeek V4 Pro ──"
- CLAUDE.md: 加"开发测试期 / 不删现有数据 / DROP COLUMN 两种情况"规则
- DESIGN §7.4 schema 加 messages.model_profile + usage_events v2 段; PROGRESS 加 0006 条目 + 文件清单
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 21:43:13 +08:00 |
caoqianming
|
e7f9b005bd
|
doc: 精简 DESIGN/PROGRESS/RUN(总 162KB → 66KB,PROGRESS -80%)
PROGRESS 每条压 2-4 句去 smoke 列表 / 文件清单 / 行数明细;DESIGN 清重复 + 删反方向已废弃的取舍段;RUN 压命令注释 + 修 db current 应输出 0005(原写 0004)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 14:20:48 +08:00 |
caoqianming
|
2baed6894b
|
auth(dev SPA): 邀请码撤回 邮箱+密码 (users.email/password_hash bcrypt; 0005 加 UNIQUE; user add CLI; 登录两 tab)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 13:58:48 +08:00 |
caoqianming
|
53f59eb78a
|
auth(dev SPA): 邀请码登录(invites 表 0005) + SENTINEL user 彻底撤
- 新增 POST /v1/auth/login_invite {token}: dev SPA 给同事试用,token → name → uuid5(NS, name) 推导 user_id;原 /v1/auth/login 保留为 platform 机器对机器入口
- 0005 migration 新表 invites(token PK / name UNIQUE / created_at);先用 ZCBOT_INVITES env 试了一版,讨论后升级到 DB 表 — schema 极薄,不入 user_id (uuid5 推导),不入 revoked_at (DELETE 即撤销);管理直接 SQL,后期可加 main.py invite CLI
- web/auth.py: 删 _parse_invites / AuthConfig.invites / env 读取;新模块函数 resolve_invite(token) 每次 SELECT,无缓存避免 DELETE 后还能登
- SENTINEL_USER_ID 常量 + ensure_local_sentinel 函数 + agent_builder fallback 全删 (CLI 撤后无 caller);storage/utils.py 三函数 user_id 改必填;TaskState 加 user_id 字段;build_agent user_id 改 KEYWORD_ONLY 必填;session.py 删多余 ensure_local_task_row (task 行 web 入口已 INSERT)
- DB 清: SENTINEL 行 + 5 个 dev task + 307 messages + workspace/users/00000000.../ 全删
- dev.html: 登录页 2 格 (uuid+key) → 1 格邀请码,header 显示 name·uuid 前 8 位
- 文档全套同步: RUN/DESIGN/PROGRESS
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 13:14:31 +08:00 |
caoqianming
|
f61503fbdb
|
ui(dev SPA): 任务/文件行 ⋯ 下拉菜单 + 顶栏长名截断 + 聊天上传按钮 + 工具调用刷新右侧
- 单例浮层菜单 (position: fixed) 避开 pane overflow 裁剪
- 任务行 ⋯:完成/废弃/导出 docx/删除 (4 色, 按 status/消息数 disabled)
- 文件行 ⋯:重命名/下载(仅文件)/删除, 替代原内联按钮
- pane-head .label 加 nowrap+flex-shrink:0;files-proj 长项目名 11 字截断+title 全名
- chat-upload 复用同一 upload-input, 上传到右侧当前目录
- tool_result 触发 scheduleFilesRefresh (debounce 500ms)
- 重构 setTaskStatus/deleteTask/exportTask 接 tid 参数, 中间 pane 按钮共用同组函数
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 10:50:45 +08:00 |
caoqianming
|
fafcb14d86
|
skill(proposal): mermaid 文件名 hash→caption + quality_check 加图相关 4 拦截 + SKILL.md 精简; web cache fix
用户报"图没渲染到 docx",诊断后修三件事(同一根因链):
- web/app.py /v1/files/download 加 Cache-Control: no-cache
Starlette FileResponse 只发 ETag/Last-Modified, 浏览器走启发式缓存,
workspace 文件改了 SPA 预览看不到新版
- quality_check 新 check_figures(): 4 条规则
1) figures/ 有 png 但 sections 0 个 ![]() 引用
2) fenced 代码块出现 box-drawing 字符 (┌─┐│└─┘ 等)
3) mermaid 块必须有首行 %% caption: <题>
4) 同 task 内 mermaid caption 不能撞名
- render_diagrams.py: hash → caption 命名
pass-1 验证 caption 完整 + 全 task 唯一, 缺/撞 退 2
pass-2 渲染落 fig_<sanitized>.png, 总是覆盖
- render_docx.py: mermaid 块按 caption 查 fig_<caption>.png
无 caption / 清洗空 / png 缺 → ASCII fallback
- SKILL.md ~193 → ~160 行:
插图段 49→22 行(压 matplotlib 细节 + 删类型选择展开)
反模式合并 ASCII/占位/手写图编号/缺 caption/撞名
删"为什么两段式"长说理段
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 10:19:09 +08:00 |
caoqianming
|
3ca37f7041
|
doc(PROGRESS): 05-19 dev SPA 文件预览弹框
加 05-19 条目 + 文件清单更新 dev.html 行数 + 加 web/static/vendor/ 一行。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-19 08:25:30 +08:00 |
caoqianming
|
d6fc004367
|
skill(proposal): mermaid 管线 + render_docx 图片插入 + 图题自动编号
新增 render_diagrams.py 把 ```mermaid``` 块预渲染到 figures/fig_<sha1>.png
(优先本地 mmdc, 回退 mermaid.ink 公网 API, 都失败留 WARN 不阻塞);
render_docx.py 加  识别 + mermaid 缓存查找, 缺缓存自动 ASCII fallback,
图题"图 N <caption>"全局自增, 替换原模板里的 [图 2-2 ...] 裸占位写法。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 21:37:16 +08:00 |
caoqianming
|
9aa2efc335
|
core(/v1/files): 加 rename + delete 顶层加 task 引用闸
- POST /v1/files/rename:任意深度;path 是顶层目录则 DB-aware
(FOR UPDATE 锁 task / 活跃 run 互锁 / check_no_subtask exclude /
UPDATE working_dir 先于 FS rename,FS 失败回滚)
- POST /v1/files/delete:顶层目录 + 有 task 引用 → 409,杜绝悬空
- check_no_subtask 加 exclude_task_ids,rename 平移自己不误判嵌套
- dev SPA:file row 加改名按钮,顶层改名后刷任务列表 + 当前 task header
- smoke 7 case 全绿(scripts/smoke_files_rename.py)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 21:06:21 +08:00 |
caoqianming
|
952a377017
|
prompt(skill 机制): 永远 load → 可选辅助,通用任务不必硬套
skill 字段在新建任务时已可留空(本轮 /v1/skills 下拉落地),原"永远 load 一下"
对简单问答 / 改 bug / 文件操作等通用任务过激;改为"Skill 是可选辅助",明确通用
任务直接用通用工具,匹配到 skill 领域再 load。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 16:27:30 +08:00 |
caoqianming
|
b057c3bd06
|
core(/v1/skills + dev SPA): GET /v1/skills + 新建任务弹窗 skill 字段改下拉
- web/app.py: lifespan 启动扫一次 SkillRegistry 挂 app.state;新增 GET /v1/skills(JWT 鉴权)
- web/static/dev.html: nt-skill input → select + loadSkillOptions 缓存到 state.skills
- PROGRESS: 记录
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 16:27:10 +08:00 |
caoqianming
|
f9311b069c
|
ui(dev SPA): 菜单 / 按钮 / 状态 / 弹窗文案全部中文化
login / header / 三栏 label / chat 按钮 / new task modal 静态文案 +
renderTaskList / renderChatMeta / fetchSse / 弹窗等动态文案全套本地化。
状态码 active/completed/abandoned 显示为「进行中/已完成/已废弃」,
role user/assistant/error → 我/助手/错误。
技术字段(user_id / platform_key / UUID / tok / CSS class / SSE event 名)
保持原状,不影响 UI 中文。Smoke 13 个中文标签全在 + 8 个英文按钮无残留。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 15:44:50 +08:00 |
caoqianming
|
0d127a7261
|
core(入口归位): cli.py→main.py, 原 main.py→core/agent_builder.py, 删 REPL
按 §5 Less Scaffolding + SoC 把混三角色的 main.py 拆开:入口归位到 main.py,
装配 lib 归位到 core/agent_builder.py。dev SPA 落地后 CLI REPL(chat/tasks/
export)与 web /v1 等价,维护双套 task 切换语义只是"对称美",一并撤(§7 E
CLI 双模式路线同样撤)。
- cli.py → main.py(入口,只剩 web/db/probe 三 click 命令组)
- 原 main.py → core/agent_builder.py(build_agent / system prompt /
validate_task_name 装配 lib;顺手删死代码 _resolve_uuid_or_prefix +
resume "last" 分支)
- 删 chat/tasks/export 三 REPL 命令 + _cleanup_if_empty / _list_task_rows
等 CLI-only helpers ~400 行
- web/app.py 5 处 from main import → from core.agent_builder import
- DESIGN §1/§2/§3.3/§3.6/§7.0/§7.6/§7.7/§7.8/§7.9 + RUN + PROGRESS 全套同步
- Smoke 6 case 全绿(in-process TestClient + 子进程 python main.py db current)
- 净减 486 行
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 14:10:59 +08:00 |
caoqianming
|
2e519ab8a6
|
core(0004): 删 runs / usage_events 表 + cancel/SSE 改 task-level
usage_events 全代码库零引用,纯死代码;runs 表实质就是"task 当前 in-flight 状态"
影子表,tokens_p/c 写但从未被读,run_id 唯二实用是 broker 频道键 + cancel 参数 —
单活 run 形态下完全冗余,客户端只需 task_id。按"开发期不写兼容层"心智一把切干净。
- alembic 0004:DROP runs / usage_events,tasks 加 run_status (idle/running/cancelling/error) +
run_error 两列;ok/cancelled 终态都回 idle 不留持久标记,只有 error 持久
- ORM 删 Run / UsageEvent class
- Broker 全 task_id 索引,加 start(tid) 在新 run 前清 _done
- /v1/tasks/{tid}/runs/{rid}/{events,cancel} → /v1/tasks/{tid}/{events,cancel}
- POST /messages 返 {events_url} 去掉 run_id
- dev SPA: state.currentRunId → state.streaming(bool),路径去掉 /runs/{rid}/
- Smoke 18 case 全绿
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 11:05:35 +08:00 |
caoqianming
|
bf41631437
|
core(run cancel): POST /runs/{rid}/cancel + AgentLoop 协作式 cancel + dev SPA stop 按钮
落地 DESIGN §7.2 原标"待"的 cancel 路由 — 等待回复 / LLM 操作时也能中断。
- broker 加 request_cancel / is_cancelled / clear_cancel(per-run threading.Event)
- AgentLoop 加 cancel_check 回调,每轮 LLM 前 + tool_calls 之间 poll;命中给
未执行 tool_call 补 [cancelled by user] tool result 保 LiteLLM 协议,emit
cancelled event
- 单活 gate + 启动 reaper 扩到 running | cancelling
- BG 装 cancel_check + 终态判 cancelled/ok + finally clear flag
- dev SPA stop 按钮 + cancelled badge + fetchSse try/finally 失败路径复原 UI
LLM 同步 call 本身不可中断,最坏等当前一轮跑完(通常几十秒)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 08:42:45 +08:00 |
caoqianming
|
976ef45e87
|
core(POST /v1/tasks/{id}/messages): 同 task 单活 run 锁 + 启动 reaper
挡住"用户连点 send 两条 → 两个 BG 线程争 messages.idx UniqueConstraint
race"的旧 TODO。POST /messages 把所有权 + 活跃 Run 检查 + 新 Run INSERT
收进一个事务,首步 SELECT Task … FOR UPDATE 锁 task 行,命中 running 已
存在则 409。lifespan 加 stale-run reaper,把进程 crash 留下的孤儿 running
标 error,避免对应 task 被 409 永挂。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 08:27:48 +08:00 |
caoqianming
|
9a7620f704
|
core(files API): user-rooted /v1/files*,去掉 task_id 前置
文件操作语义上只关心"路径 + user 边界",task_id 是多余拐杖;
同时 §7.1 心智模型把 task 和 dir 定义为正交副视图,API 不该混。
- 4 路由 /v1/tasks/{id}/files* → /v1/files*(列/下载/上传/删)
- 边界从 task_dir 改 user_root (workspace/users/<uid>/)
- dotfile 一律过滤(.memory/ 等系统区不暴露)
- dev SPA:登录即拉 user_root,选 task 自动跳到其 working_dir,
crumbs root 标"我的",新增 upload 按钮
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-18 07:59:19 +08:00 |
caoqianming
|
0c577ba0a5
|
core(GET /v1/tasks): 分页 + 多维筛选 + ordering 排序
- 响应壳固定 {page, page_size, count, results}
- 6 个 query 参数:page(1-based) / page_size(1-100 clamp) /
status / skill / working_dir(末段名,后端拼前缀比对) /
q(name + description ILIKE)
- ordering DRF 风格逗号分隔,-field 倒序;allowlist
created_at/updated_at/name/status;非法字段静默丢弃;**默认 -created_at**
- 单次 COUNT + 单次 SELECT LIMIT/OFFSET,无 N+1
- dev SPA:task pane 三段头(status + 刷新 / q + working_dir / ordering),
prev/next 翻页 + "from–to / count (第 P/L 页)" + 输入 debounce 300ms +
默认 -created_at 不发到 URL(参数干净)
- DESIGN §7.2 / RUN 路由表 / PROGRESS 同步
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-17 19:26:29 +08:00 |
caoqianming
|
4a6aaaf34d
|
core(0003): name + working_dir + skill schema 重构 + per-user .memory
- alembic 0003: TRUNCATE tasks CASCADE + task_dir→working_dir + mode→skill + 加 name TEXT NOT NULL
- name(必填,任务显示名,UI / docx 用)与 working_dir(可选,留空 fallback 用 name 作目录)解耦;
同 working_dir 多 task 共享物理目录(§7.1)
- skill 字段对齐 skills/ 注册表语义,后续可下拉强校验
- POST /v1/tasks {name(req), working_dir?, description?, skill?};
PATCH 支持改 name/skill;新增 GET /v1/folders(FS 列表 + n_tasks + last_used)
- DELETE /v1/tasks/{id} 硬删 DB(messages CASCADE)+ FS working_dir 保留;
dev SPA 加 task delete 按钮 + file per-row 删按钮
- 工作目录改 eager mkdir(取代懒创建):用户给 name 即声明项目,目录立刻存在
- dev SPA modal 拆"任务名" + "工作目录"(<datalist> autocomplete 走 /v1/folders +
输入实时提示"复用 / 新建 / fallback");renderTaskList 主行 = t.name,副行 = 📁 + skill + desc
- files 面板 UX:pane-head 显示项目名 + crumbs root 用项目名 + 修 root 处多渲 "." crumb 的 bug
- 顺手:memory 搬 workspace/users/<uid>/.memory/(per-user dotfile 隔离);
CLI --mode → --skill,--name + --working-dir 分开
- DESIGN §3.1 / §3.6 / §7.2 / §7.4 + PROGRESS + RUN 全量同步
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-17 19:15:37 +08:00 |
caoqianming
|
02a69058df
|
core(§7 D + D'): /v1 JSON API + PLATFORM_KEY→JWT auth + dev SPA
整合今日累积的 §7 D 阶段主体工作:
- §7 D /v1 JSON API:删 web/templates/* + web/static/style.css,
web/app.py 重写为纯 /v1 JSON 路由(tasks CRUD + messages +
SSE 事件 JSON 化 + files 4 路由 + export),CORS allow_origins
起步 *,GET / 改 302 → dev SPA(详 DESIGN §7.9)。
- §7 D' 过渡 auth:web/auth.py 新增 — PLATFORM_KEY env(共享密钥)
+ JWT_SECRET env(HS256 签),POST /v1/auth/login 校验 key → 签
JWT(默 7d TTL),所有 /v1/tasks* 走 Depends(require_user) 验签
并按 user_id 隔离数据;豁免 /healthz、/docs、/openapi.json、
/static/*、/v1/auth/login。env 双必填,缺则 fail-fast。
- dev SPA:web/static/dev.html ~600 行 vanilla JS 单文件,login
overlay(user_id 默 sentinel + platform_key)+ 3 栏布局(task
list + chat 流 + files 浏览)+ new-task modal + done/abandon/
export。SSE 走 fetch+ReadableStream(EventSource 不支持 Bearer)。
- task_dir 改相对存储:新增 core/paths.py(to_db_path/from_db_path)
+ alembic 0002 migration 把 ROOT-内绝对路径转 posix 相对,跨 OS
和混合分隔符历史数据天然兼容。check_no_subtask 改 Python 端归一
比对,逻辑更清晰。
- litellm 启动 cost map 网络警告兜底:core/llm.py 在 import 前
setdefault LITELLM_LOCAL_MODEL_COST_MAP=True,墙内冷启动 ~5s →
<1s。
- docs:DESIGN §7.3 改写(过渡 auth + 真 OIDC 路线)+ §7.7 状态表
+ §7.9 dev SPA 取舍;PROGRESS 加多条今日条目 + 文件清单 + 下一
步;RUN env 双 auth env + curl 示例 + 路由表 Auth 列 + 5 条故
障兜底新条目。CLAUDE.md 加"开发期不写兼容层"心智。
Smoke 全绿:env fail-fast / 8 路径无 token 全 401 / login 3 分
支 / 带 token CRUD / 跨 user 4 case 隔离 / token 异常 4 case /
真实 HTTP uvicorn 端到端 login + bearer call + dev.html 服务。
requirements: 加 pyjwt>=2.8.0;删 jinja2 / markdown-it-py /
mdit-py-plugins / pygments(模板路线撤一并清);保留 python-
multipart(files upload 还用)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-15 16:14:25 +08:00 |
caoqianming
|
1035b12847
|
core(§7 Phase G G6/new): Web 端新建 task 入口
提前于 G5 落地 — 用户反馈 Web 没"开启新对话"的地方。
- GET /new 渲染 new_task.html 表单(description / mode / task_dir 三字段);
- POST /new:strip 校验 + description 与 task_dir 至少填一个否则 400 +
check_no_subtask 同 CLI / build_agent 一致拦前缀嵌套 → 409 +
ensure_local_task_row 写占位行 + 303 See Other 跳转 /tasks/{tid};
- task_dir 空 → 默认派生 workspace/tasks/<uuid>/(同 _default_task_dir),
显式 → Path.expanduser().resolve() 同 cli.py --task-dir;
- 模板 new_task.html:三字段表单 + error 渲染(400/409 重渲带 form_state
不丢用户填的值);home.html 加 + new task 主按钮;base.html 默认 nav
也带 tasks/new 链接;
- CSS:.btn-primary 商务红主按钮 / .new-task-form 表单 + focus / .navlinks
.active 当前页高亮 / .head-actions flex 容纳 filter + new 按钮;
- 懒创建保留语义:Web /new 入库占位,后续 build_agent 走 resume(已存在
不冲突);CLI REPL 仍走 build_agent 懒创建路径,两路互不干扰。
Smoke 21 路径全绿:GET 表单 200 + 三字段 / POST happy(description-only
和 custom task_dir)→ 303 + Location 正确 / DB 行字段对 + default-derived
task_dir 含 uuid / 空+空 → 400 重渲表单带 error / no-subtask 父子嵌套 →
409 + 错误文案 / home 页 + new task 按钮 + nav 链接 / /new nav active 标记。
版本 0.4 → 0.5。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-15 09:51:35 +08:00 |
caoqianming
|
7356d25652
|
core(§7 Phase G G4): chat 发送 + SSE 流式回复
- web/broker.py RunBroker:in-process pub/sub,subscribe/emit/close/
unsubscribe;同 run_id 多订阅者 fan-out(刷新 / 多 tab / 桌面+移动
都能同时看流);_done 集合让晚到订阅者立刻收 done(不挂)。
- web/sinks.py WebEventSink:实现 §7 A sink 协议,把 AgentLoop._emit
桥到 broker.emit(run_id, ev),AgentLoop 完全不知 web 存在。
- 异步策略 = asyncio.to_thread(不改 core):POST /tasks/{tid}/messages
async handler → INSERT runs 行 + asyncio.create_task(to_thread(
_run_agent_bg)),_run_agent_bg 工作线程跑 build_agent + agent.run,
sink 通过 loop.call_soon_threadsafe 跨线程把 event 桥回 asyncio queue。
- GET /tasks/{tid}/runs/{rid}/events:StreamingResponse async gen,
响应头 text/event-stream + Cache-Control: no-cache + X-Accel-
Buffering: no(nginx 反代友好);第一帧 retry/connected 让 ES 立
即建立,30s 无 event 发 : ping 心跳。SSE multi-line data 每行加
data: 前缀(SSE spec),客户端 ES 自动还原 \n 拼接的 HTML。
- _render_event_fragment 渲染 text/tool_call/tool_result/error
HTML 片段;run_start/llm_start/llm_end/done 发空 data(只让客户端
识别 event type)。
- 新模板:_frag_text/_frag_tool_call/_frag_tool_result/_frag_error +
_send_response(POST 响应:user msg 卡 + msg-assistant streaming
容器带 sse-connect/sse-swap/sse-close)。
- chat.html 加 send 表单(Enter 发,Shift+Enter 换行,HTMX hx-post /
hx-target=#chat-stream / hx-swap=beforeend / 提交后 reset);chat
section 改 id=chat-stream;非 active task 隐藏表单。
- CSS:.streaming .run-indicator 红点脉冲 / .send-form 输入框 /
.tool-result-inline 追加式样式 / .msg-error 错误卡。
- runs 表写状态:POST 时 status=running,正常完结 ok + tokens_p/c,
异常 error + error 文本(DB 写失败不放大噪声,已 emit error 给前端)。
- lifespan bind_loop(asyncio.get_running_loop()) 让 broker 拿到
loop 引用,emit 跨线程才能 call_soon_threadsafe。
- RUN 故障兜底加 3 条:SSE 经 nginx 卡住、浏览器 send 无反应、并发
POST messages idx 冲突(已知 TODO)。
Smoke 双层全绿:
- broker 单元 8 case (subscribe/emit/get/fan-out/跨 run 隔离/close/
late subscribe instant done/unsubscribe/未 bind silent drop)
- 端到端 24 case (POST 200 + sse-connect/run_id 抽取 + content-type/
x-accel-buffering/cache-control 头对 + event 序列 run_start→done
+ text 片段 <strong> + tool_call <details> + tool_result preview
+ empty body 400 + 各种 404 + late done + runs 行 INSERT)
版本 0.3 → 0.4。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-15 09:19:25 +08:00 |
caoqianming
|
514d36c481
|
core(§7 Phase G G3): chat 只读页 + markdown + tool 折叠
- web/app.py 加 _get_md() 单例 MarkdownIt(gfm-like + linkify +
breaks,html=False 禁内联 HTML 防 XSS),fenced code 走 pygments
_pygments_highlight 回调(codehilite cssclass)。
- load_chat_messages(tid):PG idx asc 读 messages。
build_chat_blocks(messages):system / tool 不入 block(tool 内嵌进
assistant.tool_call.result),user / assistant text 走 md 渲染,
orphan tool_call → [no result]。_args_preview 60 字截断,
_pretty_json 解析失败 fallback 原串。
- /tasks/{id} 渲染 chat.html;删 task_placeholder.html。
- chat.html:.msg 卡片(user 浅蓝 / assistant 白底),tool_call 用
<details> 默认折叠(无 JS,浏览器原生);summary 显示 tool 名 +
args 前 60 字预览,展开看 args_pretty + result。
- CSS 加 .body 内 markdown 元素样式(table / blockquote / code / pre
/ strikethrough)+ .codehilite 浅色 token 配色(keyword/string/
comment/function/number/operator,余下黑色)。
- requirements: markdown-it-py[linkify] / mdit-py-plugins / pygments。
Smoke 28 路径全绿(in-process Starlette TestClient):4 display
blocks aggregation + GFM 特性(table/fence/autolink/strikethrough/
bold)+ tool 配对(命中 + orphan [no result])+ HTML 含 <details>/
tool-badge/codehilite/<s> + 空 task 文案 + invalid UUID 404 + util
单测(args_preview/pretty_json/render_md 边界)。版本 0.2 → 0.3。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-15 08:38:31 +08:00 |
caoqianming
|
80a658eba4
|
core(§7 Phase G G2): task list 页 + /tasks/{id} 占位
- web/app.py 加 list_tasks(limit, status):PG tasks + messages count,
updated_at 降序,返回模板友好 dict。Web 与 cli.py 数据形状不一致
(CLI 用 tuple,Web 用 dict),不预付抽象,等真有 schema 同步成本
再抽。
- / 路由换成 task 列表,支持 ?status=active|completed|abandoned
filter(无效值静默降级 all)。/tasks/{task_id} 占位路由:UUID 解析
失败 → 404,DB 不存在 → 404,有效则渲 task_placeholder.html(G3 来填
消息流)。
- Linux portability:_norm_path() 显示前 replace('\','/') 把 Win
存的 backslash 归一,Win Path.resolve()-str → "D:/..." 显示;Linux
forward-slash 原路通过。Path.as_posix() 在 Linux 读 Win backslash
串时不归一,所以选 replace 而非 as_posix。
- 模板 home.html 表格(id/updated/status/mode/model/msgs/tokens/desc-dir)
+ status badge 配色(active 绿 / completed 蓝 / abandoned 灰) +
filter 表单 + 空态文案。task_placeholder.html 渲染 G3 提示。CSS
tabular-nums 数字对齐 / hover 高亮 / accent-soft note。
Smoke 18 路径全绿(in-process Starlette TestClient):3 task seed
(active/completed/abandoned)+ Win\Linux 双路径形态 → / 渲染对、
status filter 正反向、garbage status 静默 all、UUID 占位、notauuid
404、ghost UUID 404、limit 生效、/healthz 不退化。版本 0.1 → 0.2。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 15:52:11 +08:00 |
caoqianming
|
91202b6172
|
core(§7 Phase G G1): Web UI 脚手架 + cli.py web 子命令
- web/ 新包:app.py FastAPI 工厂(/ + /healthz + /static),Jinja2
base.html / home.html,minimal style.css。HTMX + HTMX-SSE 走 CDN
(无 node 链路,与 §5 Less Scaffolding 一致)。
- cli.py 加 web --host --port --reload 子命令,默认 127.0.0.1:8765,
本地形态 sentinel user 无 auth(Phase D 才上 OIDC)。
- requirements: fastapi / uvicorn[standard] / jinja2 / python-multipart
(multipart 为 G5 文件上传留)。
- Starlette 新签名踩坑:TemplateResponse(request, name, context),
旧式塞 context 里会让 jinja 用 dict 当 cache key 炸 unhashable,记
RUN.md 故障兜底。
- Linux portability:模板 path 显示约定 .as_posix();SSE 头 G4 上时
带 X-Accel-Buffering: no(nginx 反代友好)。`cli.py web` 在
.venv/Scripts/python.exe(Win)/ .venv/bin/python(Linux)走同一路径。
Smoke 四路径(in-process via Starlette TestClient)全绿:/healthz →
"ok" / / → 1063B(title + static + version)/ /static/style.css →
1624B / /nonexistent → 404。`cli.py web --help` 子命令注册 OK。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 13:37:54 +08:00 |
caoqianming
|
e8dbfa57a5
|
core(§7 B Step 6): no-subtask 前缀嵌套校验
- core/storage/utils.py 加 check_no_subtask + NoSubtaskError;PG LIKE
双向(new LIKE existing/% OR existing LIKE new/%),同 task_dir
允许(同项目多对话),空 / whitespace 跳过。
- 分隔符容差:SQL replace(task_dir, '\', '/') 把存的 Windows 反斜杠
与新值统一到 '/' 再比;backslash 通过 bind 参数传,绕开 SQL 转义。
- main.py::build_agent 在 resolve_task_id 后、TaskState 构造前调,
if not resume 单层闸 —— resume 跳过(改名走未来 Folder API cascade).
- cli.py 三处 build_agent 调用现有 try/except 直接接住 NoSubtaskError.
- PROGRESS / RUN 同步:Step 6 完工,故障兜底加一条 NoSubtaskError 处理.
Smoke(9 路径 + e2e 3 分支)全绿。§7 B 完工(Step 5 取消)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 11:59:37 +08:00 |
caoqianming
|
2b3692c8bf
|
core(§7 B Step 4): --task-dir 双形态 + RUN.md 运行手册
- CLI `chat --task-dir <path>` 让用户显式指定项目目录(§7.1 task-primary +
dir 副视图心智模型落地);留空走默认派生 workspace/tasks/<uuid>/。
- main.py::resolve_task_id 加 task_dir_arg;resume 时从 PG tasks.task_dir
读,空则降级默认派生。新增 is_managed_task_dir(td, ws) 判断 task_dir
是否在默认模板下。
- cli.py::_cleanup_if_empty 拿 workspace_dir 作保护开关 —— 用户自指定的
task_dir 绝不 rmtree(可能含用户已有素材);DB 行该删还是删。
- core/export_docx.py::export_chat_to_docx 重构:task_id 升一等参数(从
task_dir.name 提取改入参传入),task_dir 留空时自动从 PG 读;cli /export
与 cli.py export 子命令均改走 _resolve_uuid_or_prefix + task_id 直传。
- 新建 RUN.md(运行手册):env / 初始化 / 日常命令 / 故障兜底 / 关键路径。
- CLAUDE.md 加 RUN.md 维护规则(三文档边界:DESIGN=为什么 / PROGRESS=做到哪
/ RUN=怎么跑),对外行为改动同步更 RUN。
Smoke 4 路径:default-derived(managed=True, cleanup rmtree)/ --task-dir
(managed=False, FS preserved)/ resume reads DB task_dir / export 自动 PG
查路径,全绿。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 11:38:05 +08:00 |
caoqianming
|
aeecc7f0f3
|
core(§7 B Step 3): TaskState ORM + Web UI 设计 (Phase G)
- TaskState dataclass 改 PG-backed:save() → upsert_task (INSERT ON CONFLICT
DO UPDATE,显式刷 updated_at);load(task_id) → SELECT。state.json 全面
废除,task_dir 只承担 skill 产物。
- TaskState 字段去 cwd / 加 task_dir(对齐 §7 SaaS task_dir-as-identity);
cwd 只在 session.meta 内存视图保留(展示用)。
- core/storage/utils.py 新增 upsert_task / update_task;ORM-level UPDATE
自带 onupdate=func.now(),DO UPDATE 需显式 set。
- session.py Session.append 的 ensure 调用补传 mode/description/
reasoning_effort,避免首次 INSERT 后 _list_task_rows 看到空 meta。
- sync_task_tokens 改成 update_task 单字段 UPDATE,避免无谓全字段 UPSERT。
- cli.py _list_task_rows 全字段从 PG 读,status 过滤走 SQL WHERE;
_cleanup_if_empty 去 state.json 特例(任何 FS 文件/子目录都算实质痕迹)。
- core/export_docx.py meta 走 TaskState.load(tid),CWD 字段从 meta 表移除。
- DESIGN.md 追加 Phase G(Web UI 简洁版,FastAPI + Jinja2 + HTMX + SSE),
排在 §7.7 D 后;§7.9 补 server-render 不上 SPA 的取舍 4 条。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 11:25:53 +08:00 |
caoqianming
|
4f87bf14ee
|
core(§7 B Step 2): Session ORM — messages 走 PG, task_id 切 UUID
Session 重写
- messages 落 PG `messages` 表(append-only, idx 严格递增, jsonb payload)
- system prompt 不入库(每次 build_agent 重建到 messages[0],memory 演化即时生效)
- Session.load(task_id, system_prompt=...) 从 DB 读历史
- Session.task_exists / n_user_msgs 工具
Storage utils
- ensure_local_task_row: 首条消息前 INSERT ... ON CONFLICT DO NOTHING
打底 tasks 行(Step 3 后由 TaskState.save 接管字段更新)
task_id 切 UUID
- resolve_task_id(workspace, arg, resume): UUID + 前缀匹配,'last' 从 PG
按 updated_at 取最近
- 显示一律截前 8 位;完整 UUID 在 /id /status 保留
- 旧 workspace 老 task(时间戳格式)**不做兼容**
CLI 适配
- _cleanup_if_empty 双检查:DB messages count + FS 产物
- _list_task_rows: PG tasks ORDER BY updated_at + state.json 兜底字段
- _task_has_messages: /export 检查改 DB
- core/export_docx.py: messages 从 PG 读,state.json 留作 meta
Step 5 (migrate-from-fs) 取消。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 10:55:50 +08:00 |
caoqianming
|
425ea59937
|
core(§7 B Step 1): Storage 基建 — SQLAlchemy ORM + alembic + db CLI
- core/storage/{engine,models}.py: 5 表 ORM(users/tasks/messages/runs/
usage_events)+ session_scope 上下文 + 本地 sentinel user 初始化
- alembic 初版 migration 0001_initial_schema: messages.payload GIN
索引 + tasks (user_id, task_dir) 复合索引 + pgcrypto 扩展兜底
- cli.py: db upgrade/downgrade/current 子命令组;ZCBOT_DB_URL 未设
给 ASCII 报错 + exit 2(避开 Windows GBK 控制台编码问题)
- requirements: +sqlalchemy>=2.0 +psycopg[binary]>=3.1 +alembic>=1.13
- DB URL 来自环境变量 ZCBOT_DB_URL,不引导 docker(用户给测试库地址)
已在远端测试 PG 跑通 db upgrade head + db current。Session/TaskState
ORM 接入留 Step 2-3。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 10:41:44 +08:00 |
caoqianming
|
efe4a91c33
|
design: 精简 DESIGN/PROGRESS (-177 行)
DESIGN 520→351,PROGRESS 88→80。砍 §7 内部重复说理与 SQL 示例,
合并 §6/§7.8 风险表,压缩 §3 字段表与启动顺序;load-bearing 细节
(rename `old/%` 前缀、ModelCapabilities 字段、阶段估时)全部保留。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-14 08:52:23 +08:00 |
caoqianming
|
b4df60062e
|
design: 更新设计
|
2026-05-14 08:46:53 +08:00 |
caoqianming
|
e4a48fbb53
|
core: Session/TaskState 原子写 + Phase 6 双层记忆
- core.session.atomic_write_text (tmp + fsync + os.replace) 接管 Session/
TaskState 落盘, 中途异常不留 0 字节; _cleanup_if_empty 放过 *.tmp 孤儿
- core/memory.py: workspace/memory/{core.md, extended/} 双层记忆.
core.md 注 system prompt, extended/*.md 索引(标题+绝对路径)注 prompt,
内容靠 read 工具按需拉
- _build_system_prompt 从 build_agent 里提出来, new 和 resume 都走同一段,
resume 时覆盖 messages[0] -> memory 演化即时生效
- PROGRESS/DESIGN 同步: §7 platform track 行 + A 阶段完成 + 双层记忆/原子写
+ 文件清单到 2429 行
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-11 15:13:56 +08:00 |
caoqianming
|
ae93016442
|
cli: REPL /resume 切 task + 懒创建 task_dir + 切走前空清理
- 加 /resume [last|<id>] REPL 命令,无参数列最近 10 个表格让用户挑;
和 /new 对称,都在 REPL 内重建五元组。tasks 命令复用 _list_task_rows
- main.py 新建分支不再 session.save() / task_state.save() 占位 ——
推迟到首条 user 消息触发的 Session.append → save() 才物化 task_dir。
启动 REPL 立刻 /exit 磁盘无痕,跨进程也安全
- _cleanup_if_empty 在 /exit /quit /new /resume + Ctrl-C/EOF 守门:
无 user 消息 + 目录在磁盘上 + 文件集 ⊆ {messages.json} 才删,
state.json 存在(/done /abandon /desc 留下的显式痕迹)就保
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 09:55:56 +08:00 |
caoqianming
|
56e414e046
|
proposal: 阶段二两段式 + render_docx 透传 fenced 代码块
- SKILL.md 阶段二改两段式: 先列 3-6 条要点 → 用户确认 → 再起草 → 用户确认。关键章节 (立项依据/研究方案/技术路线/考核指标) 一段一卡。一次性出全文容易把错方向推到底,要点阶段拦得早
- render_docx.py 支持 ```...``` 围栏: 中文新宋体 + 西文 Consolas + 行距 1.0 + 不缩进 + xml:space=preserve。原先 ASCII 流程图被当散文段落合并,框完全错位
- PROGRESS.md backlog 加 mermaid 预渲染 (mmdc → PNG → add_picture),等 ASCII 透传不够用再做
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 08:58:18 +08:00 |
caoqianming
|
a32cb049bc
|
ppt+proposal: 素材摄取改用 markitdown, 删自研 source_to_md
ppt/proposal 的"素材 → Markdown"逻辑此前各写一份 (source_to_md.py
内联 pypdf/python-docx/openpyxl), 改用微软 markitdown CLI 统一替换:
表格/标题/列表保留更好, 同时多覆盖 xlsx/url/html/csv 等格式。
- requirements.txt: 加 markitdown[pdf,docx,pptx,xlsx]
- skills/ppt/SKILL.md: 资源行改成 markitdown 说明
- skills/proposal/SKILL.md: 阶段零 32 行 Python 代码 → 4 行 CLI
- skills/ppt/scripts/source_to_md.py: 删除 (157 行)
- PROGRESS.md: scripts 列表同步
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 08:03:07 +08:00 |
caoqianming
|
3869089a44
|
DESIGN/PROGRESS: 同步 TUI 打磨 + task_dir 落地
DESIGN: 目录树补全 task_dir 内的 skill 产物;启动顺序 #5 加 task_dir 注入;
3.1 主循环增补 markdown 渲染、spinner 实时耗时/token、每轮成本行。
PROGRESS: 加 2026-05-07 条目;工具基目录决策更新;loop/main 行数刷新。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-07 14:20:59 +08:00 |
caoqianming
|
a25fcbc703
|
精简 DESIGN/PROGRESS:对齐当前实现,去掉落地前的设想
- DESIGN.md 1140 → 212 行:删 v1/v2 比较、Eval Suite 章节、Phase
roadmap、长代码草图、技术栈清单(在 requirements.txt)、超长附录
- PROGRESS.md 185 → 82 行:删超细分的 ppt v3 描述、重复测试列表
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-06 16:26:19 +08:00 |
caoqianming
|
dbb778fe10
|
Phase 4 + 6: capability probe + task 概念 / state.json
- core/probe.py + cli.py probe: basic_chat / parallel_tools /
thinking_mode / long_context 四项实测对账 yaml;不进启动路径
- core/task.py + main.py: workspace/tasks/<id>/{state.json, messages.json},
TaskState 跟 mode/desc/status/tokens/timestamps;build_agent 返 5 元组
- cli.py tasks 子命令 + REPL /status /done /abandon /desc;chat 加
--mode/--desc 选项;移除 legacy workspace/sessions/ 兼容
Phase 5 evals 评估后决定不做:个人工具用 dogfooding 判断模型升级,
probe 已覆盖健康检查;造作 case 没区分度,维护成本不划算。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-06 16:21:17 +08:00 |
caoqianming
|
0971a500e7
|
PPT skill v3: 红色硬约束 + 品牌条 + 强制尾页 + Iconify 图标库
修复上一轮生成的实际问题: 模型擅自把红色换成蓝色 / 内页全裸白 / 缺 Q&A 尾页;
并补齐"个性化图标"能力 (此前只有 MSO_SHAPE + unicode 字形,业务概念图标缺位)。
- SKILL.md: 红色主题改硬约束 + ⛔ BLOCKING 八条对齐 (bundled 推荐, 等用户拍板),
封面/尾页改强制项, 不算在 5-8 页正文预算内
- layouts.md: 加 apply_brand(slide, kind) 4 模式品牌条 (cover/inner/section/end),
9 个版式起手必调, 消灭裸白页
- 图标库: 新增 fetch_icon.py 走 Iconify CDN (tabler/lucide/heroicons 等 150+ 集),
主题色染色, 缓存到 assets/icons/, 配 INDEX.md 推荐清单
- icons.md: 移除 MSO_SHAPE 当业务图标的部分 (PENTAGON/LIGHTNING_BOLT 等视觉陈旧),
三层降级 → 两层 (Iconify / unicode 兜底); MSO_SHAPE 退为 layouts.md helper 内部原语
- canvas_presets.md 并入 design_principles.md §0 (减少零碎文件)
- .gitignore: spec_lock.md 与根目录 *.pptx 不入库 (PPT skill 工作产物)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-06 12:23:06 +08:00 |
caoqianming
|
3a66849953
|
Initial import: zcbot personal task agent
DESIGN.md / PROGRESS.md 落地 Phase 1-3:
- core/: LiteLLM 封装 + ReAct loop + 会话持久化 + Anthropic skill registry
- tools/: read/write/edit/glob/grep/shell/run_python/load_skill (Hybrid 范式)
- skills/coding | proposal: WHY+WHAT 风格 SKILL.md
- skills/ppt: 完整渐进披露 (SKILL + 4 references + 3 scripts)
· 借鉴 hugohe3/ppt-master 的两阶段 + spec lock 思路
· MSO_SHAPE 图标体系 + 安全区 + 越界检测
· 默认商务红主题 (#C00000 / #E15554 / #FFC107)
- config/models/: DeepSeek V4 flash/pro 档案
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-06 11:02:59 +08:00 |