@tencent-ai/cloud-agent-sdk 0.2.6 → 0.2.7-next.38384d9.20260128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,10 +1,633 @@
1
- require('./MockAgentProvider-D-basTXz.cjs');
1
+ let zod = require("zod");
2
2
  let _agentclientprotocol_sdk = require("@agentclientprotocol/sdk");
3
3
  require("@connectrpc/connect");
4
4
  require("@connectrpc/connect-web");
5
5
  require("@bufbuild/protobuf");
6
6
  let e2b = require("e2b");
7
7
 
8
+ //#region ../agent-provider/src/common/_legacy/tool-schemas.ts
9
+ /**
10
+ * ACP Tool Input/Output Schema 定义
11
+ *
12
+ * 用于约束 ACP 协议中 ToolCallUpdate 的 rawInput 和 rawOutput 字段
13
+ * 基于 getCraftToolProvider 使用的工具定义
14
+ */
15
+ /**
16
+ * 工具输入 Schema 定义
17
+ * 用于验证和约束 rawInput
18
+ */
19
+ const ToolInputSchemas = {
20
+ list_dir: zod.z.object({
21
+ target_directory: zod.z.string().describe("要列出内容的目录路径"),
22
+ ignore_globs: zod.z.string().optional().describe("可选的 glob 模式数组,用于忽略特定文件")
23
+ }),
24
+ search_file: zod.z.object({
25
+ target_directory: zod.z.string().describe("搜索的目录绝对路径"),
26
+ pattern: zod.z.string().describe("文件模式(如 \"*.js\"),支持通配符"),
27
+ recursive: zod.z.boolean().describe("是否递归搜索子目录"),
28
+ caseSensitive: zod.z.boolean().describe("是否区分大小写")
29
+ }),
30
+ read_file: zod.z.object({
31
+ filePath: zod.z.string().describe("要读取的文件的绝对路径"),
32
+ offset: zod.z.number().optional().describe("开始读取的行号"),
33
+ limit: zod.z.number().optional().describe("要读取的行数")
34
+ }),
35
+ read_lints: zod.z.object({ paths: zod.z.string().optional().describe("要读取 lint 错误的文件或目录路径") }),
36
+ rag_search: zod.z.object({
37
+ queryString: zod.z.string().describe("用户的实际问题或搜索查询"),
38
+ knowledgeBaseNames: zod.z.string().describe("知识库名称,多个用逗号分隔")
39
+ }),
40
+ read_rules: zod.z.object({ ruleNames: zod.z.string().describe("要读取的规则关键词,用逗号分隔,格式:{ruleName}_{ruleId}") }),
41
+ mcp_get_tool_description: zod.z.object({ toolRequests: zod.z.string().describe("JSON 字符串,二维数组格式:[[\"server1\", \"tool1\"], [\"server2\", \"tool2\"]]") }),
42
+ mcp_call_tool: zod.z.object({
43
+ serverName: zod.z.string().describe("MCP 服务器名称"),
44
+ toolName: zod.z.string().describe("要调用的工具名称"),
45
+ arguments: zod.z.string().describe("目标 MCP 工具的参数,JSON 格式字符串"),
46
+ maxOutputLength: zod.z.number().optional().describe("控制工具输出的最大长度,默认 200000")
47
+ }),
48
+ fetch_mcp_resource: zod.z.object({
49
+ server: zod.z.string().describe("MCP 服务器标识符"),
50
+ uri: zod.z.string().describe("要读取的资源 URI"),
51
+ arguments: zod.z.record(zod.z.unknown()).optional().describe("资源模板的参数"),
52
+ downloadPath: zod.z.string().optional().describe("可选的绝对路径,用于保存资源到磁盘")
53
+ }),
54
+ create_rule: zod.z.object({
55
+ ruleScope: zod.z.string().describe("规则范围,project rule 或 user rule"),
56
+ ruleName: zod.z.string().describe("规则文件名,不带扩展名"),
57
+ ruleType: zod.z.string().describe("规则类型,always、manual 或 requested"),
58
+ ruleContent: zod.z.string().describe("规则内容,使用 Markdown 格式"),
59
+ ruleDescription: zod.z.string().optional().describe("规则描述,使用 Markdown 格式")
60
+ }),
61
+ update_memory: zod.z.object({
62
+ action: zod.z.enum([
63
+ "create",
64
+ "update",
65
+ "delete"
66
+ ]).optional().describe("执行的操作"),
67
+ existing_knowledge_id: zod.z.string().optional().describe("更新或删除时必需,现有记忆的 ID"),
68
+ knowledge_to_store: zod.z.string().optional().describe("要存储的特定记忆"),
69
+ title: zod.z.string().optional().describe("记忆的标题")
70
+ }),
71
+ search_content: zod.z.object({
72
+ pattern: zod.z.string().describe("要搜索的关键字或正则表达式模式"),
73
+ directory: zod.z.string().describe("要搜索的目录的绝对路径"),
74
+ fileTypes: zod.z.string().optional().describe("可选的逗号分隔文件扩展名"),
75
+ contextBefore: zod.z.number().optional().describe("每个匹配前显示的行数"),
76
+ contextAfter: zod.z.number().optional().describe("每个匹配后显示的行数"),
77
+ contextAround: zod.z.number().optional().describe("每个匹配前后显示的行数"),
78
+ outputMode: zod.z.string().optional().describe("输出模式:content、files_with_matches 或 count"),
79
+ caseSensitive: zod.z.boolean().optional().describe("是否区分大小写")
80
+ }),
81
+ write_to_file: zod.z.object({
82
+ filePath: zod.z.string().describe("目标文件的绝对路径"),
83
+ content: zod.z.string().describe("要写入的内容")
84
+ }),
85
+ replace_in_file: zod.z.object({
86
+ filePath: zod.z.string().describe("要修改的文件的绝对路径"),
87
+ old_str: zod.z.string().describe("要替换的文本"),
88
+ new_str: zod.z.string().describe("替换后的文本")
89
+ }),
90
+ delete_file: zod.z.object({
91
+ target_file: zod.z.string().describe("要删除的文件的绝对路径"),
92
+ explanation: zod.z.string().optional().describe("为什么使用此工具的一句话解释")
93
+ }),
94
+ execute_command: zod.z.object({
95
+ command: zod.z.string().describe("要执行的 CLI 命令"),
96
+ requires_approval: zod.z.boolean().describe("命令是否需要用户批准")
97
+ }),
98
+ preview_url: zod.z.object({ url: zod.z.string().describe("要打开的完整、有效的 HTTP/HTTPS URL") }),
99
+ ask_followup_question: zod.z.object({ questions: zod.z.array(zod.z.object({
100
+ question: zod.z.string(),
101
+ header: zod.z.string().max(12),
102
+ options: zod.z.array(zod.z.object({
103
+ label: zod.z.string().max(50),
104
+ description: zod.z.string()
105
+ })).min(2).max(4),
106
+ multiSelect: zod.z.boolean().optional()
107
+ })).min(1).max(4) }),
108
+ invoke_integration: zod.z.object({}).passthrough(),
109
+ call_integration: zod.z.object({}).passthrough(),
110
+ search_integration_tool: zod.z.object({}).passthrough(),
111
+ supabase_get_logs: zod.z.object({}).passthrough(),
112
+ supabase_execute_sql: zod.z.object({}).passthrough(),
113
+ supabase_apply_migration: zod.z.object({}).passthrough(),
114
+ supabase_list_migration: zod.z.object({}).passthrough(),
115
+ supabase_list_tables: zod.z.object({}).passthrough(),
116
+ cloud_studio_fetch_log: zod.z.object({}).passthrough(),
117
+ cloud_studio_execute_command: zod.z.object({}).passthrough(),
118
+ cloud_studio_deploy_sandbox: zod.z.object({}).passthrough(),
119
+ component_get_prompt: zod.z.object({}).passthrough(),
120
+ web_fetch: zod.z.object({
121
+ url: zod.z.string().describe("要获取内容的 URL"),
122
+ fetchInfo: zod.z.string().describe("用户想要获取的信息描述")
123
+ }),
124
+ use_skill: zod.z.object({ command: zod.z.string().describe("技能名称(不含参数),如 \"pdf\" 或 \"xlsx\"") }),
125
+ web_search: zod.z.object({
126
+ explanation: zod.z.string().describe("为什么使用此工具的一句话解释"),
127
+ searchTerm: zod.z.string().describe("要在网络上搜索的搜索词")
128
+ }),
129
+ task: zod.z.object({
130
+ subagent_name: zod.z.string().describe("要调用的子代理名称"),
131
+ description: zod.z.string().describe("任务的简短描述(3-5 个词)"),
132
+ prompt: zod.z.string().describe("子代理要执行的任务"),
133
+ subagent_path: zod.z.string().optional().describe("子代理定义文件的路径")
134
+ }),
135
+ codebase_search: zod.z.object({
136
+ query: zod.z.string().describe("关于你想理解的内容的完整问题"),
137
+ path: zod.z.string().describe("限制搜索范围的目录路径前缀"),
138
+ limit: zod.z.number().max(100).optional().describe("返回的最大结果数,默认 10")
139
+ }),
140
+ lsp: zod.z.object({}).passthrough(),
141
+ spec_create: zod.z.object({
142
+ name: zod.z.string().describe("Plan 名称,用作稳定标识符/文件名"),
143
+ overview: zod.z.string().describe("用一两句话精确概括本次 plan 的主要内容"),
144
+ relative_history: zod.z.string().describe("准备阶段的上下文,包含用户需求、代码位置、额外上下文等")
145
+ }),
146
+ spec_update: zod.z.object({ status: zod.z.enum([
147
+ "prepare",
148
+ "ready",
149
+ "building",
150
+ "finished"
151
+ ]).optional().describe("Plan 状态") })
152
+ };
153
+ /**
154
+ * 工具输出 Schema 定义
155
+ * 用于验证和约束 rawOutput
156
+ */
157
+ const ToolOutputSchemas = {
158
+ list_dir: zod.z.object({
159
+ type: zod.z.literal("list_files_result"),
160
+ files: zod.z.array(zod.z.object({
161
+ filePath: zod.z.string(),
162
+ size: zod.z.string(),
163
+ modifyTime: zod.z.string()
164
+ })),
165
+ root: zod.z.string(),
166
+ listing: zod.z.string().optional()
167
+ }),
168
+ search_file: zod.z.object({
169
+ type: zod.z.literal("search_file_result"),
170
+ path: zod.z.string(),
171
+ pattern: zod.z.string(),
172
+ recursive: zod.z.boolean().optional(),
173
+ caseSensitive: zod.z.boolean().optional(),
174
+ results: zod.z.array(zod.z.object({
175
+ filePath: zod.z.string(),
176
+ size: zod.z.string(),
177
+ modifyTime: zod.z.string()
178
+ }))
179
+ }),
180
+ read_file: zod.z.object({
181
+ type: zod.z.literal("read_file_result"),
182
+ path: zod.z.string(),
183
+ content: zod.z.string(),
184
+ totalLineCount: zod.z.number(),
185
+ hasMore: zod.z.boolean(),
186
+ diagnostic: zod.z.string().optional(),
187
+ hint: zod.z.string().optional(),
188
+ image: zod.z.object({
189
+ data: zod.z.string(),
190
+ mimeType: zod.z.string()
191
+ }).optional()
192
+ }),
193
+ read_lints: zod.z.object({
194
+ type: zod.z.literal("read_lints_result"),
195
+ diagnostics: zod.z.array(zod.z.string()),
196
+ totalCount: zod.z.number().optional(),
197
+ hint: zod.z.string().optional(),
198
+ isTruncated: zod.z.boolean().optional()
199
+ }),
200
+ rag_search: zod.z.object({
201
+ type: zod.z.literal("knowledge_base_result"),
202
+ selectedKnowledgeBases: zod.z.string(),
203
+ queryInput: zod.z.string()
204
+ }),
205
+ read_rules: zod.z.object({
206
+ type: zod.z.literal("rule_match_result"),
207
+ ruleDescription: zod.z.string(),
208
+ filePaths: zod.z.array(zod.z.string())
209
+ }),
210
+ mcp_get_tool_description: zod.z.object({}).passthrough(),
211
+ mcp_call_tool: zod.z.object({
212
+ type: zod.z.literal("mcp_call_tool_result"),
213
+ serverName: zod.z.string(),
214
+ toolName: zod.z.string(),
215
+ data: zod.z.array(zod.z.union([
216
+ zod.z.object({
217
+ type: zod.z.literal("text"),
218
+ text: zod.z.string()
219
+ }),
220
+ zod.z.object({
221
+ type: zod.z.literal("image"),
222
+ data: zod.z.string(),
223
+ mimeType: zod.z.string()
224
+ }),
225
+ zod.z.object({
226
+ type: zod.z.literal("resource"),
227
+ resource: zod.z.object({
228
+ uri: zod.z.string(),
229
+ mimeType: zod.z.string().optional(),
230
+ text: zod.z.string().optional(),
231
+ blob: zod.z.string().optional()
232
+ })
233
+ })
234
+ ])),
235
+ isError: zod.z.boolean().optional(),
236
+ error: zod.z.unknown().optional(),
237
+ hint: zod.z.string().optional()
238
+ }),
239
+ fetch_mcp_resource: zod.z.object({
240
+ type: zod.z.literal("fetch_mcp_resource_result"),
241
+ server: zod.z.string(),
242
+ uri: zod.z.string(),
243
+ content: zod.z.string(),
244
+ downloadPath: zod.z.string().optional()
245
+ }),
246
+ create_rule: zod.z.object({
247
+ type: zod.z.literal("rule_create_result"),
248
+ ruleName: zod.z.string(),
249
+ createState: zod.z.enum([
250
+ "success",
251
+ "invoke",
252
+ "cancelled"
253
+ ]),
254
+ hint: zod.z.string().optional(),
255
+ filePath: zod.z.string().optional()
256
+ }),
257
+ update_memory: zod.z.object({
258
+ type: zod.z.literal("update_memory_result"),
259
+ success: zod.z.boolean(),
260
+ message: zod.z.string(),
261
+ action: zod.z.enum([
262
+ "create",
263
+ "update",
264
+ "delete"
265
+ ]),
266
+ knowledge_id: zod.z.string().optional()
267
+ }),
268
+ search_content: zod.z.object({
269
+ type: zod.z.literal("search_content_result"),
270
+ directory: zod.z.string(),
271
+ pattern: zod.z.string(),
272
+ fileTypes: zod.z.string(),
273
+ matches: zod.z.array(zod.z.object({
274
+ filePath: zod.z.string(),
275
+ content: zod.z.string(),
276
+ startLine: zod.z.number(),
277
+ endLine: zod.z.number(),
278
+ size: zod.z.string(),
279
+ modifyTime: zod.z.string()
280
+ })),
281
+ totalCount: zod.z.number(),
282
+ hasMore: zod.z.boolean(),
283
+ offset: zod.z.number(),
284
+ limit: zod.z.number(),
285
+ contextBefore: zod.z.number(),
286
+ contextAfter: zod.z.number(),
287
+ contextAround: zod.z.number().optional(),
288
+ outputMode: zod.z.string(),
289
+ caseSensitive: zod.z.boolean(),
290
+ hint: zod.z.string().optional()
291
+ }),
292
+ write_to_file: zod.z.object({
293
+ type: zod.z.literal("write_to_file_result"),
294
+ path: zod.z.string(),
295
+ addLineCount: zod.z.number(),
296
+ removedLines: zod.z.number(),
297
+ addedChars: zod.z.number().optional(),
298
+ removedChars: zod.z.number().optional(),
299
+ bytesWritten: zod.z.number(),
300
+ isNewFile: zod.z.boolean(),
301
+ oldContent: zod.z.string().optional(),
302
+ diagnostic: zod.z.string().optional()
303
+ }),
304
+ replace_in_file: zod.z.object({
305
+ type: zod.z.literal("replace_in_file_result"),
306
+ path: zod.z.string(),
307
+ addLineCount: zod.z.number().optional(),
308
+ removedLines: zod.z.number().optional(),
309
+ addedChars: zod.z.number().optional(),
310
+ removedChars: zod.z.number().optional(),
311
+ matchCount: zod.z.number().optional(),
312
+ hint: zod.z.string().optional(),
313
+ diagnosticChange: zod.z.object({
314
+ added: zod.z.string(),
315
+ removed: zod.z.string(),
316
+ unchanged: zod.z.string()
317
+ }).optional()
318
+ }),
319
+ delete_file: zod.z.object({
320
+ type: zod.z.literal("delete_file_result"),
321
+ path: zod.z.string(),
322
+ recursive: zod.z.boolean(),
323
+ hint: zod.z.string().optional()
324
+ }),
325
+ execute_command: zod.z.object({
326
+ type: zod.z.literal("execute_command_result"),
327
+ stdout: zod.z.string(),
328
+ stderr: zod.z.string(),
329
+ exitCode: zod.z.number(),
330
+ hint: zod.z.string().optional(),
331
+ serviceInfo: zod.z.object({
332
+ isWatchCommand: zod.z.boolean(),
333
+ isServiceOutput: zod.z.boolean(),
334
+ serviceReady: zod.z.boolean(),
335
+ message: zod.z.string()
336
+ }).optional(),
337
+ use_standalone_terminal: zod.z.boolean().optional()
338
+ }),
339
+ preview_url: zod.z.object({
340
+ type: zod.z.literal("preview_tool_result"),
341
+ url: zod.z.string(),
342
+ message: zod.z.string()
343
+ }),
344
+ ask_followup_question: zod.z.object({
345
+ type: zod.z.literal("multi_question_result"),
346
+ questions: zod.z.array(zod.z.object({
347
+ id: zod.z.string(),
348
+ question: zod.z.string(),
349
+ options: zod.z.array(zod.z.string()),
350
+ multiSelect: zod.z.boolean().optional(),
351
+ title: zod.z.string().optional()
352
+ })),
353
+ answers: zod.z.record(zod.z.union([zod.z.string(), zod.z.array(zod.z.string())])),
354
+ message: zod.z.string()
355
+ }),
356
+ invoke_integration: zod.z.object({
357
+ type: zod.z.literal("invoke_integration_tool_result"),
358
+ recommend: zod.z.object({
359
+ id: zod.z.string(),
360
+ type: zod.z.string(),
361
+ status: zod.z.enum(["connected", "disconnected"])
362
+ }),
363
+ message: zod.z.string()
364
+ }),
365
+ call_integration: zod.z.object({
366
+ type: zod.z.literal("call_integration_tool_result"),
367
+ integrationId: zod.z.string(),
368
+ toolName: zod.z.string(),
369
+ data: zod.z.object({
370
+ type: zod.z.literal("text"),
371
+ text: zod.z.string()
372
+ }),
373
+ isError: zod.z.boolean().optional(),
374
+ error: zod.z.unknown().optional()
375
+ }),
376
+ search_integration_tool: zod.z.object({
377
+ type: zod.z.literal("search_integration_tool_result"),
378
+ data: zod.z.array(zod.z.object({
379
+ integrationId: zod.z.string(),
380
+ integrationName: zod.z.string(),
381
+ toolName: zod.z.string(),
382
+ description: zod.z.string(),
383
+ inputSchema: zod.z.record(zod.z.unknown())
384
+ })),
385
+ hint: zod.z.string().optional()
386
+ }),
387
+ supabase_get_logs: zod.z.object({
388
+ type: zod.z.enum([
389
+ "supabase_get_logs_result",
390
+ "supabase_execute_sql_result",
391
+ "supabase_apply_migration_result",
392
+ "supabase_list_migration_result",
393
+ "supabase_list_tables_result"
394
+ ]),
395
+ message: zod.z.string()
396
+ }),
397
+ supabase_execute_sql: zod.z.object({
398
+ type: zod.z.enum([
399
+ "supabase_get_logs_result",
400
+ "supabase_execute_sql_result",
401
+ "supabase_apply_migration_result",
402
+ "supabase_list_migration_result",
403
+ "supabase_list_tables_result"
404
+ ]),
405
+ message: zod.z.string()
406
+ }),
407
+ supabase_apply_migration: zod.z.object({
408
+ type: zod.z.enum([
409
+ "supabase_get_logs_result",
410
+ "supabase_execute_sql_result",
411
+ "supabase_apply_migration_result",
412
+ "supabase_list_migration_result",
413
+ "supabase_list_tables_result"
414
+ ]),
415
+ message: zod.z.string()
416
+ }),
417
+ supabase_list_migration: zod.z.object({
418
+ type: zod.z.enum([
419
+ "supabase_get_logs_result",
420
+ "supabase_execute_sql_result",
421
+ "supabase_apply_migration_result",
422
+ "supabase_list_migration_result",
423
+ "supabase_list_tables_result"
424
+ ]),
425
+ message: zod.z.string()
426
+ }),
427
+ supabase_list_tables: zod.z.object({
428
+ type: zod.z.enum([
429
+ "supabase_get_logs_result",
430
+ "supabase_execute_sql_result",
431
+ "supabase_apply_migration_result",
432
+ "supabase_list_migration_result",
433
+ "supabase_list_tables_result"
434
+ ]),
435
+ message: zod.z.string()
436
+ }),
437
+ cloud_studio_fetch_log: zod.z.object({
438
+ type: zod.z.literal("cloud_studio_fetch_log_result"),
439
+ success: zod.z.boolean(),
440
+ logs: zod.z.record(zod.z.string())
441
+ }),
442
+ cloud_studio_execute_command: zod.z.object({
443
+ type: zod.z.literal("cloud_studio_execute_command_result"),
444
+ success: zod.z.boolean(),
445
+ message: zod.z.string()
446
+ }),
447
+ cloud_studio_deploy_sandbox: zod.z.object({
448
+ type: zod.z.literal("cloud_studio_integration_result"),
449
+ previewUrl: zod.z.string().optional(),
450
+ steps: zod.z.array(zod.z.object({
451
+ status: zod.z.enum([
452
+ "idle",
453
+ "success",
454
+ "running",
455
+ "error"
456
+ ]),
457
+ name: zod.z.enum([
458
+ "createSandbox",
459
+ "uploadProject",
460
+ "installDependencies",
461
+ "startService",
462
+ "preview"
463
+ ]),
464
+ error: zod.z.object({
465
+ code: zod.z.number().optional(),
466
+ message: zod.z.string().optional()
467
+ }).optional()
468
+ }))
469
+ }),
470
+ component_get_prompt: zod.z.object({
471
+ type: zod.z.literal("component_get_prompt_result"),
472
+ componentType: zod.z.string(),
473
+ webFramework: zod.z.string(),
474
+ data: zod.z.object({
475
+ type: zod.z.literal("text"),
476
+ text: zod.z.string()
477
+ })
478
+ }),
479
+ web_fetch: zod.z.object({
480
+ type: zod.z.literal("web_fetch_tool_result"),
481
+ message: zod.z.string(),
482
+ data: zod.z.string(),
483
+ loading: zod.z.string().optional(),
484
+ title: zod.z.string().optional(),
485
+ favicon: zod.z.string().optional()
486
+ }),
487
+ use_skill: zod.z.object({
488
+ type: zod.z.literal("use_skill_tool_result"),
489
+ commandMessage: zod.z.string(),
490
+ message: zod.z.string()
491
+ }),
492
+ web_search: zod.z.object({
493
+ type: zod.z.literal("web_search_tool_result"),
494
+ data: zod.z.array(zod.z.object({
495
+ passage: zod.z.string(),
496
+ uri: zod.z.string(),
497
+ site: zod.z.string(),
498
+ title: zod.z.string(),
499
+ snippets: zod.z.array(zod.z.string()).optional(),
500
+ content: zod.z.string().optional()
501
+ })),
502
+ searchInput: zod.z.string().optional()
503
+ }),
504
+ task: zod.z.object({
505
+ type: zod.z.literal("task_tool_result"),
506
+ toolInfo: zod.z.array(zod.z.object({
507
+ name: zod.z.string(),
508
+ info: zod.z.string(),
509
+ needApprove: zod.z.boolean().optional(),
510
+ toolCallId: zod.z.string().optional(),
511
+ executeStatus: zod.z.enum([
512
+ "ing",
513
+ "completed",
514
+ "cancel",
515
+ "fail"
516
+ ]).optional()
517
+ })).optional(),
518
+ startCallTool: zod.z.boolean().optional(),
519
+ finalResult: zod.z.string().optional(),
520
+ toolCallBrief: zod.z.string().optional()
521
+ }),
522
+ codebase_search: zod.z.object({
523
+ type: zod.z.literal("codebase_search_result"),
524
+ query: zod.z.string(),
525
+ path: zod.z.string(),
526
+ content: zod.z.string()
527
+ }),
528
+ lsp: zod.z.object({
529
+ type: zod.z.literal("lsp_tool_result"),
530
+ operation: zod.z.string(),
531
+ result: zod.z.string(),
532
+ resultCount: zod.z.number().optional(),
533
+ fileCount: zod.z.number().optional(),
534
+ character: zod.z.number().optional()
535
+ }),
536
+ spec_create: zod.z.object({
537
+ type: zod.z.literal("plan_create_tool_result"),
538
+ message: zod.z.string(),
539
+ data: zod.z.string()
540
+ }),
541
+ spec_update: zod.z.object({
542
+ type: zod.z.literal("plan_update_tool_result"),
543
+ status: zod.z.enum([
544
+ "prepare",
545
+ "ready",
546
+ "building",
547
+ "finished"
548
+ ]),
549
+ data: zod.z.string(),
550
+ reminder: zod.z.string()
551
+ })
552
+ };
553
+
554
+ //#endregion
555
+ //#region ../agent-provider/src/common/_legacy/MockAgentProvider.ts
556
+ /**
557
+ * Mock 会话数据存储
558
+ * 每个会话都有对应的模拟历史消息
559
+ */
560
+ const mockSessionHistories = /* @__PURE__ */ new Map();
561
+ mockSessionHistories.set("1", [
562
+ {
563
+ type: "user",
564
+ content: "帮我开发一个五子棋游戏,需要包含以下功能:\n1. 双人对战模式\n2. 悔棋功能\n3. 计时器",
565
+ timestamp: Date.now() - 18e5 - 6e4
566
+ },
567
+ {
568
+ type: "assistant",
569
+ content: "好的,我来帮你开发一个五子棋游戏。我会创建以下文件结构:\n\n- `index.html` - 主页面\n- `game.js` - 游戏逻辑\n- `style.css` - 样式文件\n\n让我开始创建这些文件...",
570
+ timestamp: Date.now() - 18e5 - 5e4
571
+ },
572
+ {
573
+ type: "assistant",
574
+ content: "我已经完成了所有文件的创建和修改。游戏支持双人对战、悔棋和计时功能。你可以直接在浏览器中打开 index.html 开始游戏。",
575
+ timestamp: Date.now() - 18e5
576
+ }
577
+ ]);
578
+ mockSessionHistories.set("2", [
579
+ {
580
+ type: "user",
581
+ content: "登录页面的样式有问题,按钮颜色不对齐,帮我修复一下",
582
+ timestamp: Date.now() - 72e5 - 12e4
583
+ },
584
+ {
585
+ type: "assistant",
586
+ content: "我来检查登录页面的样式。让我先看看相关的 CSS 文件...",
587
+ timestamp: Date.now() - 72e5 - 1e5
588
+ },
589
+ {
590
+ type: "assistant",
591
+ content: "样式问题已修复,请查看效果。主要修改了按钮的 flex 布局和颜色变量。",
592
+ timestamp: Date.now() - 72e5
593
+ }
594
+ ]);
595
+ mockSessionHistories.set("3", [
596
+ {
597
+ type: "user",
598
+ content: "API 接口响应太慢了,需要添加缓存和错误重试机制",
599
+ timestamp: Date.now() - 144e5 - 18e4
600
+ },
601
+ {
602
+ type: "assistant",
603
+ content: "好的,我来优化 API 接口。我会实现:\n1. Redis 缓存层\n2. 指数退避重试策略\n3. 请求去重",
604
+ timestamp: Date.now() - 144e5 - 15e4
605
+ },
606
+ {
607
+ type: "assistant",
608
+ content: "已添加缓存和错误重试机制。性能提升了约 60%。",
609
+ timestamp: Date.now() - 144e5
610
+ }
611
+ ]);
612
+ mockSessionHistories.set("4", [
613
+ {
614
+ type: "user",
615
+ content: "帮我为核心模块添加单元测试,覆盖率要达到 80% 以上",
616
+ timestamp: Date.now() - 864e5 - 3e5
617
+ },
618
+ {
619
+ type: "assistant",
620
+ content: "好的,我会使用 Jest 来编写单元测试。让我先看看核心模块的代码结构...",
621
+ timestamp: Date.now() - 864e5 - 25e4
622
+ },
623
+ {
624
+ type: "assistant",
625
+ content: "测试覆盖率已达到 85%,超过了目标。主要测试了:\n- 用户认证逻辑\n- 数据验证\n- 错误处理",
626
+ timestamp: Date.now() - 864e5
627
+ }
628
+ ]);
629
+
630
+ //#endregion
8
631
  //#region ../agent-client-protocol/src/common/types.ts
