Commit Graph

557 Commits

Author SHA1 Message Date
caoqianming 328607671a feat(web): preview HTML and source files 2026-08-03 11:16:40 +08:00
caoqianming f217672365 feat(web): render Mermaid diagrams in chat 2026-08-03 10:26:39 +08:00
caoqianming a00ebfe50e fix(markdown): repair nested code fences 2026-08-03 10:11:25 +08:00
caoqianming a8b84b1d6f feat(web): allow attachments to start conversations 2026-08-03 09:57:21 +08:00
caoqianming b0e0182b73 fix(agent): route PDF ingestion through markitdown 2026-08-03 09:43:57 +08:00
caoqianming 8999fb1b77 fix(rendering): detect LibreOffice components 2026-08-03 09:27:30 +08:00
caoqianming 21a90cf201 fix(rendering): route PDF conversion through platform tools 2026-08-03 08:55:54 +08:00
caoqianming 75bb482015 feat(media): support GPT image output controls 2026-07-31 17:32:15 +08:00
caoqianming 59c238bd34 fix(media): use dedicated GPT image model 2026-07-31 17:01:46 +08:00
caoqianming 683bdf993d fix(web): restore conversation clearing 2026-07-31 16:37:39 +08:00
caoqianming 13e3e50371 fix(web): sort tasks by recent activity 2026-07-31 15:02:13 +08:00
caoqianming cd6a76cba9 fix(storage): 兼容消息中的 NUL 字符 2026-07-31 14:43:10 +08:00
caoqianming afdcf46577 feat(tasks): streamline task creation and embedded entry 2026-07-31 14:31:50 +08:00
caoqianming da265b88d5 fix(web): open embedded task working directory 2026-07-31 13:54:22 +08:00
caoqianming 3c022494f5 fix(web): retitle cleared conversations 2026-07-31 13:00:34 +08:00
caoqianming 59c41d22df docs(scheduler): record deferred task retention design 2026-07-31 11:31:58 +08:00
caoqianming 5c80fb202b fix(web): hide lifecycle actions for channel chats 2026-07-31 11:30:50 +08:00
caoqianming 61648f1114 Add context menus to task and file lists 2026-07-29 16:35:20 +08:00
caoqianming bcdbdd4738 Streamline conversation activity UI 2026-07-29 15:59:00 +08:00
caoqianming 02b278b175 Refine mobile conversation layout 2026-07-29 15:13:51 +08:00
caoqianming 369c74483c Refine workspace reading and mobile layout 2026-07-29 14:59:10 +08:00
caoqianming 07eba5c402 Polish web workspace visual foundation 2026-07-29 14:34:46 +08:00
caoqianming ff3bc75fed 合并工作目录新建入口 2026-07-29 14:00:04 +08:00
caoqianming 03ee37e201 改进工作目录可搜索选择 2026-07-29 13:48:16 +08:00
caoqianming d75df5a4b4 优化新对话目录选择 2026-07-29 13:38:20 +08:00
caoqianming cfc1d17af7 优化工具失败观测与重复保护 2026-07-29 09:29:44 +08:00
caoqianming 6f2840a5d0 统一运行生命周期入口 2026-07-28 15:34:42 +08:00
caoqianming 7cfeebfa89 增强消息运行可靠性 2026-07-27 17:50:31 +08:00
caoqianming 70683b7d09 增强知识库文件写入一致性 2026-07-27 16:37:56 +08:00
caoqianming ade3a847f6 Fix web search date handling 2026-07-27 12:50:07 +08:00
caoqianming c3a6f7deee Add workspace-first new conversation flow 2026-07-27 12:28:56 +08:00
caoqianming 85c918dc2f Add safe conversational workspace rename 2026-07-27 11:23:20 +08:00
caoqianming 98713bb7fa feat(seedance): support image-to-video references 2026-07-27 10:50:13 +08:00
caoqianming d4965e196c Add Codex project guidance and memory 2026-07-27 10:38:31 +08:00
caoqianming eab623d5b5 fix(web): kb 条目与单篇页补显原件文件名
已入库条目此前只把 source 用于查看/下载按钮,原件名(含后缀)无处显示。
标题后加灰色小字原件名(悬停提示同步带上),单篇页头部加「原件: xxx」,
新增 .kb-src-name 样式两处共用;不破坏单行精简版式。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 16:17:39 +08:00
caoqianming e03a1ee7eb docs: bump 0.59.4 + CHANGELOG(kb 冷启动/查看原件/条目精简)+ PROGRESS
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 15:50:05 +08:00
caoqianming 0c74a44224 style(web): kb 已入库条目精简为标题+单行摘要
- 行内去掉关键词、摘要 CSS 单行省略(原 .sk-desc 省略规则只覆盖左栏
  .sk-item,右栏 kb-entry 整段换行铺开导致每条过高)
