fix(task): surfaced actionable shape error for batch calls

The flat single-spawn task wire schema carries arktype `"+": "delete"`, so a
batch `{ context, tasks[] }` payload sent while `task.batch` is disabled has
those keys stripped and is then rejected as `task must be a string (was
missing)` in the agent loop. That preempts the tool's own actionable checks
(validateShapeParams / validateSpawnParams), so the model only ever saw the
misleading arktype error instead of "task.batch is disabled…".

Mark TaskTool with lenientArgValidation so the agent loop forwards the raw
args to execute() on any arktype failure, letting the tool's shape checks
surface the real reason. Valid calls still normalize through arktype; the
success path is unchanged. Mirrors the existing yield-tool pattern.

Fixes #6039
This commit is contained in:
roboomp
2026-07-21 20:41:14 +00:00
parent 9fd6e97113
commit 05668faa5f
3 changed files with 35 additions and 0 deletions
@@ -224,6 +224,26 @@ describe("task.batch validation", () => {
);
expect(text).toContain("Duplicate task name");
});
it("marks lenientArgValidation so execute() surfaces the actionable shape error", async () => {
// Regression (#6039): the flat single-spawn wire schema carries
// `"+": "delete"`, so a batch `{ context, tasks[] }` payload is stripped
// by arktype and rejected as `task must be a string (was missing)` in the
// agent loop — preempting the tool's own actionable message. The lenient
// flag makes the loop forward the raw args to execute() on that failure.
mockDiscovery();
const tool = await TaskTool.create(createSession({ settings: { "task.batch": false } }));
expect(tool.lenientArgValidation).toBe(true);
// The raw batch payload the loop would forward reaches execute() and
// yields the actionable reason, never arktype's misleading missing-`task`.
const text = await executeText(
{ context: "Background.", tasks: [{ name: "Alpha", task: "Work." }] },
{ "task.batch": false },
);
expect(text).toContain("task.batch is disabled");
expect(text).not.toContain("was missing");
});
});
describe("task.batch spawning", () => {