test: add tests for --agent override and codex plugin registration

- Session manager: agent override uses correct agent, unknown agent throws, default used without override
- CLI spawn: --agent flag passthrough with and without issue ID
- Plugin registry: multiple agent plugins registered via loadBuiltins importFn

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
suraj-markup 2026-02-24 03:26:54 +05:30
parent b0965693c2
commit 2bdc6bb59c
3 changed files with 134 additions and 0 deletions

View File

@ -234,6 +234,62 @@ describe("spawn command", () => {
expect(output).toContain("8474d6f29887-app-7");
});
it("passes --agent flag to sessionManager.spawn()", async () => {
const fakeSession: Session = {
id: "app-1",
projectId: "my-app",
status: "spawning",
activity: null,
branch: null,
issueId: null,
pr: null,
workspacePath: "/tmp/wt",
runtimeHandle: { id: "hash-app-1", runtimeName: "tmux", data: {} },
agentInfo: null,
createdAt: new Date(),
lastActivityAt: new Date(),
metadata: {},
};
mockSessionManager.spawn.mockResolvedValue(fakeSession);
await program.parseAsync(["node", "test", "spawn", "my-app", "--agent", "codex"]);
expect(mockSessionManager.spawn).toHaveBeenCalledWith({
projectId: "my-app",
issueId: undefined,
agent: "codex",
});
});
it("passes --agent flag with issue ID", async () => {
const fakeSession: Session = {
id: "app-1",
projectId: "my-app",
status: "spawning",
activity: null,
branch: "feat/INT-42",
issueId: "INT-42",
pr: null,
workspacePath: "/tmp/wt",
runtimeHandle: { id: "hash-app-1", runtimeName: "tmux", data: {} },
agentInfo: null,
createdAt: new Date(),
lastActivityAt: new Date(),
metadata: {},
};
mockSessionManager.spawn.mockResolvedValue(fakeSession);
await program.parseAsync(["node", "test", "spawn", "my-app", "INT-42", "--agent", "codex"]);
expect(mockSessionManager.spawn).toHaveBeenCalledWith({
projectId: "my-app",
issueId: "INT-42",
agent: "codex",
});
});
it("rejects unknown project ID", async () => {
await expect(
program.parseAsync(["node", "test", "spawn", "nonexistent"]),

View File

@ -140,6 +140,26 @@ describe("loadBuiltins", () => {
// In the test environment, most are not resolvable — should not throw.
await expect(registry.loadBuiltins()).resolves.toBeUndefined();
});
it("registers multiple agent plugins from importFn", async () => {
const registry = createPluginRegistry();
const fakeClaudeCode = makePlugin("agent", "claude-code");
const fakeCodex = makePlugin("agent", "codex");
await registry.loadBuiltins(undefined, async (pkg: string) => {
if (pkg === "@composio/ao-plugin-agent-claude-code") return fakeClaudeCode;
if (pkg === "@composio/ao-plugin-agent-codex") return fakeCodex;
throw new Error(`Not found: ${pkg}`);
});
const agents = registry.list("agent");
expect(agents).toContainEqual(expect.objectContaining({ name: "claude-code", slot: "agent" }));
expect(agents).toContainEqual(expect.objectContaining({ name: "codex", slot: "agent" }));
expect(registry.get("agent", "codex")).not.toBeNull();
expect(registry.get("agent", "claude-code")).not.toBeNull();
});
});
describe("extractPluginConfig (via register with config)", () => {

View File

@ -227,6 +227,64 @@ describe("spawn", () => {
await expect(sm.spawn({ projectId: "my-app" })).rejects.toThrow("not found");
});
describe("agent override", () => {
let mockCodexAgent: Agent;
let registryWithMultipleAgents: PluginRegistry;
beforeEach(() => {
mockCodexAgent = {
name: "codex",
processName: "codex",
getLaunchCommand: vi.fn().mockReturnValue("codex --start"),
getEnvironment: vi.fn().mockReturnValue({ CODEX_VAR: "1" }),
detectActivity: vi.fn().mockReturnValue("active"),
getActivityState: vi.fn().mockResolvedValue(null),
isProcessRunning: vi.fn().mockResolvedValue(true),
getSessionInfo: vi.fn().mockResolvedValue(null),
};
registryWithMultipleAgents = {
...mockRegistry,
get: vi.fn().mockImplementation((slot: string, name: string) => {
if (slot === "runtime") return mockRuntime;
if (slot === "agent") {
if (name === "mock-agent") return mockAgent;
if (name === "codex") return mockCodexAgent;
return null;
}
if (slot === "workspace") return mockWorkspace;
return null;
}),
};
});
it("uses overridden agent when spawnConfig.agent is provided", async () => {
const sm = createSessionManager({ config, registry: registryWithMultipleAgents });
await sm.spawn({ projectId: "my-app", agent: "codex" });
expect(mockCodexAgent.getLaunchCommand).toHaveBeenCalled();
expect(mockAgent.getLaunchCommand).not.toHaveBeenCalled();
});
it("throws when agent override plugin is not found", async () => {
const sm = createSessionManager({ config, registry: registryWithMultipleAgents });
await expect(
sm.spawn({ projectId: "my-app", agent: "nonexistent" }),
).rejects.toThrow("Agent plugin 'nonexistent' not found");
});
it("uses default agent when no override specified", async () => {
const sm = createSessionManager({ config, registry: registryWithMultipleAgents });
await sm.spawn({ projectId: "my-app" });
expect(mockAgent.getLaunchCommand).toHaveBeenCalled();
expect(mockCodexAgent.getLaunchCommand).not.toHaveBeenCalled();
});
});
it("validates issue exists when issueId provided", async () => {
const mockTracker: Tracker = {
name: "mock-tracker",