mirror of
https://github.com/wassname/pi-goals.git
synced 2026-09-11 12:43:57 +08:00
Pair supervisors before starting their model
Co-Authored-By: PI[Kimi K3] <288921227+claudypoo@users.noreply.github.com>
This commit is contained in:
@@ -63,7 +63,6 @@ export function supervisorCommand(input: LaunchSupervisorInput): string {
|
||||
"--name", `goals-supervisor-${input.workerSessionId.slice(0, 8)}`,
|
||||
];
|
||||
if (input.model) args.push("--model", input.model);
|
||||
args.push("Initialize supervision startup.");
|
||||
return `env ${[...env, ...args].map(shellQuote).join(" ")}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,34 +80,28 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
|
||||
let compacting = false;
|
||||
let bootstrapping = false;
|
||||
|
||||
pi.on("before_agent_start", async (_event, ctx) => {
|
||||
await bootstrap(ctx);
|
||||
return { systemPrompt: `${ctx.getSystemPrompt()}\n\n${supervisorPrompt(settings)}` };
|
||||
});
|
||||
|
||||
const bootstrap = async (ctx: ExtensionContext): Promise<void> => {
|
||||
if (bootstrapping) return;
|
||||
const entries = ctx.sessionManager.getEntries();
|
||||
if (entries.some((entry: { type?: string; customType?: string }) => entry.type === "custom" && entry.customType === BOOTSTRAPPED)) return;
|
||||
bootstrapping = true;
|
||||
compacting = true;
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
ctx.compact({
|
||||
customInstructions: `Preserve the user's decisions, preferences, and high-level objective from planning. Preserve unresolved risks and the plan path ${settings.planPath}. Remove implementation chatter. This summary is for a read-only supervisor that will judge and steer another Pi session.`,
|
||||
onComplete: () => resolve(),
|
||||
onError: reject,
|
||||
});
|
||||
});
|
||||
await pairWithPiSupervise(pi, settings.workerIntercomId, settings.planPath);
|
||||
pi.appendEntry(BOOTSTRAPPED, { version: 1, workerSessionId: settings.workerSessionId, planPath: settings.planPath });
|
||||
pi.sendUserMessage("Supervision is paired. Inspect the worker and give its next concrete instruction.");
|
||||
} catch (error) {
|
||||
ctx.ui.notify(`Supervisor startup failed: ${error instanceof Error ? error.message : String(error)}`, "error");
|
||||
} finally {
|
||||
compacting = false;
|
||||
}
|
||||
};
|
||||
|
||||
pi.on("session_start", async (_event, ctx) => {
|
||||
setImmediate(() => { void bootstrap(ctx); });
|
||||
});
|
||||
|
||||
pi.on("before_agent_start", async (_event, ctx) => {
|
||||
return { systemPrompt: `${ctx.getSystemPrompt()}\n\n${supervisorPrompt(settings)}` };
|
||||
});
|
||||
|
||||
pi.on("agent_settled", async (_event, ctx) => {
|
||||
if (compacting || (ctx.getContextUsage()?.tokens ?? 0) < COMPACT_AT_TOKENS) return;
|
||||
compacting = true;
|
||||
|
||||
+2
-1
@@ -26,7 +26,8 @@ describe("supervisor pane command", () => {
|
||||
expect(command).toContain("'PI_GOALS_WORKER_INTERCOM_ID=intercom-12345678'");
|
||||
expect(command).toContain("'pi' '--no-extensions' '-e' 'npm:pi-intercom' '-e' 'npm:@wassname2/pi-supervise@0.0.4' '-e' '/repo/src/index.ts'");
|
||||
expect(command).toContain("'--fork' '/sessions/worker.jsonl'");
|
||||
expect(command).toContain("'--model' 'provider/supervisor' 'Initialize supervision startup.'");
|
||||
expect(command).toContain("'--model' 'provider/supervisor'");
|
||||
expect(command).not.toContain("Initialize supervision startup.");
|
||||
expect(command).not.toContain("pi-subagents");
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ function setup(cwd: string, planPath: string) {
|
||||
const tools = new Map<string, any>();
|
||||
const entries: any[] = [];
|
||||
const paired: Array<{ workerIntercomId: string; goal: string }> = [];
|
||||
const messages: string[] = [];
|
||||
let branch: any[] = [];
|
||||
const ctx = {
|
||||
cwd,
|
||||
@@ -42,34 +43,37 @@ function setup(cwd: string, planPath: string) {
|
||||
on: (name: string, handler: any) => hooks.set(name, handler),
|
||||
registerTool: (tool: any) => tools.set(tool.name, tool),
|
||||
appendEntry: (customType: string, data: unknown) => entries.push({ type: "custom", customType, data }),
|
||||
sendUserMessage: (message: string) => messages.push(message),
|
||||
};
|
||||
registerVisibleSupervisor(pi as unknown as ExtensionAPI);
|
||||
return { branch: (value: any[]) => { branch = value; }, ctx, entries, hooks, paired, tools };
|
||||
return { branch: (value: any[]) => { branch = value; }, ctx, entries, hooks, messages, paired, tools };
|
||||
}
|
||||
|
||||
afterEach(() => vi.unstubAllEnvs());
|
||||
|
||||
describe("visible supervisor session", () => {
|
||||
it("compacts the fork before pairing it with the worker", async () => {
|
||||
it("pairs from session startup before asking the supervisor to work", async () => {
|
||||
const cwd = mkdtempSync(join(tmpdir(), "pi-goals-supervisor-"));
|
||||
try {
|
||||
const runtime = setup(cwd, join(cwd, ".pi/plan/worker-v1.md"));
|
||||
await runtime.hooks.get("before_agent_start")({}, runtime.ctx);
|
||||
expect(runtime.ctx.compact).toHaveBeenCalledOnce();
|
||||
await runtime.hooks.get("session_start")({}, runtime.ctx);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
expect(runtime.ctx.compact).not.toHaveBeenCalled();
|
||||
expect(runtime.entries.at(-1)).toMatchObject({ customType: "pi-goals-visible-supervisor-v1" });
|
||||
expect(runtime.paired).toEqual([{ workerIntercomId: "worker-intercom", goal: join(cwd, ".pi/plan/worker-v1.md") }]);
|
||||
expect(runtime.messages).toEqual(["Supervision is paired. Inspect the worker and give its next concrete instruction."]);
|
||||
} finally {
|
||||
rmSync(cwd, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("does not pair twice when startup reaches a second worker turn", async () => {
|
||||
it("does not pair twice across session startup and later turns", async () => {
|
||||
const cwd = mkdtempSync(join(tmpdir(), "pi-goals-supervisor-"));
|
||||
try {
|
||||
const runtime = setup(cwd, join(cwd, ".pi/plan/worker-v1.md"));
|
||||
await runtime.hooks.get("session_start")({}, runtime.ctx);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
await runtime.hooks.get("before_agent_start")({}, runtime.ctx);
|
||||
await runtime.hooks.get("before_agent_start")({}, runtime.ctx);
|
||||
expect(runtime.ctx.compact).toHaveBeenCalledOnce();
|
||||
expect(runtime.paired).toHaveLength(1);
|
||||
} finally {
|
||||
rmSync(cwd, { recursive: true, force: true });
|
||||
|
||||
Reference in New Issue
Block a user