JianFeeeee
bce40b5099
feat(toolcall): 按 schema 预校验参数,在分派前拦下(阶段 1c)
问题:`required` 在仓内被声明 69 处,却**无任何消费方**(内核从不读)。
校验散落在每个工具内部手写成中文字符串("path is required"),
要等工具真被调用才暴露——而模型看到这类与真因无关的报错只会原样重试
(实测 cmd_run 失败率 34%~48% 的成因)。
改动:
· core/argvalidate.go: validateToolArgs(纯函数)+ validateArgsAgainstSchema。
★ 校验器刻意**宽松**:只拦真正无法解析的形态,对模型实际会写的等价形态
一律放行。依据是工具内部 getter 的既有约定(utils.go 注释:
"实际调用里 bool/string/float 三种都出现过";unitNumberRe 修的正是
`"20s"` 少引号那类)。**校验比工具更严就是在制造新失败**。
· required 判据是**键存在性** + 非空字符串;显式 null 视为已提供
(模型可能有意传 null,工具按零值处理,判成缺失即误伤)
· boolean 全放行(getBool 的 true/"1"/"0"/"yes"/0/1 全都合法)
· integer 接受 int/float64/"20"/"20s";string 接受含 JSON 的长文本
· 无 schema / 无 required / 查不到 schema ⇒ 一律放行
· core/toolcall.go: 在 __arg_error 短路**之后**、分派**之前**接入。
· io/channel.go: 新增 IOManager.ToolDefOf——没有它就只校验到插件工具,
而 cmd_run / files_write 这类**设备/通道工具会完全绕过校验**。
判据(argvalidate_test.go,7 组):
· 缺 required 被拦下并指名字段
· ★ 误伤防线:bool 传 "true"/"0"、integer 传 float64/"20"、
显式 null、字段顺序不同 —— 全部必须放行
· 类型确实不符报 type 错误
· 无约束场景一律放行(含 args 为 nil + schema 带 required ⇒ 应拦,
这条我最初**误放进放行组**,写完立刻发现改正)
· 错误文案含字段名/必填/改法(否则模型只会原样重试)
· 端到端:缺参时**设备真的没被调用** + 文案指名字段
· 端到端反向:参数齐备照常执行(校验不得阻塞正常路径)
变异验证(两轮):
· 关闭分派前校验 ⇒ 端到端判据 FAIL「仍进入了工具」
· 把 boolean 校验改严格 ⇒ 宽松防线 FAIL 两个子用例(误伤 "true"/"0")
过程中三次自伤:臆造 sdkToolError 别名;number 分支写了没有绑定的 x(v);
把"显式 null"先当成缺失、过度修正后又漏掉"键不存在"的判定——
最终改为「键存在性 + 非空串」双条件,null 与缺失各归其位。
回归:internal/agent/... internal/sdk/... internal/plugin/...
internal/plugins/... 全绿(18 包)。
2026-09-27 10:56:02 +08:00
..
2026-09-19 16:49:16 +08:00
2026-09-15 07:47:16 +08:00
2026-09-11 11:45:24 +08:00
2026-09-26 16:19:10 +08:00
2026-09-27 10:56:02 +08:00
2026-09-27 10:56:02 +08:00
2026-09-15 06:32:36 +08:00
2026-09-15 06:32:36 +08:00
2026-09-11 11:45:24 +08:00
2026-09-13 12:23:28 +08:00
2026-09-26 20:16:11 +08:00
2026-09-26 20:09:17 +08:00
2026-08-18 09:07:21 +08:00
2026-09-15 09:03:36 +08:00
2026-09-15 09:16:22 +08:00
2026-09-13 09:06:50 +08:00
2026-09-14 23:14:38 +08:00
2026-09-13 15:41:07 +08:00
2026-09-13 15:35:59 +08:00
2026-09-15 09:37:29 +08:00
2026-09-15 09:37:29 +08:00
2026-07-28 11:42:29 +08:00
2026-09-15 08:13:52 +08:00
2026-09-11 13:45:25 +08:00
2026-09-11 13:45:25 +08:00
2026-09-11 11:45:24 +08:00
2026-09-13 00:25:52 +08:00
2026-09-13 10:36:04 +08:00
2026-09-15 08:13:52 +08:00
2026-09-26 21:55:12 +08:00
2026-09-04 06:25:51 +08:00
2026-09-04 06:25:51 +08:00
2026-09-19 17:47:44 +08:00
2026-09-19 17:43:16 +08:00
2026-09-13 09:13:19 +08:00
2026-09-13 16:04:16 +08:00
2026-09-26 19:11:51 +08:00
2026-09-12 13:57:06 +08:00
2026-09-12 13:57:06 +08:00
2026-09-19 16:49:16 +08:00
2026-08-18 09:07:21 +08:00
2026-09-19 11:57:50 +08:00
2026-09-27 08:55:25 +08:00
2026-09-13 14:34:44 +08:00
2026-09-11 20:31:50 +08:00
2026-09-10 23:59:12 +08:00
2026-09-15 08:13:52 +08:00
2026-09-13 15:09:44 +08:00
2026-09-13 20:19:37 +08:00
2026-09-19 17:43:16 +08:00
2026-09-19 17:47:44 +08:00
2026-09-26 20:09:17 +08:00
2026-09-26 21:55:12 +08:00
2026-09-26 20:09:17 +08:00
2026-09-13 08:59:15 +08:00
2026-09-14 09:05:14 +08:00
2026-09-13 07:00:51 +08:00
2026-09-13 07:18:03 +08:00
2026-09-13 07:00:51 +08:00
2026-09-14 10:39:25 +08:00
2026-09-13 06:10:44 +08:00
2026-09-13 07:00:51 +08:00
2026-09-13 07:00:51 +08:00
2026-09-13 07:31:32 +08:00
2026-09-13 07:00:51 +08:00
2026-09-19 17:47:44 +08:00
2026-09-10 20:36:39 +08:00
2026-09-13 08:59:15 +08:00
2026-09-13 08:59:15 +08:00
2026-09-03 12:37:58 +08:00
2026-07-24 14:49:08 +08:00
2026-09-27 08:55:25 +08:00
2026-09-12 14:56:25 +08:00
2026-09-19 17:43:16 +08:00
2026-09-18 11:39:04 +08:00
2026-09-27 09:17:16 +08:00
2026-09-27 08:55:25 +08:00
2026-09-19 16:49:16 +08:00
2026-09-13 06:24:20 +08:00
2026-09-13 07:00:51 +08:00
2026-09-13 06:17:49 +08:00
2026-09-27 09:17:16 +08:00
2026-09-17 18:56:15 +08:00
2026-09-17 18:56:15 +08:00
2026-09-19 14:24:31 +08:00
2026-09-25 14:45:08 +08:00
2026-09-27 08:59:30 +08:00
2026-09-27 08:55:25 +08:00
2026-09-27 10:56:02 +08:00
2026-09-26 21:55:12 +08:00
2026-09-27 09:17:16 +08:00
2026-09-27 09:17:16 +08:00
2026-09-14 16:45:04 +08:00
2026-09-26 16:19:10 +08:00