From 1332139c9e4e275c03083668324bf6da42bffb6a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 23 Jul 2026 14:29:19 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20bump=200.59.1=20+=20PROGRESS=20?= =?UTF-8?q?=E6=B1=87=E6=80=BB=2015=20commit=20=E9=87=8D=E6=9E=84=20+=20DES?= =?UTF-8?q?IGN=20=C2=A72=20=E6=9E=B6=E6=9E=84=E6=A0=91=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- DESIGN.md | 16 ++++++++++------ PROGRESS.md | 23 +++++++++++++++-------- core/__init__.py | 2 +- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index aa19e67..8e5f153 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -21,7 +21,9 @@ zcbot/ ├── core/ │ ├── capabilities.py # ModelCapabilities,从 yaml 加载 │ ├── llm.py # LiteLLM 封装,按 capabilities 自动启 features -│ ├── loop.py # ReAct 主循环 + 协作式 cancel +│ ├── loop.py # ReAct 主循环 + 协作式 cancel(控制流) +│ ├── llm_transport.py # wire 层健壮性:畸形/吐空检测+留痕+非流式降级重试(自 loop 析出) +│ ├── tool_registry.py # 声明式工具注册表((组名,gate,factory);§7.5 #7 代码强制) │ ├── probe.py # 真实探测对账 yaml 声称的能力 │ ├── session.py # 消息列表 + meta,落 PG │ ├── skills.py # SkillRegistry(渐进披露,多来源) @@ -29,18 +31,20 @@ zcbot/ │ ├── memory.py # per-user .memory/ 双层记忆 │ ├── shortcuts.py # 快捷指令(入口层确定性展开) │ ├── paths.py # task_dir db form 归一 -│ ├── storage/ # SQLAlchemy 2.x ORM -│ ├── scheduler.py # 定时任务(§8.5) +│ ├── storage/ # SQLAlchemy 2.x ORM;usage(计费写)/telemetry(失败埋点)/usage_report(聚合读)三分 +│ ├── scheduler.py # 定时任务服务层(§8.5;执行引擎在 web/scheduler_runner) │ ├── wechat/ # 渠道:ilink / wecom / service / inbound(§8.7) │ ├── sandbox/ + executor*.py # Executor ABC + Docker per-user 容器池(§7.5) │ └── agent_builder.py # 装配 lib:build_agent / system prompt -├── tools/ # fs / shell / run_python / skill / 媒体 / 检索 / host-side 域工具 +├── tools/ # fs / shell / run_python / skill / 媒体(共享原语 media_common)/ 检索 / host-side 域工具 ├── skills// # SKILL.md + references / scripts / assets -├── rendering/ # 平台渲染层 md→docx/pdf(§8.6) +├── rendering/ # 平台渲染层 md→docx/pdf(§8.6;块收集器/inline 切分单一事实源在 common) ├── prompts/system/general_v1.md ├── config/{agent.yaml, models/*.yaml, media/*.yaml} ├── workspace/users//{.memory/, .skills/, /} -├── web/{app.py, auth.py, admin.py, broker.py, sinks.py, static/} +├── web/ # app.py=工厂+lifespan 编排;routers/*(11 路由模块,register 范式); +│ # background/scheduler_runner/wechat_runner(后台协程);runs(BG worker) +│ # + auth/admin/broker/sinks/common/schemas/model_gate/userfiles/static/ ├── db/migrations/ # alembic └── main.py # 入口:web / db / probe / user ``` diff --git a/PROGRESS.md b/PROGRESS.md index 88776e9..4847011 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-07-21(扫描件 PDF 直读 read_document:方舟文档理解 base64 内联,markitdown 死路补位,bump 0.58.55) +最后更新:2026-07-23(架构审查落地:15 commit 内部重构大扫除 + 测试 286→351 + 测试库基建,bump 0.59.1) --- @@ -23,6 +23,7 @@ ### 2026-07 +- **07-23 / 0.59.1 / 架构审查落地:15 commit 内部重构大扫除(对外行为零变化)**:全库审查(web/核心循环/工具渲染/数据层四路并行探查)后按优先级逐项执行。①**web 拆分**——app.py 3972→197 行:73 路由迁 11 个 `web/routers/*`(register 范式同 admin.py),lifespan 后台协程按域析出(`background`/`scheduler_runner`/`wechat_runner`),schemas/model_gate/runs/userfiles/common 各归位;②**计费收口**——units JSONB 读侧唯一出口 `core/storage/usage_report.py`(web 层清零 cast),写侧拆 `telemetry.py`(四类 cost=0 留痕与真计费分家,kind 常量成 loop↔toolfail 契约单一事实源);③**loop 拆分**——传输健壮性层(畸形/吐空检测、留痕、非流式降级重试)析出 `core/llm_transport.py`(loop 1158→812),`_execute_tool_call` 148 行拆 4 个正交方法,测试打桩缝(`_collect_stream_once`/`_nonstream_once`)原样保留;④**工具注册声明式化**——`core/tool_registry.py` (组名,gate,factory) 表收敛四种 env-gate 写法(§7.5 #7 获代码强制),32 工具挂载逐名比对不变;⑤**媒体工具去重**——五工具同构(配额闸/落盘命名/记账兜底/超时重试/递归找 URL)收 `tools/media_common.py`,净减 122 行,banner/轮询等刻意差异不动;⑥**渲染统一**——块收集器(fence 闭合/表格/blockquote/段落并合)与 brief inline 切分下沉 `rendering/common`,**golden 基线**(四 profile 渲富 fixture、document.xml 逐字节对账,`tests/golden/`)零 diff 验收,分派状态机(in_refs 等)留 profile;⑦**测试 286→351**——scheduler 服务层、usage 口径、media 原语、wecom 加解密(自造密文覆盖失败路径)、路由两套(无 DB 面:11 router 鉴权门 19 端点 + kb/skills/memory/files FS;DB 面:tasks CRUD 全链 + files 顶层目录 DB-aware 四分支 + upload);测试库基建 = docker PG@5433 + `ZCBOT_TEST_DB_URL` 显式门控(RUN.md 一键命令)。**修 2 个真 bug**:restore 恢复真软删过的任务必 500(server-side onupdate 列 flush 后 expired → DetachedInstanceError,幂等路径掩盖多时,路由测试抓出);DB 测试曾沿 .env 连到生产隧道(127.0.0.1:6012)——插入的到点 job 被生产 green 调度守护真跑,门控收紧为只认 ZCBOT_TEST_DB_URL + connect_timeout=5 兜挂库,产物已全量清理。附带:scripts 50→29(已结案诊断/backfill 归档 `scripts/archive/`)、`tools/output.py`(输出处理自 base.py 析出)、export_docx 复用 rendering.common 字体助手(rendering 保持无 core 依赖的沙箱可用性,修正审查"迁 rendering"建议)。 - **07-22 / 0.59.0 / 个人知识库(纯文件 .kb/ 机制,照记忆范式)**:方案 07-22 对齐后落地(DESIGN §3.8)。**core**:`core/kb.py`(状态/视图层:库名与文件名校验、INDEX 单行格式 `- [标题](docs/x.md)|来源 sources/x.pdf|摘要:…|关键词:…` 的 parse/format、"已入库判据 = INDEX 有条目"派生 pending、删单篇连带原件与 INDEX 行、`kb_block` 注入)+ `core/kb_ingest.py`(入库管线:markitdown Python API → 扫描件 PDF 文本近零走方舟 OCR 兜底(§8.13 同通道)→ flash 单次 chat 写标题/摘要/关键词(失败降级不阻塞)→ 追加 INDEX;编排 create_task+to_thread+per-(user,库) 锁,进度内存态供轮询)。**记账**:0022 迁移放宽 `usage_events.task_id` 可 NULL(kb 入库无 task 上下文),溯源 = kind="kb_ingest"/"vision" + units `{"kb","source"}`(record_chat/vision_usage 签名同步放宽)。**API**:`/v1/kb*` 8 端点(列/建/删库、详情带入库进度、上传即入库、手动 ingest、看/删单篇),不设 HTTP 检索端点。**agent 侧零新工具**:agent_builder 在 memory_block 后注 `kb_block`(有库才注,docker/host 路径换算同 .memory);documents skill「何时不用」补自建资料路由行。**前端**:`kb.js` 两栏 modal(建/删库、上传 XHR、入库进度 3s 轮询、看/删单篇),rail 底部四按钮改图标+小字两行布局(用户 07-22 定)。冒烟:core 层 28 项全过(真实 markitdown + flash 摘要),TestClient API 15 项全过(usage 行实测 task_id=NULL + units 溯源),受影响存量测试(usage_accounting / system_prompt_paths)绿。 - **07-21 / 0.58.55 / 扫描件 PDF 直读(read_document,方舟文档理解)**:markitdown 只抽文本层,扫描件(老标准/检测报告/红头指南)转出为空=死路。探针(`scripts/probe_ark_doc.py`)验证方舟 chat file 内容块直读 PDF:格式 `{"type":"file","file":{filename,file_data}}` + `data:application/pdf;base64,` 前缀、base64 内联 17MB 可用(免 TOS)、单页栅格化 3600 万像素硬限(PIL 存 PDF 需标对 dpi)、~1300 输入 token/页(约 1 厘/页)、100 页魔术串全覆盖。落地 `tools/read_document.py`(seed_2_lite 同 variant 同 key,记账走 record_vision_usage):体积/页数双闸(30MB/100 页,pdfminer 软探页数免白付撞上下文)+ `finish_reason=length` 截断提示 + **多页 OCR `save_md` 全文落盘只返 1500 字预览**(防上下文爆);`image_ref.py` 抽 `load_pdf_as_data_url` 复用三形态路径解析与 user_root 边界。agent_builder 注册 + 系统提示 `_MEDIA_READDOC_SEG`(何时调/何时不调防重复花钱);六 skill(paper/patent/standard/proposal/rebuttal/ppt)摄取段加扫描件兜底一行。冒烟 `scripts/smoke_read_document.py` 全过(3 页 ¥0.0066,表格→md 表、公式→LaTeX)。选型对比(外部解析 API=新增第三方数据面 / 本地 OCR=过度投资)见 DESIGN §8.13。host 侧工具,**无需重建沙箱镜像**。 - **07-21 / 0.58.55 / 长对话点目录圆点首次跳不到位修复**:根因链=loadMessagesAround 后 renderMessages 尾部无条件滚底钉到窗口末尾,底部 sentinel 入视口立刻触发 loadNewerMessages 整窗重渲染删掉平滑滚动目标。修:renderMessages 加 stickBottom 参数(三个调窗口路径传 false);jumpToMessage 重建窗口后瞬时定位(auto)不留动画窗口期;`_msgScrollObserver` 在 `_outlineJumpLock` 期间不补载、解锁时对 sentinel 重投交叉状态。 @@ -218,7 +219,9 @@ ``` core/capabilities.py 75 ← 模型档案增加 CNY/Mtok 计费兜底字段 core/llm.py 151 ← litellm 离线 cost map env + chat_stream(stream + include_usage) -core/loop.py 300 ← sink.emit + _stream_llm(chunk 间 poll cancel + emit delta)+ _RepeatGuard + usage cache 明细 +core/loop.py 812 ← ReAct 主循环:_RepeatGuard/stall 熔断/热切编排(传输健壮性层已析出) +core/llm_transport.py 438 ← wire 层健壮性:畸形/吐空检测+留痕+非流式降级重试(07-23 自 loop 析出) +core/tool_registry.py 242 ← 声明式工具注册表((组名,gate,factory);secret 工具 env-gate 代码强制) core/context.py 95 ← LLM 调用前压缩旧 tool / load_skill 消息(带压力门槛),保 tool_call 协议字段 core/sinks.py 101 core/paths.py 50 ← task_dir db form 归一 @@ -230,22 +233,26 @@ core/memory.py 81 ← per-user `.memory/` dotfile core/kb.py ~260 ← per-user `.kb/` 个人知识库(状态/视图/kb_block 注入) core/kb_ingest.py ~280 ← kb 入库管线(markitdown→OCR 兜底→flash 摘要→INDEX) core/export_docx.py 383 -core/storage/{__init__,engine,models,usage,utils}.py ← 4 表(0004-0007 演进);record_chat/image_usage +core/storage/{engine,models,usage,telemetry,usage_report,utils}.py ← 计费写/失败埋点/聚合读三分(07-23) core/ark_client.py 105 ← 火山方舟 HTTP 客户端 core/asr_xfyun.py 170 ← 讯飞语音听写 IAT wss 客户端(整段 PCM→文本;web 语音输入用,diag: scripts/diag_asr.py) core/asr_lfasr.py 250 ← 讯飞录音文件转写 LFASR 客户端(异步订单 + 说话人分离;transcribe_audio 工具底座,diag: scripts/diag_lfasr.py) -core/agent_builder.py 340 ← 装配 lib(有 ARK_API_KEY 才挂 SeedreamTool);build_skill_registry 装两来源 +core/agent_builder.py 649 ← 装配 lib:build_agent/system prompt(工具注册块已迁 tool_registry) core/executor.py / sandbox/{network,pool}.py / executor_docker.py ← Executor ABC + Docker per-user 容器池 -tools/{base,fs,shell,run_python,skill_tool,skill_authoring,seedream,seedance,look_at_image,read_document,image_ref,web_search,web_fetch,documents,materials_project,transcribe_audio}.py ← read_document=扫描件 PDF OCR(方舟文档理解);image_ref=图/PDF 路径解析+base64 共享 +tools/{base,output,fs,shell,run_python,skill_tool,skill_authoring,media_common,seedream,seedance,gpt_image,look_at_image,read_document,image_ref,web_search,web_fetch,documents,materials_project,transcribe_audio}.py ← media_common=媒体五工具共享原语;output=输出压缩/超时结果(自 base 析出) main.py ~210 ← 入口:web / db / probe / user / sandbox check db/migrations/versions/ 0001-0022 -web/app.py ~1360 ← /v1 JSON API + user_id 隔离 + run lock + cancel + files + pptx 预览 + skills(列表/正文/删) +web/app.py 197 ← 工厂 + lifespan 编排(07-23 拆分;路由在 routers/,协程在 background 等) +web/routers/*.py 11 个 ← misc/models/authroutes/wechat/kb/schedules/skills_memory/files/asr/tasks/messages +web/{background,scheduler_runner,wechat_runner}.py ← lifespan 后台协程按域析出 +web/{runs,common,schemas,model_gate,userfiles}.py ← BG worker/共享 helper/请求体/档位门控/路径安全 web/auth.py ~190 ← 邮箱密码 + platform_key → JWT -web/broker.py / sinks.py / pptx_render.py +web/broker.py / sinks.py / pptx_render.py / admin.py web/static/dev.html + js/*.js ← dev SPA 零构建 ES module(main.js 入口;skills.js=技能 modal;kb.js=知识库 modal) web/static/vendor/ ~1 MB ← jszip / docx-preview / xlsx +tests/ 351 项 ← golden/rendering 基线 + 路由两套(nodb/db)+ DB 套件(ZCBOT_TEST_DB_URL 门控) ───────────────────────────────── -Python 合计 ~3400 行(+ dev SPA + vendor 1MB);加 skills 脚本 + 配置,总仓库约 3800 行 +Python 合计 ~5.5 万行(core+web+tools+rendering+tests+scripts;+ dev SPA + vendor 1MB) ``` --- diff --git a/core/__init__.py b/core/__init__.py index 3a09de4..ab696c1 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.59.0" +__version__ = "0.59.1"