/** * Real Pi-session end-to-end test for the subagent extension. * * Spawns an actual child `pi` subprocess (a repo-local child CLI that runs a * real `AgentSession` backed by a faux provider) and exercises the extension's * real foreground execution path: the parent session calls the `subagent` tool, * the tool spawns the child, the child streams jsonl events, the extension's * real stdout parser extracts the result, and the marker flows back as a tool * result that the parent relays. No real API keys are used. * * Skips gracefully when the pi runtime packages are not importable. */ import { afterEach, describe, it } from "node:test"; import assert from "node:assert/strict"; import * as os from "node:os"; import * as path from "node:path"; import { tryImport } from "../support/helpers.ts"; import type { RealSessionRun } from "../support/real-session-runner.ts"; const piCodingAgent = await tryImport("@selesai/code"); const piAi = await tryImport("@earendil-works/pi-ai"); const available = Boolean(piCodingAgent && piAi); const CHILD_MARKER = "CHILD_REAL_SESSION_OK"; // Env vars the runner must clear so a parent that was itself spawned as a // subagent child can still launch fresh children. The values are deliberately // bogus sentinels (nonexistent paths) so a leaked value would break spawning. const BOGUS_EXTRA_DIRS = path.join(os.tmpdir(), "nonexistent-pi-subagents-e2e-extra-dirs"); const BOGUS_PI_BINARY = path.join(os.tmpdir(), "nonexistent-pi-binary-e2e"); const BOGUS_PI_PACKAGE_ROOT = path.join(os.tmpdir(), "nonexistent-pi-coding-agent-package-root-e2e"); const ISOLATED_ENV_KEYS = [ "SELESAI_SUBAGENT_CHILD", "SELESAI_SUBAGENT_FANOUT_CHILD", "SELESAI_SUBAGENT_DEPTH", "SELESAI_SUBAGENT_MAX_DEPTH", "SELESAI_SUBAGENT_EXTRA_AGENT_DIRS", "SELESAI_SUBAGENT_PARENT_SESSION", "SELESAI_SUBAGENT_PI_BINARY", "SELESAI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT", ] as const; describe("real Pi-session subagent E2E", { skip: !available ? "pi runtime packages not available" : undefined }, () => { let run: RealSessionRun | undefined; afterEach(async () => { await run?.dispose(); run = undefined; }); it("boots the extension in a real parent session and delivers a faux child result", async () => { const { routeParentThroughSubagent, runRealSubagentSession, subagentToolResults } = await import("../support/real-session-runner.ts"); const previousEnv = new Map(ISOLATED_ENV_KEYS.map((key) => [key, process.env[key]])); process.env.SELESAI_SUBAGENT_CHILD = "1"; process.env.SELESAI_SUBAGENT_FANOUT_CHILD = "1"; process.env.SELESAI_SUBAGENT_DEPTH = "1"; process.env.SELESAI_SUBAGENT_MAX_DEPTH = "1"; process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = BOGUS_EXTRA_DIRS; process.env.SELESAI_SUBAGENT_PARENT_SESSION = "polluted-parent"; process.env.SELESAI_SUBAGENT_PI_BINARY = BOGUS_PI_BINARY; process.env.SELESAI_SUBAGENTS_PI_CODING_AGENT_PACKAGE_ROOT = BOGUS_PI_PACKAGE_ROOT; try { run = await runRealSubagentSession({ prompt: "Delegate to a worker and report its exact result.", childText: CHILD_MARKER, respond: routeParentThroughSubagent({ childMarker: CHILD_MARKER, subagentArgs: { agent: "worker", task: "Return the marker from the faux child provider.", context: "fresh", agentScope: "project", }, }), }); const toolResults = subagentToolResults(run.parentSession); assert.equal(toolResults.length, 1); assert.match(toolResults[0]!, new RegExp(CHILD_MARKER)); assert.match(run.responseText, new RegExp(CHILD_MARKER)); assert.doesNotMatch(run.responseText, /CHILD_MISSING/); assert.ok(run.modelCalls >= 2, `expected parent tool-call and final turns, got ${run.modelCalls}`); } finally { await run?.dispose(); run = undefined; for (const [key, value] of previousEnv) { if (value === undefined) delete process.env[key]; else process.env[key] = value; } } }); });