Files
2026-07-13 12:20:32 +08:00

84 lines
3.4 KiB
TypeScript

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
export default function (pi: ExtensionAPI) {
pi.registerTool({
name: "propose_delegation",
label: "Propose Delegation",
description:
"Submit a sequential list of focused child-agent work units. " +
"This is the only tool available in delegation planning mode. " +
"Do not execute the task or perform desktop/browser/filesystem actions.",
parameters: Type.Object({
title: Type.String({
description: "Short title for the delegated run.",
}),
reason: Type.String({
description: "Brief reason this task benefits from sequential child agents.",
}),
units: Type.Array(
Type.Object({
id: Type.Optional(Type.String({
description: "Stable short id for this work unit, e.g. scout-1.",
})),
title: Type.String({
description: "Short label shown in the UI.",
}),
role: Type.String({
description: "Focused role such as scout, researcher, worker, reviewer, or synthesizer.",
}),
objective: Type.String({
description: "The concrete subtask for the child agent.",
}),
allowed_tools: Type.Optional(Type.Array(Type.String(), {
description: "Optional tool names or categories the child is expected to use.",
maxItems: 8,
})),
expected_output: Type.String({
description: "The specific text/artifact handoff expected from the child.",
}),
depends_on: Type.Optional(Type.Array(Type.String(), {
description: "Optional ids this unit depends on. Keep sequential ordering simple.",
maxItems: 5,
})),
requires_user_approval: Type.Optional(Type.Boolean({
description: "True only if this unit should pause for user approval before running.",
})),
}),
{
description: "Sequential child-agent work units.",
minItems: 1,
maxItems: 8,
},
),
}),
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
const payload = {
title: String(params.title || "Delegated Run").trim(),
reason: String(params.reason || "").trim(),
units: Array.isArray(params.units)
? params.units.map((unit: any, idx: number) => ({
id: String(unit.id || `step-${idx + 1}`).trim(),
title: String(unit.title || `Step ${idx + 1}`).trim(),
role: String(unit.role || "worker").trim(),
objective: String(unit.objective || "").trim(),
allowed_tools: Array.isArray(unit.allowed_tools)
? unit.allowed_tools.map((tool: string) => String(tool || "").trim()).filter(Boolean)
: [],
expected_output: String(unit.expected_output || "").trim(),
depends_on: Array.isArray(unit.depends_on)
? unit.depends_on.map((dep: string) => String(dep || "").trim()).filter(Boolean)
: [],
requires_user_approval: unit.requires_user_approval === true,
})).filter((unit: any) => unit.objective)
: [],
};
return {
content: [{ type: "text", text: JSON.stringify(payload) }],
details: payload,
};
},
});
}