Commit Graph
9 Commits
Author SHA1 Message Date
thzxx a7090214b1 fix: v0.6.2 修复工具调用不稳定与会话停止 — 纯 tool_calls 轮丢失 assistant 消息导致 API 400
CI / 类型检查 + Lint + 单元测试 (push) Failing after 5m43s
CI / 全量测试 (Electron ABI) (push) Failing after 5m20s
CI / 产物编译验证 (push) Successful in 10m5s
【根因(main.log 实证)】
19:04 / 19:05 / 19:06 三次会话终止均为同一报错:
  DeepSeek 400 "Messages with role 'tool' must be a response to a preceding
  message with 'tool_calls'"

缺陷链:engine 主循环仅在 step.thought 存在(该轮有文本或思考内容)时才
将 assistant 消息加入请求历史。当模型发起纯工具调用(零文本零思考 —
DeepSeek 高频行为)时:
  - assistant(tool_calls) 消息不进 messages
  - 但 tool 结果消息照常 push
  → 下一轮请求出现孤立 tool 消息 → 协议 400(不可重试)→ 会话 ERROR 终止
"不稳定" = 模型每轮是否附带文本是概率性行为:带文本正常,纯调用必崩。
DB 持久化侧同源缺陷(if (!step.thought) continue)导致这些步骤的
assistant 与 tool 结果全部不落库 — 重启后工具上下文丢失,模型重复调用。

【修复】
- engine.ts: 有 toolCalls 的轮次必 push assistant(content=null,C-6 规范)
- agent.ts: 持久化条件同步修复(无 thought 但有 toolCalls 的步骤落库)
- 回归测试: 纯 tool_calls 轮后第二次请求中 tool 消息前必须是带
  tool_calls 的 assistant(请求契约断言,engine-toolchain.test.ts)

【纵深防御 — 孤立 tool 消息过滤】
- openai-format.ts(DeepSeek/Agnes/MiMo/OpenAI 四家共享): 构建请求时
  按 tool_call_id 配对过滤孤立 tool 消息(任何来源的历史污染不再 400 死锁)
- anthropic.adapter.ts: tool_use/tool_result 同策略配对过滤
- 单测 ×6: 正常配对保留 / 孤立丢弃 / id 不匹配丢弃 / 多轮配对 /
  includeImages 原位转换 / 非 vision 静默丢弃

【多模态索引对齐收敛】
4 家 adapter 的 images 处理循环原按未过滤的 nonSystemMsgs[i-1] 对齐索引,
孤立 tool 过滤引入后会错位 — 统一收进 buildOpenAICompatibleMessages
(includeImages 参数,基于 sanitized 序列原位转换),4 家 adapter 删除
各自的索引对齐循环(DeepSeek vision 判断 / OpenAI 推理模型拒绝保留在 adapter)。

【终止原因可见化】
MAX_ITERATIONS / TIMEOUT 终止此前无任何提示(用户感知"会话直接停止")—
前端 DONE 事件非 completed 终止原因显示为 system 消息。

【v0.6.1 回归缓解】
web_fetch timeoutMs 120s → 240s:浏览器回退串行化后并发 3 个排队最坏
~127.5s,旧值让排队末位抓取被工具超时杀掉(表现为抓取不稳定)。

【验证】
lint 0/0;typecheck 双工程 0 错误;test:electron 259/259(+7);
electron-vite build 成功
2026-08-22 19:34:16 +08:00
thzxx 22028c91c3 fix: v0.5.5 全量复检修复 — 图片 token 估算缺失(压缩预算失真)+ 过时文案清理
CI / 类型检查 + Lint + 单元测试 (push) Failing after 5m41s
CI / 产物编译验证 (push) Successful in 10m6s
CI / 全量测试 (Electron ABI) (push) Failing after 5m21s
背景:v0.5.4 多模态增强(多轮图片记忆 + 总开关 + DeepSeek vision)发布后的
全量全方位复检,重点核查新增功能的跨模块边界。

复检通过项(无回归确认):
- 多轮图片记忆 × 五家 adapter:Anthropic(base64 块)/ OpenAI(image_url
  parts)/ Ollama(纯 base64 数组)/ Agnes / MiMo 均正确处理恢复的历史 images
- 多轮图片记忆 × 引擎运行时压缩:摘要请求仅含文本(图片不进摘要调用);
  toKeep 消息的 images 原样保留;孤立 tool 消息配对逻辑不受影响
- 多轮图片记忆 × 摘要服务:maybeSummarize 用截断文本 transcript,无图片干扰
- history 组装 slice(0,-1) × 图片恢复无冲突(当前消息 images 走独立通道)
- 编辑重发/重新生成路径与图片恢复同源(attachments.preview),行为一致

