feat(pi): add subagent config and agents
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
||||
import { Type } from "typebox";
|
||||
import { loadAgents } from "./agents.ts";
|
||||
import { loadConfig, resolveSpawn, type Diagnostics } from "./config.ts";
|
||||
import { SubprocessRpcRunner } from "./runner.ts";
|
||||
import { Supervisor } from "./supervisor.ts";
|
||||
import type { SpawnRequest } from "./types.ts";
|
||||
|
||||
let supervisor: Supervisor | undefined;
|
||||
let lastDiagnostics: Diagnostics = { warnings: [] };
|
||||
|
||||
export default function subagents(pi: ExtensionAPI) {
|
||||
const getSupervisor = (ctx: ExtensionContext): Supervisor => {
|
||||
@@ -12,18 +15,30 @@ export default function subagents(pi: ExtensionAPI) {
|
||||
return supervisor;
|
||||
};
|
||||
|
||||
const resolve = (ctx: ExtensionContext, request: SpawnRequest): SpawnRequest => {
|
||||
const diagnostics: Diagnostics = { warnings: [] };
|
||||
const cwd = cwdOf(ctx);
|
||||
const trusted = isProjectTrusted(ctx);
|
||||
const config = loadConfig(cwd, trusted, diagnostics);
|
||||
const agents = loadAgents(cwd, trusted, diagnostics);
|
||||
lastDiagnostics = diagnostics;
|
||||
return resolveSpawn(request, config, agents);
|
||||
};
|
||||
|
||||
pi.registerTool({
|
||||
name: "subagent_spawn",
|
||||
label: "Spawn subagent",
|
||||
description: "Start one ad hoc independent subagent and return immediately with its child id",
|
||||
parameters: Type.Object({
|
||||
prompt: Type.String({ description: "Prompt for the delegated subagent" }),
|
||||
agent: Type.Optional(Type.String({ description: "Named agent definition to use" })),
|
||||
context: Type.Optional(Type.Literal("independent")),
|
||||
model: Type.Optional(Type.String({ description: "Optional model selector for status metadata" })),
|
||||
thinking: Type.Optional(Type.String({ description: "Optional thinking level for status metadata" })),
|
||||
model: Type.Optional(Type.String({ description: "Optional model selector for the child" })),
|
||||
thinking: Type.Optional(Type.String({ description: "Optional thinking level for the child" })),
|
||||
tools: Type.Optional(Type.String({ description: "Tool profile name" })),
|
||||
}),
|
||||
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
||||
const accepted = getSupervisor(ctx).spawn(params as SpawnRequest);
|
||||
const accepted = getSupervisor(ctx).spawn(resolve(ctx, params as SpawnRequest));
|
||||
ctx.ui?.notify?.(`Started subagent ${accepted.id}`, "info");
|
||||
return textResult(accepted);
|
||||
},
|
||||
@@ -78,7 +93,7 @@ export default function subagents(pi: ExtensionAPI) {
|
||||
pi.registerCommand("subagent-spawn", {
|
||||
description: "Start an ad hoc independent subagent",
|
||||
handler: async (args, ctx) => {
|
||||
const accepted = getSupervisor(ctx).spawn({ prompt: args });
|
||||
const accepted = getSupervisor(ctx).spawn(resolve(ctx, parseSpawnArgs(args)));
|
||||
ctx.ui.notify(`Started subagent ${accepted.id}`, "info");
|
||||
},
|
||||
});
|
||||
@@ -104,6 +119,13 @@ export default function subagents(pi: ExtensionAPI) {
|
||||
},
|
||||
});
|
||||
|
||||
pi.registerCommand("subagent-diagnostics", {
|
||||
description: "Show subagent configuration diagnostics from the last load",
|
||||
handler: async (_args, ctx) => {
|
||||
ctx.ui.notify(JSON.stringify(lastDiagnostics, null, 2), "info");
|
||||
},
|
||||
});
|
||||
|
||||
pi.registerCommand("subagent-cancel", {
|
||||
description: "Cancel a running subagent by id",
|
||||
handler: async (args, ctx) => {
|
||||
@@ -117,6 +139,17 @@ export default function subagents(pi: ExtensionAPI) {
|
||||
});
|
||||
}
|
||||
|
||||
function parseSpawnArgs(args: string): SpawnRequest {
|
||||
const match = /^--agent\s+(\S+)\s+([\s\S]+)$/u.exec(args.trim());
|
||||
if (!match) return { prompt: args };
|
||||
return { agent: match[1], prompt: match[2] };
|
||||
}
|
||||
|
||||
function isProjectTrusted(ctx: ExtensionContext): boolean {
|
||||
const value = (ctx as unknown as { isProjectTrusted?: () => boolean }).isProjectTrusted?.();
|
||||
return value === true;
|
||||
}
|
||||
|
||||
function cwdOf(ctx: ExtensionContext): string {
|
||||
const sessionCwd = (ctx as unknown as { sessionManager?: { getCwd?: () => string }; cwd?: string }).sessionManager?.getCwd?.();
|
||||
return sessionCwd ?? (ctx as unknown as { cwd?: string }).cwd ?? process.cwd();
|
||||
|
||||
Reference in New Issue
Block a user