- 完整摘要+关键词挪进悬停 title,信息不丢

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 15:45:05 +08:00
caoqianming 0ceb4c5bd9 feat(web): kb 查看原件(复用文件预览弹框)+ 预览层级抬到 modal 之上
- kb.js: 已入库条目行/单篇页/待入库列表三处加「查看原件」,直接
  openFilePreview(.kb 相对路径,与下载同通道 /v1/files/download)
- dev.html: file-preview-modal z 90→114(盖过 kb/skills/memory 等 112 层
  modal,仍低于 app-dialog 130)、fp-open chat-form 95→115、mini 96→116
- main.js: Esc 关栈顺序同步(小预览→文件预览→各 112 层 modal→选入→新任务)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 15:38:37 +08:00
caoqianming e0aa8130af fix(kb): 零库时注入冷启动契约,修「放进知识库」被误写进记忆
根因:kb_block 零库返回空串,agent 不知道 KB 机制存在,用户点名"知识库"
被就近理解成记忆写进 .memory/(真实用户事故)。与 memory 空契约常驻同一课。

- core/kb.py: 新增 _KB_COLD_START(建库步骤 + INDEX 行格式 + KB/记忆分工,
  ~百 token);kb_block 零库分支改注该契约,有库分支不变
- tests/test_kb_block.py: 锁两分支(冷启动文案/路径展示/全量 INDEX/空库)
- DESIGN.md §3.8: "有库才注入"取舍更新为冷启动注入 + 事故记录

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 15:31:50 +08:00
caoqianming 0cd5b07124 feat(web): kb 下载入口(原件+解析 Markdown)+ bump 0.59.3
- kb.js:已入库条目行「⬇ 下载原件」、单篇页头「下载原件/下载
  Markdown」、待入库列表逐项下载;复用 media.js downloadFile 走现成
  /v1/files/download(.kb 在 user_root 下,safe_join 天然放行),零后端改动
- dev.html:新按钮三行 CSS(hover 淡入同删除按钮、待入库行间距)
- 弃选:kb 专属下载端点(与 files 下载重复,公测期白养对外契约)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 21:33:23 +08:00
caoqianming 8751f71f5a feat(web): 移动端对话附件入口(拍照/照片库/选文件)+ bump 0.59.2
chat 输入区此前仅粘贴/拖拽两条附件路,移动端双双不可用。加 [附件] 按钮:
触屏弹三项菜单(拍照 capture=environment / 照片库 accept=image,video /
选取文件无 accept),桌面端直开文件选择器;三入口 change 统一走既有
uploadAttachFiles 链路,只读镜像随 applyChannelComposerLock 禁用。
纯前端改动,无后端/schema 变化。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 14:49:16 +08:00
caoqianming 1332139c9e docs: bump 0.59.1 + PROGRESS 汇总 15 commit 重构 + DESIGN §2 架构树同步
- core/__init__.py 0.59.0 → 0.59.1(patch:全部内部重构/测试/修复,对外行为零变化)
- PROGRESS:07-23 条目(七项重构 + 2 bug + 测试 286→351 + 测试库基建)、
  文件清单刷新(loop/llm_transport/tool_registry/storage 三分/web routers 布局)、
  最后更新行
- DESIGN §2:架构树补 llm_transport/tool_registry/storage 三分/web 拆分后布局
  (实施后与代码偏离,按「同步改回」条款修正);CHANGELOG 按「纯内部重构/修复
  不记」规则不动

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 14:29:19 +08:00
caoqianming bcd2b90942 refactor(storage): 失败埋点拆出 telemetry.py + kind 契约常量化;补 wecom 加解密测试
收官三小项(架构审查残余):

