import { afterEach, describe, expect, it, vi } from "bun:test"; import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings"; import { runEvalAgent } from "@oh-my-pi/pi-coding-agent/eval/agent-bridge"; import type { LocalProtocolOptions } from "@oh-my-pi/pi-coding-agent/internal-urls"; import type { MCPManager } from "@oh-my-pi/pi-coding-agent/mcp"; import * as taskDiscovery from "@oh-my-pi/pi-coding-agent/task/discovery"; import * as taskExecutor from "@oh-my-pi/pi-coding-agent/task/executor"; import type { AgentDefinition, SingleResult, StructuredSubagentOutput } from "@oh-my-pi/pi-coding-agent/task/types"; import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools"; function createResult(overrides: Partial = {}): SingleResult { return { index: 0, id: "0-Task", agent: "task", agentSource: "bundled", task: "do work", exitCode: 0, output: "done", stderr: "", truncated: false, durationMs: 1, tokens: 0, requests: 0, ...overrides, }; } describe("runEvalAgent", () => { afterEach(() => { vi.restoreAllMocks(); }); it("forwards session-scoped MCP and local protocol options", async () => { const agent: AgentDefinition = { name: "task", description: "Task agent", systemPrompt: "Handle task", source: "bundled", }; vi.spyOn(taskDiscovery, "discoverAgents").mockResolvedValue({ agents: [agent], projectAgentsDir: null }); const runSubprocessSpy = vi.spyOn(taskExecutor, "runSubprocess").mockResolvedValue(createResult()); const mcpManager = { sentinel: "mcp" } as unknown as MCPManager; const localProtocolOptions: LocalProtocolOptions = { getArtifactsDir: () => "/tmp/parent-artifacts", getSessionId: () => "parent-session", }; const session = { cwd: "/tmp", settings: Settings.isolated(), getSessionSpawns: () => "*", getSessionFile: () => null, mcpManager, localProtocolOptions, getAgentId: () => "BridgeParent", } as unknown as ToolSession; await runEvalAgent({ prompt: "do work", agent: "task" }, { session }); expect(runSubprocessSpy).toHaveBeenCalledTimes(1); const options = runSubprocessSpy.mock.calls[0]?.[0]; expect(options?.mcpManager).toBe(mcpManager); expect(options?.localProtocolOptions).toBe(localProtocolOptions); expect(options?.parentAgentId).toBe("BridgeParent"); }); it("returns executor-parsed structured data through the public eval bridge", async () => { const agent: AgentDefinition = { name: "task", description: "Task agent", systemPrompt: "Handle task", source: "bundled", output: { type: "object" }, }; const structuredOutput: StructuredSubagentOutput = { source: "agent", mode: "strict", status: "valid", data: { status: "ok" }, }; vi.spyOn(taskDiscovery, "discoverAgents").mockResolvedValue({ agents: [agent], projectAgentsDir: null }); vi.spyOn(taskExecutor, "runSubprocess").mockResolvedValue(createResult({ output: "not JSON", structuredOutput })); const session = { cwd: "/tmp", settings: Settings.isolated(), getSessionSpawns: () => "*", getSessionFile: () => null, } as unknown as ToolSession; const result = await runEvalAgent({ prompt: "do work", agent: "task", schemaMode: "strict" }, { session }); expect(result.data).toEqual({ status: "ok" }); expect(result.details).toMatchObject({ structured: true, schemaSource: "agent", schemaMode: "strict" }); }); });