@ai-setting/roy-agent-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -0
- package/dist/bin/roy.js +127297 -0
- package/dist/roy-agent-darwin-arm64/bin/roy.js +127297 -0
- package/dist/roy-agent-darwin-x64/bin/roy.js +127297 -0
- package/dist/roy-agent-linux-arm64/bin/roy.js +127297 -0
- package/dist/roy-agent-linux-x64/bin/roy.js +127297 -0
- package/dist/roy-agent-windows-x64/bin/roy.js +127297 -0
- package/package.json +91 -0
- package/src/bin/roy.ts +12 -0
- package/src/cli.ts +101 -0
- package/src/commands/act.ts +480 -0
- package/src/commands/commands-add.ts +110 -0
- package/src/commands/commands-dirs.ts +70 -0
- package/src/commands/commands-info.ts +90 -0
- package/src/commands/commands-list.ts +161 -0
- package/src/commands/commands-remove.ts +147 -0
- package/src/commands/commands.ts +55 -0
- package/src/commands/config/config-service.test.ts +449 -0
- package/src/commands/config/config-service.ts +312 -0
- package/src/commands/config/deep-merge.test.ts +168 -0
- package/src/commands/config/deep-merge.ts +63 -0
- package/src/commands/config/export.ts +97 -0
- package/src/commands/config/filter-history-e2e.test.ts +141 -0
- package/src/commands/config/import-preserve-refs.test.ts +212 -0
- package/src/commands/config/import.ts +119 -0
- package/src/commands/config/index.ts +35 -0
- package/src/commands/config/list.ts +281 -0
- package/src/commands/config/roy-config-e2e.test.ts +297 -0
- package/src/commands/config/types.ts +54 -0
- package/src/commands/debug/index.ts +38 -0
- package/src/commands/debug/log.test.ts +233 -0
- package/src/commands/debug/log.ts +123 -0
- package/src/commands/debug/span.test.ts +297 -0
- package/src/commands/debug/span.ts +211 -0
- package/src/commands/debug/trace.test.ts +254 -0
- package/src/commands/debug/trace.ts +140 -0
- package/src/commands/eventsource/add.ts +133 -0
- package/src/commands/eventsource/index.ts +48 -0
- package/src/commands/eventsource/list.ts +194 -0
- package/src/commands/eventsource/remove.ts +95 -0
- package/src/commands/eventsource/start.ts +103 -0
- package/src/commands/eventsource/status.ts +185 -0
- package/src/commands/eventsource/stop.ts +89 -0
- package/src/commands/index.ts +22 -0
- package/src/commands/input-handler.test.ts +76 -0
- package/src/commands/input-handler.ts +43 -0
- package/src/commands/interactive-esc.test.ts +254 -0
- package/src/commands/interactive.shutdown.test.ts +122 -0
- package/src/commands/interactive.test.ts +221 -0
- package/src/commands/interactive.ts +1015 -0
- package/src/commands/lsp/check.ts +92 -0
- package/src/commands/lsp/index.ts +32 -0
- package/src/commands/lsp/install.ts +126 -0
- package/src/commands/lsp/list.ts +64 -0
- package/src/commands/mcp/index.ts +27 -0
- package/src/commands/mcp/list.ts +116 -0
- package/src/commands/mcp/reload.ts +70 -0
- package/src/commands/mcp/tools.ts +121 -0
- package/src/commands/memory/extract-e2e.test.ts +388 -0
- package/src/commands/memory/index.ts +11 -0
- package/src/commands/memory/memory-simplified.test.ts +58 -0
- package/src/commands/memory/memory.ts +25 -0
- package/src/commands/memory/organize.ts +300 -0
- package/src/commands/memory/recall.test.ts +120 -0
- package/src/commands/memory/recall.ts +88 -0
- package/src/commands/memory/record-extract-handle-query.test.ts +385 -0
- package/src/commands/memory/record-prompt-component.test.ts +343 -0
- package/src/commands/memory/record.test.ts +92 -0
- package/src/commands/memory/record.ts +332 -0
- package/src/commands/plugin.test.ts +292 -0
- package/src/commands/plugin.ts +267 -0
- package/src/commands/sessions/active.ts +96 -0
- package/src/commands/sessions/add-message.ts +96 -0
- package/src/commands/sessions/checkpoints.ts +154 -0
- package/src/commands/sessions/compact.test.ts +215 -0
- package/src/commands/sessions/compact.ts +269 -0
- package/src/commands/sessions/delete.ts +236 -0
- package/src/commands/sessions/get.ts +165 -0
- package/src/commands/sessions/grep.ts +233 -0
- package/src/commands/sessions/index.ts +95 -0
- package/src/commands/sessions/list.ts +210 -0
- package/src/commands/sessions/messages.test.ts +333 -0
- package/src/commands/sessions/messages.ts +248 -0
- package/src/commands/sessions/mock.ts +194 -0
- package/src/commands/sessions/new.ts +82 -0
- package/src/commands/sessions/rename.ts +98 -0
- package/src/commands/shared/event-handler.ts +213 -0
- package/src/commands/shared/event-message-formatter.ts +295 -0
- package/src/commands/shared/index.ts +11 -0
- package/src/commands/shared/query-executor.test.ts +434 -0
- package/src/commands/shared/query-executor.ts +324 -0
- package/src/commands/shared/repl-engine.test.ts +354 -0
- package/src/commands/shared/session-manager.test.ts +212 -0
- package/src/commands/shared/session-manager.ts +114 -0
- package/src/commands/skills/get.ts +90 -0
- package/src/commands/skills/index.ts +39 -0
- package/src/commands/skills/list.ts +129 -0
- package/src/commands/skills/reload.ts +59 -0
- package/src/commands/skills/search.ts +132 -0
- package/src/commands/skills/show-config.ts +93 -0
- package/src/commands/tasks/complete.ts +92 -0
- package/src/commands/tasks/create.ts +118 -0
- package/src/commands/tasks/delete.ts +86 -0
- package/src/commands/tasks/get.ts +116 -0
- package/src/commands/tasks/index.ts +53 -0
- package/src/commands/tasks/list.ts +140 -0
- package/src/commands/tasks/operations.ts +120 -0
- package/src/commands/tasks/update.ts +122 -0
- package/src/commands/tools/exec-tool.ts +128 -0
- package/src/commands/tools/get.ts +114 -0
- package/src/commands/tools/index.ts +35 -0
- package/src/commands/tools/list.ts +107 -0
- package/src/commands/tools/shared/index.ts +7 -0
- package/src/commands/tools/shared/schema-helper.ts +111 -0
- package/src/commands/workflow/commands/add.ts +315 -0
- package/src/commands/workflow/commands/get.ts +193 -0
- package/src/commands/workflow/commands/list.ts +137 -0
- package/src/commands/workflow/commands/nodes.ts +528 -0
- package/src/commands/workflow/commands/remove.ts +94 -0
- package/src/commands/workflow/commands/run.ts +398 -0
- package/src/commands/workflow/commands/status.ts +147 -0
- package/src/commands/workflow/commands/stop.ts +91 -0
- package/src/commands/workflow/commands/update.ts +130 -0
- package/src/commands/workflow/commands/validate.ts +139 -0
- package/src/commands/workflow/commands/workflow-cli.test.ts +196 -0
- package/src/commands/workflow/index.ts +65 -0
- package/src/commands/workflow/renderers.ts +358 -0
- package/src/commands/workflow/validators/index.ts +8 -0
- package/src/commands/workflow/validators/node-validator-factory.ts +40 -0
- package/src/commands/workflow/validators/node-validator.ts +125 -0
- package/src/commands/workflow/validators/nodes/agent-node-validator.ts +58 -0
- package/src/commands/workflow/validators/nodes/condition-node-validator.ts +34 -0
- package/src/commands/workflow/validators/nodes/decorator-node-validator.ts +45 -0
- package/src/commands/workflow/validators/nodes/merge-node-validator.ts +46 -0
- package/src/commands/workflow/validators/nodes/skill-node-validator.ts +33 -0
- package/src/commands/workflow/validators/nodes/tool-node-validator.ts +54 -0
- package/src/commands/workflow/validators/nodes/workflow-node-validator.ts +33 -0
- package/src/commands/workflow/validators/types.ts +78 -0
- package/src/commands/workflow/validators/workflow-validator.test.ts +273 -0
- package/src/commands/workflow/validators/workflow-validator.ts +320 -0
- package/src/index.ts +19 -0
- package/src/plugin/apply.ts +103 -0
- package/src/plugin/discover.ts +219 -0
- package/src/plugin/index.ts +45 -0
- package/src/plugin/registry.ts +272 -0
- package/src/plugin/types.ts +165 -0
- package/src/services/context-handler.service.test.ts +501 -0
- package/src/services/context-handler.service.ts +372 -0
- package/src/services/environment.service.commands-prompt.test.ts +167 -0
- package/src/services/environment.service.ts +656 -0
- package/src/services/output.service.test.ts +92 -0
- package/src/services/output.service.ts +122 -0
- package/src/services/quiet-mode.service.test.ts +114 -0
- package/src/services/quiet-mode.service.ts +81 -0
- package/src/services/stream-output.service.test.ts +214 -0
- package/src/services/stream-output.service.ts +323 -0
- package/src/util/which.test.ts +101 -0
- package/src/util/which.ts +55 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TDD Test for record --extract using env.handle_query
|
|
3
|
+
*
|
|
4
|
+
* 验证 record.ts 应该使用 env.handle_query() 执行 agent,
|
|
5
|
+
* 而不是直接调用 agentComponent.run()
|
|
6
|
+
*
|
|
7
|
+
* 参考 delegate_task 的实现模式
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, test, vi, beforeEach, afterEach } from "vitest";
|
|
11
|
+
|
|
12
|
+
// Mock chalk
|
|
13
|
+
vi.mock("chalk", () => ({
|
|
14
|
+
default: {
|
|
15
|
+
blue: (str: string) => str,
|
|
16
|
+
gray: (str: string) => str,
|
|
17
|
+
green: (str: string) => str,
|
|
18
|
+
red: (str: string) => str,
|
|
19
|
+
yellow: (str: string) => str,
|
|
20
|
+
cyan: (str: string) => str,
|
|
21
|
+
bold: (str: string) => str,
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
describe("RecordCommand - Extract Mode with handle_query", () => {
|
|
26
|
+
let mockEnv: any;
|
|
27
|
+
let mockAgentComponent: any;
|
|
28
|
+
let mockMemoryComponent: any;
|
|
29
|
+
let mockSessionComponent: any;
|
|
30
|
+
let mockToolComponent: any;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
// Mock components
|
|
34
|
+
mockMemoryComponent = {
|
|
35
|
+
recallMemory: vi.fn().mockResolvedValue("# 项目记忆\n\n暂无内容"),
|
|
36
|
+
recordMemory: vi.fn().mockResolvedValue({ path: "/test/memory.md", action: "overwrite" }),
|
|
37
|
+
getMemoryPaths: vi.fn().mockReturnValue([
|
|
38
|
+
{ type: "project", path: ".roy/memory" },
|
|
39
|
+
{ type: "user", path: "~/.config/roy-agent/memory" },
|
|
40
|
+
]),
|
|
41
|
+
getMemoryFile: vi.fn().mockReturnValue("memory.md"),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
mockSessionComponent = {
|
|
45
|
+
searchSessions: vi.fn().mockResolvedValue([
|
|
46
|
+
{ sessionId: "test-1", title: "Test Session", preview: "Hello world" }
|
|
47
|
+
]),
|
|
48
|
+
getSession: vi.fn().mockResolvedValue({
|
|
49
|
+
sessionId: "test-1",
|
|
50
|
+
messages: [
|
|
51
|
+
{ role: "user", content: "Hello" },
|
|
52
|
+
{ role: "assistant", content: "Hi there!" },
|
|
53
|
+
],
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
mockAgentComponent = {
|
|
58
|
+
registerAgent: vi.fn().mockReturnValue({
|
|
59
|
+
name: "memory-extract-project",
|
|
60
|
+
config: { type: "sub" },
|
|
61
|
+
status: "idle",
|
|
62
|
+
plugins: new Map(),
|
|
63
|
+
}),
|
|
64
|
+
unregisterAgent: vi.fn(),
|
|
65
|
+
setDefaultTools: vi.fn(),
|
|
66
|
+
run: vi.fn(), // Not used anymore with handle_query
|
|
67
|
+
getAgent: vi.fn().mockReturnValue({
|
|
68
|
+
name: "memory-extract-project",
|
|
69
|
+
config: { type: "sub" },
|
|
70
|
+
status: "idle",
|
|
71
|
+
plugins: new Map(),
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
mockToolComponent = {
|
|
76
|
+
register: vi.fn(),
|
|
77
|
+
unregister: vi.fn(),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Mock env with handle_query method
|
|
81
|
+
mockEnv = {
|
|
82
|
+
getComponent: vi.fn((name: string) => {
|
|
83
|
+
switch (name) {
|
|
84
|
+
case "memory":
|
|
85
|
+
return mockMemoryComponent;
|
|
86
|
+
case "agent":
|
|
87
|
+
return mockAgentComponent;
|
|
88
|
+
case "session":
|
|
89
|
+
return mockSessionComponent;
|
|
90
|
+
case "tool":
|
|
91
|
+
return mockToolComponent;
|
|
92
|
+
default:
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}),
|
|
96
|
+
// handle_query returns string (finalText), not object
|
|
97
|
+
handle_query: vi.fn().mockResolvedValue("Memory extracted successfully via handle_query"),
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
afterEach(() => {
|
|
102
|
+
vi.clearAllMocks();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("TDD: record --extract should use env.handle_query", () => {
|
|
106
|
+
|
|
107
|
+
test("should call env.handle_query with agentType instead of agentComponent.run", async () => {
|
|
108
|
+
// This test verifies the NEW behavior: using handle_query
|
|
109
|
+
// Given: mock env and components
|
|
110
|
+
// When: runExtractMode is called
|
|
111
|
+
// Then: env.handle_query should be called with agentType
|
|
112
|
+
|
|
113
|
+
const { createMemoryAgentTools, getBuiltInPrompt } = await import("@ai-setting/roy-agent-core");
|
|
114
|
+
|
|
115
|
+
const memoryTools = createMemoryAgentTools({
|
|
116
|
+
sessionComponent: mockSessionComponent,
|
|
117
|
+
memoryComponent: mockMemoryComponent,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Get prompt template
|
|
121
|
+
const promptTemplate = getBuiltInPrompt("project-memory");
|
|
122
|
+
expect(promptTemplate).toBeDefined();
|
|
123
|
+
|
|
124
|
+
// Simulate what runExtractMode does
|
|
125
|
+
const currentMemory = await mockMemoryComponent.recallMemory("project");
|
|
126
|
+
const agentName = "memory-extract-project";
|
|
127
|
+
|
|
128
|
+
const systemPrompt = promptTemplate!
|
|
129
|
+
.replace("{USER_REQUIREMENT}", "请从会话历史中提炼关键知识。")
|
|
130
|
+
.replace("{SCOPE}", "project")
|
|
131
|
+
.replace("{CURRENT_MEMORY}", currentMemory || "(无现有记忆)");
|
|
132
|
+
|
|
133
|
+
// Register agent
|
|
134
|
+
mockAgentComponent.registerAgent(agentName, {
|
|
135
|
+
type: "sub",
|
|
136
|
+
systemPrompt,
|
|
137
|
+
allowedTools: ["search_sessions", "get_session", "write_memory"],
|
|
138
|
+
deniedTools: [],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// NEW BEHAVIOR: Should call env.handle_query instead of agentComponent.run
|
|
142
|
+
const query = "请分析会话历史,提炼项目记忆并写入记忆文件。";
|
|
143
|
+
|
|
144
|
+
// This is what the new implementation does
|
|
145
|
+
let result: string;
|
|
146
|
+
try {
|
|
147
|
+
result = await mockEnv.handle_query(query, {
|
|
148
|
+
sessionId: "test-session",
|
|
149
|
+
agentType: agentName,
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
result = `执行失败: ${error instanceof Error ? error.message : String(error)}`;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Verify handle_query was called
|
|
156
|
+
expect(mockEnv.handle_query).toHaveBeenCalledWith(
|
|
157
|
+
query,
|
|
158
|
+
expect.objectContaining({
|
|
159
|
+
agentType: agentName,
|
|
160
|
+
sessionId: "test-session",
|
|
161
|
+
})
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Verify agentComponent.run was NOT called
|
|
165
|
+
expect(mockAgentComponent.run).not.toHaveBeenCalled();
|
|
166
|
+
|
|
167
|
+
// Verify result is a string (not an object)
|
|
168
|
+
expect(typeof result).toBe("string");
|
|
169
|
+
expect(result).toBe("Memory extracted successfully via handle_query");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("should register agent with allowedTools for tool filtering", async () => {
|
|
173
|
+
// Verify agent registration includes allowedTools
|
|
174
|
+
const { getBuiltInPrompt } = await import("@ai-setting/roy-agent-core");
|
|
175
|
+
|
|
176
|
+
const promptTemplate = getBuiltInPrompt("project-memory");
|
|
177
|
+
const agentName = "memory-extract-project";
|
|
178
|
+
const systemPrompt = promptTemplate!
|
|
179
|
+
.replace("{USER_REQUIREMENT}", "test")
|
|
180
|
+
.replace("{SCOPE}", "project")
|
|
181
|
+
.replace("{CURRENT_MEMORY}", "");
|
|
182
|
+
|
|
183
|
+
// Register agent with allowedTools (key for tool filtering)
|
|
184
|
+
mockAgentComponent.registerAgent(agentName, {
|
|
185
|
+
type: "sub",
|
|
186
|
+
systemPrompt,
|
|
187
|
+
allowedTools: ["search_sessions", "get_session", "write_memory"],
|
|
188
|
+
deniedTools: [],
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Verify registration was called with correct config
|
|
192
|
+
expect(mockAgentComponent.registerAgent).toHaveBeenCalledWith(
|
|
193
|
+
agentName,
|
|
194
|
+
expect.objectContaining({
|
|
195
|
+
type: "sub",
|
|
196
|
+
allowedTools: expect.arrayContaining(["search_sessions", "get_session", "write_memory"]),
|
|
197
|
+
})
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test("should handle both project and global scope via handle_query", async () => {
|
|
202
|
+
const { getBuiltInPrompt } = await import("@ai-setting/roy-agent-core");
|
|
203
|
+
|
|
204
|
+
// Test project scope
|
|
205
|
+
const projectPrompt = getBuiltInPrompt("project-memory");
|
|
206
|
+
expect(projectPrompt).toContain("{USER_REQUIREMENT}");
|
|
207
|
+
|
|
208
|
+
// Test global scope
|
|
209
|
+
const globalPrompt = getBuiltInPrompt("global-memory");
|
|
210
|
+
expect(globalPrompt).toContain("{USER_REQUIREMENT}");
|
|
211
|
+
|
|
212
|
+
// Both scopes should work with handle_query
|
|
213
|
+
for (const [scope, prompt] of [["project", projectPrompt], ["global", globalPrompt]]) {
|
|
214
|
+
const agentName = `memory-extract-${scope}`;
|
|
215
|
+
|
|
216
|
+
await mockEnv.handle_query("test query", {
|
|
217
|
+
sessionId: "test-session",
|
|
218
|
+
agentType: agentName,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(mockEnv.handle_query).toHaveBeenCalledWith(
|
|
222
|
+
"test query",
|
|
223
|
+
expect.objectContaining({
|
|
224
|
+
agentType: agentName,
|
|
225
|
+
})
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("should cleanup agent after execution", async () => {
|
|
231
|
+
// After handle_query completes, agent should be unregistered
|
|
232
|
+
const agentName = "memory-extract-project";
|
|
233
|
+
|
|
234
|
+
await mockEnv.handle_query("test query", {
|
|
235
|
+
sessionId: "test-session",
|
|
236
|
+
agentType: agentName,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Simulate cleanup (this happens in record.ts)
|
|
240
|
+
mockAgentComponent.unregisterAgent(agentName);
|
|
241
|
+
|
|
242
|
+
expect(mockAgentComponent.unregisterAgent).toHaveBeenCalledWith(agentName);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("should cleanup toolComponent tools after execution", async () => {
|
|
246
|
+
// After handle_query completes, tools should be unregistered from ToolComponent
|
|
247
|
+
const agentName = "memory-extract-project";
|
|
248
|
+
|
|
249
|
+
await mockEnv.handle_query("test query", {
|
|
250
|
+
sessionId: "test-session",
|
|
251
|
+
agentType: agentName,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Simulate tool cleanup
|
|
255
|
+
mockToolComponent.unregister("search_sessions");
|
|
256
|
+
mockToolComponent.unregister("get_session");
|
|
257
|
+
mockToolComponent.unregister("write_memory");
|
|
258
|
+
|
|
259
|
+
expect(mockToolComponent.unregister).toHaveBeenCalledTimes(3);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
describe("Comparison: delegate_task vs record --extract pattern", () => {
|
|
265
|
+
|
|
266
|
+
test("delegate_task uses handle_query pattern (reference implementation)", async () => {
|
|
267
|
+
// Reference pattern from delegate_task (delegate-tool.ts)
|
|
268
|
+
const subagentType = "general";
|
|
269
|
+
const sessionId = "test-session";
|
|
270
|
+
const query = "Complete this task";
|
|
271
|
+
|
|
272
|
+
// Pattern:
|
|
273
|
+
// 1. Register agent (with deniedTools for nested delegation prevention)
|
|
274
|
+
// 2. Call env.handle_query with agentType
|
|
275
|
+
// 3. Return result
|
|
276
|
+
|
|
277
|
+
mockEnv.handle_query(query, {
|
|
278
|
+
sessionId,
|
|
279
|
+
deniedTools: ["delegate_task", "stop_task"],
|
|
280
|
+
agentType: subagentType,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
expect(mockEnv.handle_query).toHaveBeenCalledWith(
|
|
284
|
+
query,
|
|
285
|
+
expect.objectContaining({
|
|
286
|
+
sessionId,
|
|
287
|
+
agentType: subagentType,
|
|
288
|
+
})
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test("record --extract should follow same handle_query pattern", async () => {
|
|
293
|
+
// Expected pattern for record --extract after fix
|
|
294
|
+
const agentName = "memory-extract-project";
|
|
295
|
+
const sessionId = "test-session";
|
|
296
|
+
const query = "Extract memory from session";
|
|
297
|
+
|
|
298
|
+
// Pattern (same as delegate_task):
|
|
299
|
+
// 1. Register agent with allowedTools
|
|
300
|
+
// 2. Call env.handle_query with agentType (NOT agentComponent.run)
|
|
301
|
+
// 3. Return result
|
|
302
|
+
|
|
303
|
+
await mockEnv.handle_query(query, {
|
|
304
|
+
sessionId,
|
|
305
|
+
agentType: agentName,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
expect(mockEnv.handle_query).toHaveBeenCalledWith(
|
|
309
|
+
query,
|
|
310
|
+
expect.objectContaining({
|
|
311
|
+
sessionId,
|
|
312
|
+
agentType: agentName,
|
|
313
|
+
})
|
|
314
|
+
);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe("Error handling in handle_query execution", () => {
|
|
320
|
+
|
|
321
|
+
test("should handle handle_query errors gracefully", async () => {
|
|
322
|
+
// Mock handle_query to throw an error
|
|
323
|
+
mockEnv.handle_query.mockRejectedValueOnce(new Error("LLM error"));
|
|
324
|
+
|
|
325
|
+
let result: string;
|
|
326
|
+
try {
|
|
327
|
+
result = await mockEnv.handle_query("test query", { agentType: "memory-extract-project" });
|
|
328
|
+
} catch (error) {
|
|
329
|
+
result = `执行失败: ${error instanceof Error ? error.message : String(error)}`;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
expect(result).toBe("执行失败: LLM error");
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("should handle empty handle_query result", async () => {
|
|
336
|
+
// Mock handle_query to return empty string
|
|
337
|
+
mockEnv.handle_query.mockResolvedValueOnce("");
|
|
338
|
+
|
|
339
|
+
const result = await mockEnv.handle_query("test query", { agentType: "memory-extract-project" });
|
|
340
|
+
|
|
341
|
+
expect(result).toBe("");
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("should handle long result from handle_query", async () => {
|
|
345
|
+
// Mock handle_query to return long result
|
|
346
|
+
const longResult = "A".repeat(500);
|
|
347
|
+
mockEnv.handle_query.mockResolvedValueOnce(longResult);
|
|
348
|
+
|
|
349
|
+
const result = await mockEnv.handle_query("test query", { agentType: "memory-extract-project" });
|
|
350
|
+
|
|
351
|
+
expect(result.length).toBe(500);
|
|
352
|
+
// record.ts truncates to 200 chars
|
|
353
|
+
expect(result.substring(0, 200).length).toBe(200);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
describe("Result output handling", () => {
|
|
359
|
+
|
|
360
|
+
test("should output success message when handle_query succeeds", async () => {
|
|
361
|
+
const result = await mockEnv.handle_query("test query", { agentType: "memory-extract-project" });
|
|
362
|
+
|
|
363
|
+
// Success case: result is truthy and doesn't start with "执行失败"
|
|
364
|
+
if (result && !result.startsWith("执行失败")) {
|
|
365
|
+
// This is the success branch in record.ts
|
|
366
|
+
expect(true).toBe(true); // Would output success message
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("should output error message when handle_query fails", async () => {
|
|
371
|
+
mockEnv.handle_query.mockRejectedValueOnce(new Error("Connection timeout"));
|
|
372
|
+
|
|
373
|
+
let result: string;
|
|
374
|
+
try {
|
|
375
|
+
result = await mockEnv.handle_query("test query", { agentType: "memory-extract-project" });
|
|
376
|
+
} catch (error) {
|
|
377
|
+
result = `执行失败: ${error instanceof Error ? error.message : String(error)}`;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Error case: result starts with "执行失败"
|
|
381
|
+
expect(result).toContain("执行失败");
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
});
|
|
385
|
+
});
|