schema: export union for single/parallel modes; require single preset/task; expose single-model; update tests
This commit is contained in:
@@ -36,17 +36,24 @@ test("the extension entrypoint registers the subagent tool with the currently av
|
|||||||
|
|
||||||
assert.equal(registeredTools.length, 1);
|
assert.equal(registeredTools.length, 1);
|
||||||
assert.equal(registeredTools[0]?.name, "subagent");
|
assert.equal(registeredTools[0]?.name, "subagent");
|
||||||
// no single top-level model required now (handled at runtime)
|
const params = registeredTools[0]?.parameters;
|
||||||
assert.equal("agent" in registeredTools[0]?.parameters.properties, false);
|
const branches = params?.anyOf ?? params?.oneOf ?? [params];
|
||||||
assert.equal("agentScope" in registeredTools[0]?.parameters.properties, false);
|
// ensure union branches exist: single-mode and parallel-mode
|
||||||
assert.equal("confirmProjectAgents" in registeredTools[0]?.parameters.properties, false);
|
assert(branches && branches.length === 2);
|
||||||
assert.equal("task" in registeredTools[0]?.parameters.properties, true);
|
// no agent/agentScope/confirmProjectAgents in any branch
|
||||||
assert.equal("preset" in registeredTools[0]?.parameters.properties, true);
|
for (const key of ["agent", "agentScope", "confirmProjectAgents"]) {
|
||||||
assert.equal(registeredTools[0]?.parameters.properties.model, undefined);
|
assert.equal(branches.some((b: any) => b.properties && key in b.properties), false);
|
||||||
assert.equal("agent" in registeredTools[0]?.parameters.properties.tasks.items.properties, false);
|
}
|
||||||
assert.equal("task" in registeredTools[0]?.parameters.properties.tasks.items.properties, true);
|
const singleBranch = branches.find((b: any) => b.properties && "task" in b.properties && "preset" in b.properties);
|
||||||
assert.equal("preset" in registeredTools[0]?.parameters.properties.tasks.items.properties, true);
|
assert(singleBranch, "single-mode branch present");
|
||||||
assert.deepEqual(registeredTools[0]?.parameters.properties.tasks.items.properties.model.enum, [
|
// single branch exposes optional top-level model
|
||||||
|
assert.equal("model" in singleBranch.properties, true);
|
||||||
|
const parallelBranch = branches.find((b: any) => b.properties && "tasks" in b.properties);
|
||||||
|
assert(parallelBranch, "parallel-mode branch present");
|
||||||
|
assert.equal("agent" in parallelBranch.properties.tasks.items.properties, false);
|
||||||
|
assert.equal("task" in parallelBranch.properties.tasks.items.properties, true);
|
||||||
|
assert.equal("preset" in parallelBranch.properties.tasks.items.properties, true);
|
||||||
|
assert.deepEqual(parallelBranch.properties.tasks.items.properties.model.enum, [
|
||||||
"anthropic/claude-sonnet-4-5",
|
"anthropic/claude-sonnet-4-5",
|
||||||
"openai/gpt-5",
|
"openai/gpt-5",
|
||||||
]);
|
]);
|
||||||
@@ -91,10 +98,16 @@ test("before_agent_start re-applies subagent registration when available models
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(registeredTools.length, 1);
|
assert.equal(registeredTools.length, 1);
|
||||||
assert.deepEqual(registeredTools[0]?.parameters.properties.tasks.items.properties.model.enum, [
|
{
|
||||||
"anthropic/claude-sonnet-4-5",
|
const params = registeredTools[0]?.parameters;
|
||||||
"openai/gpt-5",
|
const branches = params?.anyOf ?? params?.oneOf ?? [params];
|
||||||
]);
|
const parallelBranch = branches.find((b: any) => b.properties && "tasks" in b.properties);
|
||||||
|
assert(parallelBranch, "parallel branch present");
|
||||||
|
assert.deepEqual(parallelBranch.properties.tasks.items.properties.model.enum, [
|
||||||
|
"anthropic/claude-sonnet-4-5",
|
||||||
|
"openai/gpt-5",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
// then before agent start with a different model set — should re-register
|
// then before agent start with a different model set — should re-register
|
||||||
await handlers.before_agent_start?.(
|
await handlers.before_agent_start?.(
|
||||||
@@ -109,7 +122,13 @@ test("before_agent_start re-applies subagent registration when available models
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert.equal(registeredTools.length, 2);
|
assert.equal(registeredTools.length, 2);
|
||||||
assert.deepEqual(registeredTools[1]?.parameters.properties.tasks.items.properties.model.enum, ["openai/gpt-6"]);
|
{
|
||||||
|
const params = registeredTools[1]?.parameters;
|
||||||
|
const branches = params?.anyOf ?? params?.oneOf ?? [params];
|
||||||
|
const parallelBranch = branches.find((b: any) => b.properties && "tasks" in b.properties);
|
||||||
|
assert(parallelBranch, "parallel branch present");
|
||||||
|
assert.deepEqual(parallelBranch.properties.tasks.items.properties.model.enum, ["openai/gpt-6"]);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (original === undefined) delete process.env.PI_SUBAGENTS_CHILD;
|
if (original === undefined) delete process.env.PI_SUBAGENTS_CHILD;
|
||||||
else process.env.PI_SUBAGENTS_CHILD = original;
|
else process.env.PI_SUBAGENTS_CHILD = original;
|
||||||
|
|||||||
@@ -21,15 +21,20 @@ export function createTaskItemSchema(availableModels: readonly string[]) {
|
|||||||
export const TaskItemSchema = createTaskItemSchema([]);
|
export const TaskItemSchema = createTaskItemSchema([]);
|
||||||
|
|
||||||
export function createSubagentParamsSchema(availableModels: readonly string[]) {
|
export function createSubagentParamsSchema(availableModels: readonly string[]) {
|
||||||
return Type.Object({
|
// Single-mode schema: requires preset + task, exposes optional top-level model
|
||||||
// Single mode: provide preset + task
|
const SingleMode = Type.Object({
|
||||||
preset: Type.Optional(Type.String({ description: "Subagent preset name to use in single mode" })),
|
preset: Type.String({ description: "Subagent preset name to use in single mode" }),
|
||||||
task: Type.Optional(Type.String({ description: "Single-mode delegated task" })),
|
task: Type.String({ description: "Single-mode delegated task" }),
|
||||||
// Parallel mode: provide tasks array where each item names its own preset
|
model: createTaskModelSchema(availableModels),
|
||||||
tasks: Type.Optional(Type.Array(createTaskItemSchema(availableModels), { description: "Parallel tasks" })),
|
|
||||||
cwd: Type.Optional(Type.String({ description: "Single-mode working directory override" })),
|
cwd: Type.Optional(Type.String({ description: "Single-mode working directory override" })),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Parallel-mode schema: requires tasks array where each item contains its own preset and task
|
||||||
|
const ParallelMode = Type.Object({
|
||||||
|
tasks: Type.Array(createTaskItemSchema(availableModels), { description: "Parallel tasks" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
return Type.Union([SingleMode, ParallelMode], { description: "Either single-mode (preset+task) or parallel-mode (tasks array)" });
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SubagentParamsSchema = createSubagentParamsSchema([]);
|
export const SubagentParamsSchema = createSubagentParamsSchema([]);
|
||||||
|
|||||||
Reference in New Issue
Block a user