9
632
  /**
10
633
  * Protocol Extension Types for Agent Client Protocol
@@ -19,7 +642,8 @@ const ExtensionMethod = {
19
642
  ARTIFACT: "_codebuddy.ai/artifact",
20
643
  QUESTION: "_codebuddy.ai/question",
21
644
  CHECKPOINT: "_codebuddy.ai/checkpoint",
22
- USAGE: "_codebuddy.ai/usage"
645
+ USAGE: "_codebuddy.ai/usage",
646
+ COMMAND: "_codebuddy.ai/command"
23
647
  };
24
648
  /**
25
649
  * All known extension methods
@@ -28,7 +652,8 @@ const KNOWN_EXTENSIONS = [
28
652
  ExtensionMethod.ARTIFACT,
29
653
  ExtensionMethod.QUESTION,
30
654
  ExtensionMethod.CHECKPOINT,
31
- ExtensionMethod.USAGE
655
+ ExtensionMethod.USAGE,
656
+ ExtensionMethod.COMMAND
32
657
  ];
33
658
 
34
659
  //#endregion
@@ -81,7 +706,7 @@ function parseSSELine(line, currentEvent) {
81
706
  function streamableHttp(options) {
82
707
  const { endpoint, authToken, headers: customHeaders = {}, reconnect = {}, signal: externalSignal, fetch: customFetch = globalThis.fetch, onConnect, onDisconnect, onError, heartbeatTimeout = 6e4, postTimeout = 3e4, backpressure = {} } = options;
83
708
  const { enabled: reconnectEnabled = true, initialDelay = 1e3, maxDelay = 3e4, maxRetries = Infinity, jitter: jitterEnabled = true } = reconnect;
84
- const { highWaterMark = 100, lowWaterMark = 50 } = backpressure;
709
+ const { highWaterMark = 100, lowWaterMark = 50, pauseTimeout = 5e3 } = backpressure;
85
710
  let connectionId;
86
711
  let lastEventId;
87
712
  let reconnectAttempts = 0;
@@ -110,6 +735,7 @@ function streamableHttp(options) {
110
735
  let streamError = null;
111
736
  let isPaused = false;
112
737
  let resumeReading = null;
738
+ let backgroundSSEProcessors = /* @__PURE__ */ new Set();
113
739
  let lastActivity = Date.now();
