Files
fusion/packages/engine/src/__tests__/runtime-selection-regression.test.ts
2026-05-20 02:48:39 -07:00

348 lines
10 KiB
TypeScript

/**
* Runtime Selection Regression Tests
*
* These tests verify that engine subsystems correctly use the runtime resolution
* system and fall back to the default pi runtime when no runtime hint is configured.
*
* Key behaviors tested:
* 1. Subsystems with pluginRunner option can resolve plugin runtimes
* 2. Subsystems without pluginRunner or hint fall back to pi runtime
* 3. Runtime resolution logs are emitted correctly
*/
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
// Mock the logger to suppress output during tests
vi.mock("../logger.js", () => ({
createLogger: vi.fn(() => ({
log: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
})),
}));
// Mock pi.js to avoid actual session creation
vi.mock("../pi.js", () => ({
createFnAgent: vi.fn().mockResolvedValue({
session: {
model: { provider: "anthropic", id: "claude-sonnet-4-5" },
prompt: vi.fn(),
},
sessionFile: undefined,
}),
promptWithFallback: vi.fn().mockResolvedValue(undefined),
describeModel: vi.fn().mockReturnValue("anthropic/claude-sonnet-4-5"),
}));
// Mock the runtime resolution module
const mockResolveRuntime = vi.fn();
vi.mock("../runtime-resolution.js", async () => {
const actual = await vi.importActual<typeof import("../runtime-resolution.js")>("../runtime-resolution.js");
return {
...actual,
resolveRuntime: (...args: unknown[]) => mockResolveRuntime(...args),
buildRuntimeResolutionContext: vi.fn().mockReturnValue({
sessionPurpose: "test",
runtimeHint: undefined,
pluginRunner: {},
}),
};
});
// Mock session skill context
vi.mock("../session-skill-context.js", () => ({
buildSessionSkillContext: vi.fn().mockResolvedValue({
skillSelectionContext: undefined,
resolvedSkillNames: [],
skillSource: "none",
}),
buildSessionSkillContextSync: vi.fn().mockReturnValue({
skillSelectionContext: undefined,
resolvedSkillNames: [],
skillSource: "none",
}),
}));
// Mock agent instructions
vi.mock("../agent-instructions.js", () => ({
resolveAgentInstructions: vi.fn().mockResolvedValue(""),
buildSystemPromptWithInstructions: vi.fn().mockImplementation((base) => base),
resolveAgentInstructionsWithRatings: vi.fn().mockResolvedValue(""),
}));
describe("Runtime Selection Regression Tests", () => {
beforeEach(() => {
vi.clearAllMocks();
// Default: resolveRuntime returns pi runtime
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "pi",
name: "Default PI Runtime",
createSession: async () => ({
session: {
model: { provider: "anthropic", id: "claude-sonnet-4-5" },
prompt: vi.fn(),
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "anthropic/claude-sonnet-4-5",
},
wasConfigured: false,
runtimeId: "pi",
});
});
afterEach(() => {
vi.restoreAllMocks();
});
describe("createResolvedAgentSession", () => {
it("should call resolveRuntime when creating a session", async () => {
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
await createResolvedAgentSession({
sessionPurpose: "executor",
pluginRunner: {} as any,
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(mockResolveRuntime).toHaveBeenCalled();
});
it("should use the resolved runtime's createSession method", async () => {
const mockCreateSession = vi.fn().mockResolvedValue({
session: {
model: { provider: "test", id: "test-model" },
},
});
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "test-runtime",
name: "Test Runtime",
createSession: mockCreateSession,
promptWithFallback: vi.fn(),
describeModel: () => "test/model",
},
wasConfigured: true,
runtimeId: "test-runtime",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const permanentAgentGating = {
permissionPolicy: {
presetId: "approval-required",
rules: { command_execution: "require-approval" as const },
},
};
await createResolvedAgentSession({
sessionPurpose: "executor",
pluginRunner: {} as any,
cwd: "/test/path",
systemPrompt: "Test prompt",
permanentAgentGating,
});
expect(mockCreateSession).toHaveBeenCalledWith(expect.objectContaining({ permanentAgentGating }));
});
it("should return runtime metadata along with session", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "my-runtime",
name: "My Runtime",
createSession: async () => ({
session: {
model: { provider: "test", id: "test-model" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "test/model",
},
wasConfigured: true,
runtimeId: "my-runtime",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "triage",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("my-runtime");
expect(result.wasConfigured).toBe(true);
});
});
describe("Default pi runtime fallback", () => {
it("should fall back to pi runtime when no runtime hint provided", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "pi",
name: "Default PI Runtime",
createSession: async () => ({
session: {
model: { provider: "anthropic", id: "claude-sonnet-4-5" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "anthropic/claude-sonnet-4-5",
},
wasConfigured: false,
runtimeId: "pi",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "merger",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("pi");
expect(result.wasConfigured).toBe(false);
});
it("should fall back to pi runtime when runtime hint references non-existent runtime", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "pi",
name: "Default PI Runtime",
createSession: async () => ({
session: {
model: { provider: "anthropic", id: "claude-sonnet-4-5" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "anthropic/claude-sonnet-4-5",
},
wasConfigured: false,
runtimeId: "pi",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "heartbeat",
pluginRunner: {} as any,
runtimeHint: "non-existent-runtime",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("pi");
expect(result.wasConfigured).toBe(false);
});
});
describe("Plugin runtime selection", () => {
it("should use configured plugin runtime when hint matches", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "code-interpreter",
name: "Code Interpreter Runtime",
createSession: async () => ({
session: {
model: { provider: "custom", id: "custom-model" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "custom/model",
},
wasConfigured: true,
runtimeId: "code-interpreter",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "executor",
pluginRunner: {
getRuntimeById: vi.fn().mockReturnValue({
pluginId: "code-plugin",
runtime: {
metadata: { runtimeId: "code-interpreter", name: "Code Interpreter" },
factory: vi.fn(),
},
}),
} as any,
runtimeHint: "code-interpreter",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("code-interpreter");
expect(result.wasConfigured).toBe(true);
});
it("should route runtimeHint=openclaw to the openclaw runtime", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "openclaw",
name: "OpenClaw Runtime",
createSession: async () => ({
session: {
model: { provider: "openclaw", id: "openclaw-agent" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "openclaw/openclaw-agent",
},
wasConfigured: true,
runtimeId: "openclaw",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "executor",
pluginRunner: {} as any,
runtimeHint: "openclaw",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("openclaw");
expect(result.wasConfigured).toBe(true);
});
it("should route runtimeHint=droid to the droid runtime", async () => {
mockResolveRuntime.mockResolvedValue({
runtime: {
id: "droid",
name: "Droid Runtime",
createSession: async () => ({
session: {
model: { provider: "droid-cli", id: "droid-pro" },
},
}),
promptWithFallback: vi.fn(),
describeModel: () => "droid/droid-pro",
},
wasConfigured: true,
runtimeId: "droid",
});
const { createResolvedAgentSession } = await import("../agent-session-helpers.js");
const result = await createResolvedAgentSession({
sessionPurpose: "executor",
pluginRunner: {} as any,
runtimeHint: "droid",
cwd: "/test/path",
systemPrompt: "Test prompt",
});
expect(result.runtimeId).toBe("droid");
expect(result.wasConfigured).toBe(true);
});
});
});