@tencent-ai/cloud-agent-sdk 0.2.6 → 0.2.7-next.dbd767f.20260127

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.
@@ -1,3202 +0,0 @@
1
- import { z } from "zod";
2
-
3
- //#region ../agent-provider/src/common/_legacy/tool-schemas.ts
4
- /**
5
- * ACP Tool Input/Output Schema 定义
6
- *
7
- * 用于约束 ACP 协议中 ToolCallUpdate 的 rawInput 和 rawOutput 字段
8
- * 基于 getCraftToolProvider 使用的工具定义
9
- */
10
- /**
11
- * 工具输入 Schema 定义
12
- * 用于验证和约束 rawInput
13
- */
14
- const ToolInputSchemas = {
15
- list_dir: z.object({
16
- target_directory: z.string().describe("要列出内容的目录路径"),
17
- ignore_globs: z.string().optional().describe("可选的 glob 模式数组,用于忽略特定文件")
18
- }),
19
- search_file: z.object({
20
- target_directory: z.string().describe("搜索的目录绝对路径"),
21
- pattern: z.string().describe("文件模式(如 \"*.js\"),支持通配符"),
22
- recursive: z.boolean().describe("是否递归搜索子目录"),
23
- caseSensitive: z.boolean().describe("是否区分大小写")
24
- }),
25
- read_file: z.object({
26
- filePath: z.string().describe("要读取的文件的绝对路径"),
27
- offset: z.number().optional().describe("开始读取的行号"),
28
- limit: z.number().optional().describe("要读取的行数")
29
- }),
30
- read_lints: z.object({ paths: z.string().optional().describe("要读取 lint 错误的文件或目录路径") }),
31
- rag_search: z.object({
32
- queryString: z.string().describe("用户的实际问题或搜索查询"),
33
- knowledgeBaseNames: z.string().describe("知识库名称,多个用逗号分隔")
34
- }),
35
- read_rules: z.object({ ruleNames: z.string().describe("要读取的规则关键词,用逗号分隔,格式:{ruleName}_{ruleId}") }),
36
- mcp_get_tool_description: z.object({ toolRequests: z.string().describe("JSON 字符串,二维数组格式:[[\"server1\", \"tool1\"], [\"server2\", \"tool2\"]]") }),
37
- mcp_call_tool: z.object({
38
- serverName: z.string().describe("MCP 服务器名称"),
39
- toolName: z.string().describe("要调用的工具名称"),
40
- arguments: z.string().describe("目标 MCP 工具的参数,JSON 格式字符串"),
41
- maxOutputLength: z.number().optional().describe("控制工具输出的最大长度,默认 200000")
42
- }),
43
- fetch_mcp_resource: z.object({
44
- server: z.string().describe("MCP 服务器标识符"),
45
- uri: z.string().describe("要读取的资源 URI"),
46
- arguments: z.record(z.unknown()).optional().describe("资源模板的参数"),
47
- downloadPath: z.string().optional().describe("可选的绝对路径,用于保存资源到磁盘")
48
- }),
49
- create_rule: z.object({
50
- ruleScope: z.string().describe("规则范围,project rule 或 user rule"),
51
- ruleName: z.string().describe("规则文件名,不带扩展名"),
52
- ruleType: z.string().describe("规则类型,always、manual 或 requested"),
53
- ruleContent: z.string().describe("规则内容,使用 Markdown 格式"),
54
- ruleDescription: z.string().optional().describe("规则描述,使用 Markdown 格式")
55
- }),
56
- update_memory: z.object({
57
- action: z.enum([
58
- "create",
59
- "update",
60
- "delete"
61
- ]).optional().describe("执行的操作"),
62
- existing_knowledge_id: z.string().optional().describe("更新或删除时必需,现有记忆的 ID"),
63
- knowledge_to_store: z.string().optional().describe("要存储的特定记忆"),
64
- title: z.string().optional().describe("记忆的标题")
65
- }),
66
- search_content: z.object({
67
- pattern: z.string().describe("要搜索的关键字或正则表达式模式"),
68
- directory: z.string().describe("要搜索的目录的绝对路径"),
69
- fileTypes: z.string().optional().describe("可选的逗号分隔文件扩展名"),
70
- contextBefore: z.number().optional().describe("每个匹配前显示的行数"),
71
- contextAfter: z.number().optional().describe("每个匹配后显示的行数"),
72
- contextAround: z.number().optional().describe("每个匹配前后显示的行数"),
73
- outputMode: z.string().optional().describe("输出模式:content、files_with_matches 或 count"),
74
- caseSensitive: z.boolean().optional().describe("是否区分大小写")
75
- }),
76
- write_to_file: z.object({
77
- filePath: z.string().describe("目标文件的绝对路径"),
78
- content: z.string().describe("要写入的内容")
79
- }),
80
- replace_in_file: z.object({
81
- filePath: z.string().describe("要修改的文件的绝对路径"),
82
- old_str: z.string().describe("要替换的文本"),
83
- new_str: z.string().describe("替换后的文本")
84
- }),
85
- delete_file: z.object({
86
- target_file: z.string().describe("要删除的文件的绝对路径"),
87
- explanation: z.string().optional().describe("为什么使用此工具的一句话解释")
88
- }),
89
- execute_command: z.object({
90
- command: z.string().describe("要执行的 CLI 命令"),
91
- requires_approval: z.boolean().describe("命令是否需要用户批准")
92
- }),
93
- preview_url: z.object({ url: z.string().describe("要打开的完整、有效的 HTTP/HTTPS URL") }),
94
- ask_followup_question: z.object({ questions: z.array(z.object({
95
- question: z.string(),
96
- header: z.string().max(12),
97
- options: z.array(z.object({
98
- label: z.string().max(50),
99
- description: z.string()
100
- })).min(2).max(4),
101
- multiSelect: z.boolean().optional()
102
- })).min(1).max(4) }),
103
- invoke_integration: z.object({}).passthrough(),
104
- call_integration: z.object({}).passthrough(),
105
- search_integration_tool: z.object({}).passthrough(),
106
- supabase_get_logs: z.object({}).passthrough(),
107
- supabase_execute_sql: z.object({}).passthrough(),
108
- supabase_apply_migration: z.object({}).passthrough(),
109
- supabase_list_migration: z.object({}).passthrough(),
110
- supabase_list_tables: z.object({}).passthrough(),
111
- cloud_studio_fetch_log: z.object({}).passthrough(),
112
- cloud_studio_execute_command: z.object({}).passthrough(),
113
- cloud_studio_deploy_sandbox: z.object({}).passthrough(),
114
- component_get_prompt: z.object({}).passthrough(),
115
- web_fetch: z.object({
116
- url: z.string().describe("要获取内容的 URL"),
117
- fetchInfo: z.string().describe("用户想要获取的信息描述")
118
- }),
119
- use_skill: z.object({ command: z.string().describe("技能名称(不含参数),如 \"pdf\" 或 \"xlsx\"") }),
120
- web_search: z.object({
121
- explanation: z.string().describe("为什么使用此工具的一句话解释"),
122
- searchTerm: z.string().describe("要在网络上搜索的搜索词")
123
- }),
124
- task: z.object({
125
- subagent_name: z.string().describe("要调用的子代理名称"),
126
- description: z.string().describe("任务的简短描述(3-5 个词)"),
127
- prompt: z.string().describe("子代理要执行的任务"),
128
- subagent_path: z.string().optional().describe("子代理定义文件的路径")
129
- }),
130
- codebase_search: z.object({
131
- query: z.string().describe("关于你想理解的内容的完整问题"),
132
- path: z.string().describe("限制搜索范围的目录路径前缀"),
133
- limit: z.number().max(100).optional().describe("返回的最大结果数,默认 10")
134
- }),
135
- lsp: z.object({}).passthrough(),
136
- spec_create: z.object({
137
- name: z.string().describe("Plan 名称,用作稳定标识符/文件名"),
138
- overview: z.string().describe("用一两句话精确概括本次 plan 的主要内容"),
139
- relative_history: z.string().describe("准备阶段的上下文,包含用户需求、代码位置、额外上下文等")
140
- }),
141
- spec_update: z.object({ status: z.enum([
142
- "prepare",
143
- "ready",
144
- "building",
145
- "finished"
146
- ]).optional().describe("Plan 状态") })
147
- };
148
- /**
149
- * 工具输出 Schema 定义
150
- * 用于验证和约束 rawOutput
151
- */
152
- const ToolOutputSchemas = {
153
- list_dir: z.object({
154
- type: z.literal("list_files_result"),
155
- files: z.array(z.object({
156
- filePath: z.string(),
157
- size: z.string(),
158
- modifyTime: z.string()
159
- })),
160
- root: z.string(),
161
- listing: z.string().optional()
162
- }),
163
- search_file: z.object({
164
- type: z.literal("search_file_result"),
165
- path: z.string(),
166
- pattern: z.string(),
167
- recursive: z.boolean().optional(),
168
- caseSensitive: z.boolean().optional(),
169
- results: z.array(z.object({
170
- filePath: z.string(),
171
- size: z.string(),
172
- modifyTime: z.string()
173
- }))
174
- }),
175
- read_file: z.object({
176
- type: z.literal("read_file_result"),
177
- path: z.string(),
178
- content: z.string(),
179
- totalLineCount: z.number(),
180
- hasMore: z.boolean(),
181
- diagnostic: z.string().optional(),
182
- hint: z.string().optional(),
183
- image: z.object({
184
- data: z.string(),
185
- mimeType: z.string()
186
- }).optional()
187
- }),
188
- read_lints: z.object({
189
- type: z.literal("read_lints_result"),
190
- diagnostics: z.array(z.string()),
191
- totalCount: z.number().optional(),
192
- hint: z.string().optional(),
193
- isTruncated: z.boolean().optional()
194
- }),
195
- rag_search: z.object({
196
- type: z.literal("knowledge_base_result"),
197
- selectedKnowledgeBases: z.string(),
198
- queryInput: z.string()
199
- }),
200
- read_rules: z.object({
201
- type: z.literal("rule_match_result"),
202
- ruleDescription: z.string(),
203
- filePaths: z.array(z.string())
204
- }),
205
- mcp_get_tool_description: z.object({}).passthrough(),
206
- mcp_call_tool: z.object({
207
- type: z.literal("mcp_call_tool_result"),
208
- serverName: z.string(),
209
- toolName: z.string(),
210
- data: z.array(z.union([
211
- z.object({
212
- type: z.literal("text"),
213
- text: z.string()
214
- }),
215
- z.object({
216
- type: z.literal("image"),
217
- data: z.string(),
218
- mimeType: z.string()
219
- }),
220
- z.object({
221
- type: z.literal("resource"),
222
- resource: z.object({
223
- uri: z.string(),
224
- mimeType: z.string().optional(),
225
- text: z.string().optional(),
226
- blob: z.string().optional()
227
- })
228
- })
229
- ])),
230
- isError: z.boolean().optional(),
231
- error: z.unknown().optional(),
232
- hint: z.string().optional()
233
- }),
234
- fetch_mcp_resource: z.object({
235
- type: z.literal("fetch_mcp_resource_result"),
236
- server: z.string(),
237
- uri: z.string(),
238
- content: z.string(),
239
- downloadPath: z.string().optional()
240
- }),
241
- create_rule: z.object({
242
- type: z.literal("rule_create_result"),
243
- ruleName: z.string(),
244
- createState: z.enum([
245
- "success",
246
- "invoke",
247
- "cancelled"
248
- ]),
249
- hint: z.string().optional(),
250
- filePath: z.string().optional()
251
- }),
252
- update_memory: z.object({
253
- type: z.literal("update_memory_result"),
254
- success: z.boolean(),
255
- message: z.string(),
256
- action: z.enum([
257
- "create",
258
- "update",
259
- "delete"
260
- ]),
261
- knowledge_id: z.string().optional()
262
- }),
263
- search_content: z.object({
264
- type: z.literal("search_content_result"),
265
- directory: z.string(),
266
- pattern: z.string(),
267
- fileTypes: z.string(),
268
- matches: z.array(z.object({
269
- filePath: z.string(),
270
- content: z.string(),
271
- startLine: z.number(),
272
- endLine: z.number(),
273
- size: z.string(),
274
- modifyTime: z.string()
275
- })),
276
- totalCount: z.number(),
277
- hasMore: z.boolean(),
278
- offset: z.number(),
279
- limit: z.number(),
280
- contextBefore: z.number(),
281
- contextAfter: z.number(),
282
- contextAround: z.number().optional(),
283
- outputMode: z.string(),
284
- caseSensitive: z.boolean(),
285
- hint: z.string().optional()
286
- }),
287
- write_to_file: z.object({
288
- type: z.literal("write_to_file_result"),
289
- path: z.string(),
290
- addLineCount: z.number(),
291
- removedLines: z.number(),
292
- addedChars: z.number().optional(),
293
- removedChars: z.number().optional(),
294
- bytesWritten: z.number(),
295
- isNewFile: z.boolean(),
296
- oldContent: z.string().optional(),
297
- diagnostic: z.string().optional()
298
- }),
299
- replace_in_file: z.object({
300
- type: z.literal("replace_in_file_result"),
301
- path: z.string(),
302
- addLineCount: z.number().optional(),
303
- removedLines: z.number().optional(),
304
- addedChars: z.number().optional(),
305
- removedChars: z.number().optional(),
306
- matchCount: z.number().optional(),
307
- hint: z.string().optional(),
308
- diagnosticChange: z.object({
309
- added: z.string(),
310
- removed: z.string(),
311
- unchanged: z.string()
312
- }).optional()
313
- }),
314
- delete_file: z.object({
315
- type: z.literal("delete_file_result"),
316
- path: z.string(),
317
- recursive: z.boolean(),
318
- hint: z.string().optional()
319
- }),
320
- execute_command: z.object({
321
- type: z.literal("execute_command_result"),
322
- stdout: z.string(),
323
- stderr: z.string(),
324
- exitCode: z.number(),
325
- hint: z.string().optional(),
326
- serviceInfo: z.object({
327
- isWatchCommand: z.boolean(),
328
- isServiceOutput: z.boolean(),
329
- serviceReady: z.boolean(),
330
- message: z.string()
331
- }).optional(),
332
- use_standalone_terminal: z.boolean().optional()
333
- }),
334
- preview_url: z.object({
335
- type: z.literal("preview_tool_result"),
336
- url: z.string(),
337
- message: z.string()
338
- }),
339
- ask_followup_question: z.object({
340
- type: z.literal("multi_question_result"),
341
- questions: z.array(z.object({
342
- id: z.string(),
343
- question: z.string(),
344
- options: z.array(z.string()),
345
- multiSelect: z.boolean().optional(),
346
- title: z.string().optional()
347
- })),
348
- answers: z.record(z.union([z.string(), z.array(z.string())])),
349
- message: z.string()
350
- }),
351
- invoke_integration: z.object({
352
- type: z.literal("invoke_integration_tool_result"),
353
- recommend: z.object({
354
- id: z.string(),
355
- type: z.string(),
356
- status: z.enum(["connected", "disconnected"])
357
- }),
358
- message: z.string()
359
- }),
360
- call_integration: z.object({
361
- type: z.literal("call_integration_tool_result"),
362
- integrationId: z.string(),
363
- toolName: z.string(),
364
- data: z.object({
365
- type: z.literal("text"),
366
- text: z.string()
367
- }),
368
- isError: z.boolean().optional(),
369
- error: z.unknown().optional()
370
- }),
371
- search_integration_tool: z.object({
372
- type: z.literal("search_integration_tool_result"),
373
- data: z.array(z.object({
374
- integrationId: z.string(),
375
- integrationName: z.string(),
376
- toolName: z.string(),
377
- description: z.string(),
378
- inputSchema: z.record(z.unknown())
379
- })),
380
- hint: z.string().optional()
381
- }),
382
- supabase_get_logs: z.object({
383
- type: z.enum([
384
- "supabase_get_logs_result",
385
- "supabase_execute_sql_result",
386
- "supabase_apply_migration_result",
387
- "supabase_list_migration_result",
388
- "supabase_list_tables_result"
389
- ]),
390
- message: z.string()
391
- }),
392
- supabase_execute_sql: z.object({
393
- type: z.enum([
394
- "supabase_get_logs_result",
395
- "supabase_execute_sql_result",
396
- "supabase_apply_migration_result",
397
- "supabase_list_migration_result",
398
- "supabase_list_tables_result"
399
- ]),
400
- message: z.string()
401
- }),
402
- supabase_apply_migration: z.object({
403
- type: z.enum([
404
- "supabase_get_logs_result",
405
- "supabase_execute_sql_result",
406
- "supabase_apply_migration_result",
407
- "supabase_list_migration_result",
408
- "supabase_list_tables_result"
409
- ]),
410
- message: z.string()
411
- }),
412
- supabase_list_migration: z.object({
413
- type: z.enum([
414
- "supabase_get_logs_result",
415
- "supabase_execute_sql_result",
416
- "supabase_apply_migration_result",
417
- "supabase_list_migration_result",
418
- "supabase_list_tables_result"
419
- ]),
420
- message: z.string()
421
- }),
422
- supabase_list_tables: z.object({
423
- type: z.enum([
424
- "supabase_get_logs_result",
425
- "supabase_execute_sql_result",
426
- "supabase_apply_migration_result",
427
- "supabase_list_migration_result",
428
- "supabase_list_tables_result"
429
- ]),
430
- message: z.string()
431
- }),
432
- cloud_studio_fetch_log: z.object({
433
- type: z.literal("cloud_studio_fetch_log_result"),
434
- success: z.boolean(),
435
- logs: z.record(z.string())
436
- }),
437
- cloud_studio_execute_command: z.object({
438
- type: z.literal("cloud_studio_execute_command_result"),
439
- success: z.boolean(),
440
- message: z.string()
441
- }),
442
- cloud_studio_deploy_sandbox: z.object({
443
- type: z.literal("cloud_studio_integration_result"),
444
- previewUrl: z.string().optional(),
445
- steps: z.array(z.object({
446
- status: z.enum([
447
- "idle",
448
- "success",
449
- "running",
450
- "error"
451
- ]),
452
- name: z.enum([
453
- "createSandbox",
454
- "uploadProject",
455
- "installDependencies",
456
- "startService",
457
- "preview"
458
- ]),
459
- error: z.object({
460
- code: z.number().optional(),
461
- message: z.string().optional()
462
- }).optional()
463
- }))
464
- }),
465
- component_get_prompt: z.object({
466
- type: z.literal("component_get_prompt_result"),
467
- componentType: z.string(),
468
- webFramework: z.string(),
469
- data: z.object({
470
- type: z.literal("text"),
471
- text: z.string()
472
- })
473
- }),
474
- web_fetch: z.object({
475
- type: z.literal("web_fetch_tool_result"),
476
- message: z.string(),
477
- data: z.string(),
478
- loading: z.string().optional(),
479
- title: z.string().optional(),
480
- favicon: z.string().optional()
481
- }),
482
- use_skill: z.object({
483
- type: z.literal("use_skill_tool_result"),
484
- commandMessage: z.string(),
485
- message: z.string()
486
- }),
487
- web_search: z.object({
488
- type: z.literal("web_search_tool_result"),
489
- data: z.array(z.object({
490
- passage: z.string(),
491
- uri: z.string(),
492
- site: z.string(),
493
- title: z.string(),
494
- snippets: z.array(z.string()).optional(),
495
- content: z.string().optional()
496
- })),
497
- searchInput: z.string().optional()
498
- }),
499
- task: z.object({
500
- type: z.literal("task_tool_result"),
501
- toolInfo: z.array(z.object({
502
- name: z.string(),
503
- info: z.string(),
504
- needApprove: z.boolean().optional(),
505
- toolCallId: z.string().optional(),
506
- executeStatus: z.enum([
507
- "ing",
508
- "completed",
509
- "cancel",
510
- "fail"
511
- ]).optional()
512
- })).optional(),
513
- startCallTool: z.boolean().optional(),
514
- finalResult: z.string().optional(),
515
- toolCallBrief: z.string().optional()
516
- }),
517
- codebase_search: z.object({
518
- type: z.literal("codebase_search_result"),
519
- query: z.string(),
520
- path: z.string(),
521
- content: z.string()
522
- }),
523
- lsp: z.object({
524
- type: z.literal("lsp_tool_result"),
525
- operation: z.string(),
526
- result: z.string(),
527
- resultCount: z.number().optional(),
528
- fileCount: z.number().optional(),
529
- character: z.number().optional()
530
- }),
531
- spec_create: z.object({
532
- type: z.literal("plan_create_tool_result"),
533
- message: z.string(),
534
- data: z.string()
535
- }),
536
- spec_update: z.object({
537
- type: z.literal("plan_update_tool_result"),
538
- status: z.enum([
539
- "prepare",
540
- "ready",
541
- "building",
542
- "finished"
543
- ]),
544
- data: z.string(),
545
- reminder: z.string()
546
- })
547
- };
548
- /**
549
- * 验证工具输出
550
- * @param toolName 工具名称
551
- * @param output 输出数据
552
- * @returns 验证结果
553
- */
554
- function validateToolOutput(toolName, output) {
555
- const result = ToolOutputSchemas[toolName].safeParse(output);
556
- if (result.success) return {
557
- success: true,
558
- data: result.data
559
- };
560
- return {
561
- success: false,
562
- error: result.error
563
- };
564
- }
565
-
566
- //#endregion
567
- //#region ../agent-provider/src/common/_legacy/MockAgentProvider.ts
568
- /**
569
- * ACP 协议 Mock 数据 - 初始化响应
570
- */
571
- const mockInitializeResponse = {
572
- protocolVersion: 1,
573
- agentCapabilities: {
574
- loadSession: true,
575
- promptCapabilities: {
576
- image: true,
577
- audio: false,
578
- embeddedContext: true
579
- },
580
- mcpCapabilities: {
581
- http: true,
582
- sse: true
583
- }
584
- }
585
- };
586
- /**
587
- * ACP 协议 Mock 数据 - 会话创建响应
588
- */
589
- const mockNewSessionResponse = (sessionId) => ({ sessionId });
590
- /**
591
- * Mock 会话数据存储
592
- * 每个会话都有对应的模拟历史消息
593
- */
594
- const mockSessionHistories = /* @__PURE__ */ new Map();
595
- mockSessionHistories.set("1", [
596
- {
597
- type: "user",
598
- content: "帮我开发一个五子棋游戏,需要包含以下功能:\n1. 双人对战模式\n2. 悔棋功能\n3. 计时器",
599
- timestamp: Date.now() - 18e5 - 6e4
600
- },
601
- {
602
- type: "assistant",
603
- content: "好的,我来帮你开发一个五子棋游戏。我会创建以下文件结构:\n\n- `index.html` - 主页面\n- `game.js` - 游戏逻辑\n- `style.css` - 样式文件\n\n让我开始创建这些文件...",
604
- timestamp: Date.now() - 18e5 - 5e4
605
- },
606
- {
607
- type: "assistant",
608
- content: "我已经完成了所有文件的创建和修改。游戏支持双人对战、悔棋和计时功能。你可以直接在浏览器中打开 index.html 开始游戏。",
609
- timestamp: Date.now() - 18e5
610
- }
611
- ]);
612
- mockSessionHistories.set("2", [
613
- {
614
- type: "user",
615
- content: "登录页面的样式有问题,按钮颜色不对齐,帮我修复一下",
616
- timestamp: Date.now() - 72e5 - 12e4
617
- },
618
- {
619
- type: "assistant",
620
- content: "我来检查登录页面的样式。让我先看看相关的 CSS 文件...",
621
- timestamp: Date.now() - 72e5 - 1e5
622
- },
623
- {
624
- type: "assistant",
625
- content: "样式问题已修复,请查看效果。主要修改了按钮的 flex 布局和颜色变量。",
626
- timestamp: Date.now() - 72e5
627
- }
628
- ]);
629
- mockSessionHistories.set("3", [
630
- {
631
- type: "user",
632
- content: "API 接口响应太慢了,需要添加缓存和错误重试机制",
633
- timestamp: Date.now() - 144e5 - 18e4
634
- },
635
- {
636
- type: "assistant",
637
- content: "好的,我来优化 API 接口。我会实现:\n1. Redis 缓存层\n2. 指数退避重试策略\n3. 请求去重",
638
- timestamp: Date.now() - 144e5 - 15e4
639
- },
640
- {
641
- type: "assistant",
642
- content: "已添加缓存和错误重试机制。性能提升了约 60%。",
643
- timestamp: Date.now() - 144e5
644
- }
645
- ]);
646
- mockSessionHistories.set("4", [
647
- {
648
- type: "user",
649
- content: "帮我为核心模块添加单元测试,覆盖率要达到 80% 以上",
650
- timestamp: Date.now() - 864e5 - 3e5
651
- },
652
- {
653
- type: "assistant",
654
- content: "好的,我会使用 Jest 来编写单元测试。让我先看看核心模块的代码结构...",
655
- timestamp: Date.now() - 864e5 - 25e4
656
- },
657
- {
658
- type: "assistant",
659
- content: "测试覆盖率已达到 85%,超过了目标。主要测试了:\n- 用户认证逻辑\n- 数据验证\n- 错误处理",
660
- timestamp: Date.now() - 864e5
661
- }
662
- ]);
663
- var MockAgentProvider = class {
664
- constructor(config = {}) {
665
- this.sessionUpdateCallbacks = /* @__PURE__ */ new Set();
666
- this.permissionRequestResolvers = /* @__PURE__ */ new Map();
667
- this.errorCallbacks = /* @__PURE__ */ new Set();
668
- this.activeConnections = /* @__PURE__ */ new Map();
669
- this.pendingPermissionResolvers = /* @__PURE__ */ new Map();
670
- this.initializedSessions = /* @__PURE__ */ new Map();
671
- this.currentSessionUpdates = /* @__PURE__ */ new Map();
672
- console.log("[MockAgentProvider] Initialized");
673
- this.initializeMockSessions();
674
- }
675
- setSessionMode(params) {
676
- throw new Error("Method not implemented.");
677
- }
678
- setSessionModel(params) {
679
- throw new Error("Method not implemented.");
680
- }
681
- extMethod(method, params) {
682
- throw new Error("Method not implemented.");
683
- }
684
- extNotification(method, params) {
685
- throw new Error("Method not implemented.");
686
- }
687
- /**
688
- * 初始化默认的 Mock session 数据
689
- */
690
- initializeMockSessions() {
691
- const mockSessions = [
692
- {
693
- sessionId: "1",
694
- cwd: "/Users/example/Project",
695
- mcpServers: [],
696
- createdAt: Date.now() - 36e5
697
- },
698
- {
699
- sessionId: "2",
700
- cwd: "/Users/example/Project",
701
- mcpServers: [],
702
- createdAt: Date.now() - 72e5
703
- },
704
- {
705
- sessionId: "3",
706
- cwd: "/Users/example/Project",
707
- mcpServers: [],
708
- createdAt: Date.now() - 864e5
709
- }
710
- ];
711
- mockSessions.forEach((session) => {
712
- this.initializedSessions.set(session.sessionId, {
713
- cwd: session.cwd,
714
- mcpServers: session.mcpServers,
715
- createdAt: session.createdAt
716
- });
717
- });
718
- console.log("[MockAgentProvider] Initialized mock sessions:", mockSessions.length);
719
- }
720
- /**
721
- * 从 PromptRequest 中提取文本内容
722
- * Provider 自己决定如何处理 ContentBlock 数组
723
- */
724
- extractTextFromRequest(request) {
725
- if (request.prompt && Array.isArray(request.prompt)) return request.prompt.filter((block) => block.type === "text").map((block) => "text" in block ? block.text : "").join("\n");
726
- return "";
727
- }
728
- /**
729
- * 发送消息 - 直接使用 Mock 数据
730
- * 接收 PromptRequest,由 Provider 决定如何处理
731
- */
732
- async sendMessage(request) {
733
- const content = this.extractTextFromRequest(request);
734
- const sessionId = request.sessionId;
735
- console.log("[MockAgentProvider] Sending mock message:", {
736
- sessionId,
737
- content
738
- });
739
- try {
740
- await this.sendMockMessage(sessionId, content);
741
- } catch (error) {
742
- console.error("[MockAgentProvider] Send message failed:", error);
743
- this.emitEvent({
744
- type: "error",
745
- sessionId,
746
- timestamp: Date.now(),
747
- data: { error: error instanceof Error ? error.message : "Unknown error" }
748
- });
749
- throw error;
750
- }
751
- }
752
- /**
753
- * 使用 Mock 数据模拟流式响应
754
- */
755
- async sendMockMessage(sessionId, content) {
756
- console.log("[MockAgentProvider] Using mock data for:", content);
757
- this.currentSessionUpdates.set(sessionId, []);
758
- this.emitEvent({
759
- type: "connected",
760
- sessionId,
761
- timestamp: Date.now()
762
- });
763
- await this.delay(300);
764
- const messageId1 = `m-text-${Date.now()}`;
765
- const textReply = `我收到了你发送的「${content}」信息,这是符合 ACP 协议的 mock 数据。\n\n下面演示不同类型的 ContentBlock:\n\n`;
766
- await this.streamMockTextContent(sessionId, messageId1, textReply);
767
- await this.delay(500);
768
- const messageId2 = `m-resource-${Date.now()}`;
769
- await this.sendMockEmbeddedResource(sessionId, messageId2);
770
- await this.delay(500);
771
- const messageId3 = `m-link-${Date.now()}`;
772
- await this.sendMockResourceLink(sessionId, messageId3);
773
- await this.delay(500);
774
- const toolMessageId = `m-tool-${Date.now()}`;
775
- await this.sendMockEditContentToolCallFlow(sessionId, toolMessageId);
776
- await this.delay(500);
777
- const diffToolMessageId = `m-tool-d-${Date.now()}`;
778
- await this.sendMockEditDiffToolCallFlow(sessionId, diffToolMessageId);
779
- await this.delay(500);
780
- const readToolMessageId = `m-tool-r-${Date.now()}`;
781
- await this.sendMockReadContentToolCallFlow(sessionId, readToolMessageId);
782
- await this.delay(300);
783
- const searchContentMessageId = `m-tool-sc-${Date.now()}`;
784
- await this.sendMockSearchContentToolCallFlow(sessionId, searchContentMessageId);
785
- await this.delay(500);
786
- const searchFileMessageId = `m-tool-sf-${Date.now()}`;
787
- await this.sendMockSearchFileToolCallFlow(sessionId, searchFileMessageId);
788
- await this.delay(500);
789
- const listFilesMessageId = `m-tool-lf-${Date.now()}`;
790
- await this.sendMockListFilesToolCallFlow(sessionId, listFilesMessageId);
791
- await this.delay(500);
792
- const askFollowupMessageId = `m-tool-afq-${Date.now()}`;
793
- await this.sendMockAskFollowupQuestionToolCallFlow(sessionId, askFollowupMessageId);
794
- await this.delay(500);
795
- const deleteFileMessageId = `m-tool-df-${Date.now()}`;
796
- await this.sendMockDeleteFileToolCallFlow(sessionId, deleteFileMessageId);
797
- await this.delay(300);
798
- const executeCommandMessageId = `m-tool-ec-${Date.now()}`;
799
- await this.sendMockExecuteCommandToolCallFlow(sessionId, executeCommandMessageId);
800
- await this.delay(300);
801
- const executeCommandApprovalMessageId = `m-tool-ec-approval-${Date.now()}`;
802
- await this.sendMockExecuteCommandWithApprovalToolCallFlow(sessionId, executeCommandApprovalMessageId);
803
- await this.delay(300);
804
- const writeFileApprovalMessageId = `m-tool-wtf-approval-${Date.now()}`;
805
- await this.sendMockWriteFileWithApprovalToolCallFlow(sessionId, writeFileApprovalMessageId);
806
- await this.delay(300);
807
- const previewUrlMessageId = `m-tool-pu-${Date.now()}`;
808
- await this.sendMockPreviewUrlToolCallFlow(sessionId, previewUrlMessageId);
809
- await this.delay(300);
810
- const listCodeDefMessageId = `m-tool-lcd-${Date.now()}`;
811
- await this.sendMockListCodeDefinitionNamesToolCallFlow(sessionId, listCodeDefMessageId);
812
- await this.delay(300);
813
- const webFetchMessageId = `m-tool-wf-${Date.now()}`;
814
- await this.sendMockWebFetchToolCallFlow(sessionId, webFetchMessageId);
815
- await this.delay(300);
816
- const readLintsMessageId = `m-tool-rl-${Date.now()}`;
817
- await this.sendMockReadLintsToolCallFlow(sessionId, readLintsMessageId);
818
- await this.delay(300);
819
- const webSearchMessageId = `m-tool-ws-${Date.now()}`;
820
- await this.sendMockWebSearchToolCallFlow(sessionId, webSearchMessageId);
821
- await this.delay(300);
822
- this.emitEvent({
823
- type: "done",
824
- sessionId,
825
- timestamp: Date.now()
826
- });
827
- }
828
- /**
829
- * 流式发送 Mock 文本消息内容 (符合 ACP 协议的 agent_message_chunk)
830
- */
831
- async streamMockTextContent(sessionId, messageId, content) {
832
- const chunkSize = 10;
833
- for (let i = 0; i < content.length; i += chunkSize) {
834
- const chunk = content.substring(i, i + chunkSize);
835
- console.log(`Text Chunk: "${chunk}" | messageId: ${messageId} | sessionId: ${sessionId}`);
836
- this.emitEvent({
837
- type: "session_update",
838
- sessionId,
839
- messageId,
840
- timestamp: Date.now(),
841
- notification: {
842
- sessionId,
843
- update: {
844
- sessionUpdate: "agent_message_chunk",
845
- content: {
846
- type: "text",
847
- text: chunk
848
- }
849
- }
850
- }
851
- });
852
- await this.delay(50);
853
- }
854
- }
855
- /**
856
- * 延迟函数
857
- */
858
- delay(ms) {
859
- return new Promise((resolve) => setTimeout(resolve, ms));
860
- }
861
- /**
862
- * 取消消息 (Mock 模式下直接完成)
863
- * @deprecated 使用 cancel 代替
864
- */
865
- async cancelMessage(sessionId) {
866
- console.log("[MockAgentProvider] Message cancelled:", sessionId);
867
- this.emitEvent({
868
- type: "done",
869
- sessionId,
870
- timestamp: Date.now()
871
- });
872
- }
873
- /**
874
- * ACP 协议: prompt - 发送用户消息
875
- *
876
- * Mock 实现: 复用 sendMessage
877
- */
878
- async prompt(request) {
879
- console.log("[MockAgentProvider] prompt called:", request);
880
- await this.sendMessage(request);
881
- return { stopReason: "end_turn" };
882
- }
883
- /**
884
- * ACP 协议: cancel - 取消消息
885
- *
886
- * Mock 实现: 复用 cancelMessage
887
- */
888
- async cancel(params) {
889
- console.log("[MockAgentProvider] cancel called:", params);
890
- return this.cancelMessage(params.sessionId);
891
- }
892
- /**
893
- * 监听会话更新事件(ACP 协议原生)
894
- */
895
- onSessionUpdate(callback) {
896
- this.sessionUpdateCallbacks.add(callback);
897
- return () => {
898
- this.sessionUpdateCallbacks.delete(callback);
899
- };
900
- }
901
- /**
902
- * 监听权限请求事件(ACP 协议原生)
903
- */
904
- onRequestPermission(callback) {
905
- this.permissionRequestResolvers.set("__global__", callback);
906
- return () => {
907
- this.permissionRequestResolvers.delete("__global__");
908
- };
909
- }
910
- /**
911
- * 监听错误事件(扩展事件,非 ACP 标准协议)
912
- */
913
- onError(callback) {
914
- this.errorCallbacks.add(callback);
915
- return () => {
916
- this.errorCallbacks.delete(callback);
917
- };
918
- }
919
- /**
920
- * 触发会话更新事件(内部辅助方法)
921
- */
922
- emitSessionUpdate(params) {
923
- console.log("[MockAgentProvider] Emitting session update:", params, "to", this.sessionUpdateCallbacks.size, "callbacks");
924
- this.sessionUpdateCallbacks.forEach((callback) => {
925
- try {
926
- callback(params);
927
- } catch (error) {
928
- console.error("[MockAgentProvider] Session update callback error:", error);
929
- }
930
- });
931
- }
932
- /**
933
- * 触发错误事件(内部辅助方法)
934
- */
935
- emitError(error, sessionId) {
936
- console.log("[MockAgentProvider] Emitting error:", error, "for session:", sessionId);
937
- this.errorCallbacks.forEach((callback) => {
938
- try {
939
- callback(error, sessionId);
940
- } catch (err) {
941
- console.error("[MockAgentProvider] Error callback error:", err);
942
- }
943
- });
944
- }
945
- /**
946
- * 向后兼容的 emitEvent 方法
947
- * 将旧的事件格式桥接到新的 ACP 原生事件
948
- */
949
- emitEvent(event) {
950
- if (event.type === "error") {
951
- const error = event.data?.error ? new Error(event.data.error) : /* @__PURE__ */ new Error("Unknown error");
952
- this.emitError(error, event.sessionId);
953
- } else if (event.type === "session_update" && event.notification) {
954
- const params = {
955
- notification: event.notification,
956
- messageId: event.messageId
957
- };
958
- this.emitSessionUpdate(params);
959
- } else if (event.type === "connected" || event.type === "done") console.log("[MockAgentProvider] Ignoring deprecated event type:", event.type);
960
- else console.warn("[MockAgentProvider] Unknown event type:", event.type);
961
- }
962
- /**
963
- * ACP 协议: initialize - 初始化连接
964
- *
965
- * Mock 实现: 返回预设的初始化响应
966
- */
967
- async initialize(request) {
968
- console.log("[MockAgentProvider] initialize", request);
969
- await this.delay(100);
970
- return mockInitializeResponse;
971
- }
972
- /**
973
- * ACP 协议: authenticate - 身份验证
974
- *
975
- * Mock 实现: 直接返回成功
976
- */
977
- async authenticate(request) {
978
- console.log("[MockAgentProvider] authenticate", request);
979
- }
980
- /**
981
- * ACP 协议: newSession - 创建新会话
982
- *
983
- * Mock 实现: 生成唯一的 sessionId 并存储会话信息
984
- */
985
- async newSession(request) {
986
- console.log("[MockAgentProvider] session/new", request);
987
- await this.delay(100);
988
- const sessionId = `sess_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
989
- this.initializedSessions.set(sessionId, {
990
- cwd: request.cwd,
991
- mcpServers: request.mcpServers || [],
992
- createdAt: Date.now()
993
- });
994
- console.log("[MockAgentProvider] Created session:", sessionId, "with config:", {
995
- cwd: request.cwd,
996
- mcpServers: request.mcpServers
997
- });
998
- return mockNewSessionResponse(sessionId);
999
- }
1000
- /**
1001
- * ACP 协议: session/load - 加载已有会话
1002
- *
1003
- * Mock 实现: 流式回放会话历史(完整的事件回放)
1004
- */
1005
- async loadSession(request) {
1006
- console.log("[MockAgentProvider] session/load", request);
1007
- const { sessionId, cwd, mcpServers } = request;
1008
- this.initializedSessions.set(sessionId, {
1009
- cwd,
1010
- mcpServers: mcpServers || [],
1011
- createdAt: Date.now()
1012
- });
1013
- const history = mockSessionHistories.get(sessionId);
1014
- if (history && history.length > 0) {
1015
- console.log("[MockAgentProvider] Loading session from mockSessionHistories:", sessionId, "with", history.length, "entries");
1016
- for (let i = 0; i < history.length; i++) {
1017
- const message = history[i];
1018
- if (message.type === "assistant" && message.content && message.content.startsWith("[")) try {
1019
- const events = JSON.parse(message.content);
1020
- console.log("[MockAgentProvider] Replaying events from history:", {
1021
- index: i,
1022
- eventCount: events.length
1023
- });
1024
- for (const event of events) {
1025
- await this.delay(20);
1026
- this.emitEvent(event);
1027
- }
1028
- } catch (error) {
1029
- console.error("[MockAgentProvider] Failed to parse events from history:", error);
1030
- }
1031
- else {
1032
- const messageId = `load-${sessionId}-${i}-${Date.now()}`;
1033
- const sessionUpdateType = message.type === "user" ? "user_message_chunk" : "agent_message_chunk";
1034
- await this.delay(50);
1035
- this.emitEvent({
1036
- type: "session_update",
1037
- sessionId,
1038
- messageId,
1039
- timestamp: message.timestamp,
1040
- notification: {
1041
- sessionId,
1042
- update: {
1043
- sessionUpdate: sessionUpdateType,
1044
- content: {
1045
- type: "text",
1046
- text: message.content
1047
- }
1048
- }
1049
- }
1050
- });
1051
- }
1052
- }
1053
- console.log("[MockAgentProvider] Session loaded from mockSessionHistories:", sessionId);
1054
- return {};
1055
- }
1056
- console.log("[MockAgentProvider] No history found for session:", sessionId);
1057
- return {};
1058
- }
1059
- /**
1060
- * ACP 协议: session/request_permission - 请求用户权限
1061
- *
1062
- * Agent 调用此方法来请求用户批准工具调用。
1063
- * 此方法会:
1064
- * 1. 发送 request_permission 事件给 UI
1065
- * 2. 阻塞等待用户响应
1066
- * 3. 返回用户的决策结果
1067
- *
1068
- * @param sessionId ACP 会话 ID
1069
- * @param toolCallId 工具调用 ID
1070
- * @param toolCall 工具调用信息
1071
- * @param options 可用的权限选项
1072
- * @returns 用户的决策结果
1073
- */
1074
- async requestPermission(sessionId, toolCallId, toolCall, options) {
1075
- console.log("[MockAgentProvider] requestPermission called:", {
1076
- sessionId,
1077
- toolCallId,
1078
- toolCall,
1079
- options
1080
- });
1081
- this.emitEvent({
1082
- type: "request_permission",
1083
- sessionId,
1084
- messageId: `permission-${toolCallId}`,
1085
- timestamp: Date.now(),
1086
- data: {
1087
- sessionId,
1088
- toolCall,
1089
- options
1090
- }
1091
- });
1092
- const permissionOutcome = await new Promise((resolve) => {
1093
- this.pendingPermissionResolvers.set(toolCallId, resolve);
1094
- setTimeout(() => {
1095
- if (this.pendingPermissionResolvers.has(toolCallId)) {
1096
- this.pendingPermissionResolvers.delete(toolCallId);
1097
- console.log("[MockAgentProvider] Permission request timed out:", toolCallId);
1098
- resolve({
1099
- outcome: "cancelled",
1100
- optionId: "reject-once",
1101
- timedOut: true
1102
- });
1103
- }
1104
- }, 6e4);
1105
- });
1106
- console.log("[MockAgentProvider] Permission outcome:", permissionOutcome);
1107
- return permissionOutcome;
1108
- }
1109
- /**
1110
- * 直接释放权限请求的 await(更直接的方法)
1111
- *
1112
- * 这个方法直接从 pendingPermissionResolvers 中获取 resolver 并调用,
1113
- * 不需要经过 respondToPermissionRequest 的中转。
1114
- *
1115
- * @param toolCallId 工具调用 ID
1116
- * @param outcome 用户的决策结果
1117
- */
1118
- releasePermissionRequest(toolCallId, outcome) {
1119
- console.log("[MockAgentProvider] releasePermissionRequest called:", {
1120
- toolCallId,
1121
- outcome
1122
- });
1123
- const resolver = this.pendingPermissionResolvers.get(toolCallId);
1124
- if (resolver) {
1125
- resolver({
1126
- ...outcome,
1127
- timedOut: false
1128
- });
1129
- this.pendingPermissionResolvers.delete(toolCallId);
1130
- console.log("[MockAgentProvider] Permission request released:", toolCallId);
1131
- } else console.warn("[MockAgentProvider] No pending permission request found for:", toolCallId);
1132
- }
1133
- /**
1134
- * 响应用户的权限决策(兼容旧接口)
1135
- *
1136
- * 这个方法内部调用 releasePermissionRequest。
1137
- * 保留这个方法是为了向后兼容和符合 ACP 协议的命名规范。
1138
- *
1139
- * @param sessionId ACP 会话 ID(未使用,保留以符合接口)
1140
- * @param payload 权限响应数据
1141
- */
1142
- async respondToPermissionRequest(sessionId, payload) {
1143
- console.log("[MockAgentProvider] respondToPermissionRequest called:", payload);
1144
- this.releasePermissionRequest(payload.toolCallId, payload.outcome);
1145
- }
1146
- /**
1147
- * 销毁 Provider
1148
- */
1149
- destroy() {
1150
- this.activeConnections.clear();
1151
- this.pendingPermissionResolvers.clear();
1152
- this.permissionRequestResolvers.clear();
1153
- this.initializedSessions.clear();
1154
- this.sessionUpdateCallbacks.clear();
1155
- this.errorCallbacks.clear();
1156
- this.currentSessionUpdates.clear();
1157
- console.log("[MockAgentProvider] Destroyed");
1158
- }
1159
- /**
1160
- * 获取所有已初始化的会话列表(扩展方法,非 ACP 标准协议)
1161
- * 返回 sessionId 及其配置信息和标题
1162
- */
1163
- getAllSessions() {
1164
- const mockTitles = {
1165
- "1": "开发五子棋游戏",
1166
- "2": "修复登录页面样式",
1167
- "3": "API 接口优化"
1168
- };
1169
- const sessions = Array.from(this.initializedSessions.entries()).map(([sessionId, config]) => ({
1170
- sessionId,
1171
- title: mockTitles[sessionId] || `Session ${sessionId}`,
1172
- ...config
1173
- }));
1174
- console.log("[MockAgentProvider] Getting all sessions:", sessions.length);
1175
- return sessions;
1176
- }
1177
- /**
1178
- * 发送嵌入资源消息 (符合 ACP 协议)
1179
- */
1180
- async sendMockEmbeddedResource(sessionId, messageId) {
1181
- console.log(`📎 Sending embedded resource: ${messageId}`);
1182
- this.emitEvent({
1183
- type: "session_update",
1184
- sessionId,
1185
- messageId: `${messageId}-intro`,
1186
- timestamp: Date.now(),
1187
- notification: {
1188
- sessionId,
1189
- update: {
1190
- sessionUpdate: "agent_message_chunk",
1191
- content: {
1192
- type: "text",
1193
- text: "这是一个嵌入的 Python 文件示例:\n\n"
1194
- }
1195
- }
1196
- }
1197
- });
1198
- await this.delay(200);
1199
- this.emitEvent({
1200
- type: "session_update",
1201
- sessionId,
1202
- messageId: `${messageId}-resource`,
1203
- timestamp: Date.now(),
1204
- notification: {
1205
- sessionId,
1206
- update: {
1207
- sessionUpdate: "agent_message_chunk",
1208
- content: {
1209
- type: "resource",
1210
- resource: {
1211
- uri: "file:///mock/example.py",
1212
- mimeType: "text/x-python",
1213
- text: "def hello_world():\n print(\"Hello, World!\")\n return \"success\"\n\nif __name__ == \"__main__\":\n hello_world()"
1214
- }
1215
- }
1216
- }
1217
- }
1218
- });
1219
- await this.delay(200);
1220
- this.emitEvent({
1221
- type: "session_update",
1222
- sessionId,
1223
- messageId: `${messageId}-conclusion`,
1224
- timestamp: Date.now(),
1225
- notification: {
1226
- sessionId,
1227
- update: {
1228
- sessionUpdate: "agent_message_chunk",
1229
- content: {
1230
- type: "text",
1231
- text: "\n\n以上是直接嵌入的文件内容,无需额外请求即可显示。"
1232
- }
1233
- }
1234
- }
1235
- });
1236
- await this.delay(100);
1237
- }
1238
- /**
1239
- * 发送资源链接消息 (符合 ACP 协议)
1240
- */
1241
- async sendMockResourceLink(sessionId, messageId) {
1242
- console.log(`🔗 Sending resource link: ${messageId}`);
1243
- this.emitEvent({
1244
- type: "session_update",
1245
- sessionId,
1246
- messageId: `${messageId}-intro`,
1247
- timestamp: Date.now(),
1248
- notification: {
1249
- sessionId,
1250
- update: {
1251
- sessionUpdate: "agent_message_chunk",
1252
- content: {
1253
- type: "text",
1254
- text: "这是一个指向外部文档的资源链接:\n\n"
1255
- }
1256
- }
1257
- }
1258
- });
1259
- await this.delay(200);
1260
- this.emitEvent({
1261
- type: "session_update",
1262
- sessionId,
1263
- messageId: `${messageId}-link`,
1264
- timestamp: Date.now(),
1265
- notification: {
1266
- sessionId,
1267
- update: {
1268
- sessionUpdate: "agent_message_chunk",
1269
- content: {
1270
- type: "resource_link",
1271
- uri: "https://agentclientprotocol.com/protocol/content",
1272
- name: "ACP Content Protocol",
1273
- mimeType: "text/html",
1274
- description: "Agent Client Protocol - Content specification",
1275
- size: BigInt(256e3)
1276
- }
1277
- }
1278
- }
1279
- });
1280
- await this.delay(200);
1281
- this.emitEvent({
1282
- type: "session_update",
1283
- sessionId,
1284
- messageId: `${messageId}-conclusion`,
1285
- timestamp: Date.now(),
1286
- notification: {
1287
- sessionId,
1288
- update: {
1289
- sessionUpdate: "agent_message_chunk",
1290
- content: {
1291
- type: "text",
1292
- text: "\n\n点击上面的链接可以访问完整的协议文档。"
1293
- }
1294
- }
1295
- }
1296
- });
1297
- await this.delay(100);
1298
- }
1299
- /**
1300
- * 发送完整的工具调用流程 (符合 ACP 协议)
1301
- */
1302
- async sendMockEditDiffToolCallFlow(sessionId, messageId) {
1303
- console.log(`🔧 Starting tool call flow: ${messageId}`);
1304
- const toolCallId = `tool-${Date.now()}`;
1305
- this.emitEvent({
1306
- type: "session_update",
1307
- sessionId,
1308
- messageId,
1309
- timestamp: Date.now(),
1310
- notification: {
1311
- sessionId,
1312
- update: {
1313
- sessionUpdate: "tool_call",
1314
- toolCallId,
1315
- title: "Write File",
1316
- kind: "edit",
1317
- status: "pending",
1318
- locations: [{
1319
- path: "example.py",
1320
- line: 0
1321
- }]
1322
- }
1323
- }
1324
- });
1325
- await this.delay(100);
1326
- const content = `def hello_world():\n print("Hello from ACP tool call!")\n return "success"\n\nif __name__ == "__main__":\n hello_world()`;
1327
- const chunkSize = 10;
1328
- for (let i = 0; i < content.length; i += chunkSize) {
1329
- const chunk = content.substring(i, i + chunkSize);
1330
- console.log(`🐸 tool call Chunk: "${chunk}" | messageId: ${messageId} | sessionId: ${sessionId}`);
1331
- this.emitEvent({
1332
- type: "session_update",
1333
- sessionId,
1334
- messageId,
1335
- timestamp: Date.now(),
1336
- notification: {
1337
- sessionId,
1338
- update: {
1339
- sessionUpdate: "tool_call_update",
1340
- toolCallId,
1341
- status: "in_progress",
1342
- content: [{
1343
- type: "diff",
1344
- path: "example.py",
1345
- oldText: "",
1346
- newText: chunk
1347
- }],
1348
- locations: [{
1349
- path: "example.py",
1350
- line: 0
1351
- }]
1352
- }
1353
- }
1354
- });
1355
- await this.delay(50);
1356
- }
1357
- await this.delay(1200);
1358
- this.emitEvent({
1359
- type: "session_update",
1360
- sessionId,
1361
- messageId,
1362
- timestamp: Date.now(),
1363
- notification: {
1364
- sessionId,
1365
- update: {
1366
- sessionUpdate: "tool_call_update",
1367
- toolCallId,
1368
- status: "completed",
1369
- content: [{
1370
- type: "diff",
1371
- path: "example.py",
1372
- oldText: "def 213",
1373
- newText: "def hello_world():\n print(\"Hello from ACP tool call!\")\n return \"success\"\n\nif __name__ == \"__main__\":\n hello_world()"
1374
- }],
1375
- locations: [{
1376
- path: "example.py",
1377
- line: 0
1378
- }]
1379
- }
1380
- }
1381
- });
1382
- await this.delay(300);
1383
- this.emitEvent({
1384
- type: "session_update",
1385
- sessionId,
1386
- messageId: `${messageId}-summary`,
1387
- timestamp: Date.now(),
1388
- notification: {
1389
- sessionId,
1390
- update: {
1391
- sessionUpdate: "agent_message_chunk",
1392
- content: {
1393
- type: "text",
1394
- text: "✅ 工具调用完成!我成功创建了一个名为 `example.py` 的文件。\n\nACP 协议工具调用流程:\n1. `tool_call` (pending) - 创建工具调用\n2. `tool_call_update` (in_progress) - 开始执行\n3. `tool_call_update` (completed) - 执行完成\n\n这就是完整的工具调用生命周期!"
1395
- }
1396
- }
1397
- }
1398
- });
1399
- await this.delay(100);
1400
- this.emitEvent({
1401
- type: "session_update",
1402
- sessionId,
1403
- messageId: `${messageId}-summary`,
1404
- timestamp: Date.now(),
1405
- notification: {
1406
- sessionId,
1407
- update: {
1408
- sessionUpdate: "agent_message_chunk",
1409
- content: {
1410
- type: "text",
1411
- text: "✅ 工具调用完成!我成功创建了一个名为 `example.py` 的文件。\n\n工具调用流程包括:\n1. 发送工具调用请求 (tool_call)\n2. 返回执行结果 (tool_call_update)\n\n这就是 ACP 协议中完整的工具调用生命周期。"
1412
- }
1413
- }
1414
- }
1415
- });
1416
- await this.delay(100);
1417
- }
1418
- async sendMockEditContentToolCallFlow(sessionId, messageId) {
1419
- console.log(`🔧 Starting tool call flow: ${messageId}`);
1420
- const toolCallId = `tool-${Date.now()}`;
1421
- this.emitEvent({
1422
- type: "session_update",
1423
- sessionId,
1424
- messageId,
1425
- timestamp: Date.now(),
1426
- notification: {
1427
- sessionId,
1428
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
1429
- update: {
1430
- sessionUpdate: "tool_call",
1431
- toolCallId,
1432
- title: "Write File",
1433
- kind: "edit",
1434
- status: "pending",
1435
- locations: [{
1436
- path: "example-edit-content.py",
1437
- line: 0
1438
- }]
1439
- }
1440
- }
1441
- });
1442
- await this.delay(100);
1443
- const content = `def hello_world():\n print("Hello from ACP tool call!")\n return "success"\n\nif __name__ == "__main__":\n hello_world()`;
1444
- const chunkSize = 10;
1445
- let accumulatedInput = "";
1446
- for (let i = 0; i < content.length; i += chunkSize) {
1447
- const chunk = content.substring(i, i + chunkSize);
1448
- accumulatedInput += chunk;
1449
- console.log(`🐸 tool call Chunk: "${chunk}" | messageId: ${messageId} | sessionId: ${sessionId}`);
1450
- this.emitEvent({
1451
- type: "session_update",
1452
- sessionId,
1453
- messageId,
1454
- timestamp: Date.now(),
1455
- notification: {
1456
- sessionId,
1457
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
1458
- update: {
1459
- sessionUpdate: "tool_call_update",
1460
- toolCallId,
1461
- status: "in_progress",
1462
- content: [{
1463
- type: "content",
1464
- content: {
1465
- type: "text",
1466
- text: accumulatedInput
1467
- }
1468
- }],
1469
- rawInput: {
1470
- "filePath": "example-edit-content.py",
1471
- "content": accumulatedInput
1472
- },
1473
- locations: [{
1474
- path: "example-edit-content.py",
1475
- line: 0
1476
- }]
1477
- }
1478
- }
1479
- });
1480
- await this.delay(50);
1481
- }
1482
- await this.delay(1200);
1483
- this.emitEvent({
1484
- type: "session_update",
1485
- sessionId,
1486
- messageId,
1487
- timestamp: Date.now(),
1488
- notification: {
1489
- sessionId,
1490
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
1491
- update: {
1492
- sessionUpdate: "tool_call_update",
1493
- toolCallId,
1494
- status: "completed",
1495
- content: [{
1496
- type: "content",
1497
- content: {
1498
- type: "text",
1499
- text: content
1500
- }
1501
- }],
1502
- rawOutput: {
1503
- "type": "write_to_file_result",
1504
- "path": "example-edit-content.py",
1505
- "addLineCount": 10,
1506
- "removedLines": 20
1507
- },
1508
- locations: [{
1509
- path: "example-edit-content.py",
1510
- line: 0
1511
- }]
1512
- }
1513
- }
1514
- });
1515
- await this.delay(300);
1516
- this.emitEvent({
1517
- type: "session_update",
1518
- sessionId,
1519
- messageId: `${messageId}-summary`,
1520
- timestamp: Date.now(),
1521
- notification: {
1522
- sessionId,
1523
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
1524
- update: {
1525
- sessionUpdate: "agent_message_chunk",
1526
- content: {
1527
- type: "text",
1528
- text: "✅ 工具调用完成!我成功创建了一个名为 `example.py` 的文件。\n\nACP 协议工具调用流程:\n1. `tool_call` (pending) - 创建工具调用\n2. `tool_call_update` (in_progress) - 开始执行\n3. `tool_call_update` (completed) - 执行完成\n\n这就是完整的工具调用生命周期!"
1529
- }
1530
- },
1531
- rawInput: {
1532
- "filePath": "example-edit-content.py",
1533
- "content": accumulatedInput
1534
- }
1535
- }
1536
- });
1537
- await this.delay(100);
1538
- this.emitEvent({
1539
- type: "session_update",
1540
- sessionId,
1541
- messageId: `${messageId}-summary`,
1542
- timestamp: Date.now(),
1543
- notification: {
1544
- sessionId,
1545
- update: {
1546
- sessionUpdate: "agent_message_chunk",
1547
- content: {
1548
- type: "text",
1549
- text: "✅ 工具调用完成!我成功创建了一个名为 `example.py` 的文件。\n\n工具调用流程包括:\n1. 发送工具调用请求 (tool_call)\n2. 返回执行结果 (tool_call_update)\n\n这就是 ACP 协议中完整的工具调用生命周期。"
1550
- }
1551
- }
1552
- }
1553
- });
1554
- await this.delay(100);
1555
- }
1556
- /**
1557
- * 发送完整的工具调用流程 - kind 为 read (符合 ACP 协议)
1558
- *
1559
- * 模拟 read_file 工具调用流程,流式发送 rawInput 和 rawOutput
1560
- */
1561
- async sendMockReadContentToolCallFlow(sessionId, messageId) {
1562
- console.log(`📖 Starting read tool call flow: ${messageId}`);
1563
- const filePath = "/Users/liumingyuan/Project/caseTest/subagent/test.js";
1564
- const toolCallId = `tool-${Date.now()}`;
1565
- this.emitEvent({
1566
- type: "session_update",
1567
- sessionId,
1568
- messageId,
1569
- timestamp: Date.now(),
1570
- notification: {
1571
- sessionId,
1572
- _meta: { "codebuddy.ai": { toolName: "read_file" } },
1573
- update: {
1574
- sessionUpdate: "tool_call",
1575
- toolCallId,
1576
- title: "Read File",
1577
- status: "pending",
1578
- locations: [{
1579
- path: filePath,
1580
- line: 0
1581
- }]
1582
- }
1583
- }
1584
- });
1585
- console.log("[MockAgentProvider] tool_call (pending) sent");
1586
- await this.delay(100);
1587
- const filePathChunks = [
1588
- "/Users/liumingyuan/",
1589
- "Project/caseTest",
1590
- "/subagent/",
1591
- "test.js"
1592
- ];
1593
- let accumulatedInput = "";
1594
- for (const chunk of filePathChunks) {
1595
- accumulatedInput += chunk;
1596
- try {
1597
- this.emitEvent({
1598
- type: "session_update",
1599
- sessionId,
1600
- messageId,
1601
- timestamp: Date.now(),
1602
- notification: {
1603
- sessionId,
1604
- _meta: { "codebuddy.ai": { toolName: "read_file" } },
1605
- update: {
1606
- sessionUpdate: "tool_call_update",
1607
- toolCallId,
1608
- status: "in_progress",
1609
- rawInput: { filePath: accumulatedInput }
1610
- }
1611
- }
1612
- });
1613
- await this.delay(100);
1614
- console.log("[MockAgentProvider] tool_call_update with rawInput:", chunk);
1615
- } catch {}
1616
- }
1617
- const fileContent = `/**
1618
- * Test file for subagent functionality
1619
- */
1620
-
1621
- function helloWorld() {
1622
- console.log('Hello from test.js!');
1623
- return 'success';
1624
- }
1625
-
1626
- class TestClass {
1627
- constructor(name) {
1628
- this.name = name;
1629
- }
1630
-
1631
- greet() {
1632
- return \`Hello, \${this.name}!\`;
1633
- }
1634
- }
1635
-
1636
- // Export functions
1637
- module.exports = {
1638
- helloWorld,
1639
- TestClass
1640
- };
1641
- `;
1642
- const totalLineCount = 26;
1643
- const chunkSize = 20;
1644
- let accumulatedContent = "";
1645
- for (let i = 0; i < fileContent.length; i += chunkSize) {
1646
- const chunk = fileContent.substring(i, i + chunkSize);
1647
- accumulatedContent += chunk;
1648
- const progress = Math.round((i + chunkSize) / fileContent.length * 100);
1649
- const isLastChunk = i + chunkSize >= fileContent.length;
1650
- const rawOutput = {
1651
- type: "read_file_result",
1652
- path: filePath,
1653
- content: accumulatedContent,
1654
- totalLineCount,
1655
- hasMore: !isLastChunk,
1656
- hint: `Reading file... ${Math.min(progress, 100)}% complete`
1657
- };
1658
- const outputValidation = validateToolOutput("read_file", rawOutput);
1659
- this.emitEvent({
1660
- type: "session_update",
1661
- sessionId,
1662
- messageId,
1663
- timestamp: Date.now(),
1664
- notification: {
1665
- sessionId,
1666
- _meta: { "codebuddy.ai": { toolName: "read_file" } },
1667
- update: {
1668
- sessionUpdate: "tool_call_update",
1669
- toolCallId,
1670
- status: "in_progress",
1671
- content: [{
1672
- type: "content",
1673
- content: {
1674
- type: "text",
1675
- text: accumulatedContent
1676
- }
1677
- }],
1678
- locations: [{
1679
- path: filePath,
1680
- line: 0
1681
- }],
1682
- rawOutput: outputValidation.success ? outputValidation.data : rawOutput
1683
- }
1684
- }
1685
- });
1686
- console.log(`📖 Read chunk ${i / chunkSize + 1}: progress ${progress}%`);
1687
- await this.delay(30);
1688
- }
1689
- const finalOutputValidation = validateToolOutput("read_file", {
1690
- type: "read_file_result",
1691
- path: filePath,
1692
- content: fileContent,
1693
- totalLineCount,
1694
- hasMore: false
1695
- });
1696
- if (!finalOutputValidation.success) throw new Error(`Invalid rawOutput: ${JSON.stringify(finalOutputValidation.error.errors)}`);
1697
- this.emitEvent({
1698
- type: "session_update",
1699
- sessionId,
1700
- messageId,
1701
- timestamp: Date.now(),
1702
- notification: {
1703
- sessionId,
1704
- update: {
1705
- sessionUpdate: "tool_call_update",
1706
- toolCallId,
1707
- status: "completed",
1708
- content: [{
1709
- type: "content",
1710
- content: {
1711
- type: "text",
1712
- text: fileContent
1713
- }
1714
- }],
1715
- locations: [{
1716
- path: filePath,
1717
- line: 0
1718
- }],
1719
- rawOutput: finalOutputValidation.data
1720
- }
1721
- }
1722
- });
1723
- console.log("[MockAgentProvider] tool_call_update (completed) sent");
1724
- }
1725
- /**
1726
- * 发送 search_content 工具调用流程 (符合 ACP 协议)
1727
- *
1728
- * 用于模拟在文件内容中搜索特定文本的工具调用
1729
- * 支持显示匹配的文件路径、行号和上下文内容
1730
- */
1731
- async sendMockSearchContentToolCallFlow(sessionId, messageId) {
1732
- console.log(`🔍 Starting search_content tool call flow: ${messageId}`);
1733
- const pattern = "一行工具";
1734
- const directory = "/Users/liumingyuan/Project/caseTest/subagent";
1735
- const toolCallId = `tool-sc-${Date.now()}`;
1736
- this.emitEvent({
1737
- type: "session_update",
1738
- sessionId,
1739
- messageId,
1740
- timestamp: Date.now(),
1741
- notification: {
1742
- sessionId,
1743
- _meta: { "codebuddy.ai": { toolName: "search_content" } },
1744
- update: {
1745
- sessionUpdate: "tool_call",
1746
- toolCallId,
1747
- title: "Search Content",
1748
- kind: "search",
1749
- status: "pending",
1750
- locations: [{
1751
- path: directory,
1752
- line: 0
1753
- }],
1754
- rawInput: {
1755
- pattern,
1756
- directory
1757
- }
1758
- }
1759
- }
1760
- });
1761
- await this.delay(100);
1762
- this.emitEvent({
1763
- type: "session_update",
1764
- sessionId,
1765
- messageId,
1766
- timestamp: Date.now(),
1767
- notification: {
1768
- sessionId,
1769
- update: {
1770
- sessionUpdate: "tool_call_update",
1771
- toolCallId,
1772
- status: "in_progress",
1773
- content: [{
1774
- type: "content",
1775
- content: {
1776
- type: "text",
1777
- text: `Searching for "${pattern}" in ${directory}...`
1778
- }
1779
- }],
1780
- locations: [{
1781
- path: directory,
1782
- line: 0
1783
- }]
1784
- }
1785
- }
1786
- });
1787
- await this.delay(500);
1788
- this.emitEvent({
1789
- type: "session_update",
1790
- sessionId,
1791
- messageId,
1792
- timestamp: Date.now(),
1793
- notification: {
1794
- sessionId,
1795
- update: {
1796
- sessionUpdate: "tool_call_update",
1797
- toolCallId,
1798
- status: "completed",
1799
- content: [{
1800
- type: "content",
1801
- content: {
1802
- type: "text",
1803
- text: `Found 1 matching result\n\nconvert_to_oneline.py\n 56| print("文件内容转一行工具")\n`
1804
- }
1805
- }],
1806
- locations: [{
1807
- path: directory,
1808
- line: 0
1809
- }],
1810
- rawOutput: {
1811
- pattern,
1812
- directory,
1813
- matches: [{
1814
- filePath: "convert_to_oneline.py",
1815
- fileName: "convert_to_oneline.py",
1816
- content: " print(\"文件内容转一行工具\")",
1817
- startLine: 56,
1818
- endLine: 56
1819
- }],
1820
- totalCount: 1,
1821
- hasMore: false
1822
- }
1823
- }
1824
- }
1825
- });
1826
- await this.delay(300);
1827
- this.emitEvent({
1828
- type: "session_update",
1829
- sessionId,
1830
- messageId: `${messageId}-summary`,
1831
- timestamp: Date.now(),
1832
- notification: {
1833
- sessionId,
1834
- update: {
1835
- sessionUpdate: "agent_message_chunk",
1836
- content: {
1837
- type: "text",
1838
- text: `✅ 内容搜索完成!在 \`${directory}\` 目录中找到 1 个匹配结果。\n\n**搜索结果:**\n- \`convert_to_oneline.py\` 第 56 行: \`print("文件内容转一行工具")\`\n\n**工具调用流程:**\n1. \`tool_call\` (pending) - 创建搜索工具调用\n2. \`tool_call_update\` (in_progress) - 执行搜索\n3. \`tool_call_update\` (completed) - 返回匹配结果`
1839
- }
1840
- }
1841
- }
1842
- });
1843
- await this.delay(100);
1844
- }
1845
- /**
1846
- * 发送 search_file 工具调用流程 (符合 ACP 协议)
1847
- *
1848
- * 用于模拟按文件名模式搜索文件的工具调用
1849
- * 支持递归搜索和文件大小显示
1850
- */
1851
- async sendMockSearchFileToolCallFlow(sessionId, messageId) {
1852
- console.log(`🔍 Starting search_file tool call flow: ${messageId}`);
1853
- const pattern = "*.py";
1854
- const directory = "/Users/liumingyuan/Project/caseTest/subagent";
1855
- const toolCallId = `tool-sf-${Date.now()}`;
1856
- this.emitEvent({
1857
- type: "session_update",
1858
- sessionId,
1859
- messageId,
1860
- timestamp: Date.now(),
1861
- notification: {
1862
- sessionId,
1863
- _meta: { "codebuddy.ai": { toolName: "search_file" } },
1864
- update: {
1865
- sessionUpdate: "tool_call",
1866
- toolCallId,
1867
- title: "Search File",
1868
- kind: "search",
1869
- status: "pending",
1870
- locations: [{
1871
- path: directory,
1872
- line: 0
1873
- }],
1874
- rawInput: {
1875
- target_directory: directory,
1876
- pattern,
1877
- recursive: true,
1878
- caseSensitive: false
1879
- }
1880
- }
1881
- }
1882
- });
1883
- await this.delay(100);
1884
- this.emitEvent({
1885
- type: "session_update",
1886
- sessionId,
1887
- messageId,
1888
- timestamp: Date.now(),
1889
- notification: {
1890
- sessionId,
1891
- update: {
1892
- sessionUpdate: "tool_call_update",
1893
- toolCallId,
1894
- status: "in_progress",
1895
- content: [{
1896
- type: "content",
1897
- content: {
1898
- type: "text",
1899
- text: `Searching for files matching "${pattern}" in ${directory}...`
1900
- }
1901
- }],
1902
- locations: [{
1903
- path: directory,
1904
- line: 0
1905
- }]
1906
- }
1907
- }
1908
- });
1909
- await this.delay(500);
1910
- this.emitEvent({
1911
- type: "session_update",
1912
- sessionId,
1913
- messageId,
1914
- timestamp: Date.now(),
1915
- notification: {
1916
- sessionId,
1917
- update: {
1918
- sessionUpdate: "tool_call_update",
1919
- toolCallId,
1920
- status: "completed",
1921
- content: [{
1922
- type: "content",
1923
- content: {
1924
- type: "text",
1925
- text: `Found 5 files\n\nbubble_sort.py (10.38 KB)\nconvert_to_oneline.py (2.2 KB)\ntls12_examples.py (4.58 KB)\n.codebuddy/skills/analyzing-financial-statements/calculate_ratios.py (12.22 KB)\n.codebuddy/skills/analyzing-financial-statements/interpret_ratios.py (15.83 KB)\n`
1926
- }
1927
- }],
1928
- locations: [{
1929
- path: directory,
1930
- line: 0
1931
- }],
1932
- rawOutput: {
1933
- path: directory,
1934
- pattern,
1935
- recursive: true,
1936
- caseSensitive: false,
1937
- results: [
1938
- {
1939
- filePath: "bubble_sort.py",
1940
- size: "10.38 KB"
1941
- },
1942
- {
1943
- filePath: "convert_to_oneline.py",
1944
- size: "2.2 KB"
1945
- },
1946
- {
1947
- filePath: "tls12_examples.py",
1948
- size: "4.58 KB"
1949
- },
1950
- {
1951
- filePath: ".codebuddy/skills/analyzing-financial-statements/calculate_ratios.py",
1952
- size: "12.22 KB"
1953
- },
1954
- {
1955
- filePath: ".codebuddy/skills/analyzing-financial-statements/interpret_ratios.py",
1956
- size: "15.83 KB"
1957
- }
1958
- ]
1959
- }
1960
- }
1961
- }
1962
- });
1963
- await this.delay(300);
1964
- this.emitEvent({
1965
- type: "session_update",
1966
- sessionId,
1967
- messageId: `${messageId}-summary`,
1968
- timestamp: Date.now(),
1969
- notification: {
1970
- sessionId,
1971
- update: {
1972
- sessionUpdate: "agent_message_chunk",
1973
- content: {
1974
- type: "text",
1975
- text: `✅ 文件搜索完成!在 \`${directory}\` 目录中找到 5 个匹配的 Python 文件。\n\n**搜索结果:**\n- \`bubble_sort.py\` (10.38 KB)\n- \`convert_to_oneline.py\` (2.2 KB)\n- \`tls12_examples.py\` (4.58 KB)\n- \`.codebuddy/skills/analyzing-financial-statements/calculate_ratios.py\` (12.22 KB)\n- \`.codebuddy/skills/analyzing-financial-statements/interpret_ratios.py\` (15.83 KB)\n\n**工具调用流程:**\n1. \`tool_call\` (pending) - 创建搜索工具调用\n2. \`tool_call_update\` (in_progress) - 执行搜索\n3. \`tool_call_update\` (completed) - 返回搜索结果`
1976
- }
1977
- }
1978
- }
1979
- });
1980
- await this.delay(100);
1981
- }
1982
- /**
1983
- * 发送删除文件工具调用流程 (符合 ACP 协议)
1984
- *
1985
- * 用于模拟删除文件的工具调用
1986
- * 支持显示删除操作的进度和结果
1987
- */
1988
- async sendMockDeleteFileToolCallFlow(sessionId, messageId) {
1989
- console.log(`🗑️ Starting delete_file tool call flow: ${messageId}`);
1990
- const targetFile = "/Users/liumingyuan/Project/caseTest/subagent/temp_file.txt";
1991
- const toolCallId = `tool-df-${Date.now()}`;
1992
- this.emitEvent({
1993
- type: "session_update",
1994
- sessionId,
1995
- messageId,
1996
- timestamp: Date.now(),
1997
- notification: {
1998
- sessionId,
1999
- _meta: { "codebuddy.ai": { toolName: "delete_file" } },
2000
- update: {
2001
- sessionUpdate: "tool_call",
2002
- toolCallId,
2003
- title: "Delete File",
2004
- status: "pending",
2005
- locations: [{
2006
- path: targetFile,
2007
- line: 0
2008
- }]
2009
- }
2010
- }
2011
- });
2012
- console.log("[MockAgentProvider] delete_file tool_call (pending) sent");
2013
- await this.delay(200);
2014
- const filePathChunks = [
2015
- "/Users/liumingyuan/",
2016
- "Project/caseTest",
2017
- "/subagent/",
2018
- "temp_file.txt"
2019
- ];
2020
- let accumulatedInput = "";
2021
- for (const chunk of filePathChunks) {
2022
- accumulatedInput += chunk;
2023
- this.emitEvent({
2024
- type: "session_update",
2025
- sessionId,
2026
- messageId,
2027
- timestamp: Date.now(),
2028
- notification: {
2029
- sessionId,
2030
- _meta: { "codebuddy.ai": { toolName: "delete_file" } },
2031
- update: {
2032
- sessionUpdate: "tool_call_update",
2033
- toolCallId,
2034
- status: "in_progress",
2035
- rawInput: {
2036
- target_file: accumulatedInput,
2037
- explanation: "Deleting temporary test file"
2038
- }
2039
- }
2040
- }
2041
- });
2042
- await this.delay(100);
2043
- console.log("[MockAgentProvider] delete_file tool_call_update with rawInput:", chunk);
2044
- }
2045
- await this.delay(300);
2046
- for (const step of [
2047
- {
2048
- progress: 25,
2049
- message: "Checking file permissions..."
2050
- },
2051
- {
2052
- progress: 50,
2053
- message: "Validating file path..."
2054
- },
2055
- {
2056
- progress: 75,
2057
- message: "Removing file..."
2058
- },
2059
- {
2060
- progress: 100,
2061
- message: "File deleted successfully"
2062
- }
2063
- ]) {
2064
- const rawOutput = {
2065
- type: "delete_file_result",
2066
- path: targetFile,
2067
- recursive: false,
2068
- hint: step.message
2069
- };
2070
- const outputValidation = validateToolOutput("delete_file", rawOutput);
2071
- this.emitEvent({
2072
- type: "session_update",
2073
- sessionId,
2074
- messageId,
2075
- timestamp: Date.now(),
2076
- notification: {
2077
- sessionId,
2078
- _meta: { "codebuddy.ai": { toolName: "delete_file" } },
2079
- update: {
2080
- sessionUpdate: "tool_call_update",
2081
- toolCallId,
2082
- status: step.progress === 100 ? "deleted" : "in_progress",
2083
- content: [{
2084
- type: "content",
2085
- content: {
2086
- type: "text",
2087
- text: `🗑️ ${step.message} (${step.progress}%)`
2088
- }
2089
- }],
2090
- locations: [{
2091
- path: targetFile,
2092
- line: 0
2093
- }],
2094
- rawOutput: outputValidation.success ? outputValidation.data : rawOutput
2095
- }
2096
- }
2097
- });
2098
- console.log(`🗑️ Delete progress: ${step.progress}% - ${step.message}`);
2099
- await this.delay(200);
2100
- }
2101
- const finalOutputValidation = validateToolOutput("delete_file", {
2102
- type: "delete_file_result",
2103
- path: targetFile,
2104
- recursive: false,
2105
- hint: "File successfully deleted from filesystem"
2106
- });
2107
- if (!finalOutputValidation.success) throw new Error(`Invalid delete_file rawOutput: ${JSON.stringify(finalOutputValidation.error.errors)}`);
2108
- this.emitEvent({
2109
- type: "session_update",
2110
- sessionId,
2111
- messageId,
2112
- timestamp: Date.now(),
2113
- notification: {
2114
- sessionId,
2115
- update: {
2116
- sessionUpdate: "tool_call_update",
2117
- toolCallId,
2118
- status: "completed",
2119
- content: [{
2120
- type: "content",
2121
- content: {
2122
- type: "text",
2123
- text: `✅ 文件删除完成!\n\n**删除的文件:** \`${targetFile}\`\n\n**操作详情:**\n- 文件路径验证 ✓\n- 权限检查 ✓\n- 文件删除 ✓\n\n文件已从文件系统中成功移除。`
2124
- }
2125
- }],
2126
- locations: [{
2127
- path: targetFile,
2128
- line: 0
2129
- }],
2130
- rawOutput: finalOutputValidation.data
2131
- }
2132
- }
2133
- });
2134
- console.log("[MockAgentProvider] delete_file tool_call_update (completed) sent");
2135
- this.emitEvent({
2136
- type: "session_update",
2137
- sessionId,
2138
- messageId: `${messageId}-summary`,
2139
- timestamp: Date.now(),
2140
- notification: {
2141
- sessionId,
2142
- update: {
2143
- sessionUpdate: "agent_message_chunk",
2144
- content: {
2145
- type: "text",
2146
- text: `🗑️ **删除文件工具调用演示完成**\n\n**工具调用流程:**\n1. \`tool_call\` (pending) - 创建删除文件工具调用\n2. \`tool_call_update\` (in_progress) - 流式发送参数和执行删除操作\n3. \`tool_call_update\` (completed) - 返回删除结果\n\n**rawInput 包含:**\n- \`target_file\`: 要删除的文件路径\n- \`explanation\`: 删除原因说明\n\n**rawOutput 包含:**\n- \`type\`: 'delete_file_result'\n- \`path\`: 被删除的文件路径\n- \`recursive\`: 是否递归删除\n- \`hint\`: 操作提示信息`
2147
- }
2148
- }
2149
- }
2150
- });
2151
- await this.delay(100);
2152
- }
2153
- /**
2154
- * 发送 ask_followup_question 工具调用流程 (符合 ACP 协议)
2155
- *
2156
- * 用于模拟向用户提问并获取回答的工具调用
2157
- * 数据结构与 genie-ide 保持一致:question (单个问题字符串) + options (选项数组)
2158
- */
2159
- async sendMockAskFollowupQuestionToolCallFlow(sessionId, messageId) {
2160
- console.log(`❓ Starting ask_followup_question tool call flow: ${messageId}`);
2161
- const toolCallId = `tool-afq-${Date.now()}`;
2162
- const question = "你希望创建什么类型的项目?";
2163
- const options = [
2164
- "Web 应用(前端 + 后端)",
2165
- "命令行工具(CLI)",
2166
- "移动应用(React Native / Flutter)",
2167
- "桌面应用(Electron)",
2168
- "后端服务(API / 微服务)"
2169
- ];
2170
- this.emitEvent({
2171
- type: "session_update",
2172
- sessionId,
2173
- messageId,
2174
- timestamp: Date.now(),
2175
- notification: {
2176
- sessionId,
2177
- _meta: { "codebuddy.ai": { toolName: "ask_followup_question" } },
2178
- update: {
2179
- sessionUpdate: "tool_call",
2180
- toolCallId,
2181
- title: "Ask Followup Question",
2182
- kind: "other",
2183
- status: "pending",
2184
- rawInput: {
2185
- question,
2186
- options: JSON.stringify(options)
2187
- }
2188
- }
2189
- }
2190
- });
2191
- await this.delay(100);
2192
- this.emitEvent({
2193
- type: "session_update",
2194
- sessionId,
2195
- messageId,
2196
- timestamp: Date.now(),
2197
- notification: {
2198
- sessionId,
2199
- _meta: { "codebuddy.ai": { toolName: "ask_followup_question" } },
2200
- update: {
2201
- sessionUpdate: "tool_call_update",
2202
- toolCallId,
2203
- status: "in_progress",
2204
- rawInput: {
2205
- question,
2206
- options: JSON.stringify(options)
2207
- }
2208
- }
2209
- }
2210
- });
2211
- console.log("[MockAgentProvider] ask_followup_question tool displayed, waiting for user interaction...");
2212
- }
2213
- /**
2214
- * 发送 list_dir 工具调用流程 (符合 ACP 协议)
2215
- *
2216
- * 用于模拟列出目录中的文件
2217
- * 数据结构符合 tool-schemas.ts 中的 ListDirInput 和 ListFilesResult
2218
- */
2219
- async sendMockListFilesToolCallFlow(sessionId, messageId) {
2220
- console.log(`📁 Starting list_dir tool call flow: ${messageId}`);
2221
- const target_directory = "/Users/test/project/src";
2222
- const toolCallId = `tool-ld-${Date.now()}`;
2223
- const mockFiles = [
2224
- {
2225
- filePath: `${target_directory}/index.ts`,
2226
- size: "2.5 KB",
2227
- modifyTime: "2024-01-15 10:30:00"
2228
- },
2229
- {
2230
- filePath: `${target_directory}/App.tsx`,
2231
- size: "8.2 KB",
2232
- modifyTime: "2024-01-15 09:45:00"
2233
- },
2234
- {
2235
- filePath: `${target_directory}/utils.ts`,
2236
- size: "1.8 KB",
2237
- modifyTime: "2024-01-14 16:20:00"
2238
- },
2239
- {
2240
- filePath: `${target_directory}/components/`,
2241
- size: "-",
2242
- modifyTime: "2024-01-15 11:00:00"
2243
- },
2244
- {
2245
- filePath: `${target_directory}/hooks/`,
2246
- size: "-",
2247
- modifyTime: "2024-01-14 14:30:00"
2248
- },
2249
- {
2250
- filePath: `${target_directory}/styles/`,
2251
- size: "-",
2252
- modifyTime: "2024-01-13 09:00:00"
2253
- },
2254
- {
2255
- filePath: `${target_directory}/types.d.ts`,
2256
- size: "3.1 KB",
2257
- modifyTime: "2024-01-12 18:45:00"
2258
- },
2259
- {
2260
- filePath: `${target_directory}/constants.ts`,
2261
- size: "0.9 KB",
2262
- modifyTime: "2024-01-10 12:00:00"
2263
- }
2264
- ];
2265
- const listing = mockFiles.map((f) => {
2266
- const name = f.filePath.split("/").pop() || "";
2267
- return f.filePath.endsWith("/") ? `📁 ${name}` : `📄 ${name} (${f.size})`;
2268
- }).join("\n");
2269
- this.emitEvent({
2270
- type: "session_update",
2271
- sessionId,
2272
- messageId,
2273
- timestamp: Date.now(),
2274
- notification: {
2275
- sessionId,
2276
- _meta: { "codebuddy.ai": { toolName: "list_dir" } },
2277
- update: {
2278
- sessionUpdate: "tool_call",
2279
- toolCallId,
2280
- title: "List Directory",
2281
- kind: "search",
2282
- status: "pending",
2283
- locations: [{
2284
- path: target_directory,
2285
- line: 0
2286
- }],
2287
- rawInput: { target_directory }
2288
- }
2289
- }
2290
- });
2291
- await this.delay(100);
2292
- this.emitEvent({
2293
- type: "session_update",
2294
- sessionId,
2295
- messageId,
2296
- timestamp: Date.now(),
2297
- notification: {
2298
- sessionId,
2299
- _meta: { "codebuddy.ai": { toolName: "list_dir" } },
2300
- update: {
2301
- sessionUpdate: "tool_call_update",
2302
- toolCallId,
2303
- status: "in_progress",
2304
- content: [{
2305
- type: "content",
2306
- content: {
2307
- type: "text",
2308
- text: `Listing directory ${target_directory}...`
2309
- }
2310
- }],
2311
- locations: [{
2312
- path: target_directory,
2313
- line: 0
2314
- }]
2315
- }
2316
- }
2317
- });
2318
- await this.delay(300);
2319
- this.emitEvent({
2320
- type: "session_update",
2321
- sessionId,
2322
- messageId,
2323
- timestamp: Date.now(),
2324
- notification: {
2325
- sessionId,
2326
- _meta: { "codebuddy.ai": { toolName: "list_dir" } },
2327
- update: {
2328
- sessionUpdate: "tool_call_update",
2329
- toolCallId,
2330
- status: "completed",
2331
- content: [{
2332
- type: "content",
2333
- content: {
2334
- type: "text",
2335
- text: `Listed ${mockFiles.length} items in ${target_directory}`
2336
- }
2337
- }],
2338
- locations: [{
2339
- path: target_directory,
2340
- line: 0
2341
- }],
2342
- rawOutput: {
2343
- type: "list_files_result",
2344
- files: mockFiles,
2345
- root: target_directory,
2346
- listing
2347
- }
2348
- }
2349
- }
2350
- });
2351
- console.log("[MockAgentProvider] list_dir tool call completed");
2352
- }
2353
- /**
2354
- * 发送 preview_url 工具调用流程 (符合 ACP 协议)
2355
- *
2356
- * 用于测试 unknown-tool-renderer 的显示效果
2357
- * preview_url 是一个未知工具,会使用 UnknownToolRenderer 渲染
2358
- */
2359
- async sendMockPreviewUrlToolCallFlow(sessionId, messageId) {
2360
- console.log(`🌐 Starting preview_url tool call flow: ${messageId}`);
2361
- const toolCallId = `tool-pu-${Date.now()}`;
2362
- const url = "https://example.com/preview";
2363
- this.emitEvent({
2364
- type: "session_update",
2365
- sessionId,
2366
- messageId,
2367
- timestamp: Date.now(),
2368
- notification: {
2369
- sessionId,
2370
- _meta: { "codebuddy.ai": { toolName: "preview_url" } },
2371
- update: {
2372
- sessionUpdate: "tool_call",
2373
- toolCallId,
2374
- title: "Preview URL",
2375
- kind: "other",
2376
- status: "pending",
2377
- rawInput: { url }
2378
- }
2379
- }
2380
- });
2381
- await this.delay(200);
2382
- this.emitEvent({
2383
- type: "session_update",
2384
- sessionId,
2385
- messageId,
2386
- timestamp: Date.now(),
2387
- notification: {
2388
- sessionId,
2389
- _meta: { "codebuddy.ai": { toolName: "preview_url" } },
2390
- update: {
2391
- sessionUpdate: "tool_call_update",
2392
- toolCallId,
2393
- status: "in_progress",
2394
- content: [{
2395
- type: "content",
2396
- content: {
2397
- type: "text",
2398
- text: `Loading preview for ${url}...`
2399
- }
2400
- }]
2401
- }
2402
- }
2403
- });
2404
- await this.delay(800);
2405
- this.emitEvent({
2406
- type: "session_update",
2407
- sessionId,
2408
- messageId,
2409
- timestamp: Date.now(),
2410
- notification: {
2411
- sessionId,
2412
- _meta: { "codebuddy.ai": { toolName: "preview_url" } },
2413
- update: {
2414
- sessionUpdate: "tool_call_update",
2415
- toolCallId,
2416
- status: "completed",
2417
- content: [{
2418
- type: "content",
2419
- content: {
2420
- type: "text",
2421
- text: `Preview loaded successfully for ${url}`
2422
- }
2423
- }],
2424
- rawOutput: {
2425
- url,
2426
- title: "Example Domain",
2427
- screenshot: "base64-encoded-screenshot-data...",
2428
- status: 200
2429
- }
2430
- }
2431
- }
2432
- });
2433
- console.log("[MockAgentProvider] preview_url tool call completed");
2434
- }
2435
- /**
2436
- * 发送 list_code_definition_names 工具调用流程 (符合 ACP 协议)
2437
- *
2438
- * 用于测试 unknown-tool-renderer 的显示效果
2439
- * list_code_definition_names 是一个未知工具,会使用 UnknownToolRenderer 渲染
2440
- */
2441
- async sendMockListCodeDefinitionNamesToolCallFlow(sessionId, messageId) {
2442
- console.log(`📝 Starting list_code_definition_names tool call flow: ${messageId}`);
2443
- const toolCallId = `tool-lcd-${Date.now()}`;
2444
- const filePath = "/Users/test/project/src/utils.ts";
2445
- this.emitEvent({
2446
- type: "session_update",
2447
- sessionId,
2448
- messageId,
2449
- timestamp: Date.now(),
2450
- notification: {
2451
- sessionId,
2452
- _meta: { "codebuddy.ai": { toolName: "list_code_definition_names" } },
2453
- update: {
2454
- sessionUpdate: "tool_call",
2455
- toolCallId,
2456
- title: "List Code Definitions",
2457
- kind: "other",
2458
- status: "pending",
2459
- rawInput: { filePath }
2460
- }
2461
- }
2462
- });
2463
- await this.delay(200);
2464
- this.emitEvent({
2465
- type: "session_update",
2466
- sessionId,
2467
- messageId,
2468
- timestamp: Date.now(),
2469
- notification: {
2470
- sessionId,
2471
- _meta: { "codebuddy.ai": { toolName: "list_code_definition_names" } },
2472
- update: {
2473
- sessionUpdate: "tool_call_update",
2474
- toolCallId,
2475
- status: "in_progress",
2476
- content: [{
2477
- type: "content",
2478
- content: {
2479
- type: "text",
2480
- text: `Analyzing code definitions in ${filePath}...`
2481
- }
2482
- }]
2483
- }
2484
- }
2485
- });
2486
- await this.delay(600);
2487
- this.emitEvent({
2488
- type: "session_update",
2489
- sessionId,
2490
- messageId,
2491
- timestamp: Date.now(),
2492
- notification: {
2493
- sessionId,
2494
- _meta: { "codebuddy.ai": { toolName: "list_code_definition_names" } },
2495
- update: {
2496
- sessionUpdate: "tool_call_update",
2497
- toolCallId,
2498
- status: "completed",
2499
- content: [{
2500
- type: "content",
2501
- content: {
2502
- type: "text",
2503
- text: `Found 5 code definitions in ${filePath}`
2504
- }
2505
- }],
2506
- rawOutput: {
2507
- filePath,
2508
- definitions: [
2509
- {
2510
- name: "formatDate",
2511
- type: "function",
2512
- line: 5
2513
- },
2514
- {
2515
- name: "parseJSON",
2516
- type: "function",
2517
- line: 15
2518
- },
2519
- {
2520
- name: "debounce",
2521
- type: "function",
2522
- line: 28
2523
- },
2524
- {
2525
- name: "Config",
2526
- type: "interface",
2527
- line: 42
2528
- },
2529
- {
2530
- name: "DEFAULT_OPTIONS",
2531
- type: "const",
2532
- line: 55
2533
- }
2534
- ]
2535
- }
2536
- }
2537
- }
2538
- });
2539
- console.log("[MockAgentProvider] list_code_definition_names tool call completed");
2540
- }
2541
- /**
2542
- * 发送 web_fetch 工具调用流程 (符合 ACP 协议)
2543
- *
2544
- * 用于模拟从 URL 获取网页内容的工具调用
2545
- */
2546
- async sendMockWebFetchToolCallFlow(sessionId, messageId) {
2547
- console.log(`🌐 Starting web_fetch tool call flow: ${messageId}`);
2548
- const toolCallId = `tool-wf-${Date.now()}`;
2549
- const targetUrl = "https://github.com/anthropics/claude-code";
2550
- this.emitEvent({
2551
- type: "session_update",
2552
- sessionId,
2553
- messageId,
2554
- timestamp: Date.now(),
2555
- notification: {
2556
- sessionId,
2557
- _meta: { "codebuddy.ai": { toolName: "web_fetch" } },
2558
- update: {
2559
- sessionUpdate: "tool_call",
2560
- toolCallId,
2561
- title: "Web Fetch",
2562
- kind: "other",
2563
- status: "pending",
2564
- rawInput: {
2565
- url: targetUrl,
2566
- fetchInfo: "Fetching page content..."
2567
- }
2568
- }
2569
- }
2570
- });
2571
- await this.delay(200);
2572
- const urlChunks = [
2573
- "https://github.com/",
2574
- "anthropics/",
2575
- "claude-code"
2576
- ];
2577
- let accumulatedUrl = "";
2578
- for (const chunk of urlChunks) {
2579
- accumulatedUrl += chunk;
2580
- this.emitEvent({
2581
- type: "session_update",
2582
- sessionId,
2583
- messageId,
2584
- timestamp: Date.now(),
2585
- notification: {
2586
- sessionId,
2587
- _meta: { "codebuddy.ai": { toolName: "web_fetch" } },
2588
- update: {
2589
- sessionUpdate: "tool_call_update",
2590
- toolCallId,
2591
- status: "in_progress",
2592
- rawInput: {
2593
- url: accumulatedUrl,
2594
- fetchInfo: "Fetching page content..."
2595
- }
2596
- }
2597
- }
2598
- });
2599
- await this.delay(100);
2600
- console.log("[MockAgentProvider] web_fetch tool_call_update with rawInput:", chunk);
2601
- }
2602
- await this.delay(500);
2603
- for (const step of [
2604
- { loading: "Connecting to server..." },
2605
- { loading: "Downloading content..." },
2606
- { loading: "Parsing HTML..." }
2607
- ]) {
2608
- this.emitEvent({
2609
- type: "session_update",
2610
- sessionId,
2611
- messageId,
2612
- timestamp: Date.now(),
2613
- notification: {
2614
- sessionId,
2615
- _meta: { "codebuddy.ai": { toolName: "web_fetch" } },
2616
- update: {
2617
- sessionUpdate: "tool_call_update",
2618
- toolCallId,
2619
- status: "in_progress",
2620
- rawInput: {
2621
- url: targetUrl,
2622
- fetchInfo: step.loading
2623
- },
2624
- rawOutput: { loading: step.loading }
2625
- }
2626
- }
2627
- });
2628
- console.log(`🌐 Fetch progress: ${step.loading}`);
2629
- await this.delay(300);
2630
- }
2631
- const mockWebContent = `# Claude Code
2632
-
2633
- Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster through natural conversation.
2634
-
2635
- ## Features
2636
-
2637
- - **Agentic coding**: Claude Code can read, write, and edit files, run commands, and more.
2638
- - **Context-aware**: Claude Code understands your entire codebase and can answer questions about it.
2639
- - **Natural conversation**: Just describe what you want to do in plain English.
2640
-
2641
- ## Installation
2642
-
2643
- \`\`\`bash
2644
- npm install -g @anthropic-ai/claude-code
2645
- \`\`\`
2646
-
2647
- ## Usage
2648
-
2649
- \`\`\`bash
2650
- claude-code
2651
- \`\`\`
2652
-
2653
- Start a conversation with Claude Code and let it help you with your coding tasks!`;
2654
- this.emitEvent({
2655
- type: "session_update",
2656
- sessionId,
2657
- messageId,
2658
- timestamp: Date.now(),
2659
- notification: {
2660
- sessionId,
2661
- _meta: { "codebuddy.ai": { toolName: "web_fetch" } },
2662
- update: {
2663
- sessionUpdate: "tool_call_update",
2664
- toolCallId,
2665
- status: "completed",
2666
- rawInput: {
2667
- url: targetUrl,
2668
- fetchInfo: "Fetch web page content"
2669
- },
2670
- rawOutput: {
2671
- title: "Claude Code - GitHub",
2672
- favicon: "https://github.githubassets.com/favicons/favicon.svg",
2673
- data: mockWebContent
2674
- }
2675
- }
2676
- }
2677
- });
2678
- console.log("[MockAgentProvider] web_fetch tool_call_update (completed) sent");
2679
- this.emitEvent({
2680
- type: "session_update",
2681
- sessionId,
2682
- messageId: `${messageId}-summary`,
2683
- timestamp: Date.now(),
2684
- notification: {
2685
- sessionId,
2686
- update: {
2687
- sessionUpdate: "agent_message_chunk",
2688
- content: {
2689
- type: "text",
2690
- text: `🌐 **Web Fetch 工具调用演示完成**\n\n**工具调用流程:**\n1. \`tool_call\` (pending) - 创建 web_fetch 工具调用\n2. \`tool_call_update\` (in_progress) - 流式发送 URL 和获取进度\n3. \`tool_call_update\` (completed) - 返回网页内容\n\n**rawInput 包含:**\n- \`url\`: 目标 URL\n- \`fetchInfo\`: 获取说明\n\n**rawOutput 包含:**\n- \`title\`: 网页标题\n- \`favicon\`: 网站图标\n- \`data\`: 网页内容(Markdown 格式)`
2691
- }
2692
- }
2693
- }
2694
- });
2695
- await this.delay(100);
2696
- }
2697
- /**
2698
- * 发送 web_search 工具调用流程 (符合 ACP 协议)
2699
- *
2700
- * 用于模拟网络搜索的工具调用
2701
- * 数据结构符合 tool-schemas.ts 中的 web_search 定义
2702
- */
2703
- async sendMockWebSearchToolCallFlow(sessionId, messageId) {
2704
- console.log(`🔍 Starting web_search tool call flow: ${messageId}`);
2705
- const toolCallId = `tool-ws-${Date.now()}`;
2706
- const searchTerm = "TypeScript 5.0 new features";
2707
- const explanation = "Searching for the latest TypeScript 5.0 features to provide accurate and up-to-date information.";
2708
- this.emitEvent({
2709
- type: "session_update",
2710
- sessionId,
2711
- messageId,
2712
- timestamp: Date.now(),
2713
- notification: {
2714
- sessionId,
2715
- _meta: { "codebuddy.ai": { toolName: "web_search" } },
2716
- update: {
2717
- sessionUpdate: "tool_call",
2718
- toolCallId,
2719
- title: "Web Search",
2720
- kind: "search",
2721
- status: "pending",
2722
- rawInput: {
2723
- searchTerm,
2724
- explanation
2725
- }
2726
- }
2727
- }
2728
- });
2729
- await this.delay(200);
2730
- this.emitEvent({
2731
- type: "session_update",
2732
- sessionId,
2733
- messageId,
2734
- timestamp: Date.now(),
2735
- notification: {
2736
- sessionId,
2737
- _meta: { "codebuddy.ai": { toolName: "web_search" } },
2738
- update: {
2739
- sessionUpdate: "tool_call_update",
2740
- toolCallId,
2741
- status: "in_progress",
2742
- content: [{
2743
- type: "content",
2744
- content: {
2745
- type: "text",
2746
- text: `🔍 Searching the web for "${searchTerm}"...`
2747
- }
2748
- }],
2749
- rawInput: {
2750
- searchTerm,
2751
- explanation
2752
- }
2753
- }
2754
- }
2755
- });
2756
- await this.delay(800);
2757
- const searchResults = [
2758
- {
2759
- title: "Announcing TypeScript 5.0 - TypeScript Blog",
2760
- url: "https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/",
2761
- snippet: "TypeScript 5.0 brings many new features, including decorators, const type parameters, and improvements to enums. This release also includes significant performance improvements...",
2762
- publishedDate: "2023-03-16"
2763
- },
2764
- {
2765
- title: "TypeScript 5.0: What's New - LogRocket Blog",
2766
- url: "https://blog.logrocket.com/whats-new-typescript-5-0/",
2767
- snippet: "TypeScript 5.0 introduces several exciting features: ECMAScript decorators, const type parameters, multiple config extends, all enums are union enums, and more...",
2768
- publishedDate: "2023-04-10"
2769
- },
2770
- {
2771
- title: "TypeScript 5.0 Release Notes - GitHub",
2772
- url: "https://github.com/microsoft/TypeScript/releases/tag/v5.0.0",
2773
- snippet: "Official release notes for TypeScript 5.0. Key highlights include: Decorators, const Type Parameters, Supporting Multiple Configuration Files in extends...",
2774
- publishedDate: "2023-03-16"
2775
- },
2776
- {
2777
- title: "A Complete Guide to TypeScript 5.0 Features - Medium",
2778
- url: "https://medium.com/typescript-5-features-guide",
2779
- snippet: "Explore all the new features in TypeScript 5.0: decorators with metadata, const type parameters for better type inference, improved module resolution...",
2780
- publishedDate: "2023-05-22"
2781
- },
2782
- {
2783
- title: "TypeScript 5.0 Performance Improvements",
2784
- url: "https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html",
2785
- snippet: "TypeScript 5.0 includes significant performance improvements: faster type checking, reduced memory usage, and improved build times. Package size reduced by 50%...",
2786
- publishedDate: "2023-03-16"
2787
- }
2788
- ];
2789
- this.emitEvent({
2790
- type: "session_update",
2791
- sessionId,
2792
- messageId,
2793
- timestamp: Date.now(),
2794
- notification: {
2795
- sessionId,
2796
- _meta: { "codebuddy.ai": { toolName: "web_search" } },
2797
- update: {
2798
- sessionUpdate: "tool_call_update",
2799
- toolCallId,
2800
- status: "completed",
2801
- content: [{
2802
- type: "content",
2803
- content: {
2804
- type: "text",
2805
- text: `Found ${searchResults.length} results for "${searchTerm}"`
2806
- }
2807
- }],
2808
- rawInput: {
2809
- searchTerm,
2810
- explanation
2811
- },
2812
- rawOutput: {
2813
- query: searchTerm,
2814
- totalResults: searchResults.length,
2815
- results: searchResults,
2816
- searchEngine: "web",
2817
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
2818
- }
2819
- }
2820
- }
2821
- });
2822
- await this.delay(300);
2823
- this.emitEvent({
2824
- type: "session_update",
2825
- sessionId,
2826
- messageId: `${messageId}-summary`,
2827
- timestamp: Date.now(),
2828
- notification: {
2829
- sessionId,
2830
- update: {
2831
- sessionUpdate: "agent_message_chunk",
2832
- content: {
2833
- type: "text",
2834
- text: `🔍 **Web 搜索完成**\n\n**搜索词:** \`${searchTerm}\`\n\n**搜索结果:** 找到 ${searchResults.length} 个相关结果\n\n**主要发现:**\n1. **TypeScript 5.0 新特性** - 包括装饰器、const 类型参数、枚举改进等\n2. **性能提升** - 类型检查更快,内存使用减少,包大小减少 50%\n3. **配置增强** - 支持多配置文件继承\n\n**工具调用流程:**\n1. \`tool_call\` (pending) - 创建搜索工具调用\n2. \`tool_call_update\` (in_progress) - 执行网络搜索\n3. \`tool_call_update\` (completed) - 返回搜索结果\n\n**rawInput 包含:**\n- \`searchTerm\`: 搜索关键词\n- \`explanation\`: 搜索原因说明\n\n**rawOutput 包含:**\n- \`query\`: 搜索查询\n- \`totalResults\`: 结果总数\n- \`results\`: 搜索结果数组(包含 title、url、snippet、publishedDate)`
2835
- }
2836
- }
2837
- }
2838
- });
2839
- console.log("[MockAgentProvider] web_search tool call completed");
2840
- }
2841
- /**
2842
- * 发送 read_lints 工具调用流程 (符合 ACP 协议)
2843
- *
2844
- * 数据结构 (来自 tool-schemas.ts):
2845
- * - Input: ReadLintsInput = { paths?: string }
2846
- * - Output: ReadLintsResult = {
2847
- * type: 'read_lints_result';
2848
- * diagnostics: string[];
2849
- * totalCount?: number;
2850
- * hint?: string;
2851
- * isTruncated?: boolean;
2852
- * }
2853
- */
2854
- async sendMockReadLintsToolCallFlow(sessionId, messageId) {
2855
- console.log(`🔍 Starting read_lints tool call flow: ${messageId}`);
2856
- const toolCallId = `tool-rl-${Date.now()}`;
2857
- const targetPath = "/Users/test/project/src/components/Button.tsx";
2858
- this.emitEvent({
2859
- type: "session_update",
2860
- sessionId,
2861
- messageId,
2862
- timestamp: Date.now(),
2863
- notification: {
2864
- sessionId,
2865
- _meta: { "codebuddy.ai": { toolName: "read_lints" } },
2866
- update: {
2867
- sessionUpdate: "tool_call",
2868
- toolCallId,
2869
- title: "Read Lints",
2870
- kind: "read",
2871
- status: "pending",
2872
- rawInput: { paths: targetPath }
2873
- }
2874
- }
2875
- });
2876
- await this.delay(200);
2877
- this.emitEvent({
2878
- type: "session_update",
2879
- sessionId,
2880
- messageId,
2881
- timestamp: Date.now(),
2882
- notification: {
2883
- sessionId,
2884
- _meta: { "codebuddy.ai": { toolName: "read_lints" } },
2885
- update: {
2886
- sessionUpdate: "tool_call_update",
2887
- toolCallId,
2888
- status: "in_progress",
2889
- rawInput: { paths: targetPath }
2890
- }
2891
- }
2892
- });
2893
- await this.delay(300);
2894
- const diagnosticsText = `Button.tsx - ERROR (3 issues)
2895
- [ERROR] Line 15, Column 8: 'useState' is defined but never used. Consider removing this import.
2896
- [ERROR] Line 23, Column 12: Type 'string' is not assignable to type 'number'. Expected a numeric value.
2897
- [ERROR] Line 45, Column 4: Missing return statement in function that is expected to return 'ReactNode'.`;
2898
- this.emitEvent({
2899
- type: "session_update",
2900
- sessionId,
2901
- messageId,
2902
- timestamp: Date.now(),
2903
- notification: {
2904
- sessionId,
2905
- _meta: { "codebuddy.ai": { toolName: "read_lints" } },
2906
- update: {
2907
- sessionUpdate: "tool_call_update",
2908
- toolCallId,
2909
- status: "completed",
2910
- rawInput: { paths: targetPath },
2911
- rawOutput: {
2912
- type: "read_lints_result",
2913
- diagnostics: [diagnosticsText],
2914
- totalCount: 3,
2915
- hint: "Found 3 lint errors in Button.tsx",
2916
- isTruncated: false
2917
- }
2918
- }
2919
- }
2920
- });
2921
- console.log("[MockAgentProvider] read_lints tool call completed");
2922
- }
2923
- /**
2924
- * 发送 execute_command 工具调用流程 (符合 ACP 协议)
2925
- *
2926
- * 数据结构 (来自 tool-schemas.ts):
2927
- * - Input: ExecuteCommandInput = { command: string; requires_approval: boolean; }
2928
- * - Output: ExecuteCommandResult = {
2929
- * type: 'execute_command_result';
2930
- * stdout: string;
2931
- * stderr: string;
2932
- * exitCode: number;
2933
- * hint?: string;
2934
- * serviceInfo?: { isWatchCommand, isServiceOutput, serviceReady, message };
2935
- * use_standalone_terminal?: boolean;
2936
- * }
2937
- */
2938
- async sendMockExecuteCommandToolCallFlow(sessionId, messageId) {
2939
- console.log(`💻 Starting execute_command tool call flow: ${messageId}`);
2940
- const toolCallId = `tool-ec-${Date.now()}`;
2941
- const command = "npm run build";
2942
- this.emitEvent({
2943
- type: "session_update",
2944
- sessionId,
2945
- messageId,
2946
- timestamp: Date.now(),
2947
- notification: {
2948
- sessionId,
2949
- _meta: { "codebuddy.ai": { toolName: "execute_command" } },
2950
- update: {
2951
- sessionUpdate: "tool_call",
2952
- toolCallId,
2953
- title: "Execute Command",
2954
- kind: "execute",
2955
- status: "pending",
2956
- rawInput: {
2957
- command,
2958
- requires_approval: false
2959
- }
2960
- }
2961
- }
2962
- });
2963
- await this.delay(200);
2964
- this.emitEvent({
2965
- type: "session_update",
2966
- sessionId,
2967
- messageId,
2968
- timestamp: Date.now(),
2969
- notification: {
2970
- sessionId,
2971
- _meta: { "codebuddy.ai": { toolName: "execute_command" } },
2972
- update: {
2973
- sessionUpdate: "tool_call_update",
2974
- toolCallId,
2975
- status: "in_progress",
2976
- content: [{
2977
- type: "content",
2978
- content: {
2979
- type: "text",
2980
- text: "> npm run build\n\nRunning build script..."
2981
- }
2982
- }]
2983
- }
2984
- }
2985
- });
2986
- await this.delay(1e3);
2987
- this.emitEvent({
2988
- type: "session_update",
2989
- sessionId,
2990
- messageId,
2991
- timestamp: Date.now(),
2992
- notification: {
2993
- sessionId,
2994
- _meta: { "codebuddy.ai": { toolName: "execute_command" } },
2995
- update: {
2996
- sessionUpdate: "tool_call_update",
2997
- toolCallId,
2998
- status: "completed",
2999
- content: [{
3000
- type: "content",
3001
- content: {
3002
- type: "text",
3003
- text: "> npm run build\n\n> genie@1.0.0 build\n> tsc -b\n\nBuild completed successfully."
3004
- }
3005
- }],
3006
- rawOutput: {
3007
- type: "execute_command_result",
3008
- stdout: "> genie@1.0.0 build\n> tsc -b\n\nBuild completed successfully.",
3009
- stderr: "",
3010
- exitCode: 0,
3011
- hint: "Build completed in 2.5s"
3012
- }
3013
- }
3014
- }
3015
- });
3016
- console.log("[MockAgentProvider] execute_command tool call completed");
3017
- }
3018
- /**
3019
- * 发送 execute_command 工具调用流程(需要权限确认)(符合 ACP 协议)
3020
- *
3021
- * 这个方法模拟需要用户确认才能执行的命令
3022
- * 用于测试权限确认菜单 (Run/Skip/Reject)
3023
- *
3024
- * 数据结构 (来自 tool-schemas.ts):
3025
- * - Input: ExecuteCommandInput = { command: string; requires_approval: boolean; }
3026
- *
3027
- * 权限请求通过 rawInput.permissionRequest 字段传递:
3028
- * - permissionRequest.options: 可选的权限选项数组
3029
- */
3030
- async sendMockExecuteCommandWithApprovalToolCallFlow(sessionId, messageId) {
3031
- console.log(`💻 Starting execute_command (with approval) tool call flow: ${messageId}`);
3032
- const toolCallId = `tool-ec-approval-${Date.now()}`;
3033
- const command = "rm -rf node_modules && npm install";
3034
- const permissionRequest = { options: [
3035
- {
3036
- optionId: "allow-once",
3037
- name: "运行",
3038
- kind: "allow_once"
3039
- },
3040
- {
3041
- optionId: "skip-once",
3042
- name: "跳过",
3043
- kind: "skip_once"
3044
- },
3045
- {
3046
- optionId: "reject-once",
3047
- name: "拒绝",
3048
- kind: "reject_once"
3049
- }
3050
- ] };
3051
- this.emitEvent({
3052
- type: "session_update",
3053
- sessionId,
3054
- messageId,
3055
- timestamp: Date.now(),
3056
- notification: {
3057
- sessionId,
3058
- _meta: { "codebuddy.ai": { toolName: "execute_command" } },
3059
- update: {
3060
- sessionUpdate: "tool_call",
3061
- toolCallId,
3062
- title: "Execute Command",
3063
- kind: "execute",
3064
- status: "pending",
3065
- rawInput: {
3066
- command,
3067
- requires_approval: true,
3068
- permissionRequest
3069
- }
3070
- }
3071
- }
3072
- });
3073
- await this.delay(200);
3074
- this.emitEvent({
3075
- type: "session_update",
3076
- sessionId,
3077
- messageId,
3078
- timestamp: Date.now(),
3079
- notification: {
3080
- sessionId,
3081
- _meta: { "codebuddy.ai": { toolName: "execute_command" } },
3082
- update: {
3083
- sessionUpdate: "tool_call_update",
3084
- toolCallId,
3085
- status: "pending",
3086
- content: [{
3087
- type: "content",
3088
- content: {
3089
- type: "text",
3090
- text: `$ ${command}\n\nWaiting for approval...`
3091
- }
3092
- }],
3093
- rawInput: {
3094
- command,
3095
- requires_approval: true,
3096
- permissionRequest
3097
- }
3098
- }
3099
- }
3100
- });
3101
- console.log("[MockAgentProvider] execute_command (with approval) tool call waiting for user approval");
3102
- }
3103
- /**
3104
- * 发送 write_to_file 工具调用流程(需要权限确认)(符合 ACP 协议)
3105
- *
3106
- * 这个方法模拟需要用户确认才能执行的文件写入
3107
- * 用于测试权限确认菜单 (允许/跳过/拒绝)
3108
- *
3109
- * 权限请求通过 rawInput.permissionRequest 字段传递:
3110
- * - permissionRequest.options: 可选的权限选项数组
3111
- */
3112
- async sendMockWriteFileWithApprovalToolCallFlow(sessionId, messageId) {
3113
- console.log(`📝 Starting write_to_file (with approval) tool call flow: ${messageId}`);
3114
- const toolCallId = `tool-wtf-approval-${Date.now()}`;
3115
- const filePath = "/Users/test/project/src/config.ts";
3116
- const content = `export const config = {
3117
- apiUrl: 'https://api.example.com',
3118
- debug: true,
3119
- timeout: 5000,
3120
- };`;
3121
- const permissionRequest = { options: [
3122
- {
3123
- optionId: "allow-once",
3124
- name: "允许",
3125
- kind: "allow_once"
3126
- },
3127
- {
3128
- optionId: "skip-once",
3129
- name: "跳过",
3130
- kind: "skip_once"
3131
- },
3132
- {
3133
- optionId: "reject-once",
3134
- name: "拒绝",
3135
- kind: "reject_once"
3136
- }
3137
- ] };
3138
- this.emitEvent({
3139
- type: "session_update",
3140
- sessionId,
3141
- messageId,
3142
- timestamp: Date.now(),
3143
- notification: {
3144
- sessionId,
3145
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
3146
- update: {
3147
- sessionUpdate: "tool_call",
3148
- toolCallId,
3149
- title: "Write File",
3150
- kind: "edit",
3151
- status: "pending",
3152
- locations: [{
3153
- path: filePath,
3154
- line: 0
3155
- }],
3156
- rawInput: {
3157
- filePath,
3158
- content,
3159
- permissionRequest
3160
- }
3161
- }
3162
- }
3163
- });
3164
- await this.delay(200);
3165
- this.emitEvent({
3166
- type: "session_update",
3167
- sessionId,
3168
- messageId,
3169
- timestamp: Date.now(),
3170
- notification: {
3171
- sessionId,
3172
- _meta: { "codebuddy.ai": { toolName: "write_to_file" } },
3173
- update: {
3174
- sessionUpdate: "tool_call_update",
3175
- toolCallId,
3176
- status: "pending",
3177
- content: [{
3178
- type: "content",
3179
- content: {
3180
- type: "text",
3181
- text: content
3182
- }
3183
- }],
3184
- locations: [{
3185
- path: filePath,
3186
- line: 0
3187
- }],
3188
- rawInput: {
3189
- filePath,
3190
- content,
3191
- permissionRequest
3192
- }
3193
- }
3194
- }
3195
- });
3196
- console.log("[MockAgentProvider] write_to_file (with approval) tool call waiting for user approval");
3197
- }
3198
- };
3199
-
3200
- //#endregion
3201
- export { mockInitializeResponse as n, mockNewSessionResponse as r, MockAgentProvider as t };
3202
- //# sourceMappingURL=MockAgentProvider-TNsV559x.mjs.map