diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent_native_tools.rs b/apps/ai-game-creator-shell/src-tauri/src/agent_native_tools.rs index 1b582897f..9ead2654a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent_native_tools.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent_native_tools.rs @@ -1475,7 +1475,7 @@ fn runtime_tool_description(tool: &str) -> &'static str { "blackboard.write" => "向项目级共享黑板追加稳定结论。", "agent.message" => "向一个目标 Agent 写入定向上下文消息。", "agent.delegate" => { - "用持久验收合同把边界清晰的后台任务委派给另一个 Agent;返工时 repairOfDelegationId 指向原 delivery,且 runId 必须为 null。" + "用持久验收合同把边界清晰的后台任务委派给另一个 Agent;返工时 repairOfDelegationId 指向原 delivery,runId 必须为 null,acceptanceCriteria 与 expectedArtifacts 一起传 null 由 Runtime 从原 delivery 继承。" } "agent.spawn_isolated" => "创建最多三个写范围互不重叠的隔离子 Agent。", "agent.goal_contract" => { @@ -1722,8 +1722,8 @@ fn runtime_tool_input_schema(tool: &str) -> Value { "properties": { "agentId": { "type": "string", "minLength": 1 }, "task": { "type": "string", "minLength": 1, "maxLength": 2400 }, - "acceptanceCriteria": { "type": "array", "minItems": 1, "maxItems": 8, "items": { "type": "string", "minLength": 1, "maxLength": 240 } }, - "expectedArtifacts": { "type": "array", "maxItems": 16, "items": { "type": "string", "minLength": 1, "maxLength": 240 } }, + "acceptanceCriteria": { "type": ["array", "null"], "minItems": 1, "maxItems": 8, "items": { "type": "string", "minLength": 1, "maxLength": 240 }, "description": "初次委派必填。带 repairOfDelegationId 的返工或澄清续跑传 null:Runtime 会从原 delivery 继承权威合同,手抄一遍不增加任何信息,抄错会被直接拒收。" }, + "expectedArtifacts": { "type": ["array", "null"], "maxItems": 16, "items": { "type": "string", "minLength": 1, "maxLength": 240 }, "description": "与 acceptanceCriteria 同进同出:初次委派必填,返工与澄清续跑一起传 null 由 Runtime 继承。" }, "repairOfDelegationId": { "type": ["string", "null"] }, "runId": { "type": ["string", "null"] }, "continuationOfDelegationId": { "type": ["string", "null"] }, @@ -2214,6 +2214,22 @@ mod tests { assert!(description.contains("repairOfDelegationId 指向原 delivery")); assert!(description.contains("runId 必须为 null")); + // 广告给模型的 schema 一度把这两个数组写死成非空数组,模型于是根本无法 + // 传 null,只能手抄——实测每条 continuation 固定先失败 2 次才抄对。 + assert!( + description.contains("acceptanceCriteria 与 expectedArtifacts 一起传 null"), + "{description}" + ); + let schema = runtime_tool_input_schema("agent.delegate"); + for field in ["acceptanceCriteria", "expectedArtifacts"] { + let types = schema["properties"][field]["type"] + .as_array() + .unwrap_or_else(|| panic!("{field} 必须允许 null")); + assert!( + types.iter().any(|value| value == "null"), + "{field} 的广告 schema 必须允许 null,否则 Runtime 侧的继承分支永远走不到" + ); + } } /// plan 根 Supervisor 只广告 7 个原生工具 + 2 个协议控制。全量注册表里其余