- core/storage/telemetry.py:四个留痕函数(malformed/salvaged/empty/run_error,
  cost 恒 0)从 usage.py 迁出——「usage=计费」心智不再被埋点污染(数据层 Top4);
  kind 字符串升为常量,loop/llm_transport(写)与 toolfail(读 SQL)两侧共用
  同一事实源,此前靠字面量约定、改名会静默漏读。core.storage.__init__ 转发
  出口不变,调用面仅 web/runs.py 一处改 import
- tests/test_wecom_crypto.py:7 用例,企微回调加解密(WXBizMsgCrypt 等价实现)
  测试侧按同方案自造密文,覆盖验签/receiveid/padding 各失败路径——wechat 子系统
  (审查 Top3 零测试)中唯一可纯测的一块补上
- DB 测试探针补 connect_timeout=5:测试库挂掉时快速降级 skip,不再把整个
  discovery 挂死在 TCP 建连上(Docker engine 打嗝时实测挂死过)

带测试库 351 全过 / 无测试库 341 过(DB 组干净 skip)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 14:21:45 +08:00
caoqianming fd79edb344 test(web): DB 面路由测试(tasks CRUD/files DB-aware/upload)+ 修 restore 500
测试库基建落地(docker postgres:16-alpine @5433 + migration 0001-0022,
RUN.md 补一键命令),tests/test_web_routes_db.py 10 用例补齐 nodb 套件留待面:
- tasks CRUD 全链:建(默认模型/working_dir)/列(分页壳)/详(上下文压力
  字段)/PATCH 校验/软删→列表消失→恢复/同 wd 共享 + folders 计数
- files 顶层目录 DB-aware(§7.4):rename 级联改 tasks.working_dir(tasks_
  updated=1 且 DB 生效)、running→409、move 被引用→409、递归删被引用→409、
  软删 task 后放行
- upload 配额 gate 路径 + 根目录列表(system_wd_names)+ 非法文件名 400
- clear/cancel 状态闸、models 档位列表、schedules 404 路径

修 bug(本套件抓出的存量缺陷,重构前即有):POST /v1/tasks/{id}/restore
用 ORM 脏标记恢复,updated_at 是 server-side onupdate,flush 后列被标记
expired,session 关闭后序列化读它抛 DetachedInstanceError——真软删过的
任务恢复必 500(幂等路径无脏标记故此前未暴露)。修法:flush+refresh 后
在 session 内完成 task_dict 序列化。

带测试库全量 344 全过;未设 ZCBOT_TEST_DB_URL 时干净 skip;测试库零残留。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:50:57 +08:00
caoqianming 0d34141527 test(web): 路由级测试首批(无 DB 面)——鉴权门全覆盖 + kb/skills/memory/files FS 路径
拆分 router 后的接线回归(审查 Top1 风险面此前零路由测试):
- 公开端点:/healthz、/v1/changelog(limit clamp)、/ 302
- 鉴权门:11 个 router 的 19 个代表端点无 token 一律 401(哪个模块漏挂
  Depends(require_user) 当场红);坏 token 401、坏 platform_key 403、
  user_id 非法 400(落库之前拦下)
- FS 类业务:kb 建/详/删/非法名、skills 列/详/内置不可删、memory 只读+穿越
  404、files 子目录列/下载/越界 400/非顶层改名/拷贝 409 预检/删文件/非空目录 400
- 隔离:JWT 与 app 同源 env 直签(不假设 key 值,兼容 litellm dotenv 抢先加载);
  随机 user_id 子树 teardown 整树删;TestClient 不进 with(不跑 lifespan 不碰 DB)
- 顶层目录 DB-aware 分支与 upload 配额留给 ZCBOT_TEST_DB_URL 套件

334 测试全过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:34:07 +08:00
caoqianming 21e7dad7f1 refactor(rendering): 块收集器与 inline 切分下沉 common——golden 零 diff 验收
审查 P1:docx_brief 与 docx_manuscript 的 render_md_block 各手写一套块级
扫描,同一 md 走两条路径最易漂移。按「分派语义留 profile、边界收集归 common」
拆分:

- common 新增 gather_fence(闭合判据单一事实源)/ gather_table /
  gather_blockquote / gather_paragraph(软换行并合,is_list 谓词注入)
  ——此前两份逐字拷贝的循环全部换成共享调用