修复项:
- P1 token 估算器完全忽略 images(estimateMessagesTokens):
  带 10 张图的消息被按纯文本估算。影响:压缩 keepBudget 严重低估 →
  压缩后实际 token 仍超 80% 阈值 → 反复触发压缩循环(每轮多一次 LLM
  摘要调用);上下文占用显示严重失真。修复:每张图按 1000 tokens 计入
  (1024px 压缩图在主流 Provider 约 700~1500 视觉 token,取保守上界)
- 文案清理:ChatInput 附件按钮 Tooltip 硬编码"DeepSeek 不支持图片"改为
  按拒绝原因区分(开关未开启 vs 当前模型不支持);openai-format.ts 共享层
  注释更新(DeepSeek vision 已支持,非 vision 模型才丢弃)

测试(243 → 245 用例):
- 新增 token 估算图片用例 ×2:带 images 消息按每张 1000 tokens 计入 /
  无 images 字段消息行为不变(向后兼容)

验证: lint 0 / typecheck 双工程 0 / test:electron 245 全过 / build 成功
2026-08-21 23:09:36 +08:00
thzxx 2c2ca4a692 feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端) 2026-07-22 10:31:13 +08:00
thzxx ceb8ee644d feat: 升级至 v0.3.7 — 前后端状态同步与错误处理全量修复
核心引擎修复:
- CE-1: 上下文压缩摘要 role 从 system 改为 user,避免被 adapter 过滤
- CE-2: 工具失败时优先使用 error 字段(engine/openai-format/ollama 三处)
- P0-1: DeadLoopError 终止时正确传 error 参数,前端可见 ERROR 事件
- MT-1: 新增 waitForAbort 方法,abortSession 等待 run 结束再返回
- MT-2: TERMINATED 状态到达时标记步骤完成,避免 Trace Viewer 转圈
- MT-3: 压缩边界检测孤立 tool 消息,避免 API 400 错误
- isRetryableError 与 catch 分支统一 toLowerCase

IPC 与主进程修复:
- P0-2: createAdapter 配置缺失返回 null,FALLBACK_ADAPTER 兜底
- P0-3: reloadAdapter 失败返回 success:false 通知前端
- P1-5: 校验失败发 ERROR+DONE 流事件,防止 isStreaming 卡死
- P1-6: configLoaded 标志,配置加载前禁用发送按钮
- P1-7: MCP initialize 移到 agentLoop 后,完成后同步工具
- P2-11: beforeLoad 在 loadURL 前注册 IPC handler
- P2-12: provider 切换竞态保护

前端状态同步修复:
- clearSessions 后同步清空前端会话与消息状态
- clearMemories 通过 memoryVersion 触发 MemoryViewer 重新加载
- ContextMenu 4 个 session 操作补全 IPC 调用与 try/catch
- useConfig 配置保存失败回滚 UI 并提示
- handleToggle 工具切换失败回滚单个工具状态

错误处理全量补全:
- 所有 await window.metona 调用补全 try/catch 与 toast 反馈
- MCP addServer/toggleServer/removeServer 检查返回值
- showItemInFolder 检查返回值(handleOpen/handleOpenInFolder)
- sse-stream/ollama NDJSON 解析失败改为 log.warn
- adapter throwHttpError 带 status 属性供 isRetryableError 判断
2026-07-16 22:40:32 +08:00
thzxx 656c6b7af1 feat: 升级至 v0.3.4 — 接入 Xiaomi MiMo Provider + 文档全量校准
新增 MiMo (小米) LLM Provider 适配器,支持 mimo-v2.5-pro 和 mimo-v2.5 两个文本模型,复用 OpenAI 兼容 SSE 流式解析,支持 Thinking 模式和 Function Calling。同步校准全量 docs 文档与 README 使其与实际代码一致。

主要变更:
- 新增 mimo.adapter.ts 适配器(SSE + thinking.type + max_completion_tokens)
- 修复 thinking 逻辑 bug:禁用思考时未传 temperature/top_p
- 补全 sse-stream.ts 的 MiMo 缓存字段映射(prompt_tokens_details.cached_tokens)
- 补全 sse-stream.ts 的 finish_reason 映射(repetition_truncation)
- 注册 MiMo 适配器到 adapters/index.ts、main.ts 工厂
- handlers.ts 添加 mimo.contextWindow 热重载触发
- database.service.ts seed 添加 mimo 默认配置
- SettingsModal/OnboardingWizard/Header 添加 MiMo Provider UI
- constants.ts PROVIDER_LABELS 添加 mimo
- .env.example 添加 MIMO_API_KEY/MIMO_BASE_URL
- 反向修改 4 个 docs HTML 设计文档(工具数量/版本日期/适配器列表/数据库表)
- 反向修改 Agent网络工具通用设计-v2.md 附录 B 文件索引
- 完全重写 README.md(v0.3.4、27 工具、4 适配器、9 表)
2026-07-15 22:28:09 +08:00
thzxx 4f5f570ac8 fix: 修复多轮对话400/Provider通知反复弹出/浏览器环境隔离三大缺陷
1. 多轮对话第二次发消息 AI 不响应 (CRITICAL)

