Commit Graph

5 Commits

Author SHA1 Message Date
caoqianming 7d6109b932 feat(delegate): §8.11 最小子循环——上下文隔离的检索子助手(bump 0.58.30)
触发条件已满足(diag_tool_repeat.py 实测 document_search 122 次地毯搜 /
mp_search 562 次占主上下文大头)。形态 = 一个工具 delegate(instruction):
复用现成 AgentLoop 起空上下文子循环,只注只读/落盘检索白名单,硬轮数上限 20,
固定降 flash 档,跑完只把文字结论返主循环。主循环视角 = 一次普通 tool call
(零并行/零状态共享/深度 1 禁递归)。

对标 Claude Code / Agent SDK subagent:照抄 fresh-context / allowlist 工具 /
只返回最终消息 / maxTurns;有意砍掉并行与嵌套(§6 拒编排),采纳 per-subagent
模型 override 思路(降 flash)。

实现:
- core/delegate.py(新):DELEGATE_ALLOWED 白名单 + FilteredExecutor(包父
  executor 只暴露白名单∩已注册,backend 无关、delegate 不入表天然禁递归)+
  run_delegate(懒加载 AgentLoop 避 litellm 导入/循环 import)
- tools/delegate.py(新):DelegateTool schema 载体,execute 防御性 no-op
- core/loop.py:_run_delegate + _execute_tool_call 内建拦截(拦在 executor 前,
  要读活的 self.llm/caps/executor)+ usage_kind(记账 kind 区分)+
  delegate_model_factory(降档失败降级父模型)+ 内存态子循环禁折叠守卫
  (防 persist_fold 按主 task_id 污染主上下文状态)
- core/session.py:persist=False 内存态(复用主 task_id 计费归主 task、
  消息不入库不污染主流不撞 idx)
- core/agent_builder.py:注册工具 + _delegate_model 工厂(载 deepseek_v4.flash)

落地决策:① 白名单给"落盘检索"(document_download/mp_get_*)写口、不给
write/edit/run_python/shell;② 不引 Redis 抗重启(run 本进程绑定,值钱抓取数据
已落 FS,真要抗重启走 §8.12 bg-proc);③ 未收敛显式标注不当完成。

前端零结构改动(既有工具卡 spinner+跳秒覆盖不冻屏),只加 toolActivityLabel 的
delegate case。skills/brief 加 delegate 引导。tests/test_delegate.py +8
(FilteredExecutor 过滤/拒穿透/交集 + 白名单不变量 + Session persist);loop 全
路径要 litellm 本机跑不了靠生产手验(同 salvage)。DESIGN §8.11 标 。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:43:04 +08:00
caoqianming d3bd40fad7 fix(web): 对话正文文件锚点两处回归——含·的 pptx 丢 chip + 链接点击整页404(bump 0.58.29)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:40:12 +08:00
caoqianming 4a591e1a90 fix(web): 历史消息丢图片预览/chip——taskMeta 竞态 + 中文路径抽取(bump 0.58.17)
两根因:
1. selectTask 并发化(0.12.16)后 renderMessages 在 Promise.all 内执行,
   state.taskMeta 必然还是旧值/null → wd 错 → chip+inline 图整体丢失。
   loadMessages 加 {render} 开关,首屏渲染延后到 taskMeta 赋值后(零额外 RTT)。
2. extractArtifactRels lead 边界不认汉字("已保存到<wd>/xxx.png"不命中),
   tail 会把紧贴的中文标点连后文吞进文件名。lead 改任意非 [A-Za-z0-9._-],
   tail 排除集抽 _TAIL_CLS 常量补中文标点(主规则+legacy 双处)。

node 离线回归 12 用例全绿;CHANGELOG 面向用户补记。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 10:29:23 +08:00
caoqianming 5a8f5bd930 feat(media): 第二图像后端 gpt_image(unifyllm 网关,pro 档)(bump 0.58.0)
- config/media/unifyllm.yaml + tools/gpt_image.py:仅 prompt 参数(网关忽略
  size/quality,尺寸上游自动定,不支持 i2i),b64 直落 figures/,banner 协议
  同 seedream,价目未知期 cost 记 0、usage tokens 进 units 留对账
- 媒体装配泛化:ArkConfig 通用键名(api_key_env/base_url,ark_* 兜底);
  _choose_image_variant 跨 provider 选 image variant(默认仍 seedream_5,
  本 run 只挂一个图像工具);_MEDIA_TOOLS_BLOCK 拆分段按实挂工具拼装
- web:_list_media_variants 扫 config/media/*.yaml(image/video 清单 +
  admin 门控 catalog);media.js 三处白名单加 gpt_image;prompt 润色 hint
  无 default_size 不再谎报 2048
- gpt_image 进 pro 档,与 seedream 共享 images_per_day 配额
- 手工验证 scripts/test_gpt_image_manual.py 全过(含真调网关落图),
  unittest 201 过

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:47:06 +08:00
caoqianming e5940266ca refactor(dev): 前端模块化 Step 2 — 抽出 media.js + 收敛 downloadFile 反向依赖
对话内工具活动标签 + artifact(产物)抽取/渲染:toolActivityLabel /
extractArtifactRels / extractMediaBanner / renderArtifactBarHtml /
upgradeMediaArtifacts / downloadFile → media.js(237 行,原 main 1134–1359)。

收敛点:downloadFile 移入 media 后,preview.js / files.js 对它的 import
从 ./main.js 改指 ./media.js —— 把这条反向依赖从 main 挪开。media 导入极少
(escapeHtml / _categorize(preview)/ state / logout),与 preview 成
media↔preview 环(均运行时调用,安全)。

两次险漏靠校验抓回:
- 共享 const ARTIFACT_PRODUCING_TOOLS(main renderMessages/SSE 用 4 处,
  .has() 访问非函数调用,"被调标识符"法漏掉)
- 内部函数 _flushMediaArtifactCache(selectTask 切任务清缓存用)
两者经残留符号检查发现后补 export。

新增全模块 import/export 一致性校验脚本(每个 import{X} 必在目标 export),
11 模块全过。main.js 删至 1393 行。node --check 11 模块全过、静态测试 2 过。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:05:48 +08:00