Harden task state and terminal rendering
This commit is contained in:
@@ -51,6 +51,72 @@ test("set_tasks schema hoists $defs to the root with #/$defs/ refs", () => {
|
||||
assert.ok(!/"\$ref":"(?!\#)/.test(serialized), "no bare $ref values remain");
|
||||
});
|
||||
|
||||
test("task schemas publish text and batch limits", () => {
|
||||
const { tools } = registeredTools();
|
||||
const setParams = tools.get("set_tasks").parameters;
|
||||
const addTask = setParams.$defs.AddTask;
|
||||
const updateTask = tools.get("update_task").parameters.properties.tasks.items;
|
||||
|
||||
assert.equal(setParams.properties.tasks.maxItems, 50);
|
||||
assert.equal(addTask.properties.children.maxItems, 50);
|
||||
assert.equal(addTask.properties.name.maxLength, 200);
|
||||
assert.match(addTask.properties.name.pattern, /061C/i);
|
||||
assert.equal(addTask.properties.description.anyOf[0].maxLength, 4_000);
|
||||
assert.match(addTask.properties.description.anyOf[0].pattern, /061C/i);
|
||||
assert.equal(tools.get("update_task").parameters.properties.tasks.maxItems, 50);
|
||||
assert.equal(updateTask.properties.name.anyOf[0].maxLength, 200);
|
||||
assert.equal(updateTask.properties.description.anyOf[0].maxLength, 4_000);
|
||||
assert.equal(tools.get("rm_task").parameters.properties.ids.maxItems, 50);
|
||||
assert.equal(tools.get("get_task").parameters.properties.ids.maxItems, 50);
|
||||
|
||||
const setTool = tools.get("set_tasks");
|
||||
const validUnicode = setTool.prepareArguments({
|
||||
mode: "append",
|
||||
tasks: [{ name: "😀".repeat(200), description: "line one\nline two" }],
|
||||
});
|
||||
assert.doesNotThrow(() =>
|
||||
validateToolArguments(setTool, { name: setTool.name, arguments: validUnicode } as never),
|
||||
);
|
||||
const unsafeText = setTool.prepareArguments({ mode: "append", tasks: [{ name: "unsafe\u061cname" }] });
|
||||
assert.throws(
|
||||
() => validateToolArguments(setTool, { name: setTool.name, arguments: unsafeText } as never),
|
||||
/validation failed/i,
|
||||
);
|
||||
});
|
||||
|
||||
test("set_tasks preparation bounds hostile recursive input before validation", () => {
|
||||
const { tools } = registeredTools();
|
||||
const setTool = tools.get("set_tasks");
|
||||
let nested: Record<string, unknown> = { name: "Leaf" };
|
||||
for (let depth = 0; depth < 10_000; depth += 1) nested = { name: `Level ${depth}`, children: [nested] };
|
||||
|
||||
const prepared = setTool.prepareArguments({ mode: "append", tasks: [nested] });
|
||||
assert.throws(
|
||||
() => validateToolArguments(setTool, { name: setTool.name, arguments: prepared } as never),
|
||||
/validation failed/i,
|
||||
);
|
||||
|
||||
const oversized = setTool.prepareArguments({
|
||||
mode: "append",
|
||||
tasks: Array.from({ length: 1_000 }, (_, index) => ({ name: `Task ${index}` })),
|
||||
});
|
||||
assert.equal(oversized.tasks.length, 51);
|
||||
assert.throws(
|
||||
() => validateToolArguments(setTool, { name: setTool.name, arguments: oversized } as never),
|
||||
/validation failed/i,
|
||||
);
|
||||
|
||||
const updateTool = tools.get("update_task");
|
||||
const oversizedUpdate = updateTool.prepareArguments({
|
||||
tasks: Array.from({ length: 1_000 }, (_, index) => ({ id: index + 1 })),
|
||||
});
|
||||
assert.equal(oversizedUpdate.tasks.length, 51);
|
||||
assert.throws(
|
||||
() => validateToolArguments(updateTool, { name: updateTool.name, arguments: oversizedUpdate } as never),
|
||||
/validation failed/i,
|
||||
);
|
||||
});
|
||||
|
||||
test("strict task schemas normalize legacy optional arguments", () => {
|
||||
const { tools } = registeredTools();
|
||||
const setTool = tools.get("set_tasks");
|
||||
|
||||
Reference in New Issue
Block a user