fix(runtime): 工具调用 P1/P2/P3 全面修复
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
P1: 流式模式工具并行执行
- 三阶段执行: Phase 1 中间件预检(serial) → Phase 2 并行+串行分区 → Phase 3 结果排序
- ReadOnly 工具用 JoinSet + Semaphore(3) 并行,Exclusive/Interactive 串行
- 与非流式模式保持一致的执行策略
P2: OpenAI 驱动工具参数解析
- 解析失败不再静默替换为 {},改为返回 _parse_error + _raw_args
- 让 LLM 和工具能感知参数问题并自我修正
P2: ToolOutputGuard 精确匹配
- 从 to_lowercase() 关键词匹配改为 regex 精确匹配实际密钥值
- 检测 sk-xxx(20+), AKIA(16), PEM 私钥, key=value 模式
- 移除 "system:", "you are now" 等过于宽泛的注入检测
- 消除合法内容包含 "password" 等词汇时的误拦
P2: ToolErrorMiddleware per-session 计数
- 从全局 AtomicU32 改为 Mutex<HashMap<session_id, u32>>
- 每个会话独立跟踪连续失败次数,消除跨会话误触发 AbortLoop
P3: Gateway client onTool 回调语义
- 明确 tool_call 的 output 始终为空串 (start 信号)
- 添加注释说明 start/end 语义约定
This commit is contained in:
@@ -34,15 +34,15 @@
|
||||
|
||||
**修复**: 区分完整工具(收到 ToolUseEnd)和不完整工具(仅收到 ToolUseStart/Delta)。完整工具照常执行,不完整工具发送取消 ToolEnd 事件。
|
||||
|
||||
### P1: 流式模式工具全串行
|
||||
### P1: 流式模式工具全串行 — ✅ 已修复 (2026-04-24)
|
||||
|
||||
**文件**: `loop_runner.rs` 第 893-1070 行
|
||||
**文件**: `loop_runner.rs` 流式模式工具执行段
|
||||
|
||||
非流式模式有 `JoinSet` + `Semaphore(3)` 并行执行 ReadOnly 工具,但流式模式用简单 `for` 循环串行执行所有工具。
|
||||
|
||||
**影响**: 多工具调用时延迟显著增加。
|
||||
**修复**: 流式模式采用三阶段执行:Phase 1 中间件预检(serial) → Phase 2 并行+串行分区执行 → Phase 3 after_tool_call + 结果排序推送。
|
||||
|
||||
### P2: OpenAI 驱动工具参数静默替换
|
||||
### P2: OpenAI 驱动工具参数静默替换 — ✅ 已修复 (2026-04-24)
|
||||
|
||||
**文件**: `crates/zclaw-runtime/src/driver/openai.rs` 第 222-228 行
|
||||
|
||||
@@ -59,24 +59,32 @@ let parsed_args = if args.is_empty() {
|
||||
|
||||
JSON 解析失败时静默替换为 `{}`,结合 loop_runner.rs 的空参数处理(第 412-423 行),会注入 `_fallback_query` 替代实际参数。
|
||||
|
||||
### P2: ToolOutputGuard 过于激进
|
||||
**修复**: 解析失败时返回 `_parse_error` + `_raw_args` 字段,让工具和 LLM 能感知到参数问题并自我修正。
|
||||
|
||||
### P2: ToolOutputGuard 过于激进 — ✅ 已修复 (2026-04-24)
|
||||
|
||||
**文件**: `crates/zclaw-runtime/src/middleware/tool_output_guard.rs` 第 109 行
|
||||
|
||||
使用 `to_lowercase()` 匹配敏感模式,合法内容中包含 "password"、"system:" 等字符串会被误拦。
|
||||
|
||||
### P2: ToolErrorMiddleware 失败计数器是全局的
|
||||
**修复**: 改用 `regex` 精确匹配实际密钥值格式(如 `sk-[a-zA-Z0-9]{20,}`、`AKIA[A-Z0-9]{16}`、`key=value` 模式),不再误拦仅包含关键词的合法内容。移除了 "system:" 等过于宽泛的注入检测模式。
|
||||
|
||||
### P2: ToolErrorMiddleware 失败计数器是全局的 — ✅ 已修复 (2026-04-24)
|
||||
|
||||
**文件**: `crates/zclaw-runtime/src/middleware/tool_error.rs` 第 27 行
|
||||
|
||||
`consecutive_failures: AtomicU32` 是结构体字段,所有 session 共享。高并发下 A session 失败 2 次 + B session 失败 1 次就会触发 AbortLoop(阈值 3)。
|
||||
|
||||
### P3: Gateway 客户端 onTool 回调语义不一致
|
||||
**修复**: 改用 `Mutex<HashMap<String, u32>>` 以 session_id 为 key 存储计数,每个会话独立跟踪。
|
||||
|
||||
### P3: Gateway 客户端 onTool 回调语义不一致 — ✅ 已修复 (2026-04-24)
|
||||
|
||||
**文件**: `desktop/src/lib/gateway-client.ts` 第 698-707 行
|
||||
|
||||
`tool_call` 和 `tool_result` 两个 case 共用 `onTool` 回调,但参数约定不同,调用者必须通过 `output` 是否为空判断 start/end。
|
||||
|
||||
**修复**: 明确 `tool_call` 的 output 始终为 `''`(修复了可能传递 data.output 的问题),添加清晰注释说明 start/end 语义约定。
|
||||
|
||||
---
|
||||
|
||||
## 二、根因分析
|
||||
|
||||
Reference in New Issue
Block a user