- brief 的 add_inline_rich 手写 INLINE_RE 循环换 common.parse_inline 迭代
  (与 manuscript 同一切分事实源);brief 差异收敛到 plain 段处理
  (引文上标 + 化学式)一处
- 刻意不动:分派顺序与 brief 状态机(in_refs/expect_meta/in_tldr 会改变块
  边界语义,是 profile 的产品行为不是重复)、各 profile 样式

验收:golden 基线(上一提交)逐字节零 diff;319 测试全过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:27:31 +08:00
caoqianming 035aec44ac test(rendering): golden 基线——四 profile 渲染富 fixture,docx XML 逐字节对账
给 md 解析路径的后续重构上硬闸(§8.6 当年"前后字节一致"验收的固化):
- fixture 覆盖信息带/TL;DR 卡/判断 callout/blockquote/表格/代码块(含 mermaid
  回退)/缺图占位/四类列表/参考文献 DOI·URL 条目/相邻引文上标/化学式/软换行
  并合/refs 段外 [n] 行等全部分支
- 对账面 word/document.xml + footer*.xml(无时间戳,确定性已验证:连续两次
  渲染逐字节一致);core.xml 元数据刻意不比
- 5 份 golden(brief 彩/黑白、paper zh、proposal、report+toc);有意变更走
  ZCBOT_REGEN_GOLDENS=1 重生成并在 commit 里说明,重构类改动必须零 diff

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:24:26 +08:00
caoqianming 5a5ebfbe24 refactor(tools): 输出处理原语移出 base.py——base 只留 Tool 基类与路径边界
compact_tool_output / format_timeout_result 是「工具输出处理」关注点,与
Tool ABC / FileOutOfBounds 路径安全混装在 base.py(审查小项)。析出
tools/output.py,8 处引用(5 工具 + executor_docker + 2 测试)同步改。
318 测试全过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:15:04 +08:00
caoqianming 8038fb7491 refactor(tools): 媒体工具同构析出 tools/media_common.py + 17 个单测
审查 P1#6:seedance/seedream/gpt_image/look_at_image/read_document 五处
同构(逐字或参数化后逐字)收敛为共享原语:

- quota_gate(每日配额闸,文案逐字保持)/ stamped_path(<ts>-<rand6> 落盘
  命名+建目录)/ write_meta(.meta.json)/ record_usage_safe(记账失败不
  阻塞)/ ark_chat_with_retry(超时透明重试,业务错误不重试)/
  extract_chat_answer(chat 文本+截断标志)/ find_first_url(递归找 URL,
  accept 谓词覆盖 seedance 的 video_url 优先语义)
- 五工具各自的 banner 格式 / body 组装 / seedance 轮询刻意保持不动
- tests/test_media_common.py:17 个纯函数/打桩单测(配额文案、重试次序、
  业务错误不重试、视频 URL 谓词等)

318 测试全过;真实配置冒烟 32 工具挂载不变、schema 完整。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:10:32 +08:00
caoqianming 7568ceeb48 test(scheduler): 补 core/scheduler 服务层测试(审查 Top3 缺口)+ DB 测试门控收紧
- tests/test_scheduler.py:纯逻辑(cron 校验/next_run 墙钟时区折算/run message
  包装)+ DB 级(create 校验、claim 推进 next_run 不重复认领、disabled/软删/
  过期不认领、连续失败自动停用、skipped 不动计数)。认领类用例统一用 2000 年
  纪元时间,claim_due_jobs(now=纪元) 只可能命中测试 job,永不触碰真实 job
- **DB 测试门控收紧(test_scheduler + test_usage_report)**:只认显式
  ZCBOT_TEST_DB_URL,绝不回退 .env 的 ZCBOT_DB_URL —— 实锤教训:.env 的 URL
  经隧道指向生产库,测试插入的到点 job 被生产 green 实例调度守护认领并真跑了
  agent(4 次一句话迷你调用,费用几厘,产物已按测试专属 user 全量清理,零残留)
- RUN.md:环境段补 ZCBOT_TEST_DB_URL 说明,故障兜底表加一行

301 测试全过(未设测试库时 DB 组自动 skip)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:00:13 +08:00