-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Expand file tree
/
Copy pathsubagent.test.ts
More file actions
121 lines (99 loc) · 3.31 KB
/
subagent.test.ts
File metadata and controls
121 lines (99 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { beforeEach, describe, expect, it, vi } from "vitest";
import { services } from "../services/index.js";
import { serviceContainer } from "../services/ServiceContainer.js";
import { executeSubAgent } from "../subagent/executor.js";
import { getAgentNames, getSubagent } from "../subagent/getAgents.js";
import { subagentTool } from "./subagent.js";
vi.mock("../subagent/get-agents.js");
vi.mock("../subagent/executor.js");
vi.mock("../services/ServiceContainer.js", () => ({
serviceContainer: {
get: vi.fn(),
},
}));
vi.mock("../services/index.js", () => ({
services: {
chatHistory: {
getSessionId: vi.fn().mockReturnValue("parent-session-id"),
addToolResult: vi.fn(),
},
},
}));
describe("subagentTool", () => {
const modelServiceState = {} as any;
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(serviceContainer.get).mockResolvedValue(modelServiceState);
});
it("preprocess throws when agent is not found", async () => {
vi.mocked(getAgentNames).mockReturnValue(["code-agent"]);
const tool = await subagentTool();
const args = {
description: "Test task",
prompt: "Do something",
subagent_name: "unknown-agent",
};
await expect(tool.preprocess!(args)).rejects.toThrow(
"Unknown agent type: unknown-agent",
);
expect(vi.mocked(getSubagent)).toHaveBeenCalledWith(
modelServiceState,
"unknown-agent",
);
});
it("preprocess includes agent model name when agent exists", async () => {
vi.mocked(getAgentNames).mockReturnValue(["code-agent"]);
const tool = await subagentTool();
vi.mocked(getSubagent).mockReturnValue({
model: { name: "test-model" },
} as any);
const args = {
description: "Handle specialized task",
prompt: "Do it",
subagent_name: "code-agent",
};
const result = await tool.preprocess!(args);
expect(result.preview).toEqual([
{
type: "text",
content: "Spawning test-model to: Handle specialized task",
},
]);
expect(vi.mocked(getSubagent)).toHaveBeenCalledWith(
modelServiceState,
"code-agent",
);
});
it("run executes subagent and returns formatted output", async () => {
vi.mocked(getAgentNames).mockReturnValue(["code-agent"]);
vi.mocked(getSubagent).mockReturnValue({
model: { name: "test-model" },
} as any);
vi.mocked(executeSubAgent).mockResolvedValue({
success: true,
response: "subagent-output",
} as any);
const tool = await subagentTool();
const result = await tool.run(
{
prompt: "Subagent prompt",
subagent_name: "code-agent",
},
{ toolCallId: "tool-call-id", parallelToolCallCount: 1 },
);
expect(vi.mocked(executeSubAgent)).toHaveBeenCalledTimes(1);
const [options] = vi.mocked(executeSubAgent).mock.calls[0];
expect(options.prompt).toBe("Subagent prompt");
expect(options.parentSessionId).toBe("parent-session-id");
expect(typeof options.onOutputUpdate).toBe("function");
options.onOutputUpdate?.("partial-output");
expect(vi.mocked(services.chatHistory.addToolResult)).toHaveBeenCalledWith(
"tool-call-id",
"partial-output",
"calling",
);
expect(result).toBe(
"subagent-output\n<task_metadata>\nstatus: completed\n</task_metadata>",
);
});
});