114
740
  let heartbeatCheckTimer;
115
741
  function enqueueMessage(message) {
@@ -132,7 +758,8 @@ function streamableHttp(options) {
132
758
  const message = messageQueue.shift();
133
759
  if (isPaused && messageQueue.length <= lowWaterMark) {
134
760
  isPaused = false;
135
- resumeReading?.();
761
+ const resume = resumeReading;
762
+ if (resume) queueMicrotask(() => resume());
136
763
  }
137
764
  return Promise.resolve(message);
138
765
  }
@@ -186,6 +813,7 @@ function streamableHttp(options) {
186
813
  resumeReading();
187
814
  resumeReading = null;
188
815
  }
816
+ backgroundSSEProcessors.clear();
189
817
  while (messageResolvers.length > 0) messageResolvers.shift()(null);
190
818
  }
191
819
  async function sendDelete() {
@@ -218,7 +846,21 @@ function streamableHttp(options) {
218
846
  while (true) {
219
847
  if (isPaused) {
220
848
  await new Promise((resolve) => {
221
- resumeReading = resolve;
849
+ let resolved = false;
850
+ const timeoutId = setTimeout(() => {
851
+ if (!resolved) {
852
+ resolved = true;
853
+ console.warn("[StreamableHTTP] Backpressure pause timeout, forcing resume");
854
+ resolve();
855
+ }
856
+ }, pauseTimeout);
857
+ resumeReading = () => {
858
+ if (!resolved) {
859
+ resolved = true;
860
+ clearTimeout(timeoutId);
861
+ resolve();
862
+ }
863
+ };
222
864
  });
223
865
  resumeReading = null;
224
866
  }
@@ -251,6 +893,19 @@ function streamableHttp(options) {
251
893
  reader.releaseLock();
252
894
  }
253
895
  }
896
+ /**
897
+ * Process SSE stream in background without blocking the caller.
898
+ * This prevents deadlock when POST responses return SSE streams.
899
+ */
900
+ function processSSEStreamBackground(reader) {
901
+ const promise = processSSEStream(reader).catch((error) => {
902
+ console.error("[StreamableHTTP] Background SSE processing error:", error);
903
+ onError?.(error instanceof Error ? error : new Error(String(error)));
904
+ }).finally(() => {
905
+ backgroundSSEProcessors.delete(promise);
906
+ });
907
+ backgroundSSEProcessors.add(promise);
908
+ }
254
909
  async function startSSEConnection() {
255
910
  let currentReader = null;
256
911
  const triggerReconnect = () => {
@@ -286,14 +941,14 @@ function streamableHttp(options) {
286
941
  stopHeartbeatCheck();
287
942
  const endedConnectionId = connectionId;
288
943
  connectionId = void 0;
289
- if (!reconnectEnabled || closed) {
290
- if (endedConnectionId) onDisconnect?.(endedConnectionId);
291
- break;
292
- }
944
+ if (endedConnectionId) onDisconnect?.(endedConnectionId);
945
+ if (!reconnectEnabled || closed) break;
293
946
  connectionReady = new Promise((resolve, reject) => {
294
947
  resolveConnection = resolve;
295
948
  rejectConnection = reject;
296
949
  });
950
+ const reconnectDelay = calculateDelay(1);
951
+ await new Promise((resolve) => setTimeout(resolve, reconnectDelay));
297
952
  } catch (error) {
298
953
  stopHeartbeatCheck();
299
954
  currentReader = null;
@@ -310,14 +965,21 @@ function streamableHttp(options) {
310
965
  }
311
966
  async function sendMessage(message) {
312
967
  if (closed) throw new Error("Connection is closed");
313
- const versionBeforeWait = connectionVersion;
314
- await connectionReady;
315
- if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) await connectionReady;
316
- if (!connectionId) throw new Error("No connection ID available");
968
+ const maxWaitAttempts = 5;
969
+ let currentConnectionId;
970
+ for (let attempt = 0; attempt < maxWaitAttempts; attempt++) {
971
+ const versionBeforeWait = connectionVersion;
972
+ await connectionReady;
973
+ if (versionBeforeWait !== connectionVersion && versionBeforeWait > 0) await connectionReady;
974
+ currentConnectionId = connectionId;
975
+ if (currentConnectionId) break;
976
+ if (attempt < maxWaitAttempts - 1) await new Promise((resolve) => setTimeout(resolve, 100));
977
+ }
978
+ if (!currentConnectionId) throw new Error("No connection ID available after multiple attempts");
317
979
  const headers = buildHeaders();
318
980
  headers["Content-Type"] = "application/json";
319
981
  headers["Accept"] = "application/json, text/event-stream";
320
- headers["Acp-Connection-Id"] = connectionId;
982
+ headers["Acp-Connection-Id"] = currentConnectionId;
321
983
  const postController = new AbortController();
322
984
  let timeoutId;
323
985
  const postSignal = postTimeout > 0 ? postController.signal : combinedSignal;
@@ -340,7 +1002,7 @@ function streamableHttp(options) {
340
1002
  const contentType = response.headers.get("Content-Type") || "";
341
1003
  if (contentType.includes("text/event-stream")) {
342
1004
  const reader = response.body?.getReader();
343
- if (reader) await processSSEStream(reader);
1005
+ if (reader) processSSEStreamBackground(reader);
344
1006
  } else if (contentType.includes("application/json")) {
345
1007
  const data = await response.json();
346
1008
  if (data && typeof data === "object" && "jsonrpc" in data) enqueueMessage(data);
@@ -2155,12 +2817,13 @@ var AccountService = class {
2155
2817
  */
2156
2818
  setAccount(account) {
2157
2819
  const prev = this.account;
2820
+ const wasInitialized = this.initialized;
2158
2821
  this.account = account;
2159
2822
  if (!this.initialized) {
2160
2823
  this.initialized = true;
2161
2824
  this.initResolve?.(account);
2162
2825
  }
2163
- if (prev?.uid !== account?.uid) this.notifyListeners();
2826
+ if (!wasInitialized || prev?.uid !== account?.uid) this.notifyListeners();
2164
2827
  }
2165
2828
  /**
2166
2829
  * 清除账号(登出)
@@ -2467,7 +3130,6 @@ var CloudAgentProvider = class CloudAgentProvider {
2467
3130
  */
2468
3131
  async list(options) {
2469
3132
  try {
2470
- console.log("[CloudAgentProvider] list called with options:", JSON.stringify(options, null, 2));
2471
3133
  const params = {
2472
3134
  page: 1,
2473
3135
  size: 30,
@@ -2484,7 +3146,6 @@ var CloudAgentProvider = class CloudAgentProvider {
2484
3146
  ...options.title !== void 0 && { title: options.title }
2485
3147
  }
2486
3148
  };
2487
- console.log("[CloudAgentProvider] API request params:", JSON.stringify(params, null, 2));
2488
3149
  const response = await this.request("GET", "/console/cloudagent/agentmgmt/agents", params);
2489
3150
  if (!response.ok) throw new Error(`Failed to list agents: ${response.statusText}`);
2490
3151
  const apiResponse = await response.json();
@@ -2576,7 +3237,7 @@ var CloudAgentProvider = class CloudAgentProvider {
2576
3237
  }
2577
3238
  }
2578
3239
  };
2579
- const connection = new CloudAgentConnection(agentId, {
3240
+ const connection = new CloudAgentConnection(sessionData.sessionId || agentId, {
2580
3241
  endpoint,
2581
3242
  authToken: sessionData.token,
2582
3243
  logger: this.logger,
@@ -2692,9 +3353,9 @@ var CloudAgentProvider = class CloudAgentProvider {
2692
3353
  /**
2693
3354
  * Get available models from product configuration
2694
3355
  *
2695
- * GET {endpoint}/v3/config?repos[]={repo}
3356
+ * GET {endpoint}/console/enterprises/{personal|enterpriseId}/models?repos[]={repo}
2696
3357
  *
2697
- * This method fetches the product configuration from /v3/config API
3358
+ * This method fetches the models from /console/enterprises API
2698
3359
  * and extracts the models array from the response.
2699
3360
  *
2700
3361
  * @param repo - Optional repository URL for context-specific config
@@ -2702,7 +3363,13 @@ var CloudAgentProvider = class CloudAgentProvider {
2702
3363
  */
2703
3364
  async getModels(repo) {
2704
3365
  try {
2705
- let url = `${this.options.endpoint}/v3/config`;
3366
+ const account = accountService.getAccount();
3367
+ if (!account) {
3368
+ this.logger?.warn("[CloudAgentProvider] No account info available, cannot get models");
3369
+ return [];
3370
+ }
3371
+ const accountIdentifier = account.enterpriseId || "personal";
3372
+ let url = `${this.options.endpoint}/console/enterprises/${accountIdentifier}/models`;
2706
3373
  if (repo) url += `?repos[]=${encodeURIComponent(repo)}`;
2707
3374
  const headers = {
2708
3375
  "Accept": "application/json, text/plain, */*",
@@ -2710,7 +3377,6 @@ var CloudAgentProvider = class CloudAgentProvider {
2710
3377
  ...this.options.headers
2711
3378
  };
2712
3379
  if (this.options.authToken) headers["Authorization"] = `Bearer ${this.options.authToken}`;
2713
- const account = accountService.getAccount();
2714
3380
  if (account?.uid) headers["X-User-Id"] = account.uid;
2715
3381
  if (account?.enterpriseId) {
2716
3382
  headers["X-Enterprise-Id"] = account.enterpriseId;
@@ -2732,7 +3398,7 @@ var CloudAgentProvider = class CloudAgentProvider {
2732
3398
  return [];
2733
3399
  }
2734
3400
  const models = apiResponse.data.models ?? [];
2735
- this.logger?.info(`[CloudAgentProvider] Retrieved ${models.length} models from /v3/config`);
3401
+ this.logger?.info(`[CloudAgentProvider] Retrieved ${models.length} models from /console/enterprises API`);
2736
3402
  return models.map((model) => ({
2737
3403
  id: model.id,
2738
3404
  name: model.name ?? model.id,
@@ -3048,6 +3714,13 @@ var ActiveSessionImpl = class {
3048
3714
  return this._availableCommands;
3049
3715
  }
3050
3716
  /**
3717
+ * Set available commands (called when available_commands_update is received)
3718
+ */
3719
+ setAvailableCommands(commands) {
3720
+ this._availableCommands = commands;
3721
+ this.logger?.info(`Session ${this._id}: Available commands updated, count: ${commands.length}`);
3722
+ }
3723
+ /**
3051
3724
  * Check if the session is active
3052
3725
  */
3053
3726
  get isActive() {
@@ -3359,6 +4032,9 @@ var ActiveSessionImpl = class {
3359
4032
  connection.on("questionRequest", (request) => {
3360
4033
  this.emit("questionRequest", request);
3361
4034
  });
4035
+ connection.on("questionCancelled", () => {
4036
+ this.prompts.cancel();
4037
+ });
3362
4038
  connection.on("usageUpdate", (usage) => {
3363
4039
  this.emit("usageUpdate", usage);
3364
4040
  });
@@ -3368,6 +4044,13 @@ var ActiveSessionImpl = class {
3368
4044
  connection.on("checkpointUpdated", (checkpoint) => {
3369
4045
  this.emit("checkpointUpdated", checkpoint);
3370
4046
  });
4047
+ connection.on("command", (command) => {
4048
+ console.log("[Session] Forwarding command:", {
4049
+ action: command.action,
4050
+ paramsKeys: command.params ? Object.keys(command.params) : []
4051
+ });
4052
+ this.emit("command", command);
4053
+ });
3371
4054
  }
3372
4055
  mapPromptResponse(response) {
3373
4056
  return {
@@ -3420,12 +4103,7 @@ var SessionManager = class {
3420
4103
  * @param options - Optional query parameters for filtering, sorting, and pagination
3421
4104
  */
3422
4105
  async listSessions(options) {
3423
- console.log("[SessionManager] listSessions called with options:", JSON.stringify(options, null, 2));
3424
4106
  const result = await this.provider.list(options);
3425
- console.log("[SessionManager] provider.list returned:", {
3426
- agentsCount: result.agents.length,
3427
- pagination: result.pagination
3428
- });
3429
4107
  const sessions = result.agents.map((agent) => ({
3430
4108
  id: agent.id,
3431
4109
  agentId: agent.id,
@@ -3433,7 +4111,8 @@ var SessionManager = class {
3433
4111
  status: agent.status,
3434
4112
  createdAt: agent.createdAt,
3435
4113
  lastActivityAt: agent.updatedAt,
3436
- cwd: agent.type === "local" ? agent.cwd : void 0
4114
+ cwd: agent.type === "local" ? agent.cwd : void 0,
4115
+ isPlayground: agent.isPlayground
3437
4116
  }));
3438
4117
  console.log("[SessionManager] Returning sessions:", {
3439
4118
  count: sessions.length,
@@ -3464,6 +4143,7 @@ var SessionManager = class {
3464
4143
  const connection = await this.provider.connect(agentId);
3465
4144
  this.logger?.debug(`Connected to agent: ${agentId}`);
3466
4145
  const response = await connection.createSession({
4146
+ _meta: params._meta,
3467
4147
  cwd: params.cwd,
3468
4148
  mcpServers: params.mcpServers
3469
4149
  });
@@ -3623,6 +4303,20 @@ var AgentClient = class {
3623
4303
  throw error;
3624
4304
  }
3625
4305
  },
4306
+ move: async (sessionId) => {
4307
+ this.logger?.debug("AgentClient.sessions.move called", { sessionId });
4308
+ try {
4309
+ if (this.provider.move) {
4310
+ const result = await this.provider.move(sessionId);
4311
+ this.logger?.info("Session moved successfully", { sessionId });
4312
+ return result;
4313
+ }
4314
+ throw new Error("Provider does not support move method");
4315
+ } catch (error) {
4316
+ this.logger?.error("Failed to move session", error);
4317
+ throw error;
4318
+ }
4319
+ },
3626
4320
  initializeWorkspace: async (params) => {
3627
4321
  this.logger?.debug("AgentClient.sessions.initializeWorkspace called", params);
3628
4322
  try {
@@ -3775,6 +4469,36 @@ var AgentClient = class {
3775
4469
  };
3776
4470
  }
3777
4471
  },
4472
+ batchTogglePlugins: async (request) => {
4473
+ try {
4474
+ if (this.provider && this.provider.batchTogglePlugins) {
4475
+ const result = await this.provider.batchTogglePlugins(request);
4476
+ this.logger?.info("Batch toggle plugins completed", {
4477
+ succeededCount: result.succeededPlugins.length,
4478
+ failedCount: result.failedPlugins.length
4479
+ });
4480
+ return result;
4481
+ }
4482
+ return {
4483
+ success: false,
4484
+ succeededPlugins: [],
4485
+ failedPlugins: request.items.map((item) => ({
4486
+ ...item,
4487
+ error: "Provider does not support batchTogglePlugins"
4488
+ }))
4489
+ };
4490
+ } catch (error) {
4491
+ this.logger?.error("Failed to batch toggle plugins", error);
4492
+ return {
4493
+ success: false,
4494
+ succeededPlugins: [],
4495
+ failedPlugins: request.items.map((item) => ({
4496
+ ...item,
4497
+ error: error instanceof Error ? error.message : "Unknown error"
4498
+ }))
4499
+ };
4500
+ }
4501
+ },
3778
4502
  models: this.createModelsResource()
3779
4503
  };
3780
4504
  }
@@ -3855,12 +4579,33 @@ const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
3855
4579
  /** localStorage 中存储选中账号 ID 的 key */
3856
4580
  const SELECTED_ACCOUNT_KEY = "CODEBUDDY_IDE_SELECTED_ACCOUNT_ID";
3857
4581
  /**
4582
+ * 套餐代码对应的 i18n key 映射
4583
+ */
4584
+ const CommodityCodeText = {
4585
+ [CommodityCode.free]: "plan.codebuddyFreePlan",
4586
+ [CommodityCode.proMon]: "plan.codebuddyProPlanMonthly",
4587
+ [CommodityCode.proMonPlus]: "plan.codebuddyProPlanMonthly",
4588
+ [CommodityCode.gift]: "plan.codebuddyProPlanTrial",
4589
+ [CommodityCode.activity]: "plan.codebuddyGrowthPlan",
4590
+ [CommodityCode.proYear]: "plan.codebuddyProPlanYearly",
4591
+ [CommodityCode.freeMon]: "plan.codebuddyProPlanDaily",
4592
+ [CommodityCode.extra]: "plan.codebuddyCreditPackage"
4593
+ };
4594
+ /**
4595
+ * 获取套餐名称的 i18n key
4596
+ */
4597
+ const getPackageName = (packageCode) => {
4598
+ return CommodityCodeText[packageCode] || "";
4599
+ };
4600
+ /**
3858
4601
  * Backend Provider 实现类
3859
4602
  *
3860
4603
  * 职责:
3861
- * - 与后端 API 通信(getAgents, getModels, getAccount 等)
3862
4604
  * - 触发登录/登出流程
3863
4605
  * - 获取 account 后自动同步到 accountService
4606
+ *
4607
+ * 注意:getAgents 和 getModels 方法已废弃并移除,
4608
+ * 请使用 IAgentAdapter 中的对应方法
3864
4609
  */
3865
4610
  var BackendProvider = class {
3866
4611
  constructor(config) {
@@ -3868,98 +4613,6 @@ var BackendProvider = class {
3868
4613
  this.authToken = config.authToken;
3869
4614
  }
3870
4615
  /**
3871
- * 获取 Agent 列表
3872
- * API 端点: GET /v2/cloudagent/agentmgmt/agents
3873
- */
3874
- async getAgents(request = {}) {
3875
- const { MockAgentProvider } = await Promise.resolve().then(() => require("./MockAgentProvider-4e4oOusg.cjs"));
3876
- const sessions = new MockAgentProvider().getAllSessions();
3877
- const mockTitles = {
3878
- "1": "开发五子棋游戏",
3879
- "2": "修复登录页面样式",
3880
- "3": "API 接口优化"
3881
- };
3882
- const agents = sessions.map((session, index) => ({
3883
- id: session.sessionId,
3884
- name: mockTitles[session.sessionId] || `Agent ${session.sessionId}`,
3885
- status: "RUNNING",
3886
- visibility: "PRIVATE",
3887
- createdAt: new Date(session.createdAt).toISOString(),
3888
- summary: `Session created at ${new Date(session.createdAt).toLocaleString()}`,
3889
- source: {
3890
- provider: "github",
3891
- ref: "refs/heads/main",
3892
- repository: session.cwd
3893
- },
3894
- target: {
3895
- autoCreatePr: false,
3896
- branchName: "feature/mock",
3897
- prUrl: void 0,
3898
- url: void 0
3899
- }
3900
- }));
3901
- return {
3902
- agents,
3903
- pagination: {
3904
- hasNext: false,
3905
- hasPrev: false,
3906
- page: 1,
3907
- size: agents.length,
3908
- total: agents.length,
3909
- totalPages: 1
3910
- }
3911
- };
3912
- }
3913
- /**
3914
- * 获取可用模型列表
3915
- * API 端点: GET /v2/cloudagent/models (假设)
3916
- *
3917
- * 当前实现: 返回 Mock 数据
3918
- */
3919
- async getModels(request) {
3920
- const mockModels = [{
3921
- id: "glm-4.7",
3922
- name: "GLM-4.7",
3923
- vendor: "f",
3924
- maxOutputTokens: 48e3,
3925
- maxInputTokens: 2e5,
3926
- supportsToolCall: true,
3927
- supportsImages: false,
3928
- disabledMultimodal: true,
3929
- maxAllowedSize: 2e5,
3930
- supportsReasoning: true,
3931
- onlyReasoning: true,
3932
- temperature: 1,
3933
- reasoning: {
3934
- effort: "medium",
3935
- summary: "auto"
3936
- },
3937
- descriptionEn: "GLM-4.7 model, Well-rounded model for everyday use",
3938
- descriptionZh: "GLM-4.7 大模型,能力均衡,适合日常使用"
3939
- }, {
3940
- id: "glm-4.7-flash",
3941
- name: "GLM-4.7 Flash",
3942
- vendor: "f",
3943
- maxOutputTokens: 4e4,
3944
- maxInputTokens: 128e3,
3945
- supportsToolCall: true,
3946
- supportsImages: false,
3947
- disabledMultimodal: false,
3948
- maxAllowedSize: 128e3,
3949
- supportsReasoning: false,
3950
- onlyReasoning: false,
3951
- temperature: .7,
3952
- reasoning: {
3953
- effort: "low",
3954
- summary: "never"
3955
- },
3956
- descriptionEn: "GLM-4.7 Flash, Fast and efficient model",
3957
- descriptionZh: "GLM-4.7 Flash,快速高效的模型"
3958
- }];
3959
- console.log("[BackendProvider] getModels called for repository:", request.repository);
3960
- return { models: mockModels };
3961
- }
3962
- /**
3963
4616
  * 获取当前账号信息
3964
4617
  * API 端点: GET /console/accounts (返回账号列表)
3965
4618
  *
@@ -4010,53 +4663,335 @@ var BackendProvider = class {
4010
4663
  if (account.type === "personal") return account.uid === selectedAccountId;
4011
4664
  return account.enterpriseId === selectedAccountId;
4012
4665
  });
4013
- if (selectedAccount) try {
4014
- const plan = await this.getCurrentPlan();
4015
- const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);
4016
- console.log("account", {
4017
- ...selectedAccount,
4018
- ...plan,
4019
- editionType
4020
- });
4021
- const account = {
4022
- ...selectedAccount,
4023
- ...plan,
4024
- editionType
4025
- };
4666
+ if (selectedAccount) {
4667
+ const account = await this.enrichAccountWithUsage(selectedAccount);
4026
4668
  accountService.setAccount(account);
4027
4669
  return account;
4028
- } catch (error) {
4029
- accountService.setAccount(selectedAccount);
4030
- return { ...selectedAccount };
4031
4670
  }
4032
4671
  }
4033
4672
  if (accounts.length === 1) {
4034
4673
  selectedAccount = accounts[0];
4035
4674
  const accountId = selectedAccount.type === "personal" ? selectedAccount.uid : selectedAccount.enterpriseId;
4036
4675
  if (accountId) localStorage.setItem(SELECTED_ACCOUNT_KEY, accountId);
4676
+ const account = await this.enrichAccountWithUsage(selectedAccount);
4677
+ console.log("account (auto-selected)", account);
4678
+ accountService.setAccount(account);
4679
+ return account;
4680
+ }
4681
+ const redirectUrl = encodeURIComponent(window.location.href);
4682
+ window.location.href = `${getSelectAccountUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;
4683
+ accountService.setAccount(null);
4684
+ return null;
4685
+ } catch (error) {
4686
+ console.error("[BackendProvider] getAccount failed:", error);
4687
+ accountService.setAccount(null);
4688
+ return null;
4689
+ }
4690
+ }
4691
+ /**
4692
+ * 获取用户连接器列表
4693
+ * API 端点: GET /console/as/connector/user/
4694
+ */
4695
+ async getUserConnector() {
4696
+ const url = `${this.baseUrl}/console/as/connector/user/`;
4697
+ const headers = {
4698
+ "Content-Type": "application/json",
4699
+ "Accept": "application/json"
4700
+ };
4701
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4702
+ try {
4703
+ const result = await (await fetch(url, {
4704
+ method: "GET",
4705
+ headers,
4706
+ credentials: "include"
4707
+ })).json();
4708
+ if (result.code === 0) {
4709
+ const { connectors } = result.data;
4710
+ return { connectors: connectors.map((connector) => ({
4711
+ ...connector,
4712
+ connectStatus: connector.connect_status,
4713
+ activeStatus: connector.active_status,
4714
+ displayName: connector.display_name,
4715
+ oauthClientId: connector.oauth_client_id,
4716
+ oauthRedirectUrl: connector.oauth_redirect_url
4717
+ })) };
4718
+ }
4719
+ throw result;
4720
+ } catch (error) {
4721
+ throw error;
4722
+ }
4723
+ }
4724
+ /**
4725
+ * 修改用户连接器连接状态
4726
+ * API 端点: PATCH /console/as/connector/user/:name/connect_status
4727
+ */
4728
+ async modifyUserConnectorConnectStatus(request) {
4729
+ const url = `${this.baseUrl}/console/as/connector/user/${request.name}/connect_status`;
4730
+ const headers = {
4731
+ "Content-Type": "application/json",
4732
+ "Accept": "application/json"
4733
+ };
4734
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4735
+ const body = {
4736
+ name: request.name,
4737
+ connect_status: request.connectStatus
4738
+ };
4739
+ if (request.activeStatus !== void 0) body.active_status = request.activeStatus;
4740
+ if (request.repos !== void 0) body.repos = request.repos;
4741
+ try {
4742
+ const result = await (await fetch(url, {
4743
+ method: "PATCH",
4744
+ headers,
4745
+ credentials: "include",
4746
+ body: JSON.stringify(body)
4747
+ })).json();
4748
+ if (result.code === 0) return;
4749
+ throw result;
4750
+ } catch (error) {
4751
+ throw error;
4752
+ }
4753
+ }
4754
+ /**
4755
+ * 修改用户连接器仓库
4756
+ * API 端点: PATCH /console/as/connector/user/:name/repo/
4757
+ */
4758
+ async modifyUserConnectorRepo(request) {
4759
+ const url = `${this.baseUrl}/console/as/connector/user/${request.name}/repo`;
4760
+ const headers = {
4761
+ "Content-Type": "application/json",
4762
+ "Accept": "application/json"
4763
+ };
4764
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4765
+ const body = { name: request.name };
4766
+ if (request.repo !== void 0) body.repo = request.repo;
4767
+ try {
4768
+ const result = await (await fetch(url, {
4769
+ method: "PATCH",
4770
+ headers,
4771
+ credentials: "include",
4772
+ body: JSON.stringify(body)
4773
+ })).json();
4774
+ if (result.code === 0) return;
4775
+ throw result;
4776
+ } catch (error) {
4777
+ throw error;
4778
+ }
4779
+ }
4780
+ /**
4781
+ * 修改用户连接器激活状态
4782
+ * API 端点: PATCH /console/as/connector/user/:name/active_status
4783
+ */
4784
+ async modifyUserConnectorActiveStatus(request) {
4785
+ const url = `${this.baseUrl}/console/as/connector/user/${request.name}/active_status`;
4786
+ const headers = {
4787
+ "Content-Type": "application/json",
4788
+ "Accept": "application/json"
4789
+ };
4790
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4791
+ const body = {
4792
+ name: request.name,
4793
+ active_status: request.activeStatus
4794
+ };
4795
+ try {
4796
+ const result = await (await fetch(url, {
4797
+ method: "PATCH",
4798
+ headers,
4799
+ credentials: "include",
4800
+ body: JSON.stringify(body)
4801
+ })).json();
4802
+ if (result.code === 0) return;
4803
+ throw result;
4804
+ } catch (error) {
4805
+ throw error;
4806
+ }
4807
+ }
4808
+ /**
4809
+ * 删除用户连接器
4810
+ * API 端点: DELETE /console/as/connector/user/:name/
4811
+ */
4812
+ async deleteUserConnector(name) {
4813
+ const url = `${this.baseUrl}/console/as/connector/user/${name}/`;
4814
+ const headers = {
4815
+ "Content-Type": "application/json",
4816
+ "Accept": "application/json"
4817
+ };
4818
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4819
+ try {
4820
+ const result = await (await fetch(url, {
4821
+ method: "DELETE",
4822
+ headers,
4823
+ credentials: "include"
4824
+ })).json();
4825
+ if (result.code === 0) return;
4826
+ throw result;
4827
+ } catch (error) {
4828
+ throw error;
4829
+ }
4830
+ }
4831
+ /**
4832
+ * 添加任务
4833
+ * API 端点: POST /console/as/connector/task/
4834
+ */
4835
+ async addConnectorTask(request) {
4836
+ const url = `${this.baseUrl}/console/as/connector/task/`;
4837
+ const headers = {
4838
+ "Content-Type": "application/json",
4839
+ "Accept": "application/json"
4840
+ };
4841
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4842
+ const body = { task_id: request.taskId };
4843
+ if (request.connectors !== void 0) body.connectors = request.connectors.map((c) => ({
4844
+ name: c.name,
4845
+ repos: c.repos,
4846
+ active_status: c.activeStatus
4847
+ }));
4848
+ try {
4849
+ const result = await (await fetch(url, {
4850
+ method: "POST",
4851
+ headers,
4852
+ credentials: "include",
4853
+ body: JSON.stringify(body)
4854
+ })).json();
4855
+ if (result.code === 0) return { taskId: result.data?.task_id || request.taskId };
4856
+ throw result;
4857
+ } catch (error) {
4858
+ throw error;
4859
+ }
4860
+ }
4861
+ /**
4862
+ * 获取任务连接器列表
4863
+ * API 端点: GET /console/as/connector/task/:taskid
4864
+ */
4865
+ async getTaskConnector(taskId) {
4866
+ const url = `${this.baseUrl}/console/as/connector/task/${taskId}`;
4867
+ const headers = {
4868
+ "Content-Type": "application/json",
4869
+ "Accept": "application/json"
4870
+ };
4871
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4872
+ try {
4873
+ const result = await (await fetch(url, {
4874
+ method: "GET",
4875
+ headers,
4876
+ credentials: "include"
4877
+ })).json();
4878
+ if (result.code === 0) {
4879
+ const { connectors } = result.data;
4880
+ return { connectors: (connectors || []).map((connector) => ({
4881
+ ...connector,
4882
+ activeStatus: connector.active_status,
4883
+ connectStatus: connector.connect_status,
4884
+ displayName: connector.display_name,
4885
+ oauthClientId: connector.oauth_client_id,
4886
+ oauthRedirectUrl: connector.oauth_redirect_url
4887
+ })) };
4888
+ }
4889
+ throw result;
4890
+ } catch (error) {
4891
+ throw error;
4892
+ }
4893
+ }
4894
+ /**
4895
+ * 修改任务连接器激活状态
4896
+ * API 端点: PATCH /console/as/connector/task/:taskid/active_status
4897
+ */
4898
+ async modifyTaskConnectorActiveStatus(request) {
4899
+ const url = `${this.baseUrl}/console/as/connector/task/${request.taskId}/active_status`;
4900
+ const headers = {
4901
+ "Content-Type": "application/json",
4902
+ "Accept": "application/json"
4903
+ };
4904
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4905
+ const body = {
4906
+ task_id: request.taskId,
4907
+ name: request.name,
4908
+ active_status: request.activeStatus
4909
+ };
4910
+ try {
4911
+ const result = await (await fetch(url, {
4912
+ method: "PATCH",
4913
+ headers,
4914
+ credentials: "include",
4915
+ body: JSON.stringify(body)
4916
+ })).json();
4917
+ if (result.code === 0) return { taskId: result.data?.task_id || request.taskId };
4918
+ throw result;
4919
+ } catch (error) {
4920
+ throw error;
4921
+ }
4922
+ }
4923
+ /**
4924
+ * 修改任务连接器仓库
4925
+ * API 端点: PATCH /console/as/connector/task/:taskid/repo
4926
+ */
4927
+ async modifyTaskConnectorRepo(request) {
4928
+ const url = `${this.baseUrl}/console/as/connector/task/${request.taskId}/repo`;
4929
+ const headers = {
4930
+ "Content-Type": "application/json",
4931
+ "Accept": "application/json"
4932
+ };
4933
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4934
+ const body = {
4935
+ task_id: request.taskId,
4936
+ name: request.name,
4937
+ repo: request.repo
4938
+ };
4939
+ try {
4940
+ const result = await (await fetch(url, {
4941
+ method: "PATCH",
4942
+ headers,
4943
+ credentials: "include",
4944
+ body: JSON.stringify(body)
4945
+ })).json();
4946
+ if (result.code === 0) return { taskId: result.data?.task_id || request.taskId };
4947
+ throw result;
4948
+ } catch (error) {
4949
+ throw error;
4950
+ }
4951
+ }
4952
+ /**
4953
+ * 根据账号类型获取用量信息并合并到账号中
4954
+ * - 企业用户:调用 getEnterpriseUsage 获取月度限额
4955
+ * - 个人用户:调用 getCurrentPlan 获取套餐信息
4956
+ */
4957
+ async enrichAccountWithUsage(selectedAccount) {
4958
+ const isEnterpriseUser = !!(selectedAccount.enterpriseId && selectedAccount.enterpriseId !== "");
4959
+ try {
4960
+ if (isEnterpriseUser) {
4961
+ const enterpriseUsage = await this.getEnterpriseUsage(selectedAccount.enterpriseId);
4962
+ const editionType = this.getEditionDisplayType(selectedAccount.type, false);
4963
+ if (enterpriseUsage) {
4964
+ const usageLeft = (enterpriseUsage.limitNum - enterpriseUsage.credit).toString();
4965
+ const usageTotal = enterpriseUsage.limitNum.toString();
4966
+ return {
4967
+ ...selectedAccount,
4968
+ editionType,
4969
+ usageLeft,
4970
+ usageTotal,
4971
+ refreshAt: enterpriseUsage.cycleResetTime ? new Date(enterpriseUsage.cycleResetTime).getTime() : void 0
4972
+ };
4973
+ }
4974
+ return {
4975
+ ...selectedAccount,
4976
+ editionType
4977
+ };
4978
+ } else {
4037
4979
  const plan = await this.getCurrentPlan();
4038
4980
  const editionType = this.getEditionDisplayType(selectedAccount.type, plan.isPro);
4039
- console.log("account (auto-selected)", {
4981
+ console.log("account", {
4040
4982
  ...selectedAccount,
4041
4983
  ...plan,
4042
4984
  editionType
4043
4985
  });
4044
- const account = {
4986
+ return {
4045
4987
  ...selectedAccount,
4046
4988
  ...plan,
4047
4989
  editionType
4048
4990
  };
4049
- accountService.setAccount(account);
4050
- return account;
4051
4991
  }
4052
- const redirectUrl = encodeURIComponent(window.location.href);
4053
- window.location.href = `${getSelectAccountUrl()}?platform=website&state=0&redirect_uri=${redirectUrl}`;
4054
- accountService.setAccount(null);
4055
- return null;
4056
4992
  } catch (error) {
4057
- console.error("[BackendProvider] getAccount failed:", error);
4058
- accountService.setAccount(null);
4059
- return null;
4993
+ console.error("[BackendProvider] enrichAccountWithUsage failed:", error);
4994
+ return { ...selectedAccount };
4060
4995
  }
4061
4996
  }
4062
4997
  /**
@@ -4078,7 +5013,6 @@ var BackendProvider = class {
4078
5013
  "Content-Type": "application/json",
4079
5014
  "Accept": "application/json"
4080
5015
  };
4081
- if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
4082
5016
  const now = /* @__PURE__ */ new Date();
4083
5017
  const futureDate = new Date(now.getTime() + 101 * 365 * 24 * 60 * 60 * 1e3);
4084
5018
  const formatDate = (d) => {
@@ -4105,34 +5039,174 @@ var BackendProvider = class {
4105
5039
  }
4106
5040
  const resources = (await response.json())?.data?.Response?.Data?.Accounts || [];
4107
5041
  if (!resources || resources.length === 0) return defaultPlan;
5042
+ const parseTime = (time) => {
5043
+ if (!time) return 0;
5044
+ return new Date(time).getTime();
5045
+ };
5046
+ const dailyCredits = [CommodityCode.free, CommodityCode.freeMon];
5047
+ const planResources = resources.map((r) => {
5048
+ const isDaily = dailyCredits.includes(r.PackageCode);
5049
+ const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
5050
+ return {
5051
+ id: r.ResourceId,
5052
+ name: isDaily ? "plan.addonCredits" : getPackageName(r.PackageCode),
5053
+ packageCode: r.PackageCode,
5054
+ isDaily,
5055
+ total: Number(r.CycleCapacitySizePrecise) || 0,
5056
+ used: Math.max(0, Number(r.CycleCapacitySizePrecise) - Number(r.CycleCapacityRemainPrecise)) || 0,
5057
+ left: Number(r.CycleCapacityRemainPrecise) || 0,
5058
+ expireAt: parseTime(endTime),
5059
+ refreshAt: isDaily ? void 0 : parseTime(r.CycleEndTime)
5060
+ };
5061
+ }).sort((a, b) => {
5062
+ const getPriority = (code) => {
5063
+ if ([
5064
+ CommodityCode.proMon,
5065
+ CommodityCode.proMonPlus,
5066
+ CommodityCode.proYear,
5067
+ CommodityCode.extra
5068
+ ].includes(code)) return 1;
5069
+ if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
5070
+ if ([CommodityCode.free, CommodityCode.freeMon].includes(code)) return 3;
5071
+ return 4;
5072
+ };
5073
+ return getPriority(a.packageCode) - getPriority(b.packageCode);
5074
+ });
4108
5075
  const proPlan = resources.find((r) => r.PackageCode === CommodityCode.proYear || r.PackageCode === CommodityCode.proMon || r.PackageCode === CommodityCode.proMonPlus);
4109
5076
  const trialPlan = resources.find((r) => r.PackageCode === CommodityCode.gift || r.PackageCode === CommodityCode.freeMon);
4110
5077
  const activePlan = proPlan || trialPlan;
4111
- if (activePlan) {
4112
- const parseTime = (time) => {
4113
- if (!time) return 0;
4114
- return new Date(time).getTime();
4115
- };
4116
- return {
4117
- isPro: !!proPlan,
4118
- isTria: [AccountStatus.valid, AccountStatus.usedUp].includes(trialPlan?.Status),
4119
- expireAt: parseTime(activePlan.DeductionEndTime || activePlan.ExpiredTime || activePlan.CycleEndTime),
4120
- refreshAt: parseTime(activePlan.CycleEndTime),
4121
- renewFlag: Number(activePlan.AutoRenewFlag) === 1 ? 1 : 0,
4122
- PackageCode: activePlan.PackageCode,
4123
- name: activePlan.PackageName || "",
4124
- usageTotal: activePlan.CycleCapacitySizePrecise,
4125
- usageUsed: activePlan.CapacityUsedPrecise,
4126
- usageLeft: activePlan.CycleCapacityRemainPrecise
4127
- };
4128
- }
4129
- return defaultPlan;
5078
+ const totalUsageLeft = planResources.reduce((sum, r) => sum + r.left, 0);
5079
+ const totalUsageTotal = planResources.reduce((sum, r) => sum + r.total, 0);
5080
+ const totalUsageUsed = planResources.reduce((sum, r) => sum + r.used, 0);
5081
+ if (activePlan) return {
5082
+ isPro: !!proPlan,
5083
+ isTria: trialPlan ? [AccountStatus.valid, AccountStatus.usedUp].includes(trialPlan.Status) : false,
5084
+ expireAt: parseTime(activePlan.DeductionEndTime || activePlan.ExpiredTime || activePlan.CycleEndTime),
5085
+ refreshAt: parseTime(activePlan.CycleEndTime),
5086
+ renewFlag: Number(activePlan.AutoRenewFlag) === 1 ? 1 : 0,
5087
+ PackageCode: activePlan.PackageCode,
5088
+ name: getPackageName(activePlan.PackageCode),
5089
+ usageTotal: String(totalUsageTotal),
5090
+ usageUsed: String(totalUsageUsed),
5091
+ usageLeft: String(totalUsageLeft),
5092
+ resources: planResources
5093
+ };
5094
+ return {
5095
+ ...defaultPlan,
5096
+ usageTotal: String(totalUsageTotal),
5097
+ usageUsed: String(totalUsageUsed),
5098
+ usageLeft: String(totalUsageLeft),
5099
+ resources: planResources
5100
+ };
4130
5101
  } catch (error) {
4131
5102
  console.error("[BackendProvider] getCurrentPlan error:", error);
4132
5103
  return defaultPlan;
4133
5104
  }
4134
5105
  }
4135
5106
  /**
5107
+ * 通过回调code,换token
5108
+ * @param request
5109
+ * @returns
5110
+ */
5111
+ async saveOauthToken(request) {
5112
+ const url = `${this.baseUrl}/console/as/connector/oauth/${request.name}/connect`;
5113
+ const headers = {
5114
+ "Content-Type": "application/json",
5115
+ "Accept": "application/json"
5116
+ };
5117
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
5118
+ const body = { authorization_code: request.authorizationCode };
5119
+ try {
5120
+ const result = await (await fetch(url, {
5121
+ method: "POST",
5122
+ headers,
5123
+ credentials: "include",
5124
+ body: JSON.stringify(body)
5125
+ })).json();
5126
+ if (result.code === 0) return;
5127
+ throw result;
5128
+ } catch (error) {
5129
+ throw error;
5130
+ }
5131
+ }
5132
+ /**
5133
+ * 获取OAuth连接器的仓库列表
5134
+ */
5135
+ async getRepoList(request) {
5136
+ const url = `${this.baseUrl}/console/as/connector/oauth/${request.name}/repos`;
5137
+ const headers = {
5138
+ "Content-Type": "application/json",
5139
+ "Accept": "application/json"
5140
+ };
5141
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
5142
+ try {
5143
+ const result = await (await fetch(url, {
5144
+ method: "GET",
5145
+ headers,
5146
+ credentials: "include"
5147
+ })).json();
5148
+ if (result.code === 0) return result.data;
5149
+ throw result;
5150
+ } catch (error) {
5151
+ throw error;
5152
+ }
5153
+ }
5154
+ /**
5155
+ * 撤销OAuth连接器的所有连接
5156
+ */
5157
+ async revokeAll(request) {
5158
+ const url = `${this.baseUrl}/console/as/connector/oauth/${request.name}/revokeall`;
5159
+ const installationIds = request?.installationIds ?? [];
5160
+ const headers = {
5161
+ "Content-Type": "application/json",
5162
+ "Accept": "application/json"
5163
+ };
5164
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
5165
+ const body = { name: request.name };
5166
+ if (installationIds) body.installation_ids = installationIds;
5167
+ try {
5168
+ const result = await (await fetch(url, {
5169
+ method: "POST",
5170
+ headers,
5171
+ credentials: "include",
5172
+ body: JSON.stringify(body)
5173
+ })).json();
5174
+ if (result.code === 0) return;
5175
+ throw result;
5176
+ } catch (error) {
5177
+ throw error;
5178
+ }
5179
+ }
5180
+ /**
5181
+ * 获取 OAuth 用户信息
5182
+ * API 端点: GET /console/as/connector/oauth/:name/oauthuser
5183
+ */
5184
+ async getOauthUser(request) {
5185
+ const url = `${this.baseUrl}/console/as/connector/oauth/${request.name}/oauthuser`;
5186
+ const headers = {
5187
+ "Content-Type": "application/json",
5188
+ "Accept": "application/json"
5189
+ };
5190
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
5191
+ try {
5192
+ const result = await (await fetch(url, {
5193
+ method: "GET",
5194
+ headers,
5195
+ credentials: "include"
5196
+ })).json();
5197
+ if (result.code === 0) {
5198
+ const data = result.data || {};
5199
+ return { user: {
5200
+ avatarUrl: data.user?.avatar_url || "",
5201
+ name: data.user?.name || ""
5202
+ } };
5203
+ }
5204
+ throw result;
5205
+ } catch (error) {
5206
+ throw error;
5207
+ }
5208
+ }
5209
+ /**
4136
5210
  * 根据账号类型和 Pro 状态计算版本展示类型
4137
5211
  * - personal + isPro = 'pro'
4138
5212
  * - personal + !isPro = 'free'
@@ -4155,14 +5229,28 @@ var BackendProvider = class {
4155
5229
  }
4156
5230
  /**
4157
5231
  * 登出账号
4158
- * Web 环境: 调用登出接口并清除本地状态
5232
+ * Web 环境: 通过 iframe 访问登出 URL 清除 cookie
4159
5233
  */
4160
5234
  async logout() {
4161
5235
  const url = `${this.baseUrl}/console/logout`;
4162
5236
  try {
4163
- await fetch(url, {
4164
- method: "POST",
4165
- credentials: "include"
5237
+ await new Promise((resolve) => {
5238
+ const iframe = document.createElement("iframe");
5239
+ iframe.style.cssText = "position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;border:none;";
5240
+ iframe.src = url;
5241
+ const timeout = setTimeout(() => {
5242
+ cleanup();
5243
+ resolve();
5244
+ }, 5e3);
5245
+ const cleanup = () => {
5246
+ clearTimeout(timeout);
5247
+ if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
5248
+ };
5249
+ iframe.onerror = () => {
5250
+ cleanup();
5251
+ resolve();
5252
+ };
5253
+ document.body.appendChild(iframe);
4166
5254
  });
4167
5255
  } catch (error) {
4168
5256
  console.error("[BackendProvider] logout failed:", error);
@@ -4170,6 +5258,54 @@ var BackendProvider = class {
4170
5258
  localStorage.removeItem(SELECTED_ACCOUNT_KEY);
4171
5259
  accountService.clearAccount();
4172
5260
  }
5261
+ /**
5262
+ * 批量切换插件状态
5263
+ * Web 环境不支持此功能
5264
+ */
5265
+ async batchTogglePlugins(request) {
5266
+ console.warn("[BackendProvider] batchTogglePlugins is not supported in web environment");
5267
+ return {
5268
+ success: false,
5269
+ succeededPlugins: [],
5270
+ failedPlugins: request.items.map((item) => ({
5271
+ ...item,
5272
+ error: "Plugin batch toggle is not supported in web environment"
5273
+ }))
5274
+ };
5275
+ }
5276
+ /**
5277
+ * 获取企业用户用量信息
5278
+ * API: POST /billing/meter/get-enterprise-user-usage
5279
+ * 构建查询参数字符串
5280
+ */
5281
+ async getEnterpriseUsage(enterpriseId) {
5282
+ try {
5283
+ const url = `${this.baseUrl}/billing/meter/get-enterprise-user-usage`;
5284
+ const headers = {
5285
+ "Content-Type": "application/json",
5286
+ "Accept": "application/json",
5287
+ "X-Enterprise-Id": enterpriseId
5288
+ };
5289
+ if (this.authToken) headers["Authorization"] = `Bearer ${this.authToken}`;
5290
+ const response = await fetch(url, {
5291
+ method: "POST",
5292
+ headers,
5293
+ credentials: "include",
5294
+ body: JSON.stringify({})
5295
+ });
5296
+ if (!response.ok) {
5297
+ console.warn("[BackendProvider] getEnterpriseUsage failed:", response.status);
5298
+ return null;
5299
+ }
5300
+ const result = await response.json();
5301
+ const usageData = result?.data?.data || result?.data || result;
5302
+ if (usageData && typeof usageData.limitNum === "number") return usageData;
5303
+ return null;
5304
+ } catch (error) {
5305
+ console.error("[BackendProvider] getEnterpriseUsage error:", error);
5306
+ return null;
5307
+ }
5308
+ }
4173
5309
  };
4174
5310
  /**
4175
5311
  * 创建 BackendProvider 实例
@@ -4184,11 +5320,24 @@ function createBackendProvider(config) {
4184
5320
  * Backend 请求类型常量
4185
5321
  */
4186
5322
  const BACKEND_REQUEST_TYPES = {
4187
- GET_AGENTS: "backend:get-agents-request",
4188
- GET_MODELS: "backend:get-models",
4189
5323
  LOGIN: "backend:login",
4190
5324
  LOGOUT: "backend:logout",
4191
- GET_ACCOUNT: "backend:get-account"
5325
+ GET_ACCOUNT: "backend:get-account",
5326
+ GET_USER_CONNECTOR: "backend:get-user-connector",
5327
+ MODIFY_USER_CONNECTOR_CONNECT_STATUS: "backend:modify-user-connector-connect-status",
5328
+ MODIFY_USER_CONNECTOR_REPO: "backend:modify-user-connector-repo",
5329
+ MODIFY_USER_CONNECTOR_ACTIVE_STATUS: "backend:modify-user-connector-active-status",
5330
+ DELETE_USER_CONNECTOR: "backend:delete-user-connector",
5331
+ ADD_CONNECTOR_TASK: "backend:add-connector-task",
5332
+ GET_TASK_CONNECTOR: "backend:get-task-connector",
5333
+ MODIFY_TASK_CONNECTOR_ACTIVE_STATUS: "backend:modify-task-connector-active-status",
5334
+ MODIFY_TASK_CONNECTOR_REPO: "backend:modify-task-connector-repo",
5335
+ GET_OAUTH_USER: "backend:get-oauth-user",
5336
+ SAVE_OAUTH_TOKEN: "backend:save-oauth-token",
5337
+ GET_REPO_LIST: "backend:get-repo-list",
5338
+ REVOKE_ALL: "backend:revoke-all",
5339
+ RELOAD_WINDOW: "backend:reload-window",
5340
+ BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins"
4192
5341
  };
4193
5342
  /**
4194
5343
  * 生成唯一请求 ID
@@ -4199,7 +5348,7 @@ function generateRequestId() {
4199
5348
  /**
4200
5349
  * IPC Backend Provider 实现类
4201
5350
  *
4202
- * 通过 IWidgetChannel 与后端通信获取 Agent 列表
5351
+ * 通过 IWidgetChannel 与后端通信
4203
5352
  */
4204
5353
  var IPCBackendProvider = class {
4205
5354
  constructor(config) {
@@ -4230,45 +5379,188 @@ var IPCBackendProvider = class {
4230
5379
  return response?.data !== void 0 ? response.data : response;
4231
5380
  }
4232
5381
  /**
4233
- * 获取 Agent 列表
4234
- * 通过 IWidgetChannel 发送请求到后端
5382
+ * 获取当前账号信息
5383
+ * IDE 环境: 通过 IPC 获取账号信息,并同步到 accountService
5384
+ */
5385
+ async getAccount() {
5386
+ this.log("Getting account via IPC");
5387
+ try {
5388
+ const account = await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT);
5389
+ accountService.setAccount(account);
5390
+ return account;
5391
+ } catch (error) {
5392
+ this.log("Get account failed:", error);
5393
+ accountService.setAccount(null);
5394
+ return null;
5395
+ }
5396
+ }
5397
+ /**
5398
+ * 获取用户连接器列表
5399
+ * IDE 环境: 通过 IPC 获取用户连接器列表
4235
5400
  */
4236
- async getAgents(request = {}) {
4237
- this.log("Getting agents with request:", request);
5401
+ async getUserConnector() {
5402
+ this.log("Getting user connector via IPC");
4238
5403
  try {
4239
- return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_AGENTS, request);
5404
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_USER_CONNECTOR);
4240
5405
  } catch (error) {
4241
- this.log("Get agents failed:", error);
5406
+ this.log("Get user connector failed:", error);
4242
5407
  throw error;
4243
5408
  }
4244
5409
  }
4245
5410
  /**
4246
- * 获取可用模型列表
4247
- * 通过 IWidgetChannel 发送请求到后端
5411
+ * 修改用户连接器连接状态
5412
+ * IDE 环境: 通过 IPC 修改用户连接器连接状态
4248
5413
  */
4249
- async getModels(request) {
4250
- this.log("Getting models with request:", request);
5414
+ async modifyUserConnectorConnectStatus(request) {
5415
+ this.log("Modifying user connector connect status via IPC:", request);
4251
5416
  try {
4252
- return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_MODELS, request);
5417
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.MODIFY_USER_CONNECTOR_CONNECT_STATUS, request);
4253
5418
  } catch (error) {
4254
- this.log("Get models failed:", error);
5419
+ this.log("Modify user connector connect status failed:", error);
4255
5420
  throw error;
4256
5421
  }
4257
5422
  }
4258
5423
  /**
4259
- * 获取当前账号信息
4260
- * IDE 环境: 通过 IPC 获取账号信息,并同步到 accountService
5424
+ * 修改用户连接器仓库
5425
+ * IDE 环境: 通过 IPC 修改用户连接器仓库
4261
5426
  */
4262
- async getAccount() {
4263
- this.log("Getting account via IPC");
5427
+ async modifyUserConnectorRepo(request) {
5428
+ this.log("Modifying user connector repo via IPC:", request);
4264
5429
  try {
4265
- const account = await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT);
4266
- accountService.setAccount(account);
4267
- return account;
5430
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.MODIFY_USER_CONNECTOR_REPO, request);
4268
5431
  } catch (error) {
4269
- this.log("Get account failed:", error);
4270
- accountService.setAccount(null);
4271
- return null;
5432
+ this.log("Modify user connector repo failed:", error);
5433
+ throw error;
5434
+ }
5435
+ }
5436
+ /**
5437
+ * 修改用户连接器激活状态
5438
+ * IDE 环境: 通过 IPC 修改用户连接器激活状态
5439
+ */
5440
+ async modifyUserConnectorActiveStatus(request) {
5441
+ this.log("Modifying user connector active status via IPC:", request);
5442
+ try {
5443
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.MODIFY_USER_CONNECTOR_ACTIVE_STATUS, request);
5444
+ } catch (error) {
5445
+ this.log("Modify user connector active status failed:", error);
5446
+ throw error;
5447
+ }
5448
+ }
5449
+ /**
5450
+ * 删除用户连接器
5451
+ * IDE 环境: 通过 IPC 删除用户连接器
5452
+ */
5453
+ async deleteUserConnector(name) {
5454
+ this.log("Deleting user connector via IPC:", name);
5455
+ try {
5456
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.DELETE_USER_CONNECTOR, { name });
5457
+ } catch (error) {
5458
+ this.log("Delete user connector failed:", error);
5459
+ throw error;
5460
+ }
5461
+ }
5462
+ /**
5463
+ * 添加任务
5464
+ * IDE 环境: 通过 IPC 添加任务
5465
+ */
5466
+ async addConnectorTask(request) {
5467
+ this.log("Adding connector task via IPC:", request);
5468
+ try {
5469
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.ADD_CONNECTOR_TASK, request);
5470
+ } catch (error) {
5471
+ this.log("Add task failed:", error);
5472
+ throw error;
5473
+ }
5474
+ }
5475
+ /**
5476
+ * 获取任务连接器列表
5477
+ * IDE 环境: 通过 IPC 获取任务连接器列表
5478
+ */
5479
+ async getTaskConnector(taskId) {
5480
+ this.log("Getting task connector via IPC:", taskId);
5481
+ try {
5482
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_TASK_CONNECTOR, { taskId });
5483
+ } catch (error) {
5484
+ this.log("Get task connector failed:", error);
5485
+ throw error;
5486
+ }
5487
+ }
5488
+ /**
5489
+ * 修改任务连接器激活状态
5490
+ * IDE 环境: 通过 IPC 修改任务连接器激活状态
5491
+ */
5492
+ async modifyTaskConnectorActiveStatus(request) {
5493
+ this.log("Modifying task connector active status via IPC:", request);
5494
+ try {
5495
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.MODIFY_TASK_CONNECTOR_ACTIVE_STATUS, request);
5496
+ } catch (error) {
5497
+ this.log("Modify task connector active status failed:", error);
5498
+ throw error;
5499
+ }
5500
+ }
5501
+ /**
5502
+ * 修改任务连接器仓库
5503
+ * IDE 环境: 通过 IPC 修改任务连接器仓库
5504
+ */
5505
+ async modifyTaskConnectorRepo(request) {
5506
+ this.log("Modifying task connector repo via IPC:", request);
5507
+ try {
5508
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.MODIFY_TASK_CONNECTOR_REPO, request);
5509
+ } catch (error) {
5510
+ this.log("Modify task connector repo failed:", error);
5511
+ throw error;
5512
+ }
5513
+ }
5514
+ /**
5515
+ * 获取 OAuth 用户信息
5516
+ * IDE 环境: 通过 IPC 获取 OAuth 用户信息
5517
+ */
5518
+ async getOauthUser(request) {
5519
+ this.log("Getting OAuth user via IPC:", request);
5520
+ try {
5521
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_OAUTH_USER, request);
5522
+ } catch (error) {
5523
+ this.log("Get OAuth user failed:", error);
5524
+ throw error;
5525
+ }
5526
+ }
5527
+ /**
5528
+ * 通过回调code,换token
5529
+ * IDE 环境: 通过 IPC 保存 OAuth Token
5530
+ */
5531
+ async saveOauthToken(request) {
5532
+ this.log("Saving OAuth token via IPC:", request);
5533
+ try {
5534
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_OAUTH_TOKEN, request);
5535
+ } catch (error) {
5536
+ this.log("Save OAuth token failed:", error);
5537
+ throw error;
5538
+ }
5539
+ }
5540
+ /**
5541
+ * 获取OAuth连接器的仓库列表
5542
+ * IDE 环境: 通过 IPC 获取仓库列表
5543
+ */
5544
+ async getRepoList(request) {
5545
+ this.log("Getting repo list via IPC:", request);
5546
+ try {
5547
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_REPO_LIST, request);
5548
+ } catch (error) {
5549
+ this.log("Get repo list failed:", error);
5550
+ throw error;
5551
+ }
5552
+ }
5553
+ /**
5554
+ * 撤销OAuth连接器的所有连接
5555
+ * IDE 环境: 通过 IPC 撤销所有连接
5556
+ */
5557
+ async revokeAll(request) {
5558
+ this.log("Revoking all connections via IPC:", request);
5559
+ try {
5560
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.REVOKE_ALL, request);
5561
+ } catch (error) {
5562
+ this.log("Revoke all connections failed:", error);
5563
+ throw error;
4272
5564
  }
4273
5565
  }
4274
5566
  /**
@@ -4299,6 +5591,33 @@ var IPCBackendProvider = class {
4299
5591
  }
4300
5592
  }
4301
5593
  /**
5594
+ * 重新加载窗口
5595
+ * IDE 环境: 通过 IPC 通知 IDE 重新加载窗口(用于应用语言设置等)
5596
+ * @param params 可选参数,如 locale
5597
+ */
5598
+ async reloadWindow(params) {
5599
+ this.log("Triggering reload window via IPC", params);
5600
+ try {
5601
+ await this.sendBackendRequest(BACKEND_REQUEST_TYPES.RELOAD_WINDOW, params);
5602
+ } catch (error) {
5603
+ this.log("Reload window request failed:", error);
5604
+ throw error;
5605
+ }
5606
+ }
5607
+ /**
5608
+ * 批量切换插件状态
5609
+ * IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
5610
+ */
5611
+ async batchTogglePlugins(request) {
5612
+ this.log("Batch toggling plugins via IPC:", request);
5613
+ try {
5614
+ return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.BATCH_TOGGLE_PLUGINS, request);
5615
+ } catch (error) {
5616
+ this.log("Batch toggle plugins failed:", error);
5617
+ throw error;
5618
+ }
5619
+ }
5620
+ /**
4302
5621
  * 调试日志
4303
5622
  */
4304
5623
  log(...args) {