handlers.ts: 保存 tool 结果消息到数据库,DeepSeek API 要求 assistant 有 tool_calls 时后续必须有对应 tool 结果消息

openai-format.ts: assistant 有 tool_calls 时 content 设为 null (API 规范,空字符串会导致 400)

agent-store.ts: 前端加载历史时过滤 tool 消息,避免冗余卡片

2. Provider 切换通知每次发消息都弹出

main.ts: reloadAdapter 添加配置签名比较 (lastConfigSig),配置未变化时幂等返回 true,不再重建 adapter 或发 toast

3. 浏览器工具无环境隔离

browser-window-manager.ts: 独立 partition 隔离 Cookie/存储; 恢复 webSecurity,CORS 通过 webRequest 处理; setWindowOpenHandler 拦截 window.open; 并发互斥锁串行化 open 调用; destroy() 改用 win.destroy() + clearStorageData 清理残留
2026-07-12 21:21:55 +08:00
thzxx 97a3d3d53b fix: 全面修复审计问题并优化系统提示词
**崩溃/挂死修复 (5):**
- 统一 TrayManager.isQuitting 变量,修复 Cmd+Q 无法退出
- useAgentStream 闭包过期快照 → 每次 getState()
- Agnes chatStream 添加 AbortSignal.timeout
- SSE JSON.parse 添加 try-catch 保护
- Orchestrator setTools 污染 → save/restore 模式

**功能修复 (14):**
- 上下文压缩实现 (每5轮 COMPRESSING 状态)
- 修复 requestId 硬编码空串
- ConfigService.set() 保留已有 category
- MemoryManager 新增 working 类型搜索
- PromptInjectionDefender 补全 sanitize()
- Ollama: 补全 dynamicReminders + reasoningContent
- openai-format: 所有 assistant 消息保留 reasoningContent
- SSE: finish_reason 时提前 flush tool_calls
- DeepSeek thinking effort 映射注释
- Ollama done_reason load→stop
- RateLimitHook >= 边界修复
- WorkspaceService isValid 首次启动修复
- sessions:archive IPC handler
- 托盘/窗口图标路径生产环境修复

**系统提示词优化:**
- SOUL.md 存在时不显示兜底身份,原文放最前
- 兜底身份改为中文 (MetonaAI 自身描述)
- 用户文本在前,附件内容在后

**文件上传:**
- 非图片文件不再 base64 编码,保留 JSON 结构
- 用户文本优先于文件内容

**UI 修复:**
- 首页 Logo 路径修复 (public/ + 相对路径)
- TokenUsage contextWindow 动态计算 (Provider 感知)
- 切换 Provider 同步 contextWindow
- 托盘图标始终显示 Logo (状态由右键菜单展示)
2026-06-30 23:17:38 +08:00
thzxx 7f975de20e fix: 从共享工具中移除图片处理,DeepSeek 不应接收图片
问题:shared/openai-format.ts 对所有 OpenAI 兼容 Adapter 统一处理
多模态图片 → content 数组。但 DeepSeek 不支持多模态,不应发送图片。

修复:
- shared/openai-format.ts: 移除图片处理逻辑(由各 Provider 自行决定)
- AgnesAdapter.toNativeRequest: 添加多模态图片转换(OpenAI content 数组)
- DeepSeekAdapter: 不处理图片(DeepSeek 不支持多模态)
- OllamaAdapter: 已有独立的图片处理(images: [base64] 数组)

各 Provider 多模态支持:
  DeepSeek   不支持 → 不发送 images 字段
  Agnes AI   支持 → OpenAI content 数组 [{type:image_url}]
  Ollama     支持 → images: [base64]
2026-06-27 21:43:53 +08:00
thzxx bd6856c7e4 refactor: 解耦 Provider Adapter 继承关系
问题:AgnesAdapter extends DeepSeekAdapter 在架构上不合理。
DeepSeek、Agnes AI、Ollama 是三个完全不同的 API,不应有继承关系。

重构:
  BaseAdapter
  ├── DeepSeekAdapter  (独立)
  ├── AgnesAdapter     (独立)
  └── OllamaAdapter    (独立)

变更:
- 新增 shared/openai-format.ts — 提取 OpenAI 兼容消息/工具格式构建
- 新增 shared/sse-stream.ts   — 提取 SSE 流式解析逻辑
- DeepSeekAdapter  重写为独立继承 BaseAdapter,使用共享工具
- AgnesAdapter     重写为独立继承 BaseAdapter,使用共享工具
- OllamaAdapter    无需变更(原本就独立继承)
- adapters/index.ts 清理导出,移除隐式耦合
2026-06-27 21:41:43 +08:00