@tencent-ai/cloud-agent-sdk 0.2.13 → 0.2.14-next.17885cf.20260323
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/e2b-filesystem-4-LU6-jg.cjs +168 -0
- package/dist/e2b-filesystem-4-LU6-jg.cjs.map +1 -0
- package/dist/e2b-filesystem-BNmEfpoW.mjs +162 -0
- package/dist/e2b-filesystem-BNmEfpoW.mjs.map +1 -0
- package/dist/e2b-filesystem-B_WoA22S.cjs +252 -0
- package/dist/e2b-filesystem-B_WoA22S.cjs.map +1 -0
- package/dist/e2b-filesystem-Cac-bpRR.cjs +3 -0
- package/dist/e2b-filesystem-DM_jsT05.mjs +234 -0
- package/dist/e2b-filesystem-DM_jsT05.mjs.map +1 -0
- package/dist/e2b-filesystem-DWj9UkV8.mjs +3 -0
- package/dist/e2b-filesystem-DcVVT_tP.cjs +4 -0
- package/dist/e2b-filesystem-UheQECjB.mjs +3 -0
- package/dist/index.cjs +2345 -384
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2131 -131
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2131 -131
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2331 -372
- package/dist/index.mjs.map +1 -1
- package/dist/legacy/index.cjs +24204 -0
- package/dist/legacy/index.cjs.map +1 -0
- package/dist/legacy/index.d.cts +6590 -0
- package/dist/legacy/index.d.cts.map +1 -0
- package/dist/legacy/index.d.mts +6590 -0
- package/dist/legacy/index.d.mts.map +1 -0
- package/dist/legacy/index.mjs +13480 -0
- package/dist/legacy/index.mjs.map +1 -0
- package/dist/tencent-ai-cloud-agent-sdk-0.2.14-next.17885cf.20260323.tgz +0 -0
- package/package.json +44 -7
- package/dist/tencent-ai-cloud-agent-sdk-0.2.13.tgz +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { t as E2BFilesystem } from "./e2b-filesystem-BNmEfpoW.mjs";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import { ClientSideConnection, PROTOCOL_VERSION } from "@agentclientprotocol/sdk";
|
|
3
4
|
import "@bufbuild/protobuf";
|
|
4
5
|
import "@connectrpc/connect";
|
|
5
6
|
import "@connectrpc/connect-web";
|
|
6
|
-
import { Sandbox } from "e2b";
|
|
7
7
|
|
|
8
8
|
//#region rolldown:runtime
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
@@ -54,7 +54,6 @@ const ToolInputSchemas = {
|
|
|
54
54
|
queryString: z.string().describe("用户的实际问题或搜索查询"),
|
|
55
55
|
knowledgeBaseNames: z.string().describe("知识库名称,多个用逗号分隔")
|
|
56
56
|
}),
|
|
57
|
-
read_rules: z.object({ ruleNames: z.string().describe("要读取的规则关键词,用逗号分隔,格式:{ruleName}_{ruleId}") }),
|
|
58
57
|
mcp_get_tool_description: z.object({ toolRequests: z.string().describe("JSON 字符串,二维数组格式:[[\"server1\", \"tool1\"], [\"server2\", \"tool2\"]]") }),
|
|
59
58
|
mcp_call_tool: z.object({
|
|
60
59
|
serverName: z.string().describe("MCP 服务器名称"),
|
|
@@ -68,13 +67,6 @@ const ToolInputSchemas = {
|
|
|
68
67
|
arguments: z.record(z.unknown()).optional().describe("资源模板的参数"),
|
|
69
68
|
downloadPath: z.string().optional().describe("可选的绝对路径,用于保存资源到磁盘")
|
|
70
69
|
}),
|
|
71
|
-
create_rule: z.object({
|
|
72
|
-
ruleScope: z.string().describe("规则范围,project rule 或 user rule"),
|
|
73
|
-
ruleName: z.string().describe("规则文件名,不带扩展名"),
|
|
74
|
-
ruleType: z.string().describe("规则类型,always、manual 或 requested"),
|
|
75
|
-
ruleContent: z.string().describe("规则内容,使用 Markdown 格式"),
|
|
76
|
-
ruleDescription: z.string().optional().describe("规则描述,使用 Markdown 格式")
|
|
77
|
-
}),
|
|
78
70
|
update_memory: z.object({
|
|
79
71
|
action: z.enum([
|
|
80
72
|
"create",
|
|
@@ -133,7 +125,6 @@ const ToolInputSchemas = {
|
|
|
133
125
|
cloud_studio_fetch_log: z.object({}).passthrough(),
|
|
134
126
|
cloud_studio_execute_command: z.object({}).passthrough(),
|
|
135
127
|
cloud_studio_deploy_sandbox: z.object({}).passthrough(),
|
|
136
|
-
component_get_prompt: z.object({}).passthrough(),
|
|
137
128
|
web_fetch: z.object({
|
|
138
129
|
url: z.string().describe("要获取内容的 URL"),
|
|
139
130
|
fetchInfo: z.string().describe("用户想要获取的信息描述")
|
|
@@ -141,7 +132,9 @@ const ToolInputSchemas = {
|
|
|
141
132
|
use_skill: z.object({ command: z.string().describe("技能名称(不含参数),如 \"pdf\" 或 \"xlsx\"") }),
|
|
142
133
|
web_search: z.object({
|
|
143
134
|
explanation: z.string().describe("为什么使用此工具的一句话解释"),
|
|
144
|
-
|
|
135
|
+
query: z.string().describe("搜索关键词"),
|
|
136
|
+
max_results: z.number().optional().describe("最大返回数量"),
|
|
137
|
+
language: z.string().optional().describe("语言代码,例如 zh-CN")
|
|
145
138
|
}),
|
|
146
139
|
task: z.object({
|
|
147
140
|
subagent_name: z.string().describe("要调用的子代理名称"),
|
|
@@ -219,11 +212,6 @@ const ToolOutputSchemas = {
|
|
|
219
212
|
selectedKnowledgeBases: z.string(),
|
|
220
213
|
queryInput: z.string()
|
|
221
214
|
}),
|
|
222
|
-
read_rules: z.object({
|
|
223
|
-
type: z.literal("rule_match_result"),
|
|
224
|
-
ruleDescription: z.string(),
|
|
225
|
-
filePaths: z.array(z.string())
|
|
226
|
-
}),
|
|
227
215
|
mcp_get_tool_description: z.object({}).passthrough(),
|
|
228
216
|
mcp_call_tool: z.object({
|
|
229
217
|
type: z.literal("mcp_call_tool_result"),
|
|
@@ -260,17 +248,6 @@ const ToolOutputSchemas = {
|
|
|
260
248
|
content: z.string(),
|
|
261
249
|
downloadPath: z.string().optional()
|
|
262
250
|
}),
|
|
263
|
-
create_rule: z.object({
|
|
264
|
-
type: z.literal("rule_create_result"),
|
|
265
|
-
ruleName: z.string(),
|
|
266
|
-
createState: z.enum([
|
|
267
|
-
"success",
|
|
268
|
-
"invoke",
|
|
269
|
-
"cancelled"
|
|
270
|
-
]),
|
|
271
|
-
hint: z.string().optional(),
|
|
272
|
-
filePath: z.string().optional()
|
|
273
|
-
}),
|
|
274
251
|
update_memory: z.object({
|
|
275
252
|
type: z.literal("update_memory_result"),
|
|
276
253
|
success: z.boolean(),
|
|
@@ -284,9 +261,9 @@ const ToolOutputSchemas = {
|
|
|
284
261
|
}),
|
|
285
262
|
search_content: z.object({
|
|
286
263
|
type: z.literal("search_content_result"),
|
|
287
|
-
|
|
264
|
+
path: z.string(),
|
|
288
265
|
pattern: z.string(),
|
|
289
|
-
|
|
266
|
+
glob: z.string(),
|
|
290
267
|
matches: z.array(z.object({
|
|
291
268
|
filePath: z.string(),
|
|
292
269
|
content: z.string(),
|
|
@@ -298,7 +275,7 @@ const ToolOutputSchemas = {
|
|
|
298
275
|
totalCount: z.number(),
|
|
299
276
|
hasMore: z.boolean(),
|
|
300
277
|
offset: z.number(),
|
|
301
|
-
|
|
278
|
+
headLimit: z.number(),
|
|
302
279
|
contextBefore: z.number(),
|
|
303
280
|
contextAfter: z.number(),
|
|
304
281
|
contextAround: z.number().optional(),
|
|
@@ -484,15 +461,6 @@ const ToolOutputSchemas = {
|
|
|
484
461
|
}).optional()
|
|
485
462
|
}))
|
|
486
463
|
}),
|
|
487
|
-
component_get_prompt: z.object({
|
|
488
|
-
type: z.literal("component_get_prompt_result"),
|
|
489
|
-
componentType: z.string(),
|
|
490
|
-
webFramework: z.string(),
|
|
491
|
-
data: z.object({
|
|
492
|
-
type: z.literal("text"),
|
|
493
|
-
text: z.string()
|
|
494
|
-
})
|
|
495
|
-
}),
|
|
496
464
|
web_fetch: z.object({
|
|
497
465
|
type: z.literal("web_fetch_tool_result"),
|
|
498
466
|
message: z.string(),
|
|
@@ -508,14 +476,29 @@ const ToolOutputSchemas = {
|
|
|
508
476
|
}),
|
|
509
477
|
web_search: z.object({
|
|
510
478
|
type: z.literal("web_search_tool_result"),
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
479
|
+
query: z.string().optional(),
|
|
480
|
+
searchType: z.literal("text2text").optional(),
|
|
481
|
+
provider: z.string().optional(),
|
|
482
|
+
results: z.array(z.object({
|
|
515
483
|
title: z.string(),
|
|
516
|
-
|
|
517
|
-
|
|
484
|
+
url: z.string(),
|
|
485
|
+
snippet: z.string().optional(),
|
|
486
|
+
site: z.string().optional(),
|
|
487
|
+
highlights: z.array(z.string()).optional(),
|
|
488
|
+
content: z.string().optional(),
|
|
489
|
+
favicon: z.string().optional()
|
|
518
490
|
})),
|
|
491
|
+
images: z.array(z.object({
|
|
492
|
+
url: z.string(),
|
|
493
|
+
description: z.string().optional(),
|
|
494
|
+
sourceUrl: z.string().optional(),
|
|
495
|
+
width: z.number().optional(),
|
|
496
|
+
height: z.number().optional(),
|
|
497
|
+
title: z.string().optional(),
|
|
498
|
+
siteName: z.string().optional()
|
|
499
|
+
})),
|
|
500
|
+
totalResults: z.number().optional(),
|
|
501
|
+
responseTimeMs: z.number().optional(),
|
|
519
502
|
searchInput: z.string().optional()
|
|
520
503
|
}),
|
|
521
504
|
task: z.object({
|
|
@@ -661,7 +644,11 @@ const ExtensionMethod = {
|
|
|
661
644
|
CHECKPOINT: "_codebuddy.ai/checkpoint",
|
|
662
645
|
USAGE: "_codebuddy.ai/usage",
|
|
663
646
|
COMMAND: "_codebuddy.ai/command",
|
|
664
|
-
AUTH_URL: "_codebuddy.ai/authUrl"
|
|
647
|
+
AUTH_URL: "_codebuddy.ai/authUrl",
|
|
648
|
+
FILE_HISTORY_SNAPSHOT: "_codebuddy.ai/file_history_snapshot",
|
|
649
|
+
DELEGATE_TOOL: "_codebuddy.ai/delegateTool",
|
|
650
|
+
DELEGATE_TOOLS_CHANGED: "_codebuddy.ai/delegateToolsChanged",
|
|
651
|
+
UI_CONTROL: "_codebuddy.ai/uiControl"
|
|
665
652
|
};
|
|
666
653
|
/**
|
|
667
654
|
* All known extension methods
|
|
@@ -672,7 +659,10 @@ const KNOWN_EXTENSIONS = [
|
|
|
672
659
|
ExtensionMethod.CHECKPOINT,
|
|
673
660
|
ExtensionMethod.USAGE,
|
|
674
661
|
ExtensionMethod.COMMAND,
|
|
675
|
-
ExtensionMethod.AUTH_URL
|
|
662
|
+
ExtensionMethod.AUTH_URL,
|
|
663
|
+
ExtensionMethod.FILE_HISTORY_SNAPSHOT,
|
|
664
|
+
ExtensionMethod.DELEGATE_TOOL,
|
|
665
|
+
ExtensionMethod.DELEGATE_TOOLS_CHANGED
|
|
676
666
|
];
|
|
677
667
|
|
|
678
668
|
//#endregion
|
|
@@ -723,7 +713,7 @@ function parseSSELine(line, currentEvent) {
|
|
|
723
713
|
};
|
|
724
714
|
}
|
|
725
715
|
function streamableHttp(options) {
|
|
726
|
-
const { endpoint, authToken, headers: customHeaders = {}, reconnect = {}, signal: externalSignal, fetch: customFetch = globalThis.fetch, onConnect, onDisconnect, onError, heartbeatTimeout = 6e4, postTimeout = 3e4, backpressure = {} } = options;
|
|
716
|
+
const { endpoint, authToken, headers: customHeaders = {}, reconnect = {}, signal: externalSignal, fetch: customFetch = globalThis.fetch, onConnect, onDisconnect, onError, heartbeatTimeout = 6e4, connectionTimeout = 3e4, postTimeout = 3e4, backpressure = {} } = options;
|
|
727
717
|
const { enabled: reconnectEnabled = true, initialDelay = 1e3, maxDelay = 3e4, maxRetries = Infinity, jitter: jitterEnabled = true } = reconnect;
|
|
728
718
|
const { highWaterMark = 100, lowWaterMark = 50, pauseTimeout = 5e3 } = backpressure;
|
|
729
719
|
let connectionId;
|
|
@@ -934,11 +924,21 @@ function streamableHttp(options) {
|
|
|
934
924
|
const headers = buildHeaders();
|
|
935
925
|
headers["Accept"] = "text/event-stream";
|
|
936
926
|
if (lastEventId) headers["Last-Event-ID"] = lastEventId;
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
});
|
|
927
|
+
const connectTimeoutMs = connectionTimeout > 0 ? connectionTimeout : 3e4;
|
|
928
|
+
const connectController = new AbortController();
|
|
929
|
+
const connectTimer = setTimeout(() => connectController.abort(), connectTimeoutMs);
|
|
930
|
+
if (externalSignal) externalSignal.addEventListener("abort", () => connectController.abort(), { once: true });
|
|
931
|
+
abortController.signal.addEventListener("abort", () => connectController.abort(), { once: true });
|
|
932
|
+
let response;
|
|
933
|
+
try {
|
|
934
|
+
response = await customFetch(endpoint, {
|
|
935
|
+
method: "GET",
|
|
936
|
+
headers,
|
|
937
|
+
signal: connectController.signal
|
|
938
|
+
});
|
|
939
|
+
} finally {
|
|
940
|
+
clearTimeout(connectTimer);
|
|
941
|
+
}
|
|
942
942
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
943
943
|
const newConnectionId = response.headers.get("Acp-Connection-Id");
|
|
944
944
|
if (!newConnectionId) throw new Error("Server did not return Acp-Connection-Id header");
|
|
@@ -1143,6 +1143,10 @@ var ArtifactManager = class {
|
|
|
1143
1143
|
*/
|
|
1144
1144
|
const DEFAULT_INITIALIZE_TIMEOUT = 3e4;
|
|
1145
1145
|
/**
|
|
1146
|
+
* Default timeout for session/new operation (waiting for sessionId via SSE)
|
|
1147
|
+
*/
|
|
1148
|
+
const DEFAULT_SESSION_TIMEOUT = 3e4;
|
|
1149
|
+
/**
|
|
1146
1150
|
* Default timeout for permission requests
|
|
1147
1151
|
*/
|
|
1148
1152
|
const DEFAULT_PERMISSION_TIMEOUT = 3e5;
|
|
@@ -1198,8 +1202,14 @@ var InitializationError = class extends ACPClientError {
|
|
|
1198
1202
|
* Error thrown for session-related failures
|
|
1199
1203
|
*/
|
|
1200
1204
|
var SessionError = class extends ACPClientError {
|
|
1201
|
-
constructor(message, sessionId, cause) {
|
|
1202
|
-
|
|
1205
|
+
constructor(message, sessionId, agentIdOrCause, cause) {
|
|
1206
|
+
if (agentIdOrCause instanceof Error) {
|
|
1207
|
+
super(message, "SESSION_ERROR", agentIdOrCause);
|
|
1208
|
+
this.agentId = void 0;
|
|
1209
|
+
} else {
|
|
1210
|
+
super(message, "SESSION_ERROR", cause);
|
|
1211
|
+
this.agentId = agentIdOrCause;
|
|
1212
|
+
}
|
|
1203
1213
|
this.name = "SessionError";
|
|
1204
1214
|
this.sessionId = sessionId;
|
|
1205
1215
|
}
|
|
@@ -1874,6 +1884,9 @@ var StreamableHttpClient = class {
|
|
|
1874
1884
|
headers: this.options.headers,
|
|
1875
1885
|
reconnect: this.options.reconnect,
|
|
1876
1886
|
fetch: this.options.fetch,
|
|
1887
|
+
heartbeatTimeout: this.options.heartbeatTimeout,
|
|
1888
|
+
postTimeout: this.options.postTimeout,
|
|
1889
|
+
connectionTimeout: this.options.connectionTimeout,
|
|
1877
1890
|
onConnect: (connectionId) => {
|
|
1878
1891
|
this.options.logger?.debug(`Transport connected: ${connectionId}`);
|
|
1879
1892
|
},
|
|
@@ -1948,10 +1961,6 @@ var StreamableHttpClient = class {
|
|
|
1948
1961
|
},
|
|
1949
1962
|
requestPermission: async (params) => this.handleRequestPermission(params),
|
|
1950
1963
|
extNotification: async (method, params) => {
|
|
1951
|
-
console.log("[ACP-Client] extNotification callback invoked:", {
|
|
1952
|
-
method,
|
|
1953
|
-
paramsKeys: Object.keys(params)
|
|
1954
|
-
});
|
|
1955
1964
|
await this.handleExtNotification(method, params);
|
|
1956
1965
|
},
|
|
1957
1966
|
extMethod: async (method, params) => this.handleExtMethod(method, params)
|
|
@@ -1959,19 +1968,47 @@ var StreamableHttpClient = class {
|
|
|
1959
1968
|
}
|
|
1960
1969
|
/**
|
|
1961
1970
|
* Create a new session
|
|
1971
|
+
*
|
|
1972
|
+
* Retries on transient network errors (e.g., proxy connection reset)
|
|
1973
|
+
* since session/new is idempotent and safe to retry.
|
|
1974
|
+
*
|
|
1975
|
+
* A timeout (`options.sessionTimeout`, default 30 s) guards against the
|
|
1976
|
+
* SSE response never arriving — the POST returns 202 immediately and the
|
|
1977
|
+
* sessionId comes back via GET SSE, which can hang indefinitely.
|
|
1978
|
+
* On timeout a `SessionError` is thrown.
|
|
1962
1979
|
*/
|
|
1963
1980
|
async createSession(cwd) {
|
|
1964
1981
|
this.ensureInitialized("createSession");
|
|
1965
|
-
|
|
1966
|
-
|
|
1982
|
+
const maxRetries = 2;
|
|
1983
|
+
const timeout = this.options.sessionTimeout ?? DEFAULT_SESSION_TIMEOUT;
|
|
1984
|
+
let lastError;
|
|
1985
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
1986
|
+
const sessionPromise = this.connection.newSession({
|
|
1967
1987
|
cwd,
|
|
1968
1988
|
mcpServers: []
|
|
1969
1989
|
});
|
|
1990
|
+
let response;
|
|
1991
|
+
if (timeout > 0) {
|
|
1992
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1993
|
+
setTimeout(() => {
|
|
1994
|
+
reject(new SessionError(`session/new timed out after ${timeout}ms`));
|
|
1995
|
+
}, timeout);
|
|
1996
|
+
});
|
|
1997
|
+
response = await Promise.race([sessionPromise, timeoutPromise]);
|
|
1998
|
+
} else response = await sessionPromise;
|
|
1970
1999
|
this.options.logger?.info(`Session created: ${response.sessionId}`);
|
|
1971
2000
|
return response;
|
|
1972
2001
|
} catch (err) {
|
|
1973
|
-
|
|
2002
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
2003
|
+
if (attempt < maxRetries && isRetryableNetworkError(err)) {
|
|
2004
|
+
const delay = 500 * Math.pow(2, attempt);
|
|
2005
|
+
this.options.logger?.warn(`session/new network error, retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries}): ${lastError.message}`);
|
|
2006
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
throw new SessionError(`Failed to create session: ${lastError.message}`, void 0, lastError);
|
|
1974
2010
|
}
|
|
2011
|
+
throw new SessionError(`Failed to create session: ${lastError?.message}`, void 0, lastError);
|
|
1975
2012
|
}
|
|
1976
2013
|
/**
|
|
1977
2014
|
* Load an existing session
|
|
@@ -2195,6 +2232,18 @@ var StreamableHttpClient = class {
|
|
|
2195
2232
|
if (this.state !== "initialized") throw new InvalidStateError(operation, this.state, ["initialized"]);
|
|
2196
2233
|
}
|
|
2197
2234
|
};
|
|
2235
|
+
/**
|
|
2236
|
+
* Check if an error is a retryable network-level error.
|
|
2237
|
+
* Only network failures (TypeError from fetch) are retried, NOT HTTP errors (4xx/5xx).
|
|
2238
|
+
*/
|
|
2239
|
+
function isRetryableNetworkError(error) {
|
|
2240
|
+
if (error instanceof TypeError) return true;
|
|
2241
|
+
if (error instanceof Error) {
|
|
2242
|
+
const msg = error.message.toLowerCase();
|
|
2243
|
+
return msg.includes("failed to fetch") || msg.includes("fetch failed") || msg.includes("network request failed") || msg.includes("econnreset") || msg.includes("econnrefused") || msg.includes("socket hang up");
|
|
2244
|
+
}
|
|
2245
|
+
return false;
|
|
2246
|
+
}
|
|
2198
2247
|
|
|
2199
2248
|
//#endregion
|
|
2200
2249
|
//#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-connection.ts
|
|
@@ -2230,7 +2279,7 @@ var CloudAgentConnection = class {
|
|
|
2230
2279
|
fetch: config.fetch,
|
|
2231
2280
|
clientCapabilities: config.clientCapabilities,
|
|
2232
2281
|
onSessionUpdate: (update) => {
|
|
2233
|
-
if (!this._isStreaming) this.emit("sessionUpdate", update);
|
|
2282
|
+
if (!this._isStreaming && this.isOwnSessionNotification(update)) this.emit("sessionUpdate", update);
|
|
2234
2283
|
},
|
|
2235
2284
|
onArtifact: (artifact, event) => {
|
|
2236
2285
|
console.log("[CloudConnection] onArtifact callback:", {
|
|
@@ -2244,10 +2293,41 @@ var CloudAgentConnection = class {
|
|
|
2244
2293
|
},
|
|
2245
2294
|
onUsageUpdate: (usage) => {
|
|
2246
2295
|
this.emit("usageUpdate", usage);
|
|
2296
|
+
},
|
|
2297
|
+
onExtNotification: (method, params) => {
|
|
2298
|
+
console.log("[CloudConnection] Received extNotification:", {
|
|
2299
|
+
method,
|
|
2300
|
+
paramsKeys: Object.keys(params)
|
|
2301
|
+
});
|
|
2302
|
+
if (method === ExtensionMethod.COMMAND) {
|
|
2303
|
+
const action = params.action;
|
|
2304
|
+
const commandParams = params.params;
|
|
2305
|
+
console.log("[CloudConnection] Emitting command event:", {
|
|
2306
|
+
action,
|
|
2307
|
+
paramsKeys: commandParams ? Object.keys(commandParams) : []
|
|
2308
|
+
});
|
|
2309
|
+
this.emit("command", {
|
|
2310
|
+
action,
|
|
2311
|
+
params: commandParams
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2247
2314
|
}
|
|
2248
2315
|
});
|
|
2249
2316
|
this.setupEventForwarding();
|
|
2250
2317
|
}
|
|
2318
|
+
/**
|
|
2319
|
+
* Check whether a notification belongs to this connection's own session.
|
|
2320
|
+
*
|
|
2321
|
+
* CloudConnection.createSession() overrides sessionId to agentId, so the
|
|
2322
|
+
* rest of the client stack uses agentId as the canonical session
|
|
2323
|
+
* identifier. Notifications whose sessionId differs from agentId
|
|
2324
|
+
* originate from sub-agent sessions running inside the same sandbox and
|
|
2325
|
+
* should be silently ignored at this layer — the adapter layer handles
|
|
2326
|
+
* sub-agent messages independently via parentToolUseId in _meta.
|
|
2327
|
+
*/
|
|
2328
|
+
isOwnSessionNotification(notification) {
|
|
2329
|
+
return notification.sessionId === this.agentId;
|
|
2330
|
+
}
|
|
2251
2331
|
setupEventForwarding() {
|
|
2252
2332
|
this.client.on("connecting", () => {
|
|
2253
2333
|
this.emit("connecting", void 0);
|
|
@@ -2408,6 +2488,7 @@ var CloudAgentConnection = class {
|
|
|
2408
2488
|
let resolveUpdate = null;
|
|
2409
2489
|
let done = false;
|
|
2410
2490
|
const listener = (update) => {
|
|
2491
|
+
if (!this.isOwnSessionNotification(update)) return;
|
|
2411
2492
|
if (resolveUpdate) {
|
|
2412
2493
|
resolveUpdate(update);
|
|
2413
2494
|
resolveUpdate = null;
|
|
@@ -2490,6 +2571,16 @@ var CloudAgentConnection = class {
|
|
|
2490
2571
|
get sessionConnectionInfo() {
|
|
2491
2572
|
return this._sessionConnectionInfo;
|
|
2492
2573
|
}
|
|
2574
|
+
async reportTelemetry(eventName, payload) {
|
|
2575
|
+
try {
|
|
2576
|
+
await this.client.extMethod("reportTelemetry", {
|
|
2577
|
+
eventName,
|
|
2578
|
+
payload
|
|
2579
|
+
});
|
|
2580
|
+
} catch (error) {
|
|
2581
|
+
console.warn("[CloudAgentConnection] reportTelemetry failed:", error);
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2493
2584
|
async extMethod(method, params) {
|
|
2494
2585
|
return this.client.extMethod(method, params);
|
|
2495
2586
|
}
|
|
@@ -3092,7 +3183,7 @@ var utils_default = {
|
|
|
3092
3183
|
*
|
|
3093
3184
|
* @returns {Error} The created error.
|
|
3094
3185
|
*/
|
|
3095
|
-
function AxiosError(message, code, config, request, response) {
|
|
3186
|
+
function AxiosError$1(message, code, config, request, response) {
|
|
3096
3187
|
Error.call(this);
|
|
3097
3188
|
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
3098
3189
|
else this.stack = (/* @__PURE__ */ new Error()).stack;
|
|
@@ -3106,7 +3197,7 @@ function AxiosError(message, code, config, request, response) {
|
|
|
3106
3197
|
this.status = response.status ? response.status : null;
|
|
3107
3198
|
}
|
|
3108
3199
|
}
|
|
3109
|
-
utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
|
|
3200
|
+
utils_default.inherits(AxiosError$1, Error, { toJSON: function toJSON() {
|
|
3110
3201
|
return {
|
|
3111
3202
|
message: this.message,
|
|
3112
3203
|
name: this.name,
|
|
@@ -3121,7 +3212,7 @@ utils_default.inherits(AxiosError, Error, { toJSON: function toJSON() {
|
|
|
3121
3212
|
status: this.status
|
|
3122
3213
|
};
|
|
3123
3214
|
} });
|
|
3124
|
-
const prototype$1 = AxiosError.prototype;
|
|
3215
|
+
const prototype$1 = AxiosError$1.prototype;
|
|
3125
3216
|
const descriptors = {};
|
|
3126
3217
|
[
|
|
3127
3218
|
"ERR_BAD_OPTION_VALUE",
|
|
@@ -3139,22 +3230,22 @@ const descriptors = {};
|
|
|
3139
3230
|
].forEach((code) => {
|
|
3140
3231
|
descriptors[code] = { value: code };
|
|
3141
3232
|
});
|
|
3142
|
-
Object.defineProperties(AxiosError, descriptors);
|
|
3233
|
+
Object.defineProperties(AxiosError$1, descriptors);
|
|
3143
3234
|
Object.defineProperty(prototype$1, "isAxiosError", { value: true });
|
|
3144
|
-
AxiosError.from = (error, code, config, request, response, customProps) => {
|
|
3235
|
+
AxiosError$1.from = (error, code, config, request, response, customProps) => {
|
|
3145
3236
|
const axiosError = Object.create(prototype$1);
|
|
3146
3237
|
utils_default.toFlatObject(error, axiosError, function filter(obj) {
|
|
3147
3238
|
return obj !== Error.prototype;
|
|
3148
3239
|
}, (prop) => {
|
|
3149
3240
|
return prop !== "isAxiosError";
|
|
3150
3241
|
});
|
|
3151
|
-
AxiosError.call(axiosError, error.message, code, config, request, response);
|
|
3242
|
+
AxiosError$1.call(axiosError, error.message, code, config, request, response);
|
|
3152
3243
|
axiosError.cause = error;
|
|
3153
3244
|
axiosError.name = error.name;
|
|
3154
3245
|
customProps && Object.assign(axiosError, customProps);
|
|
3155
3246
|
return axiosError;
|
|
3156
3247
|
};
|
|
3157
|
-
var AxiosError_default = AxiosError;
|
|
3248
|
+
var AxiosError_default = AxiosError$1;
|
|
3158
3249
|
|
|
3159
3250
|
//#endregion
|
|
3160
3251
|
//#region ../agent-provider/node_modules/axios/lib/helpers/null.js
|
|
@@ -3233,7 +3324,7 @@ const predicates = utils_default.toFlatObject(utils_default, {}, null, function
|
|
|
3233
3324
|
*
|
|
3234
3325
|
* @returns
|
|
3235
3326
|
*/
|
|
3236
|
-
function toFormData(obj, formData, options) {
|
|
3327
|
+
function toFormData$1(obj, formData, options) {
|
|
3237
3328
|
if (!utils_default.isObject(obj)) throw new TypeError("target must be an object");
|
|
3238
3329
|
formData = formData || new (null_default || FormData)();
|
|
3239
3330
|
options = utils_default.toFlatObject(options, {
|
|
@@ -3304,7 +3395,7 @@ function toFormData(obj, formData, options) {
|
|
|
3304
3395
|
build(obj);
|
|
3305
3396
|
return formData;
|
|
3306
3397
|
}
|
|
3307
|
-
var toFormData_default = toFormData;
|
|
3398
|
+
var toFormData_default = toFormData$1;
|
|
3308
3399
|
|
|
3309
3400
|
//#endregion
|
|
3310
3401
|
//#region ../agent-provider/node_modules/axios/lib/helpers/AxiosURLSearchParams.js
|
|
@@ -3821,7 +3912,7 @@ function buildAccessors(obj, header) {
|
|
|
3821
3912
|
});
|
|
3822
3913
|
});
|
|
3823
3914
|
}
|
|
3824
|
-
var AxiosHeaders = class {
|
|
3915
|
+
var AxiosHeaders$1 = class {
|
|
3825
3916
|
constructor(headers) {
|
|
3826
3917
|
headers && this.set(headers);
|
|
3827
3918
|
}
|
|
@@ -3959,7 +4050,7 @@ var AxiosHeaders = class {
|
|
|
3959
4050
|
return this;
|
|
3960
4051
|
}
|
|
3961
4052
|
};
|
|
3962
|
-
AxiosHeaders.accessor([
|
|
4053
|
+
AxiosHeaders$1.accessor([
|
|
3963
4054
|
"Content-Type",
|
|
3964
4055
|
"Content-Length",
|
|
3965
4056
|
"Accept",
|
|
@@ -3967,7 +4058,7 @@ AxiosHeaders.accessor([
|
|
|
3967
4058
|
"User-Agent",
|
|
3968
4059
|
"Authorization"
|
|
3969
4060
|
]);
|
|
3970
|
-
utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
|
|
4061
|
+
utils_default.reduceDescriptors(AxiosHeaders$1.prototype, ({ value }, key) => {
|
|
3971
4062
|
let mapped = key[0].toUpperCase() + key.slice(1);
|
|
3972
4063
|
return {
|
|
3973
4064
|
get: () => value,
|
|
@@ -3976,8 +4067,8 @@ utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
|
|
|
3976
4067
|
}
|
|
3977
4068
|
};
|
|
3978
4069
|
});
|
|
3979
|
-
utils_default.freezeMethods(AxiosHeaders);
|
|
3980
|
-
var AxiosHeaders_default = AxiosHeaders;
|
|
4070
|
+
utils_default.freezeMethods(AxiosHeaders$1);
|
|
4071
|
+
var AxiosHeaders_default = AxiosHeaders$1;
|
|
3981
4072
|
|
|
3982
4073
|
//#endregion
|
|
3983
4074
|
//#region ../agent-provider/node_modules/axios/lib/core/transformData.js
|
|
@@ -4003,7 +4094,7 @@ function transformData(fns, response) {
|
|
|
4003
4094
|
|
|
4004
4095
|
//#endregion
|
|
4005
4096
|
//#region ../agent-provider/node_modules/axios/lib/cancel/isCancel.js
|
|
4006
|
-
function isCancel(value) {
|
|
4097
|
+
function isCancel$1(value) {
|
|
4007
4098
|
return !!(value && value.__CANCEL__);
|
|
4008
4099
|
}
|
|
4009
4100
|
|
|
@@ -4018,12 +4109,12 @@ function isCancel(value) {
|
|
|
4018
4109
|
*
|
|
4019
4110
|
* @returns {CanceledError} The created error.
|
|
4020
4111
|
*/
|
|
4021
|
-
function CanceledError(message, config, request) {
|
|
4112
|
+
function CanceledError$1(message, config, request) {
|
|
4022
4113
|
AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);
|
|
4023
4114
|
this.name = "CanceledError";
|
|
4024
4115
|
}
|
|
4025
|
-
utils_default.inherits(CanceledError, AxiosError_default, { __CANCEL__: true });
|
|
4026
|
-
var CanceledError_default = CanceledError;
|
|
4116
|
+
utils_default.inherits(CanceledError$1, AxiosError_default, { __CANCEL__: true });
|
|
4117
|
+
var CanceledError_default = CanceledError$1;
|
|
4027
4118
|
|
|
4028
4119
|
//#endregion
|
|
4029
4120
|
//#region ../agent-provider/node_modules/axios/lib/core/settle.js
|
|
@@ -4250,7 +4341,7 @@ const headersToObject = (thing) => thing instanceof AxiosHeaders_default ? { ...
|
|
|
4250
4341
|
*
|
|
4251
4342
|
* @returns {Object} New object resulting from merging config2 to config1
|
|
4252
4343
|
*/
|
|
4253
|
-
function mergeConfig(config1, config2) {
|
|
4344
|
+
function mergeConfig$1(config1, config2) {
|
|
4254
4345
|
config2 = config2 || {};
|
|
4255
4346
|
const config = {};
|
|
4256
4347
|
function getMergedValue(target, source, prop, caseless) {
|
|
@@ -4316,7 +4407,7 @@ function mergeConfig(config1, config2) {
|
|
|
4316
4407
|
//#endregion
|
|
4317
4408
|
//#region ../agent-provider/node_modules/axios/lib/helpers/resolveConfig.js
|
|
4318
4409
|
var resolveConfig_default = (config) => {
|
|
4319
|
-
const newConfig = mergeConfig({}, config);
|
|
4410
|
+
const newConfig = mergeConfig$1({}, config);
|
|
4320
4411
|
let { data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth } = newConfig;
|
|
4321
4412
|
newConfig.headers = headers = AxiosHeaders_default.from(headers);
|
|
4322
4413
|
newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url, newConfig.allowAbsoluteUrls), config.params, config.paramsSerializer);
|
|
@@ -4747,7 +4838,7 @@ function dispatchRequest(config) {
|
|
|
4747
4838
|
response.headers = AxiosHeaders_default.from(response.headers);
|
|
4748
4839
|
return response;
|
|
4749
4840
|
}, function onAdapterRejection(reason) {
|
|
4750
|
-
if (!isCancel(reason)) {
|
|
4841
|
+
if (!isCancel$1(reason)) {
|
|
4751
4842
|
throwIfCancellationRequested(config);
|
|
4752
4843
|
if (reason && reason.response) {
|
|
4753
4844
|
reason.response.data = transformData.call(config, config.transformResponse, reason.response);
|
|
@@ -4760,7 +4851,7 @@ function dispatchRequest(config) {
|
|
|
4760
4851
|
|
|
4761
4852
|
//#endregion
|
|
4762
4853
|
//#region ../agent-provider/node_modules/axios/lib/env/data.js
|
|
4763
|
-
const VERSION = "1.10.0";
|
|
4854
|
+
const VERSION$1 = "1.10.0";
|
|
4764
4855
|
|
|
4765
4856
|
//#endregion
|
|
4766
4857
|
//#region ../agent-provider/node_modules/axios/lib/helpers/validator.js
|
|
@@ -4789,7 +4880,7 @@ const deprecatedWarnings = {};
|
|
|
4789
4880
|
*/
|
|
4790
4881
|
validators$1.transitional = function transitional(validator, version, message) {
|
|
4791
4882
|
function formatMessage(opt, desc) {
|
|
4792
|
-
return "[Axios v" + VERSION + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
|
|
4883
|
+
return "[Axios v" + VERSION$1 + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : "");
|
|
4793
4884
|
}
|
|
4794
4885
|
return (value, opt, opts) => {
|
|
4795
4886
|
if (validator === false) throw new AxiosError_default(formatMessage(opt, " has been removed" + (version ? " in " + version : "")), AxiosError_default.ERR_DEPRECATED);
|
|
@@ -4846,7 +4937,7 @@ const validators = validator_default.validators;
|
|
|
4846
4937
|
*
|
|
4847
4938
|
* @return {Axios} A new instance of Axios
|
|
4848
4939
|
*/
|
|
4849
|
-
var Axios = class {
|
|
4940
|
+
var Axios$1 = class {
|
|
4850
4941
|
constructor(instanceConfig) {
|
|
4851
4942
|
this.defaults = instanceConfig || {};
|
|
4852
4943
|
this.interceptors = {
|
|
@@ -4883,7 +4974,7 @@ var Axios = class {
|
|
|
4883
4974
|
config = config || {};
|
|
4884
4975
|
config.url = configOrUrl;
|
|
4885
4976
|
} else config = configOrUrl || {};
|
|
4886
|
-
config = mergeConfig(this.defaults, config);
|
|
4977
|
+
config = mergeConfig$1(this.defaults, config);
|
|
4887
4978
|
const { transitional, paramsSerializer, headers } = config;
|
|
4888
4979
|
if (transitional !== void 0) validator_default.assertOptions(transitional, {
|
|
4889
4980
|
silentJSONParsing: validators.transitional(validators.boolean),
|
|
@@ -4962,7 +5053,7 @@ var Axios = class {
|
|
|
4962
5053
|
return promise;
|
|
4963
5054
|
}
|
|
4964
5055
|
getUri(config) {
|
|
4965
|
-
config = mergeConfig(this.defaults, config);
|
|
5056
|
+
config = mergeConfig$1(this.defaults, config);
|
|
4966
5057
|
return buildURL(buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls), config.params, config.paramsSerializer);
|
|
4967
5058
|
}
|
|
4968
5059
|
};
|
|
@@ -4972,8 +5063,8 @@ utils_default.forEach([
|
|
|
4972
5063
|
"head",
|
|
4973
5064
|
"options"
|
|
4974
5065
|
], function forEachMethodNoData(method) {
|
|
4975
|
-
Axios.prototype[method] = function(url, config) {
|
|
4976
|
-
return this.request(mergeConfig(config || {}, {
|
|
5066
|
+
Axios$1.prototype[method] = function(url, config) {
|
|
5067
|
+
return this.request(mergeConfig$1(config || {}, {
|
|
4977
5068
|
method,
|
|
4978
5069
|
url,
|
|
4979
5070
|
data: (config || {}).data
|
|
@@ -4987,7 +5078,7 @@ utils_default.forEach([
|
|
|
4987
5078
|
], function forEachMethodWithData(method) {
|
|
4988
5079
|
function generateHTTPMethod(isForm) {
|
|
4989
5080
|
return function httpMethod(url, data, config) {
|
|
4990
|
-
return this.request(mergeConfig(config || {}, {
|
|
5081
|
+
return this.request(mergeConfig$1(config || {}, {
|
|
4991
5082
|
method,
|
|
4992
5083
|
headers: isForm ? { "Content-Type": "multipart/form-data" } : {},
|
|
4993
5084
|
url,
|
|
@@ -4995,10 +5086,10 @@ utils_default.forEach([
|
|
|
4995
5086
|
}));
|
|
4996
5087
|
};
|
|
4997
5088
|
}
|
|
4998
|
-
Axios.prototype[method] = generateHTTPMethod();
|
|
4999
|
-
Axios.prototype[method + "Form"] = generateHTTPMethod(true);
|
|
5089
|
+
Axios$1.prototype[method] = generateHTTPMethod();
|
|
5090
|
+
Axios$1.prototype[method + "Form"] = generateHTTPMethod(true);
|
|
5000
5091
|
});
|
|
5001
|
-
var Axios_default = Axios;
|
|
5092
|
+
var Axios_default = Axios$1;
|
|
5002
5093
|
|
|
5003
5094
|
//#endregion
|
|
5004
5095
|
//#region ../agent-provider/node_modules/axios/lib/cancel/CancelToken.js
|
|
@@ -5009,7 +5100,7 @@ var Axios_default = Axios;
|
|
|
5009
5100
|
*
|
|
5010
5101
|
* @returns {CancelToken}
|
|
5011
5102
|
*/
|
|
5012
|
-
var CancelToken = class CancelToken {
|
|
5103
|
+
var CancelToken$1 = class CancelToken$1 {
|
|
5013
5104
|
constructor(executor) {
|
|
5014
5105
|
if (typeof executor !== "function") throw new TypeError("executor must be a function.");
|
|
5015
5106
|
let resolvePromise;
|
|
@@ -5081,14 +5172,14 @@ var CancelToken = class CancelToken {
|
|
|
5081
5172
|
static source() {
|
|
5082
5173
|
let cancel;
|
|
5083
5174
|
return {
|
|
5084
|
-
token: new CancelToken(function executor(c) {
|
|
5175
|
+
token: new CancelToken$1(function executor(c) {
|
|
5085
5176
|
cancel = c;
|
|
5086
5177
|
}),
|
|
5087
5178
|
cancel
|
|
5088
5179
|
};
|
|
5089
5180
|
}
|
|
5090
5181
|
};
|
|
5091
|
-
var CancelToken_default = CancelToken;
|
|
5182
|
+
var CancelToken_default = CancelToken$1;
|
|
5092
5183
|
|
|
5093
5184
|
//#endregion
|
|
5094
5185
|
//#region ../agent-provider/node_modules/axios/lib/helpers/spread.js
|
|
@@ -5113,7 +5204,7 @@ var CancelToken_default = CancelToken;
|
|
|
5113
5204
|
*
|
|
5114
5205
|
* @returns {Function}
|
|
5115
5206
|
*/
|
|
5116
|
-
function spread(callback) {
|
|
5207
|
+
function spread$1(callback) {
|
|
5117
5208
|
return function wrap(arr) {
|
|
5118
5209
|
return callback.apply(null, arr);
|
|
5119
5210
|
};
|
|
@@ -5128,13 +5219,13 @@ function spread(callback) {
|
|
|
5128
5219
|
*
|
|
5129
5220
|
* @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
|
|
5130
5221
|
*/
|
|
5131
|
-
function isAxiosError(payload) {
|
|
5222
|
+
function isAxiosError$1(payload) {
|
|
5132
5223
|
return utils_default.isObject(payload) && payload.isAxiosError === true;
|
|
5133
5224
|
}
|
|
5134
5225
|
|
|
5135
5226
|
//#endregion
|
|
5136
5227
|
//#region ../agent-provider/node_modules/axios/lib/helpers/HttpStatusCode.js
|
|
5137
|
-
const HttpStatusCode = {
|
|
5228
|
+
const HttpStatusCode$1 = {
|
|
5138
5229
|
Continue: 100,
|
|
5139
5230
|
SwitchingProtocols: 101,
|
|
5140
5231
|
Processing: 102,
|
|
@@ -5199,10 +5290,10 @@ const HttpStatusCode = {
|
|
|
5199
5290
|
NotExtended: 510,
|
|
5200
5291
|
NetworkAuthenticationRequired: 511
|
|
5201
5292
|
};
|
|
5202
|
-
Object.entries(HttpStatusCode).forEach(([key, value]) => {
|
|
5203
|
-
HttpStatusCode[value] = key;
|
|
5293
|
+
Object.entries(HttpStatusCode$1).forEach(([key, value]) => {
|
|
5294
|
+
HttpStatusCode$1[value] = key;
|
|
5204
5295
|
});
|
|
5205
|
-
var HttpStatusCode_default = HttpStatusCode;
|
|
5296
|
+
var HttpStatusCode_default = HttpStatusCode$1;
|
|
5206
5297
|
|
|
5207
5298
|
//#endregion
|
|
5208
5299
|
//#region ../agent-provider/node_modules/axios/lib/axios.js
|
|
@@ -5219,7 +5310,7 @@ function createInstance(defaultConfig) {
|
|
|
5219
5310
|
utils_default.extend(instance, Axios_default.prototype, context, { allOwnKeys: true });
|
|
5220
5311
|
utils_default.extend(instance, context, null, { allOwnKeys: true });
|
|
5221
5312
|
instance.create = function create(instanceConfig) {
|
|
5222
|
-
return createInstance(mergeConfig(defaultConfig, instanceConfig));
|
|
5313
|
+
return createInstance(mergeConfig$1(defaultConfig, instanceConfig));
|
|
5223
5314
|
};
|
|
5224
5315
|
return instance;
|
|
5225
5316
|
}
|
|
@@ -5227,17 +5318,17 @@ const axios = createInstance(defaults_default);
|
|
|
5227
5318
|
axios.Axios = Axios_default;
|
|
5228
5319
|
axios.CanceledError = CanceledError_default;
|
|
5229
5320
|
axios.CancelToken = CancelToken_default;
|
|
5230
|
-
axios.isCancel = isCancel;
|
|
5231
|
-
axios.VERSION = VERSION;
|
|
5321
|
+
axios.isCancel = isCancel$1;
|
|
5322
|
+
axios.VERSION = VERSION$1;
|
|
5232
5323
|
axios.toFormData = toFormData_default;
|
|
5233
5324
|
axios.AxiosError = AxiosError_default;
|
|
5234
5325
|
axios.Cancel = axios.CanceledError;
|
|
5235
5326
|
axios.all = function all(promises) {
|
|
5236
5327
|
return Promise.all(promises);
|
|
5237
5328
|
};
|
|
5238
|
-
axios.spread = spread;
|
|
5239
|
-
axios.isAxiosError = isAxiosError;
|
|
5240
|
-
axios.mergeConfig = mergeConfig;
|
|
5329
|
+
axios.spread = spread$1;
|
|
5330
|
+
axios.isAxiosError = isAxiosError$1;
|
|
5331
|
+
axios.mergeConfig = mergeConfig$1;
|
|
5241
5332
|
axios.AxiosHeaders = AxiosHeaders_default;
|
|
5242
5333
|
axios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing);
|
|
5243
5334
|
axios.getAdapter = adapters_default.getAdapter;
|
|
@@ -5245,6 +5336,10 @@ axios.HttpStatusCode = HttpStatusCode_default;
|
|
|
5245
5336
|
axios.default = axios;
|
|
5246
5337
|
var axios_default = axios;
|
|
5247
5338
|
|
|
5339
|
+
//#endregion
|
|
5340
|
+
//#region ../agent-provider/node_modules/axios/index.js
|
|
5341
|
+
const { Axios, AxiosError, CanceledError, isCancel, CancelToken, VERSION, all, Cancel, isAxiosError, spread, toFormData, AxiosHeaders, HttpStatusCode, formToJSON, getAdapter, mergeConfig } = axios_default;
|
|
5342
|
+
|
|
5248
5343
|
//#endregion
|
|
5249
5344
|
//#region ../agent-provider/src/http/http-service.ts
|
|
5250
5345
|
/**
|
|
@@ -5253,7 +5348,7 @@ var axios_default = axios;
|
|
|
5253
5348
|
* 特性:
|
|
5254
5349
|
* - 单例模式,全局唯一实例,延迟初始化(首次使用时自动创建)
|
|
5255
5350
|
* - 支持拦截器注册(其他模块可注入 header)
|
|
5256
|
-
* - 统一 401
|
|
5351
|
+
* - 统一 401 处理(支持自动刷新 token 并重试)
|
|
5257
5352
|
* - 自动携带凭证(withCredentials)
|
|
5258
5353
|
* - 类型安全
|
|
5259
5354
|
*
|
|
@@ -5293,6 +5388,8 @@ var HttpService = class HttpService {
|
|
|
5293
5388
|
*/
|
|
5294
5389
|
constructor(config = {}) {
|
|
5295
5390
|
this.unauthorizedCallbacks = /* @__PURE__ */ new Set();
|
|
5391
|
+
this.isRefreshing = false;
|
|
5392
|
+
this.refreshSubscribers = [];
|
|
5296
5393
|
this.config = config;
|
|
5297
5394
|
this.axiosInstance = axios_default.create({
|
|
5298
5395
|
baseURL: config.baseURL?.replace(/\/$/, "") || "",
|
|
@@ -5333,18 +5430,54 @@ var HttpService = class HttpService {
|
|
|
5333
5430
|
}, (error) => Promise.reject(error));
|
|
5334
5431
|
}
|
|
5335
5432
|
/**
|
|
5336
|
-
* 注册默认响应拦截器(处理 401
|
|
5433
|
+
* 注册默认响应拦截器(处理 401,支持自动重试)
|
|
5337
5434
|
*/
|
|
5338
5435
|
registerDefaultResponseInterceptor() {
|
|
5339
|
-
this.axiosInstance.interceptors.response.use((response) => response, (error) => {
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5436
|
+
this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
|
|
5437
|
+
const originalRequest = error.config;
|
|
5438
|
+
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
|
|
5439
|
+
if (originalRequest.url?.includes("/console/accounts")) {
|
|
5440
|
+
console.warn("[HttpService] Unauthorized 401 on refresh endpoint, not retrying");
|
|
5441
|
+
return Promise.reject(error);
|
|
5442
|
+
}
|
|
5443
|
+
console.warn("[HttpService] Unauthorized 401, attempting token refresh and retry");
|
|
5444
|
+
originalRequest._retry = true;
|
|
5445
|
+
if (this.isRefreshing) return new Promise((resolve, reject) => {
|
|
5446
|
+
this.refreshSubscribers.push((success) => {
|
|
5447
|
+
if (success) this.axiosInstance.request(originalRequest).then(resolve).catch(reject);
|
|
5448
|
+
else reject(error);
|
|
5449
|
+
});
|
|
5450
|
+
});
|
|
5451
|
+
this.isRefreshing = true;
|
|
5452
|
+
try {
|
|
5453
|
+
await this.triggerUnauthorizedCallbacks();
|
|
5454
|
+
this.onRefreshSuccess();
|
|
5455
|
+
return this.axiosInstance.request(originalRequest);
|
|
5456
|
+
} catch (refreshError) {
|
|
5457
|
+
this.onRefreshFailure();
|
|
5458
|
+
return Promise.reject(error);
|
|
5459
|
+
} finally {
|
|
5460
|
+
this.isRefreshing = false;
|
|
5461
|
+
}
|
|
5343
5462
|
}
|
|
5344
5463
|
return Promise.reject(error);
|
|
5345
5464
|
});
|
|
5346
5465
|
}
|
|
5347
5466
|
/**
|
|
5467
|
+
* token 刷新成功,通知所有等待的请求
|
|
5468
|
+
*/
|
|
5469
|
+
onRefreshSuccess() {
|
|
5470
|
+
this.refreshSubscribers.forEach((callback) => callback(true));
|
|
5471
|
+
this.refreshSubscribers = [];
|
|
5472
|
+
}
|
|
5473
|
+
/**
|
|
5474
|
+
* token 刷新失败,通知所有等待的请求
|
|
5475
|
+
*/
|
|
5476
|
+
onRefreshFailure() {
|
|
5477
|
+
this.refreshSubscribers.forEach((callback) => callback(false));
|
|
5478
|
+
this.refreshSubscribers = [];
|
|
5479
|
+
}
|
|
5480
|
+
/**
|
|
5348
5481
|
* 注册请求拦截器
|
|
5349
5482
|
* @param onFulfilled 请求成功拦截器
|
|
5350
5483
|
* @param onRejected 请求失败拦截器
|
|
@@ -5421,16 +5554,18 @@ var HttpService = class HttpService {
|
|
|
5421
5554
|
this.unauthorizedCallbacks.delete(callback);
|
|
5422
5555
|
}
|
|
5423
5556
|
/**
|
|
5424
|
-
* 触发所有 401
|
|
5557
|
+
* 触发所有 401 回调并等待完成
|
|
5558
|
+
* @returns Promise,等待所有回调完成
|
|
5559
|
+
* @throws 如果任何回调失败,则抛出错误
|
|
5425
5560
|
*/
|
|
5426
|
-
triggerUnauthorizedCallbacks() {
|
|
5427
|
-
this.unauthorizedCallbacks
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
}
|
|
5561
|
+
async triggerUnauthorizedCallbacks() {
|
|
5562
|
+
const callbacks = Array.from(this.unauthorizedCallbacks);
|
|
5563
|
+
const failedResults = (await Promise.allSettled(callbacks.map((callback) => callback()))).filter((r) => r.status === "rejected");
|
|
5564
|
+
if (failedResults.length > 0) {
|
|
5565
|
+
const errors = failedResults.map((r) => r.reason);
|
|
5566
|
+
console.error("[HttpService] Some unauthorized callbacks failed:", errors);
|
|
5567
|
+
throw errors[0];
|
|
5568
|
+
}
|
|
5434
5569
|
}
|
|
5435
5570
|
/**
|
|
5436
5571
|
* 更新 authToken
|
|
@@ -5496,6 +5631,14 @@ var HttpService = class HttpService {
|
|
|
5496
5631
|
return (await this.axiosInstance.put(url, data, config)).data;
|
|
5497
5632
|
}
|
|
5498
5633
|
/**
|
|
5634
|
+
* 通用请求方法
|
|
5635
|
+
* @param config axios 请求配置
|
|
5636
|
+
* @returns 原始 AxiosResponse
|
|
5637
|
+
*/
|
|
5638
|
+
async request(config) {
|
|
5639
|
+
return this.axiosInstance.request(config);
|
|
5640
|
+
}
|
|
5641
|
+
/**
|
|
5499
5642
|
* 获取原始 axios 实例(用于高级场景)
|
|
5500
5643
|
*/
|
|
5501
5644
|
getAxiosInstance() {
|
|
@@ -5689,6 +5832,109 @@ const accountService = new AccountService();
|
|
|
5689
5832
|
*/
|
|
5690
5833
|
if (typeof window !== "undefined") window.__genieAccountService = accountService;
|
|
5691
5834
|
|
|
5835
|
+
//#endregion
|
|
5836
|
+
//#region ../agent-provider/src/common/utils/lru-cache.ts
|
|
5837
|
+
/**
|
|
5838
|
+
* LRU (Least Recently Used) Cache
|
|
5839
|
+
* 当缓存达到容量上限时,自动淘汰最久未使用的数据
|
|
5840
|
+
*
|
|
5841
|
+
* @template K - Key 类型
|
|
5842
|
+
* @template V - Value 类型
|
|
5843
|
+
*/
|
|
5844
|
+
var LRUCache = class {
|
|
5845
|
+
/**
|
|
5846
|
+
* 创建 LRU 缓存实例
|
|
5847
|
+
* @param capacity - 缓存容量上限
|
|
5848
|
+
*/
|
|
5849
|
+
constructor(capacity) {
|
|
5850
|
+
if (capacity <= 0) throw new Error("Cache capacity must be greater than 0");
|
|
5851
|
+
this.capacity = capacity;
|
|
5852
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
5853
|
+
}
|
|
5854
|
+
/**
|
|
5855
|
+
* 获取缓存值
|
|
5856
|
+
* @param key - 键
|
|
5857
|
+
* @returns 值,如果不存在返回 undefined
|
|
5858
|
+
*/
|
|
5859
|
+
get(key) {
|
|
5860
|
+
if (!this.cache.has(key)) return;
|
|
5861
|
+
const value = this.cache.get(key);
|
|
5862
|
+
this.cache.delete(key);
|
|
5863
|
+
this.cache.set(key, value);
|
|
5864
|
+
return value;
|
|
5865
|
+
}
|
|
5866
|
+
/**
|
|
5867
|
+
* 设置缓存值
|
|
5868
|
+
* @param key - 键
|
|
5869
|
+
* @param value - 值
|
|
5870
|
+
*/
|
|
5871
|
+
set(key, value) {
|
|
5872
|
+
if (this.cache.has(key)) this.cache.delete(key);
|
|
5873
|
+
else if (this.cache.size >= this.capacity) {
|
|
5874
|
+
const firstKey = this.cache.keys().next().value;
|
|
5875
|
+
this.cache.delete(firstKey);
|
|
5876
|
+
}
|
|
5877
|
+
this.cache.set(key, value);
|
|
5878
|
+
}
|
|
5879
|
+
/**
|
|
5880
|
+
* 检查 key 是否存在
|
|
5881
|
+
* @param key - 键
|
|
5882
|
+
* @returns 是否存在
|
|
5883
|
+
*/
|
|
5884
|
+
has(key) {
|
|
5885
|
+
return this.cache.has(key);
|
|
5886
|
+
}
|
|
5887
|
+
/**
|
|
5888
|
+
* 删除指定 key
|
|
5889
|
+
* @param key - 键
|
|
5890
|
+
* @returns 是否删除成功
|
|
5891
|
+
*/
|
|
5892
|
+
delete(key) {
|
|
5893
|
+
return this.cache.delete(key);
|
|
5894
|
+
}
|
|
5895
|
+
/**
|
|
5896
|
+
* 清空缓存
|
|
5897
|
+
*/
|
|
5898
|
+
clear() {
|
|
5899
|
+
this.cache.clear();
|
|
5900
|
+
}
|
|
5901
|
+
/**
|
|
5902
|
+
* 获取当前缓存大小
|
|
5903
|
+
* @returns 当前缓存的元素数量
|
|
5904
|
+
*/
|
|
5905
|
+
get size() {
|
|
5906
|
+
return this.cache.size;
|
|
5907
|
+
}
|
|
5908
|
+
/**
|
|
5909
|
+
* 获取缓存容量
|
|
5910
|
+
* @returns 缓存容量上限
|
|
5911
|
+
*/
|
|
5912
|
+
get maxSize() {
|
|
5913
|
+
return this.capacity;
|
|
5914
|
+
}
|
|
5915
|
+
/**
|
|
5916
|
+
* 获取所有 key
|
|
5917
|
+
* @returns key 数组
|
|
5918
|
+
*/
|
|
5919
|
+
keys() {
|
|
5920
|
+
return Array.from(this.cache.keys());
|
|
5921
|
+
}
|
|
5922
|
+
/**
|
|
5923
|
+
* 获取所有 value
|
|
5924
|
+
* @returns value 数组
|
|
5925
|
+
*/
|
|
5926
|
+
values() {
|
|
5927
|
+
return Array.from(this.cache.values());
|
|
5928
|
+
}
|
|
5929
|
+
/**
|
|
5930
|
+
* 遍历缓存
|
|
5931
|
+
* @param callback - 回调函数
|
|
5932
|
+
*/
|
|
5933
|
+
forEach(callback) {
|
|
5934
|
+
this.cache.forEach((value, key) => callback(value, key));
|
|
5935
|
+
}
|
|
5936
|
+
};
|
|
5937
|
+
|
|
5692
5938
|
//#endregion
|
|
5693
5939
|
//#region ../agent-provider/src/common/utils/concurrency.ts
|
|
5694
5940
|
/**
|
|
@@ -5790,20 +6036,32 @@ var CosUploadService = class {
|
|
|
5790
6036
|
* 上传单个文件到 COS
|
|
5791
6037
|
*
|
|
5792
6038
|
* @param file - 要上传的文件
|
|
6039
|
+
* @param abortSignal - 可选的 AbortSignal,用于取消上传
|
|
5793
6040
|
* @returns 上传结果,包含访问 URL 或错误信息
|
|
5794
6041
|
*/
|
|
5795
|
-
async uploadFile(file) {
|
|
6042
|
+
async uploadFile(file, abortSignal) {
|
|
5796
6043
|
const filename = file.name;
|
|
5797
6044
|
this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);
|
|
5798
6045
|
try {
|
|
6046
|
+
if (abortSignal?.aborted) return {
|
|
6047
|
+
success: false,
|
|
6048
|
+
error: "Upload cancelled",
|
|
6049
|
+
aborted: true
|
|
6050
|
+
};
|
|
5799
6051
|
const objectKey = this.generateObjectKey(filename);
|
|
5800
6052
|
this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);
|
|
5801
6053
|
const presignedItem = (await this.getPresignedUrls([objectKey])).items[0];
|
|
5802
6054
|
if (!presignedItem) throw new Error("No presigned URL item returned");
|
|
6055
|
+
if (abortSignal?.aborted) return {
|
|
6056
|
+
success: false,
|
|
6057
|
+
error: "Upload cancelled",
|
|
6058
|
+
aborted: true
|
|
6059
|
+
};
|
|
5803
6060
|
const uploadResponse = await fetch(presignedItem.upload_url, {
|
|
5804
6061
|
method: "PUT",
|
|
5805
6062
|
body: file,
|
|
5806
|
-
headers: { "Content-Type": file.type || "application/octet-stream" }
|
|
6063
|
+
headers: { "Content-Type": file.type || "application/octet-stream" },
|
|
6064
|
+
signal: abortSignal
|
|
5807
6065
|
});
|
|
5808
6066
|
if (!uploadResponse.ok) {
|
|
5809
6067
|
const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
|
|
@@ -5817,6 +6075,11 @@ var CosUploadService = class {
|
|
|
5817
6075
|
objectKey
|
|
5818
6076
|
};
|
|
5819
6077
|
} catch (error) {
|
|
6078
|
+
if (error instanceof Error && error.name === "AbortError") return {
|
|
6079
|
+
success: false,
|
|
6080
|
+
error: "Upload cancelled",
|
|
6081
|
+
aborted: true
|
|
6082
|
+
};
|
|
5820
6083
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
5821
6084
|
this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);
|
|
5822
6085
|
return {
|
|
@@ -5831,14 +6094,25 @@ var CosUploadService = class {
|
|
|
5831
6094
|
* 使用并发控制,限制同时上传的文件数量
|
|
5832
6095
|
*
|
|
5833
6096
|
* @param files - 要上传的文件数组
|
|
6097
|
+
* @param abortSignal - 可选的 AbortSignal,用于取消上传
|
|
5834
6098
|
* @returns 所有文件的上传结果
|
|
5835
6099
|
*/
|
|
5836
|
-
async uploadFiles(files) {
|
|
6100
|
+
async uploadFiles(files, abortSignal) {
|
|
5837
6101
|
if (files.length === 0) return {
|
|
5838
6102
|
success: true,
|
|
5839
6103
|
urls: [],
|
|
5840
6104
|
results: []
|
|
5841
6105
|
};
|
|
6106
|
+
if (abortSignal?.aborted) return {
|
|
6107
|
+
success: false,
|
|
6108
|
+
error: "Upload cancelled",
|
|
6109
|
+
aborted: true,
|
|
6110
|
+
results: files.map(() => ({
|
|
6111
|
+
success: false,
|
|
6112
|
+
error: "Upload cancelled",
|
|
6113
|
+
aborted: true
|
|
6114
|
+
}))
|
|
6115
|
+
};
|
|
5842
6116
|
this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s) with concurrency ${this.uploadConcurrency}`);
|
|
5843
6117
|
try {
|
|
5844
6118
|
const fileInfos = files.map((file) => ({
|
|
@@ -5850,6 +6124,12 @@ var CosUploadService = class {
|
|
|
5850
6124
|
this.logger?.debug(`[CosUploadService] Got ${presignedResponse.items.length} presigned URLs`);
|
|
5851
6125
|
if (presignedResponse.items.length !== fileInfos.length) throw new Error(`Expected ${fileInfos.length} presigned URLs, got ${presignedResponse.items.length}`);
|
|
5852
6126
|
const results = (await runWithConcurrencySettled(fileInfos.map(({ file }, index) => async () => {
|
|
6127
|
+
if (abortSignal?.aborted) return {
|
|
6128
|
+
success: false,
|
|
6129
|
+
error: "Upload cancelled",
|
|
6130
|
+
aborted: true,
|
|
6131
|
+
objectKey: fileInfos[index].objectKey
|
|
6132
|
+
};
|
|
5853
6133
|
const presignedItem = presignedResponse.items[index];
|
|
5854
6134
|
if (!presignedItem) return {
|
|
5855
6135
|
success: false,
|
|
@@ -5860,7 +6140,8 @@ var CosUploadService = class {
|
|
|
5860
6140
|
const uploadResponse = await fetch(presignedItem.upload_url, {
|
|
5861
6141
|
method: "PUT",
|
|
5862
6142
|
body: file,
|
|
5863
|
-
headers: { "Content-Type": file.type || "application/octet-stream" }
|
|
6143
|
+
headers: { "Content-Type": file.type || "application/octet-stream" },
|
|
6144
|
+
signal: abortSignal
|
|
5864
6145
|
});
|
|
5865
6146
|
if (!uploadResponse.ok) {
|
|
5866
6147
|
const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
|
|
@@ -5877,6 +6158,12 @@ var CosUploadService = class {
|
|
|
5877
6158
|
objectKey: presignedItem.object_key
|
|
5878
6159
|
};
|
|
5879
6160
|
} catch (error) {
|
|
6161
|
+
if (error instanceof Error && error.name === "AbortError") return {
|
|
6162
|
+
success: false,
|
|
6163
|
+
error: "Upload cancelled",
|
|
6164
|
+
aborted: true,
|
|
6165
|
+
objectKey: presignedItem.object_key
|
|
6166
|
+
};
|
|
5880
6167
|
return {
|
|
5881
6168
|
success: false,
|
|
5882
6169
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
@@ -5924,91 +6211,6 @@ var CosUploadService = class {
|
|
|
5924
6211
|
}
|
|
5925
6212
|
};
|
|
5926
6213
|
|
|
5927
|
-
//#endregion
|
|
5928
|
-
//#region ../agent-provider/src/common/providers/cloud-agent-provider/e2b-filesystem.ts
|
|
5929
|
-
/**
|
|
5930
|
-
* E2B Filesystem Implementation
|
|
5931
|
-
*
|
|
5932
|
-
* Provides FilesResource implementation using E2B Sandbox SDK.
|
|
5933
|
-
* Directly uses e2b SDK types.
|
|
5934
|
-
*
|
|
5935
|
-
* @see https://e2b.dev/docs/filesystem/read-write
|
|
5936
|
-
* @see https://e2b.dev/docs/filesystem/watch
|
|
5937
|
-
*/
|
|
5938
|
-
/**
|
|
5939
|
-
* E2B Filesystem Implementation
|
|
5940
|
-
*
|
|
5941
|
-
* Wraps E2B Sandbox SDK's filesystem operations to implement FilesResource interface.
|
|
5942
|
-
*
|
|
5943
|
-
* @example
|
|
5944
|
-
* ```typescript
|
|
5945
|
-
* const fs = await E2BFilesystem.connect({
|
|
5946
|
-
* sandboxId: 'sandbox-123',
|
|
5947
|
-
* apiKey: 'e2b_xxx'
|
|
5948
|
-
* });
|
|
5949
|
-
*
|
|
5950
|
-
* // Read/write files
|
|
5951
|
-
* await fs.write('/test.txt', 'Hello World');
|
|
5952
|
-
* const content = await fs.read('/test.txt');
|
|
5953
|
-
*
|
|
5954
|
-
* // Watch for changes
|
|
5955
|
-
* const handle = await fs.watchDir('/workspace', (event) => {
|
|
5956
|
-
* console.log('File changed:', event);
|
|
5957
|
-
* });
|
|
5958
|
-
* ```
|
|
5959
|
-
*/
|
|
5960
|
-
var E2BFilesystem = class E2BFilesystem {
|
|
5961
|
-
constructor(sandbox) {
|
|
5962
|
-
this.sandbox = sandbox;
|
|
5963
|
-
}
|
|
5964
|
-
/**
|
|
5965
|
-
* Connect to an E2B Sandbox and create filesystem instance
|
|
5966
|
-
*/
|
|
5967
|
-
static async connect(info) {
|
|
5968
|
-
return new E2BFilesystem(await Sandbox.connect(info.sandboxId, {
|
|
5969
|
-
domain: info.domain,
|
|
5970
|
-
apiUrl: info.apiUrl,
|
|
5971
|
-
requestTimeoutMs: info.requestTimeoutMs,
|
|
5972
|
-
debug: info.debug,
|
|
5973
|
-
headers: info.headers
|
|
5974
|
-
}));
|
|
5975
|
-
}
|
|
5976
|
-
/**
|
|
5977
|
-
* Get the underlying E2B Sandbox instance
|
|
5978
|
-
*/
|
|
5979
|
-
getSandbox() {
|
|
5980
|
-
return this.sandbox;
|
|
5981
|
-
}
|
|
5982
|
-
read(path, opts) {
|
|
5983
|
-
return this.sandbox.files.read(path, opts);
|
|
5984
|
-
}
|
|
5985
|
-
write(pathOrFiles, dataOrOpts, opts) {
|
|
5986
|
-
if (Array.isArray(pathOrFiles)) return this.sandbox.files.write(pathOrFiles, dataOrOpts);
|
|
5987
|
-
return this.sandbox.files.write(pathOrFiles, dataOrOpts, opts);
|
|
5988
|
-
}
|
|
5989
|
-
async list(path, opts) {
|
|
5990
|
-
return this.sandbox.files.list(path, opts);
|
|
5991
|
-
}
|
|
5992
|
-
async exists(path, opts) {
|
|
5993
|
-
return this.sandbox.files.exists(path, opts);
|
|
5994
|
-
}
|
|
5995
|
-
async makeDir(path, opts) {
|
|
5996
|
-
return this.sandbox.files.makeDir(path, opts);
|
|
5997
|
-
}
|
|
5998
|
-
async remove(path, opts) {
|
|
5999
|
-
return this.sandbox.files.remove(path, opts);
|
|
6000
|
-
}
|
|
6001
|
-
async rename(oldPath, newPath, opts) {
|
|
6002
|
-
return this.sandbox.files.rename(oldPath, newPath, opts);
|
|
6003
|
-
}
|
|
6004
|
-
async getInfo(path, opts) {
|
|
6005
|
-
return this.sandbox.files.getInfo(path, opts);
|
|
6006
|
-
}
|
|
6007
|
-
async watchDir(path, onEvent, opts) {
|
|
6008
|
-
return this.sandbox.files.watchDir(path, onEvent, opts);
|
|
6009
|
-
}
|
|
6010
|
-
};
|
|
6011
|
-
|
|
6012
6214
|
//#endregion
|
|
6013
6215
|
//#region ../agent-provider/src/common/providers/cloud-agent-provider/cloud-provider.ts
|
|
6014
6216
|
/**
|
|
@@ -6157,8 +6359,11 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6157
6359
|
this.filesystemCache = /* @__PURE__ */ new Map();
|
|
6158
6360
|
this.connectionCache = /* @__PURE__ */ new Map();
|
|
6159
6361
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
6362
|
+
this.productConfigCache = null;
|
|
6160
6363
|
this.options = options;
|
|
6161
6364
|
this.logger = options.logger;
|
|
6365
|
+
this.marketplaceCache = new LRUCache(200);
|
|
6366
|
+
this.pluginCache = new LRUCache(2e3);
|
|
6162
6367
|
if (options.endpoint) httpService.setBaseURL(options.endpoint);
|
|
6163
6368
|
if (options.authToken) httpService.setAuthToken(options.authToken);
|
|
6164
6369
|
if (options.headers && Object.keys(options.headers).length > 0) this.requestInterceptorId = httpService.registerRequestInterceptor((config) => {
|
|
@@ -6209,7 +6414,19 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6209
6414
|
const cached = this.filesystemCache.get(agentId);
|
|
6210
6415
|
if (cached) return cached;
|
|
6211
6416
|
const info = await this.getSandboxInfo(agentId);
|
|
6212
|
-
|
|
6417
|
+
let e2bFilesystem;
|
|
6418
|
+
if (this.options.filesystemFactory) e2bFilesystem = await this.options.filesystemFactory(info);
|
|
6419
|
+
else {
|
|
6420
|
+
const { E2BFilesystem } = await import("./e2b-filesystem-DWj9UkV8.mjs");
|
|
6421
|
+
e2bFilesystem = await E2BFilesystem.connect(info);
|
|
6422
|
+
}
|
|
6423
|
+
if (e2bFilesystem.setReconnectFn) e2bFilesystem.setReconnectFn(async () => {
|
|
6424
|
+
this.logger?.debug(`Reconnecting E2B sandbox for agent: ${agentId}`);
|
|
6425
|
+
const newInfo = await this.getSandboxInfo(agentId);
|
|
6426
|
+
this.logger?.debug(`E2B sandbox reconnected for agent: ${agentId}`);
|
|
6427
|
+
return newInfo;
|
|
6428
|
+
});
|
|
6429
|
+
const filesystem = createAgentFilesystem(e2bFilesystem);
|
|
6213
6430
|
this.filesystemCache.set(agentId, filesystem);
|
|
6214
6431
|
this.logger?.debug(`Created filesystem for agent: ${agentId}`);
|
|
6215
6432
|
return filesystem;
|
|
@@ -6277,15 +6494,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6277
6494
|
const url = this.buildGetUrl("/console/as/conversations/", params);
|
|
6278
6495
|
const apiResponse = await httpService.get(url);
|
|
6279
6496
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
6280
|
-
const agents = apiResponse.data.conversations.map((a) => this.toAgentState(a));
|
|
6281
|
-
const pagination = apiResponse.data.pagination;
|
|
6282
|
-
console.log("[CloudAgentProvider] API response:", {
|
|
6283
|
-
agentsCount: agents.length,
|
|
6284
|
-
pagination
|
|
6285
|
-
});
|
|
6286
6497
|
return {
|
|
6287
|
-
agents,
|
|
6288
|
-
pagination
|
|
6498
|
+
agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
|
|
6499
|
+
pagination: apiResponse.data.pagination
|
|
6289
6500
|
};
|
|
6290
6501
|
} catch (error) {
|
|
6291
6502
|
this.logger?.error("Failed to list agents:", error);
|
|
@@ -6295,15 +6506,17 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6295
6506
|
/**
|
|
6296
6507
|
* Create a new conversation
|
|
6297
6508
|
* POST {endpoint}/console/as/conversations
|
|
6298
|
-
* @param params -
|
|
6509
|
+
* @param params - Session params containing cwd and optional configuration
|
|
6299
6510
|
*/
|
|
6300
6511
|
async create(params) {
|
|
6301
6512
|
try {
|
|
6302
|
-
const
|
|
6513
|
+
const { options = {} } = params;
|
|
6514
|
+
const codebuddyMeta = options._meta?.["codebuddy.ai"];
|
|
6515
|
+
const tagsObj = options.tags || codebuddyMeta?.tags;
|
|
6303
6516
|
const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
|
|
6304
6517
|
const createPayload = {
|
|
6305
|
-
prompt: "",
|
|
6306
|
-
model: "deepseek-r1",
|
|
6518
|
+
prompt: (options.prompt || "").slice(0, 100),
|
|
6519
|
+
model: options.model || "deepseek-r1",
|
|
6307
6520
|
...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
|
|
6308
6521
|
};
|
|
6309
6522
|
console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
|
|
@@ -6357,7 +6570,14 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6357
6570
|
} catch (error) {
|
|
6358
6571
|
this.logger?.debug(`Failed to fetch conversation details for ${agentId}:`, error);
|
|
6359
6572
|
}
|
|
6360
|
-
|
|
6573
|
+
const existingConnection = this.connectionCache.get(endpoint);
|
|
6574
|
+
if (existingConnection) {
|
|
6575
|
+
this.connectionCache.delete(endpoint);
|
|
6576
|
+
existingConnection.removeAllListeners();
|
|
6577
|
+
existingConnection.disconnect().catch((err) => {
|
|
6578
|
+
this.logger?.debug("Failed to disconnect old connection:", err);
|
|
6579
|
+
});
|
|
6580
|
+
}
|
|
6361
6581
|
const clientCapabilities = {
|
|
6362
6582
|
...this.options.clientCapabilities,
|
|
6363
6583
|
_meta: {
|
|
@@ -6477,6 +6697,35 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6477
6697
|
}
|
|
6478
6698
|
}
|
|
6479
6699
|
/**
|
|
6700
|
+
* Update conversation status by ID
|
|
6701
|
+
* POST {endpoint}/console/as/conversations/{agentId}
|
|
6702
|
+
*
|
|
6703
|
+
* @param agentId - Conversation ID to update
|
|
6704
|
+
* @param status - New status for the conversation
|
|
6705
|
+
* @returns PatchConversationResponse containing the updated conversation ID
|
|
6706
|
+
*
|
|
6707
|
+
* @example
|
|
6708
|
+
* ```typescript
|
|
6709
|
+
* const result = await provider.updateStatus('agent-123', 'completed');
|
|
6710
|
+
* console.log('Updated conversation status:', result.id);
|
|
6711
|
+
* ```
|
|
6712
|
+
*/
|
|
6713
|
+
async updateStatus(agentId, status) {
|
|
6714
|
+
try {
|
|
6715
|
+
const body = { status };
|
|
6716
|
+
const apiResponse = await httpService.post(`/console/as/conversations/${agentId}`, body);
|
|
6717
|
+
if (!apiResponse.data) {
|
|
6718
|
+
this.logger?.info(`Updated conversation status: ${agentId} to "${status}"`);
|
|
6719
|
+
return { id: agentId };
|
|
6720
|
+
}
|
|
6721
|
+
this.logger?.info(`Updated conversation status: ${apiResponse.data.id} to "${status}"`);
|
|
6722
|
+
return apiResponse.data;
|
|
6723
|
+
} catch (error) {
|
|
6724
|
+
this.logger?.error(`Failed to update conversation status ${agentId}:`, error);
|
|
6725
|
+
throw error;
|
|
6726
|
+
}
|
|
6727
|
+
}
|
|
6728
|
+
/**
|
|
6480
6729
|
* Get available models from product configuration
|
|
6481
6730
|
*
|
|
6482
6731
|
* GET {endpoint}/console/enterprises/{personal|enterpriseId}/models?repos[]={repo}
|
|
@@ -6507,9 +6756,13 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6507
6756
|
this.logger?.warn("[CloudAgentProvider] No data in config response, returning empty models");
|
|
6508
6757
|
return [];
|
|
6509
6758
|
}
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6759
|
+
this.productConfigCache = apiResponse.data;
|
|
6760
|
+
const productConfig = apiResponse.data;
|
|
6761
|
+
const allModels = productConfig.models ?? [];
|
|
6762
|
+
const cliModelIds = (productConfig.agents ?? []).find((agent) => agent.name === "cli")?.models ?? [];
|
|
6763
|
+
const filteredModels = cliModelIds.length > 0 ? allModels.filter((model) => cliModelIds.includes(model.id)) : allModels;
|
|
6764
|
+
this.logger?.info(`[CloudAgentProvider] Retrieved ${filteredModels.length} models for cli agent (total: ${allModels.length})`);
|
|
6765
|
+
return filteredModels.map((model) => ({
|
|
6513
6766
|
id: model.id,
|
|
6514
6767
|
name: model.name ?? model.id,
|
|
6515
6768
|
description: model.description,
|
|
@@ -6531,6 +6784,43 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6531
6784
|
}
|
|
6532
6785
|
}
|
|
6533
6786
|
/**
|
|
6787
|
+
* 获取产品部署类型(从缓存)
|
|
6788
|
+
* 需要先调用 getModels() 初始化缓存
|
|
6789
|
+
*
|
|
6790
|
+
* @returns 部署类型:'SaaS' | 'Cloud-Hosted' | 'Self-Hosted',默认为 'SaaS'
|
|
6791
|
+
*/
|
|
6792
|
+
getDeploymentType() {
|
|
6793
|
+
return this.productConfigCache?.deploymentType ?? "SaaS";
|
|
6794
|
+
}
|
|
6795
|
+
/**
|
|
6796
|
+
* 获取 Credit 购买引导配置(从缓存)
|
|
6797
|
+
* 需要先调用 getModels() 初始化缓存
|
|
6798
|
+
*
|
|
6799
|
+
* @returns Credit 购买引导配置,key 为错误码。如果后端未返回,则使用默认配置
|
|
6800
|
+
*/
|
|
6801
|
+
getCreditPurchaseActions() {
|
|
6802
|
+
return this.productConfigCache?.config?.creditPurchaseActions ?? {
|
|
6803
|
+
"14018": {
|
|
6804
|
+
labelZh: "获取 Credits",
|
|
6805
|
+
labelEn: "Get credits",
|
|
6806
|
+
url: "https://www.codebuddy.cn/profile/plan",
|
|
6807
|
+
showButton: true
|
|
6808
|
+
},
|
|
6809
|
+
"6004": {
|
|
6810
|
+
labelZh: "升级专业版",
|
|
6811
|
+
labelEn: "Upgrade to Pro",
|
|
6812
|
+
url: "https://www.codebuddy.cn/profile/plan",
|
|
6813
|
+
showButton: true
|
|
6814
|
+
},
|
|
6815
|
+
"6005": {
|
|
6816
|
+
labelZh: "升级专业版",
|
|
6817
|
+
labelEn: "Upgrade to Pro",
|
|
6818
|
+
url: "https://www.codebuddy.cn/profile/plan",
|
|
6819
|
+
showButton: true
|
|
6820
|
+
}
|
|
6821
|
+
};
|
|
6822
|
+
}
|
|
6823
|
+
/**
|
|
6534
6824
|
* Generate a unique request ID
|
|
6535
6825
|
*/
|
|
6536
6826
|
generateRequestId() {
|
|
@@ -6613,7 +6903,7 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6613
6903
|
/**
|
|
6614
6904
|
* Upload files to cloud storage via COS presigned URL
|
|
6615
6905
|
*
|
|
6616
|
-
* @param params - files array (File objects in browser)
|
|
6906
|
+
* @param params - files array (File objects in browser), optional abortSignal
|
|
6617
6907
|
* @returns Response with corresponding cloud URLs
|
|
6618
6908
|
*/
|
|
6619
6909
|
async uploadFile(params) {
|
|
@@ -6623,12 +6913,13 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6623
6913
|
success: false,
|
|
6624
6914
|
error: "No valid File objects provided"
|
|
6625
6915
|
};
|
|
6626
|
-
const result = await this.cosUploadService.uploadFiles(files);
|
|
6916
|
+
const result = await this.cosUploadService.uploadFiles(files, params.abortSignal);
|
|
6627
6917
|
return {
|
|
6628
6918
|
success: result.success,
|
|
6629
6919
|
urls: result.urls,
|
|
6630
6920
|
expireSeconds: result.expireSeconds,
|
|
6631
|
-
error: result.error
|
|
6921
|
+
error: result.error,
|
|
6922
|
+
aborted: result.aborted
|
|
6632
6923
|
};
|
|
6633
6924
|
}
|
|
6634
6925
|
/**
|
|
@@ -6670,20 +6961,22 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6670
6961
|
}
|
|
6671
6962
|
/**
|
|
6672
6963
|
* 获取支持的场景列表
|
|
6673
|
-
* API 端点: GET /
|
|
6964
|
+
* API 端点: GET /v2/as/support/scenes (不鉴权)
|
|
6674
6965
|
* 用于 Welcome 页面的 QuickActions 快捷操作
|
|
6675
6966
|
*
|
|
6967
|
+
* @param locale - 可选,语言环境(如 'zh-CN', 'en-US'),用于获取对应语言的场景数据
|
|
6676
6968
|
* @returns Promise<SupportScene[]> 支持的场景列表
|
|
6677
6969
|
*/
|
|
6678
|
-
async getSupportScenes() {
|
|
6970
|
+
async getSupportScenes(locale) {
|
|
6679
6971
|
try {
|
|
6680
|
-
const
|
|
6972
|
+
const url = this.buildGetUrl("/v2/as/support/scenes", locale ? { locale } : void 0);
|
|
6973
|
+
const apiResponse = await httpService.get(url);
|
|
6681
6974
|
if (!apiResponse.data) {
|
|
6682
6975
|
this.logger?.warn("[CloudAgentProvider] No data in support scenes response");
|
|
6683
6976
|
return [];
|
|
6684
6977
|
}
|
|
6685
6978
|
const scenes = apiResponse.data.scenes || [];
|
|
6686
|
-
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes`);
|
|
6979
|
+
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes${locale ? ` for locale: ${locale}` : ""}`);
|
|
6687
6980
|
return scenes;
|
|
6688
6981
|
} catch (error) {
|
|
6689
6982
|
this.logger?.error("[CloudAgentProvider] Failed to get support scenes:", error);
|
|
@@ -6699,7 +6992,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6699
6992
|
type: "cloud",
|
|
6700
6993
|
status,
|
|
6701
6994
|
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
6702
|
-
|
|
6995
|
+
updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0,
|
|
6996
|
+
capabilities: this.options.clientCapabilities,
|
|
6997
|
+
isUserDefinedTitle: data.isUserDefinedTitle
|
|
6703
6998
|
};
|
|
6704
6999
|
}
|
|
6705
7000
|
/**
|
|
@@ -6715,58 +7010,501 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6715
7010
|
const queryString = searchParams.toString();
|
|
6716
7011
|
return queryString ? `${path}?${queryString}` : path;
|
|
6717
7012
|
}
|
|
6718
|
-
};
|
|
6719
|
-
|
|
6720
|
-
//#endregion
|
|
6721
|
-
//#region ../agent-provider/src/common/client/session.ts
|
|
6722
|
-
/**
|
|
6723
|
-
* ActiveSessionImpl - Implements the ActiveSession interface
|
|
6724
|
-
*
|
|
6725
|
-
* This class wraps an AgentConnection and provides the session-centric API.
|
|
6726
|
-
* It is created by SessionManager when creating or loading sessions.
|
|
6727
|
-
*
|
|
6728
|
-
* @example
|
|
6729
|
-
* ```typescript
|
|
6730
|
-
* // Created by client.sessions.new() or client.sessions.load()
|
|
6731
|
-
* const session = await client.sessions.new({ cwd: '/workspace' });
|
|
6732
|
-
*
|
|
6733
|
-
* // Access agent state
|
|
6734
|
-
* console.log(session.agentState.status);
|
|
6735
|
-
*
|
|
6736
|
-
* // Send prompt
|
|
6737
|
-
* const response = await session.prompts.send({ content: 'Hello!' });
|
|
6738
|
-
*
|
|
6739
|
-
* // Cleanup
|
|
6740
|
-
* session.disconnect();
|
|
6741
|
-
* ```
|
|
6742
|
-
*/
|
|
6743
|
-
var ActiveSessionImpl = class {
|
|
6744
7013
|
/**
|
|
6745
|
-
*
|
|
6746
|
-
*
|
|
6747
|
-
* @param sessionId - Session ID
|
|
6748
|
-
* @param agentId - Agent ID
|
|
6749
|
-
* @param connection - Already connected AgentConnection
|
|
6750
|
-
* @param options - Additional options
|
|
7014
|
+
* 获取已安装插件列表
|
|
7015
|
+
* GET /console/as/user/plugins/installed
|
|
6751
7016
|
*/
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
6766
|
-
|
|
7017
|
+
async getInstalledPlugins(forceRefresh) {
|
|
7018
|
+
try {
|
|
7019
|
+
const result = ((await httpService.get("/console/as/user/plugins/installed")).data?.plugins || []).map((p) => ({
|
|
7020
|
+
name: p.plugin_name,
|
|
7021
|
+
marketplaceName: p.marketplace_name,
|
|
7022
|
+
status: p.enabled ? "enabled" : "disabled",
|
|
7023
|
+
description: p.description,
|
|
7024
|
+
version: p.version,
|
|
7025
|
+
installScope: p.scope === "local" ? "project" : p.scope,
|
|
7026
|
+
installedScopes: [p.scope],
|
|
7027
|
+
installId: p.id
|
|
7028
|
+
}));
|
|
7029
|
+
result.forEach((plugin) => {
|
|
7030
|
+
this.pluginCache.set(plugin.name, plugin);
|
|
7031
|
+
});
|
|
7032
|
+
return result;
|
|
7033
|
+
} catch (error) {
|
|
7034
|
+
this.logger?.error("[CloudAgentProvider] getInstalledPlugins failed:", error);
|
|
7035
|
+
throw error;
|
|
7036
|
+
}
|
|
6767
7037
|
}
|
|
6768
7038
|
/**
|
|
6769
|
-
*
|
|
7039
|
+
* 安装插件
|
|
7040
|
+
* POST /console/as/user/plugins/install
|
|
7041
|
+
*
|
|
7042
|
+
* @param pluginNames - 插件名称数组
|
|
7043
|
+
* @param marketplaceNameOrId - 市场名称或 ID
|
|
7044
|
+
*/
|
|
7045
|
+
async installPlugins(pluginNames, marketplaceNameOrId, installScope, marketplaceSource, workspacePath) {
|
|
7046
|
+
try {
|
|
7047
|
+
const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
|
|
7048
|
+
if (!marketplaceId) return {
|
|
7049
|
+
success: false,
|
|
7050
|
+
error: `Marketplace not found: ${marketplaceNameOrId}`
|
|
7051
|
+
};
|
|
7052
|
+
const failed = (await Promise.allSettled(pluginNames.map((pluginName) => httpService.post("/console/as/user/plugins/install", {
|
|
7053
|
+
plugin_name: pluginName,
|
|
7054
|
+
marketplace_id: marketplaceId,
|
|
7055
|
+
version: "latest"
|
|
7056
|
+
})))).filter((r) => r.status === "rejected");
|
|
7057
|
+
if (failed.length > 0) {
|
|
7058
|
+
const errors = failed.map((r) => r.reason?.message || "Unknown error");
|
|
7059
|
+
return {
|
|
7060
|
+
success: false,
|
|
7061
|
+
error: `安装失败 ${failed.length} 个插件: ${errors.join(", ")}`
|
|
7062
|
+
};
|
|
7063
|
+
}
|
|
7064
|
+
return { success: true };
|
|
7065
|
+
} catch (error) {
|
|
7066
|
+
return {
|
|
7067
|
+
success: false,
|
|
7068
|
+
error: this.extractErrorMessage(error)
|
|
7069
|
+
};
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
/**
|
|
7073
|
+
* 卸载插件
|
|
7074
|
+
* POST /console/as/user/plugins/installed/:id/uninstall
|
|
7075
|
+
*
|
|
7076
|
+
* 完整链路:
|
|
7077
|
+
* CloudAgentProvider.uninstallPlugin()
|
|
7078
|
+
* -> HTTP POST /console/as/user/plugins/installed/:id/uninstall
|
|
7079
|
+
* -> agentserver: PluginInstallService.Uninstall()
|
|
7080
|
+
* -> 软删除 DB + 异步同步到活跃沙箱
|
|
7081
|
+
*
|
|
7082
|
+
* @param pluginName - 插件名称
|
|
7083
|
+
* @param marketplaceName - 市场名称(用于标识唯一插件)
|
|
7084
|
+
* @param scope - 卸载范围 ('user' | 'project' | 'project-local')
|
|
7085
|
+
*/
|
|
7086
|
+
async uninstallPlugin(pluginName, marketplaceName, scope) {
|
|
7087
|
+
try {
|
|
7088
|
+
const installId = await this.findPluginInstallId(pluginName);
|
|
7089
|
+
if (!installId) return {
|
|
7090
|
+
success: false,
|
|
7091
|
+
error: `Plugin not found or not installed: ${pluginName}`
|
|
7092
|
+
};
|
|
7093
|
+
await httpService.post(`/console/as/user/plugins/installed/${installId}/uninstall`);
|
|
7094
|
+
return { success: true };
|
|
7095
|
+
} catch (error) {
|
|
7096
|
+
return {
|
|
7097
|
+
success: false,
|
|
7098
|
+
error: this.extractErrorMessage(error)
|
|
7099
|
+
};
|
|
7100
|
+
}
|
|
7101
|
+
}
|
|
7102
|
+
/**
|
|
7103
|
+
* 获取插件市场列表
|
|
7104
|
+
* GET /console/as/marketplace/sources
|
|
7105
|
+
*/
|
|
7106
|
+
async getPluginMarketplaces(forceRefresh) {
|
|
7107
|
+
try {
|
|
7108
|
+
const result = ((await httpService.get("/console/as/marketplace/sources")).data?.sources || []).map((src) => ({
|
|
7109
|
+
id: src.id,
|
|
7110
|
+
name: src.name,
|
|
7111
|
+
type: this.mapSourceType(src.source_type),
|
|
7112
|
+
source: { url: src.url },
|
|
7113
|
+
description: src.name,
|
|
7114
|
+
isBuiltin: src.is_default
|
|
7115
|
+
}));
|
|
7116
|
+
result.forEach((m) => {
|
|
7117
|
+
const marketplaceInfo = {
|
|
7118
|
+
id: m.id,
|
|
7119
|
+
name: m.name
|
|
7120
|
+
};
|
|
7121
|
+
this.marketplaceCache.set(m.name, marketplaceInfo);
|
|
7122
|
+
this.marketplaceCache.set(m.id, marketplaceInfo);
|
|
7123
|
+
});
|
|
7124
|
+
return result;
|
|
7125
|
+
} catch (error) {
|
|
7126
|
+
this.logger?.error("[CloudAgentProvider] getPluginMarketplaces failed:", error);
|
|
7127
|
+
throw error;
|
|
7128
|
+
}
|
|
7129
|
+
}
|
|
7130
|
+
/**
|
|
7131
|
+
* 获取市场下的插件列表
|
|
7132
|
+
* - 有 searchText: GET /console/as/marketplace/plugins/search (跨所有市场搜索)
|
|
7133
|
+
* - 无 searchText: GET /console/as/marketplace/plugins (指定市场)
|
|
7134
|
+
*
|
|
7135
|
+
* @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
|
|
7136
|
+
* @param forceRefresh - 是否强制刷新
|
|
7137
|
+
* @param searchText - 搜索关键字(如果提供,则跨所有市场搜索)
|
|
7138
|
+
*/
|
|
7139
|
+
async getMarketplacePlugins(marketplaceNameOrId, forceRefresh, searchText) {
|
|
7140
|
+
try {
|
|
7141
|
+
if (searchText) return ((await httpService.get("/console/as/marketplace/plugins/search", { params: {
|
|
7142
|
+
q: searchText,
|
|
7143
|
+
page: 1,
|
|
7144
|
+
page_size: 100
|
|
7145
|
+
} })).data?.plugins || []).map((p) => this.mapPluginData(p));
|
|
7146
|
+
const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
|
|
7147
|
+
if (!sourceId) {
|
|
7148
|
+
this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
|
|
7149
|
+
return [];
|
|
7150
|
+
}
|
|
7151
|
+
const params = {
|
|
7152
|
+
source_id: sourceId,
|
|
7153
|
+
page: 1,
|
|
7154
|
+
page_size: 100
|
|
7155
|
+
};
|
|
7156
|
+
return ((await httpService.get("/console/as/marketplace/plugins", { params })).data?.plugins || []).map((p) => this.mapPluginData(p));
|
|
7157
|
+
} catch (error) {
|
|
7158
|
+
this.logger?.error("[CloudAgentProvider] getMarketplacePlugins failed:", error);
|
|
7159
|
+
throw error;
|
|
7160
|
+
}
|
|
7161
|
+
}
|
|
7162
|
+
/**
|
|
7163
|
+
* 获取插件详情
|
|
7164
|
+
* GET /console/as/marketplace/plugins/:name/detail
|
|
7165
|
+
*
|
|
7166
|
+
* @param pluginName - 插件名称
|
|
7167
|
+
* @param marketplaceNameOrId - 市场名称或 ID(优先使用 ID,如果是名称则从缓存查询 ID)
|
|
7168
|
+
*/
|
|
7169
|
+
async getPluginDetail(pluginName, marketplaceNameOrId) {
|
|
7170
|
+
try {
|
|
7171
|
+
const sourceId = await this.findMarketplaceId(marketplaceNameOrId);
|
|
7172
|
+
if (!sourceId) {
|
|
7173
|
+
this.logger?.warn(`[CloudAgentProvider] Marketplace not found: ${marketplaceNameOrId}`);
|
|
7174
|
+
return null;
|
|
7175
|
+
}
|
|
7176
|
+
const p = (await httpService.get(`/console/as/marketplace/plugins/${pluginName}/detail`, { params: { source_id: sourceId } })).data?.plugin;
|
|
7177
|
+
if (!p) return null;
|
|
7178
|
+
const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
|
|
7179
|
+
const tags = p.tags ? JSON.parse(p.tags) : [];
|
|
7180
|
+
return {
|
|
7181
|
+
name: p.name,
|
|
7182
|
+
marketplaceName: p.marketplace_name,
|
|
7183
|
+
description: p.description,
|
|
7184
|
+
version: p.version,
|
|
7185
|
+
iconUrl: p.icon_url,
|
|
7186
|
+
tags,
|
|
7187
|
+
installed: p.installed,
|
|
7188
|
+
status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
|
|
7189
|
+
readme: p.readme,
|
|
7190
|
+
author: p.author,
|
|
7191
|
+
homepage: p.homepage,
|
|
7192
|
+
repositoryUrl: p.repository_url,
|
|
7193
|
+
license: p.license,
|
|
7194
|
+
...capabilities
|
|
7195
|
+
};
|
|
7196
|
+
} catch (error) {
|
|
7197
|
+
this.logger?.error("[CloudAgentProvider] getPluginDetail failed:", error);
|
|
7198
|
+
throw error;
|
|
7199
|
+
}
|
|
7200
|
+
}
|
|
7201
|
+
/**
|
|
7202
|
+
* 添加插件市场
|
|
7203
|
+
* POST /console/as/marketplace/sources
|
|
7204
|
+
*/
|
|
7205
|
+
async addPluginMarketplace(sourceUrl, name) {
|
|
7206
|
+
try {
|
|
7207
|
+
const body = {
|
|
7208
|
+
source_type: sourceUrl.startsWith("http") ? "url" : "github",
|
|
7209
|
+
url: sourceUrl,
|
|
7210
|
+
name: name || sourceUrl
|
|
7211
|
+
};
|
|
7212
|
+
const sourceData = (await httpService.post("/console/as/marketplace/sources", body)).data?.source;
|
|
7213
|
+
if (!sourceData) throw new Error("Invalid response from server");
|
|
7214
|
+
const marketplaceInfo = {
|
|
7215
|
+
id: sourceData.id,
|
|
7216
|
+
name: sourceData.name
|
|
7217
|
+
};
|
|
7218
|
+
this.marketplaceCache.set(sourceData.name, marketplaceInfo);
|
|
7219
|
+
this.marketplaceCache.set(sourceData.id, marketplaceInfo);
|
|
7220
|
+
return {
|
|
7221
|
+
success: true,
|
|
7222
|
+
marketplace: {
|
|
7223
|
+
id: sourceData.id,
|
|
7224
|
+
name: sourceData.name,
|
|
7225
|
+
type: this.mapSourceType(sourceData.source_type),
|
|
7226
|
+
source: { url: sourceData.url },
|
|
7227
|
+
isBuiltin: sourceData.is_default
|
|
7228
|
+
}
|
|
7229
|
+
};
|
|
7230
|
+
} catch (error) {
|
|
7231
|
+
return {
|
|
7232
|
+
success: false,
|
|
7233
|
+
error: this.extractErrorMessage(error)
|
|
7234
|
+
};
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
7237
|
+
/**
|
|
7238
|
+
* 删除插件市场
|
|
7239
|
+
* POST /console/as/marketplace/sources/:id/delete
|
|
7240
|
+
*/
|
|
7241
|
+
async removePluginMarketplace(marketplaceNameOrId) {
|
|
7242
|
+
try {
|
|
7243
|
+
const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
|
|
7244
|
+
if (!marketplaceId) return {
|
|
7245
|
+
success: false,
|
|
7246
|
+
error: `Marketplace not found: ${marketplaceNameOrId}`
|
|
7247
|
+
};
|
|
7248
|
+
await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/delete`, {});
|
|
7249
|
+
return { success: true };
|
|
7250
|
+
} catch (error) {
|
|
7251
|
+
return {
|
|
7252
|
+
success: false,
|
|
7253
|
+
error: this.extractErrorMessage(error)
|
|
7254
|
+
};
|
|
7255
|
+
}
|
|
7256
|
+
}
|
|
7257
|
+
/**
|
|
7258
|
+
* 刷新插件市场
|
|
7259
|
+
* POST /console/as/marketplace/sources/:id/check-updates
|
|
7260
|
+
*/
|
|
7261
|
+
async refreshPluginMarketplace(marketplaceNameOrId) {
|
|
7262
|
+
try {
|
|
7263
|
+
const marketplaceId = await this.findMarketplaceId(marketplaceNameOrId);
|
|
7264
|
+
if (!marketplaceId) return {
|
|
7265
|
+
success: false,
|
|
7266
|
+
error: `Marketplace not found: ${marketplaceNameOrId}`
|
|
7267
|
+
};
|
|
7268
|
+
return {
|
|
7269
|
+
success: true,
|
|
7270
|
+
plugins: (await httpService.post(`/console/as/marketplace/sources/${marketplaceId}/check-updates`, {})).data?.updated_plugins || []
|
|
7271
|
+
};
|
|
7272
|
+
} catch (error) {
|
|
7273
|
+
return {
|
|
7274
|
+
success: false,
|
|
7275
|
+
error: this.extractErrorMessage(error)
|
|
7276
|
+
};
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
/**
|
|
7280
|
+
* 批量切换插件启用/禁用状态
|
|
7281
|
+
* POST /console/as/user/plugins/installed/:id/toggle
|
|
7282
|
+
*/
|
|
7283
|
+
async batchTogglePlugins(request) {
|
|
7284
|
+
try {
|
|
7285
|
+
const results = await Promise.allSettled(request.items.map(async (item) => {
|
|
7286
|
+
const installId = await this.findPluginInstallId(item.pluginName);
|
|
7287
|
+
if (!installId) throw new Error(`Plugin not found or not installed: ${item.pluginName}`);
|
|
7288
|
+
const enabled = item.operation === "enable";
|
|
7289
|
+
await httpService.post(`/console/as/user/plugins/installed/${installId}/toggle`, { enabled });
|
|
7290
|
+
return item;
|
|
7291
|
+
}));
|
|
7292
|
+
const succeededPlugins = [];
|
|
7293
|
+
const failedPlugins = [];
|
|
7294
|
+
results.forEach((r, i) => {
|
|
7295
|
+
const item = request.items[i];
|
|
7296
|
+
if (r.status === "fulfilled") succeededPlugins.push(item);
|
|
7297
|
+
else failedPlugins.push({
|
|
7298
|
+
...item,
|
|
7299
|
+
error: r.reason?.message || "Unknown error"
|
|
7300
|
+
});
|
|
7301
|
+
});
|
|
7302
|
+
return {
|
|
7303
|
+
success: failedPlugins.length === 0,
|
|
7304
|
+
succeededPlugins,
|
|
7305
|
+
failedPlugins
|
|
7306
|
+
};
|
|
7307
|
+
} catch (error) {
|
|
7308
|
+
return {
|
|
7309
|
+
success: false,
|
|
7310
|
+
succeededPlugins: [],
|
|
7311
|
+
failedPlugins: request.items.map((item) => ({
|
|
7312
|
+
...item,
|
|
7313
|
+
error: this.extractErrorMessage(error)
|
|
7314
|
+
}))
|
|
7315
|
+
};
|
|
7316
|
+
}
|
|
7317
|
+
}
|
|
7318
|
+
/**
|
|
7319
|
+
* 将后端插件数据映射为前端格式
|
|
7320
|
+
*/
|
|
7321
|
+
mapPluginData(p) {
|
|
7322
|
+
const capabilities = p.capabilities ? this.parseCapabilities(p.capabilities) : {};
|
|
7323
|
+
let tags = [];
|
|
7324
|
+
if (p.tags) {
|
|
7325
|
+
if (Array.isArray(p.tags)) tags = p.tags;
|
|
7326
|
+
else if (typeof p.tags === "string") try {
|
|
7327
|
+
const parsed = JSON.parse(p.tags);
|
|
7328
|
+
tags = Array.isArray(parsed) ? parsed : [parsed];
|
|
7329
|
+
} catch {
|
|
7330
|
+
tags = p.tags.split(",").map((t) => t.trim()).filter((t) => t);
|
|
7331
|
+
}
|
|
7332
|
+
}
|
|
7333
|
+
return {
|
|
7334
|
+
name: p.name,
|
|
7335
|
+
marketplaceName: p.marketplace_name,
|
|
7336
|
+
description: p.description,
|
|
7337
|
+
version: p.version,
|
|
7338
|
+
iconUrl: p.icon_url,
|
|
7339
|
+
tags,
|
|
7340
|
+
installed: p.installed,
|
|
7341
|
+
status: p.enabled ? "enabled" : p.installed ? "disabled" : "not-installed",
|
|
7342
|
+
installedScopes: p.installed ? [p.installed_scope] : [],
|
|
7343
|
+
...capabilities
|
|
7344
|
+
};
|
|
7345
|
+
}
|
|
7346
|
+
/**
|
|
7347
|
+
* 从缓存中查找插件的 install_id
|
|
7348
|
+
* 如果缓存未命中,则调用 API 获取并缓存
|
|
7349
|
+
*
|
|
7350
|
+
* @param pluginName - 插件名称
|
|
7351
|
+
* @returns install_id 或 null
|
|
7352
|
+
*/
|
|
7353
|
+
async findPluginInstallId(pluginName) {
|
|
7354
|
+
const cached = this.pluginCache.get(pluginName);
|
|
7355
|
+
if (cached) return cached.installId;
|
|
7356
|
+
await this.getInstalledPlugins();
|
|
7357
|
+
return this.pluginCache.get(pluginName)?.installId || null;
|
|
7358
|
+
}
|
|
7359
|
+
/**
|
|
7360
|
+
* 从缓存中查找 marketplace ID
|
|
7361
|
+
* 如果缓存未命中,则调用 API 获取并缓存
|
|
7362
|
+
*/
|
|
7363
|
+
async findMarketplaceId(nameOrId) {
|
|
7364
|
+
const cached = this.marketplaceCache.get(nameOrId);
|
|
7365
|
+
if (cached) return cached.id;
|
|
7366
|
+
await this.getPluginMarketplaces();
|
|
7367
|
+
return this.marketplaceCache.get(nameOrId)?.id || null;
|
|
7368
|
+
}
|
|
7369
|
+
/**
|
|
7370
|
+
* 提取 API 错误信息
|
|
7371
|
+
* 从 AxiosError 中提取详细的错误信息,包括 HTTP 状态码、错误码和错误消息
|
|
7372
|
+
*/
|
|
7373
|
+
extractErrorMessage(error) {
|
|
7374
|
+
if (error instanceof AxiosError) {
|
|
7375
|
+
const status = error.response?.status;
|
|
7376
|
+
const apiResponse = error.response?.data;
|
|
7377
|
+
const parts = [];
|
|
7378
|
+
if (status) parts.push(`HTTP ${status}`);
|
|
7379
|
+
if (apiResponse?.code) parts.push(`Code ${apiResponse.code}`);
|
|
7380
|
+
if (apiResponse?.msg) parts.push(apiResponse.msg);
|
|
7381
|
+
else if (error.message) parts.push(error.message);
|
|
7382
|
+
const errorMessage = parts.join(" - ");
|
|
7383
|
+
this.logger?.error("[CloudAgentProvider] API Error:", {
|
|
7384
|
+
status,
|
|
7385
|
+
code: apiResponse?.code,
|
|
7386
|
+
msg: apiResponse?.msg,
|
|
7387
|
+
requestId: apiResponse?.requestId,
|
|
7388
|
+
url: error.config?.url,
|
|
7389
|
+
method: error.config?.method
|
|
7390
|
+
});
|
|
7391
|
+
return errorMessage;
|
|
7392
|
+
}
|
|
7393
|
+
if (error instanceof Error) return error.message;
|
|
7394
|
+
return "Unknown error";
|
|
7395
|
+
}
|
|
7396
|
+
/**
|
|
7397
|
+
* 映射后端 source_type 到前端类型
|
|
7398
|
+
*/
|
|
7399
|
+
mapSourceType(sourceType) {
|
|
7400
|
+
switch (sourceType) {
|
|
7401
|
+
case "github": return "github";
|
|
7402
|
+
case "official": return "custom";
|
|
7403
|
+
default: return "custom";
|
|
7404
|
+
}
|
|
7405
|
+
}
|
|
7406
|
+
/**
|
|
7407
|
+
* 解析 capabilities JSON 字符串
|
|
7408
|
+
*/
|
|
7409
|
+
parseCapabilities(capabilitiesStr) {
|
|
7410
|
+
try {
|
|
7411
|
+
const cap = JSON.parse(capabilitiesStr);
|
|
7412
|
+
return {
|
|
7413
|
+
commands: cap.commands,
|
|
7414
|
+
skills: cap.skills,
|
|
7415
|
+
mcpServers: cap.mcp,
|
|
7416
|
+
agents: cap.agents,
|
|
7417
|
+
hooks: cap.hooks,
|
|
7418
|
+
rules: cap.rules
|
|
7419
|
+
};
|
|
7420
|
+
} catch {
|
|
7421
|
+
return {};
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
/**
|
|
7425
|
+
* 上报 telemetry 事件(Cloud 模式)
|
|
7426
|
+
* 通过 HTTP POST 发送到 /v2/report
|
|
7427
|
+
* 注入用户信息和浏览器环境等公共字段
|
|
7428
|
+
*/
|
|
7429
|
+
async reportTelemetry(eventName, payload) {
|
|
7430
|
+
try {
|
|
7431
|
+
const account = accountService.getAccount();
|
|
7432
|
+
const commonFields = {};
|
|
7433
|
+
if (account) {
|
|
7434
|
+
commonFields.userId = account.uid;
|
|
7435
|
+
commonFields.userNickname = account.nickname;
|
|
7436
|
+
if (account.enterpriseId) commonFields.enterpriseId = account.enterpriseId;
|
|
7437
|
+
if (account.enterpriseUserName) commonFields.username = account.enterpriseUserName;
|
|
7438
|
+
}
|
|
7439
|
+
if (typeof navigator !== "undefined") {
|
|
7440
|
+
commonFields.userAgent = navigator.userAgent;
|
|
7441
|
+
commonFields.os = navigator.platform;
|
|
7442
|
+
}
|
|
7443
|
+
const events = [{
|
|
7444
|
+
eventCode: eventName,
|
|
7445
|
+
timestamp: Date.now(),
|
|
7446
|
+
reportDelay: 0,
|
|
7447
|
+
...commonFields,
|
|
7448
|
+
...payload
|
|
7449
|
+
}];
|
|
7450
|
+
await httpService.post("/v2/report", events);
|
|
7451
|
+
} catch (error) {
|
|
7452
|
+
this.logger?.warn("reportTelemetry() failed:", error);
|
|
7453
|
+
}
|
|
7454
|
+
}
|
|
7455
|
+
};
|
|
7456
|
+
|
|
7457
|
+
//#endregion
|
|
7458
|
+
//#region ../agent-provider/src/common/client/session.ts
|
|
7459
|
+
/**
|
|
7460
|
+
* ActiveSessionImpl - Implements the ActiveSession interface
|
|
7461
|
+
*
|
|
7462
|
+
* This class wraps an AgentConnection and provides the session-centric API.
|
|
7463
|
+
* It is created by SessionManager when creating or loading sessions.
|
|
7464
|
+
*
|
|
7465
|
+
* @example
|
|
7466
|
+
* ```typescript
|
|
7467
|
+
* // Created by client.sessions.new() or client.sessions.load()
|
|
7468
|
+
* const session = await client.sessions.new({ cwd: '/workspace' });
|
|
7469
|
+
*
|
|
7470
|
+
* // Access agent state
|
|
7471
|
+
* console.log(session.agentState.status);
|
|
7472
|
+
*
|
|
7473
|
+
* // Send prompt
|
|
7474
|
+
* const response = await session.prompts.send({ content: 'Hello!' });
|
|
7475
|
+
*
|
|
7476
|
+
* // Cleanup
|
|
7477
|
+
* session.disconnect();
|
|
7478
|
+
* ```
|
|
7479
|
+
*/
|
|
7480
|
+
var ActiveSessionImpl = class {
|
|
7481
|
+
/**
|
|
7482
|
+
* Create an ActiveSessionImpl instance
|
|
7483
|
+
*
|
|
7484
|
+
* @param sessionId - Session ID
|
|
7485
|
+
* @param agentId - Agent ID
|
|
7486
|
+
* @param connection - Already connected AgentConnection
|
|
7487
|
+
* @param options - Additional options
|
|
7488
|
+
*/
|
|
7489
|
+
constructor(sessionId, agentId, connection, options = {}) {
|
|
7490
|
+
this._availableCommands = [];
|
|
7491
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
7492
|
+
this.onceListeners = /* @__PURE__ */ new Map();
|
|
7493
|
+
this.connectionListeners = [];
|
|
7494
|
+
this._id = sessionId;
|
|
7495
|
+
this._agentId = agentId;
|
|
7496
|
+
this.connection = connection;
|
|
7497
|
+
this.logger = options.logger;
|
|
7498
|
+
this._getFilesystem = options.getFilesystem;
|
|
7499
|
+
this._connectionInfo = options.connectionInfo;
|
|
7500
|
+
this.setupConnectionEvents(connection);
|
|
7501
|
+
this.agent = this.createAgentOperations();
|
|
7502
|
+
this.prompts = this.createPromptsResource();
|
|
7503
|
+
this.artifacts = this.createArtifactsResource();
|
|
7504
|
+
this.files = this.createFilesResource();
|
|
7505
|
+
}
|
|
7506
|
+
/**
|
|
7507
|
+
* Session ID
|
|
6770
7508
|
*/
|
|
6771
7509
|
get id() {
|
|
6772
7510
|
return this._id;
|
|
@@ -6778,6 +7516,18 @@ var ActiveSessionImpl = class {
|
|
|
6778
7516
|
return this._agentId;
|
|
6779
7517
|
}
|
|
6780
7518
|
/**
|
|
7519
|
+
* Actual workspace path (set from newSession response _meta)
|
|
7520
|
+
*/
|
|
7521
|
+
get cwd() {
|
|
7522
|
+
return this._cwd;
|
|
7523
|
+
}
|
|
7524
|
+
/**
|
|
7525
|
+
* Set actual workspace path (called by SessionManager after createSession)
|
|
7526
|
+
*/
|
|
7527
|
+
setCwd(cwd) {
|
|
7528
|
+
this._cwd = cwd;
|
|
7529
|
+
}
|
|
7530
|
+
/**
|
|
6781
7531
|
* Agent state (live connection state)
|
|
6782
7532
|
* Returns LocalAgentState or CloudAgentState based on transport type
|
|
6783
7533
|
*/
|
|
@@ -6971,10 +7721,10 @@ var ActiveSessionImpl = class {
|
|
|
6971
7721
|
return this.connection.cancelQuestion(toolCallId, reason);
|
|
6972
7722
|
}
|
|
6973
7723
|
/**
|
|
6974
|
-
* Callback for tool operations (skip
|
|
7724
|
+
* Callback for tool operations (approve / skip / cancel)
|
|
6975
7725
|
* @param toolCallId Tool call ID
|
|
6976
7726
|
* @param toolName Tool name
|
|
6977
|
-
* @param action Action to perform ('skip'
|
|
7727
|
+
* @param action Action to perform ('approve' / 'skip' / 'cancel')
|
|
6978
7728
|
*/
|
|
6979
7729
|
async toolCallback(toolCallId, toolName, action) {
|
|
6980
7730
|
return await this.getConnectionOrThrow().toolCallback(this._id, toolCallId, toolName, action);
|
|
@@ -7018,6 +7768,7 @@ var ActiveSessionImpl = class {
|
|
|
7018
7768
|
* ```
|
|
7019
7769
|
*/
|
|
7020
7770
|
async setSessionModel(modelId) {
|
|
7771
|
+
this._currentModelId = modelId;
|
|
7021
7772
|
await this.getConnectionOrThrow().setSessionModel(this._id, modelId);
|
|
7022
7773
|
}
|
|
7023
7774
|
/**
|
|
@@ -7095,11 +7846,23 @@ var ActiveSessionImpl = class {
|
|
|
7095
7846
|
* Disconnect from the session/agent
|
|
7096
7847
|
*/
|
|
7097
7848
|
disconnect() {
|
|
7849
|
+
this.removeConnectionListeners();
|
|
7098
7850
|
this.connection.disconnect();
|
|
7099
7851
|
this.removeAllListeners();
|
|
7100
7852
|
this.logger?.info(`Session ${this._id}: Disconnected`);
|
|
7101
7853
|
}
|
|
7102
7854
|
/**
|
|
7855
|
+
* Detach the session from connection events without disconnecting the connection.
|
|
7856
|
+
* This should be called when the session is being replaced but the connection is shared.
|
|
7857
|
+
* Unlike disconnect(), this only removes event listeners without closing the connection.
|
|
7858
|
+
*/
|
|
7859
|
+
detach() {
|
|
7860
|
+
this.logger?.info(`Session ${this._id}: Detaching from connection events`);
|
|
7861
|
+
this.removeConnectionListeners();
|
|
7862
|
+
this.removeAllListeners();
|
|
7863
|
+
this.logger?.info(`Session ${this._id}: Detached successfully`);
|
|
7864
|
+
}
|
|
7865
|
+
/**
|
|
7103
7866
|
* Symbol.dispose for 'using' keyword support
|
|
7104
7867
|
* Automatically disconnects and cleans up when session goes out of scope
|
|
7105
7868
|
*
|
|
@@ -7118,60 +7881,85 @@ var ActiveSessionImpl = class {
|
|
|
7118
7881
|
if (!this.connection.isInitialized) throw new Error(`Session ${this._id}: Connection not initialized.`);
|
|
7119
7882
|
return this.connection;
|
|
7120
7883
|
}
|
|
7884
|
+
/**
|
|
7885
|
+
* 在 connection 上注册 listener 并保存引用,便于 disconnect 时移除
|
|
7886
|
+
*/
|
|
7887
|
+
addConnectionListener(connection, event, listener) {
|
|
7888
|
+
connection.on(event, listener);
|
|
7889
|
+
this.connectionListeners.push({
|
|
7890
|
+
event,
|
|
7891
|
+
listener
|
|
7892
|
+
});
|
|
7893
|
+
}
|
|
7894
|
+
/**
|
|
7895
|
+
* 从 connection 上移除所有本 session 注册的 listener
|
|
7896
|
+
*/
|
|
7897
|
+
removeConnectionListeners() {
|
|
7898
|
+
for (const { event, listener } of this.connectionListeners) this.connection.off(event, listener);
|
|
7899
|
+
this.connectionListeners = [];
|
|
7900
|
+
}
|
|
7121
7901
|
setupConnectionEvents(connection) {
|
|
7122
|
-
|
|
7902
|
+
this.addConnectionListener(connection, "connected", () => {
|
|
7123
7903
|
this.emit("connected", void 0);
|
|
7124
7904
|
});
|
|
7125
|
-
|
|
7905
|
+
this.addConnectionListener(connection, "disconnected", () => {
|
|
7126
7906
|
this.emit("disconnected", void 0);
|
|
7127
7907
|
});
|
|
7128
|
-
|
|
7908
|
+
this.addConnectionListener(connection, "error", (error) => {
|
|
7129
7909
|
this.emit("error", error);
|
|
7130
7910
|
});
|
|
7131
|
-
|
|
7911
|
+
this.addConnectionListener(connection, "sessionUpdate", (update) => {
|
|
7912
|
+
const notificationSessionId = update?.sessionId;
|
|
7913
|
+
if (notificationSessionId && notificationSessionId !== this._id) {
|
|
7914
|
+
console.log(`[RT-DEBUG][AgentMgr:Session] sessionUpdate SKIPPED: notifSessionId mismatch, notif=${notificationSessionId?.substring(0, 8)}, my=${this._id?.substring(0, 8)}`);
|
|
7915
|
+
return;
|
|
7916
|
+
}
|
|
7132
7917
|
this.emit("sessionUpdate", update);
|
|
7133
7918
|
});
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
artifactUri: artifact.uri,
|
|
7137
|
-
artifactType: artifact.type
|
|
7138
|
-
});
|
|
7919
|
+
this.addConnectionListener(connection, "artifactCreated", (artifact) => {
|
|
7920
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7139
7921
|
this.emit("artifactCreated", artifact);
|
|
7140
7922
|
});
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
artifactUri: artifact.uri,
|
|
7144
|
-
artifactType: artifact.type
|
|
7145
|
-
});
|
|
7923
|
+
this.addConnectionListener(connection, "artifactUpdated", (artifact) => {
|
|
7924
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7146
7925
|
this.emit("artifactUpdated", artifact);
|
|
7147
7926
|
});
|
|
7148
|
-
|
|
7149
|
-
|
|
7927
|
+
this.addConnectionListener(connection, "artifactDeleted", (artifact) => {
|
|
7928
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7150
7929
|
this.emit("artifactDeleted", artifact);
|
|
7151
7930
|
});
|
|
7152
|
-
|
|
7931
|
+
this.addConnectionListener(connection, "permissionRequest", (request) => {
|
|
7153
7932
|
this.emit("permissionRequest", request);
|
|
7154
7933
|
});
|
|
7155
|
-
|
|
7934
|
+
this.addConnectionListener(connection, "questionRequest", (request) => {
|
|
7156
7935
|
this.emit("questionRequest", request);
|
|
7157
7936
|
});
|
|
7158
|
-
|
|
7937
|
+
this.addConnectionListener(connection, "questionCancelled", () => {
|
|
7159
7938
|
this.prompts.cancel();
|
|
7160
7939
|
});
|
|
7161
|
-
|
|
7940
|
+
this.addConnectionListener(connection, "usageUpdate", (usage) => {
|
|
7162
7941
|
this.emit("usageUpdate", usage);
|
|
7163
7942
|
});
|
|
7164
|
-
|
|
7943
|
+
this.addConnectionListener(connection, "checkpointCreated", (checkpoint) => {
|
|
7944
|
+
const originSessionId = checkpoint.__sessionId;
|
|
7945
|
+
if (originSessionId && originSessionId !== this._id) return;
|
|
7165
7946
|
this.emit("checkpointCreated", checkpoint);
|
|
7166
7947
|
});
|
|
7167
|
-
|
|
7948
|
+
this.addConnectionListener(connection, "checkpointUpdated", (checkpoint) => {
|
|
7949
|
+
const originSessionId = checkpoint.__sessionId;
|
|
7950
|
+
if (originSessionId && originSessionId !== this._id) return;
|
|
7168
7951
|
this.emit("checkpointUpdated", checkpoint);
|
|
7169
7952
|
});
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7953
|
+
this.addConnectionListener(connection, "command", (command) => {
|
|
7954
|
+
const originSessionId = command.__sessionId;
|
|
7955
|
+
if (originSessionId && originSessionId !== this._id) {
|
|
7956
|
+
console.log("[Session] Command not forwarded:", {
|
|
7957
|
+
command,
|
|
7958
|
+
originSessionId,
|
|
7959
|
+
sessionId: this._id
|
|
7960
|
+
});
|
|
7961
|
+
return;
|
|
7962
|
+
}
|
|
7175
7963
|
this.emit("command", command);
|
|
7176
7964
|
});
|
|
7177
7965
|
}
|
|
@@ -7181,6 +7969,15 @@ var ActiveSessionImpl = class {
|
|
|
7181
7969
|
_meta: response._meta ?? void 0
|
|
7182
7970
|
};
|
|
7183
7971
|
}
|
|
7972
|
+
/**
|
|
7973
|
+
* 判断 artifact 是否应该转发给当前 session
|
|
7974
|
+
* 所有类型的 artifact 都按 __sessionId 严格隔离
|
|
7975
|
+
*/
|
|
7976
|
+
shouldForwardArtifact(artifact) {
|
|
7977
|
+
const originSessionId = artifact.__sessionId;
|
|
7978
|
+
if (!originSessionId || originSessionId !== this._id) return false;
|
|
7979
|
+
return true;
|
|
7980
|
+
}
|
|
7184
7981
|
};
|
|
7185
7982
|
|
|
7186
7983
|
//#endregion
|
|
@@ -7213,6 +8010,7 @@ var ActiveSessionImpl = class {
|
|
|
7213
8010
|
*/
|
|
7214
8011
|
var SessionManager = class {
|
|
7215
8012
|
constructor(options) {
|
|
8013
|
+
this.pendingConnections = /* @__PURE__ */ new Map();
|
|
7216
8014
|
this.provider = options.provider;
|
|
7217
8015
|
this.logger = options.logger;
|
|
7218
8016
|
}
|
|
@@ -7233,9 +8031,11 @@ var SessionManager = class {
|
|
|
7233
8031
|
name: agent.name,
|
|
7234
8032
|
status: agent.status,
|
|
7235
8033
|
createdAt: agent.createdAt,
|
|
8034
|
+
updatedAt: agent.updatedAt,
|
|
7236
8035
|
lastActivityAt: agent.updatedAt,
|
|
7237
8036
|
cwd: agent.type === "local" ? agent.cwd : void 0,
|
|
7238
|
-
isPlayground: agent.isPlayground
|
|
8037
|
+
isPlayground: agent.isPlayground,
|
|
8038
|
+
isUserDefinedTitle: agent.isUserDefinedTitle
|
|
7239
8039
|
}));
|
|
7240
8040
|
console.log("[SessionManager] Returning sessions:", {
|
|
7241
8041
|
count: sessions.length,
|
|
@@ -7262,14 +8062,92 @@ var SessionManager = class {
|
|
|
7262
8062
|
if (this.provider.create) {
|
|
7263
8063
|
agentId = await this.provider.create(params);
|
|
7264
8064
|
this.logger?.debug(`Created new agent: ${agentId}`);
|
|
8065
|
+
if (params.options?.onSessionPrepared) {
|
|
8066
|
+
const initialPrompt = params.options?.prompt;
|
|
8067
|
+
const initialTitle = initialPrompt?.slice(0, 50) || "";
|
|
8068
|
+
params.options.onSessionPrepared({
|
|
8069
|
+
id: agentId,
|
|
8070
|
+
agentId,
|
|
8071
|
+
name: initialTitle + (initialPrompt && initialPrompt.length > 50 ? "..." : ""),
|
|
8072
|
+
status: "connecting",
|
|
8073
|
+
cwd: params.cwd || "",
|
|
8074
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
8075
|
+
});
|
|
8076
|
+
this.logger?.debug(`Called onSessionPrepared for: ${agentId}`);
|
|
8077
|
+
}
|
|
7265
8078
|
} else throw new Error("Provider does not support creating agents. Use sessions.load() with an existing sessionId.");
|
|
7266
8079
|
const connection = await this.provider.connect(agentId);
|
|
7267
8080
|
this.logger?.debug(`Connected to agent: ${agentId}`);
|
|
8081
|
+
let response;
|
|
8082
|
+
try {
|
|
8083
|
+
response = await connection.createSession({
|
|
8084
|
+
_meta: params.options?._meta,
|
|
8085
|
+
cwd: params.cwd,
|
|
8086
|
+
mcpServers: params.options?.mcpServers
|
|
8087
|
+
});
|
|
8088
|
+
} catch (err) {
|
|
8089
|
+
this.pendingConnections.set(agentId, connection);
|
|
8090
|
+
this.logger?.debug(`Cached pending connection for agent: ${agentId}`);
|
|
8091
|
+
if (err instanceof SessionError) throw new SessionError(err.message, err.sessionId, agentId, err.cause instanceof Error ? err.cause : void 0);
|
|
8092
|
+
const cause = err instanceof Error ? err : new Error(String(err));
|
|
8093
|
+
throw new SessionError(`Failed to create session: ${cause.message}`, void 0, agentId, cause);
|
|
8094
|
+
}
|
|
8095
|
+
return this.buildActiveSession(response, agentId, connection, params);
|
|
8096
|
+
}
|
|
8097
|
+
/**
|
|
8098
|
+
* Retry creating a session after initial session/new request failed.
|
|
8099
|
+
*
|
|
8100
|
+
* Use this when `sessions.create()` fails at the `session/new` step
|
|
8101
|
+
* (after agent creation and connection establishment succeeded).
|
|
8102
|
+
* The caller retrieves `agentId` from the thrown `SessionError.agentId`,
|
|
8103
|
+
* then calls this method to re-attempt only the `session/new` request
|
|
8104
|
+
* while reusing the already-initialized connection (no re-connect).
|
|
8105
|
+
*
|
|
8106
|
+
* @experimental This API is subject to change
|
|
8107
|
+
*
|
|
8108
|
+
* @param agentId - Agent ID from the failed SessionError
|
|
8109
|
+
* @param params - Original create session params (cwd, mcpServers, etc.)
|
|
8110
|
+
* @returns ActiveSession on success
|
|
8111
|
+
* @throws SessionError if session/new fails again
|
|
8112
|
+
*
|
|
8113
|
+
* @example
|
|
8114
|
+
* ```typescript
|
|
8115
|
+
* try {
|
|
8116
|
+
* const session = await client.sessions.create({ cwd: '/workspace' });
|
|
8117
|
+
* } catch (err) {
|
|
8118
|
+
* if (err instanceof SessionError && err.agentId) {
|
|
8119
|
+
* // Retry with custom logic
|
|
8120
|
+
* for (let i = 0; i < 3; i++) {
|
|
8121
|
+
* try {
|
|
8122
|
+
* const session = await client.sessions.retryNewSession(err.agentId, { cwd: '/workspace' });
|
|
8123
|
+
* break; // success
|
|
8124
|
+
* } catch (retryErr) {
|
|
8125
|
+
* await new Promise(r => setTimeout(r, 1000 * (i + 1)));
|
|
8126
|
+
* }
|
|
8127
|
+
* }
|
|
8128
|
+
* }
|
|
8129
|
+
* }
|
|
8130
|
+
* ```
|
|
8131
|
+
*/
|
|
8132
|
+
async retryNewSession(agentId, params) {
|
|
8133
|
+
this.logger?.info(`Retrying session/new for agent: ${agentId}`);
|
|
8134
|
+
const connection = this.pendingConnections.get(agentId);
|
|
8135
|
+
if (!connection) throw new SessionError(`No pending connection found for agent: ${agentId}. retryNewSession() can only be called after a failed sessions.create().`, void 0, agentId);
|
|
8136
|
+
this.logger?.debug(`Reusing cached connection for agent: ${agentId}`);
|
|
7268
8137
|
const response = await connection.createSession({
|
|
7269
|
-
_meta: params._meta,
|
|
8138
|
+
_meta: params.options?._meta,
|
|
7270
8139
|
cwd: params.cwd,
|
|
7271
|
-
mcpServers: params.mcpServers
|
|
8140
|
+
mcpServers: params.options?.mcpServers
|
|
7272
8141
|
});
|
|
8142
|
+
this.pendingConnections.delete(agentId);
|
|
8143
|
+
this.logger?.debug(`Cleared pending connection for agent: ${agentId}`);
|
|
8144
|
+
return this.buildActiveSession(response, agentId, connection, params);
|
|
8145
|
+
}
|
|
8146
|
+
/**
|
|
8147
|
+
* Build an ActiveSession from a NewSessionResponse.
|
|
8148
|
+
* Shared by createSession() and retryNewSession().
|
|
8149
|
+
*/
|
|
8150
|
+
buildActiveSession(response, agentId, connection, params) {
|
|
7273
8151
|
if (this.provider.registerSession) {
|
|
7274
8152
|
this.provider.registerSession(response.sessionId, agentId);
|
|
7275
8153
|
this.logger?.debug(`Registered session mapping: ${response.sessionId} → ${agentId}`);
|
|
@@ -7283,6 +8161,8 @@ var SessionManager = class {
|
|
|
7283
8161
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
7284
8162
|
const availableModels = this.extractAvailableModels(response);
|
|
7285
8163
|
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
8164
|
+
const responseCwd = response._meta?.["codebuddy.ai"]?.cwd;
|
|
8165
|
+
if (responseCwd) session.setCwd(responseCwd);
|
|
7286
8166
|
this.logger?.info(`Session created: ${response.sessionId}`);
|
|
7287
8167
|
return session;
|
|
7288
8168
|
}
|
|
@@ -7411,6 +8291,7 @@ var AgentClient = class {
|
|
|
7411
8291
|
return {
|
|
7412
8292
|
list: async (options) => this.sessionManager.listSessions(options),
|
|
7413
8293
|
create: async (params) => this.sessionManager.createSession(params),
|
|
8294
|
+
retryNewSession: async (agentId, params) => this.sessionManager.retryNewSession(agentId, params),
|
|
7414
8295
|
load: async (params) => {
|
|
7415
8296
|
console.log("[AgentClient] sessions.load called:", params.sessionId);
|
|
7416
8297
|
return this.sessionManager.loadSession(params);
|
|
@@ -7449,8 +8330,28 @@ var AgentClient = class {
|
|
|
7449
8330
|
throw error;
|
|
7450
8331
|
}
|
|
7451
8332
|
},
|
|
7452
|
-
|
|
7453
|
-
this.logger?.debug("AgentClient.sessions.
|
|
8333
|
+
updateStatus: async (sessionId, status) => {
|
|
8334
|
+
this.logger?.debug("AgentClient.sessions.updateStatus called", {
|
|
8335
|
+
sessionId,
|
|
8336
|
+
status
|
|
8337
|
+
});
|
|
8338
|
+
try {
|
|
8339
|
+
if (this.provider.updateStatus) {
|
|
8340
|
+
const result = await this.provider.updateStatus(sessionId, status);
|
|
8341
|
+
this.logger?.info("Session status updated successfully", {
|
|
8342
|
+
sessionId,
|
|
8343
|
+
status
|
|
8344
|
+
});
|
|
8345
|
+
return result;
|
|
8346
|
+
}
|
|
8347
|
+
throw new Error("Provider does not support updateStatus method");
|
|
8348
|
+
} catch (error) {
|
|
8349
|
+
this.logger?.error("Failed to update session status", error);
|
|
8350
|
+
throw error;
|
|
8351
|
+
}
|
|
8352
|
+
},
|
|
8353
|
+
move: async (sessionId) => {
|
|
8354
|
+
this.logger?.debug("AgentClient.sessions.move called", { sessionId });
|
|
7454
8355
|
try {
|
|
7455
8356
|
if (this.provider.move) {
|
|
7456
8357
|
const result = await this.provider.move(sessionId);
|
|
@@ -7481,6 +8382,16 @@ var AgentClient = class {
|
|
|
7481
8382
|
};
|
|
7482
8383
|
}
|
|
7483
8384
|
},
|
|
8385
|
+
requestYieldAfterCurrentStep: async (sessionId) => {
|
|
8386
|
+
try {
|
|
8387
|
+
if (this.provider?.requestYieldAfterCurrentStep) return await this.provider.requestYieldAfterCurrentStep(sessionId);
|
|
8388
|
+
this.logger?.warn("Provider does not support requestYieldAfterCurrentStep");
|
|
8389
|
+
return false;
|
|
8390
|
+
} catch (error) {
|
|
8391
|
+
this.logger?.error("Failed to request yield after current step", error);
|
|
8392
|
+
return false;
|
|
8393
|
+
}
|
|
8394
|
+
},
|
|
7484
8395
|
getCurrentWorkspaces: async (filter) => {
|
|
7485
8396
|
this.logger?.debug("AgentClient.sessions.getCurrentWorkspaces called", filter);
|
|
7486
8397
|
try {
|
|
@@ -7496,6 +8407,100 @@ var AgentClient = class {
|
|
|
7496
8407
|
return [];
|
|
7497
8408
|
}
|
|
7498
8409
|
},
|
|
8410
|
+
getAutomationSnapshot: async () => {
|
|
8411
|
+
try {
|
|
8412
|
+
if (this.provider?.getAutomationSnapshot) return await this.provider.getAutomationSnapshot();
|
|
8413
|
+
this.logger?.warn("Provider does not support getAutomationSnapshot");
|
|
8414
|
+
} catch (error) {
|
|
8415
|
+
this.logger?.error("Failed to get automation snapshot", error);
|
|
8416
|
+
}
|
|
8417
|
+
return {
|
|
8418
|
+
automations: [],
|
|
8419
|
+
inbox: [],
|
|
8420
|
+
runtimeState: {},
|
|
8421
|
+
updatedAt: Date.now()
|
|
8422
|
+
};
|
|
8423
|
+
},
|
|
8424
|
+
updateAutomation: async (payload) => {
|
|
8425
|
+
try {
|
|
8426
|
+
if (this.provider?.updateAutomation) return await this.provider.updateAutomation(payload);
|
|
8427
|
+
this.logger?.warn("Provider does not support updateAutomation");
|
|
8428
|
+
} catch (error) {
|
|
8429
|
+
this.logger?.error("Failed to update automation", error);
|
|
8430
|
+
return {
|
|
8431
|
+
success: false,
|
|
8432
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
8433
|
+
};
|
|
8434
|
+
}
|
|
8435
|
+
return {
|
|
8436
|
+
success: false,
|
|
8437
|
+
message: "Provider does not support updateAutomation"
|
|
8438
|
+
};
|
|
8439
|
+
},
|
|
8440
|
+
deleteAutomation: async (id) => {
|
|
8441
|
+
try {
|
|
8442
|
+
if (this.provider?.deleteAutomation) return await this.provider.deleteAutomation(id);
|
|
8443
|
+
this.logger?.warn("Provider does not support deleteAutomation");
|
|
8444
|
+
} catch (error) {
|
|
8445
|
+
this.logger?.error("Failed to delete automation", error);
|
|
8446
|
+
return {
|
|
8447
|
+
success: false,
|
|
8448
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
8449
|
+
};
|
|
8450
|
+
}
|
|
8451
|
+
return {
|
|
8452
|
+
success: false,
|
|
8453
|
+
message: "Provider does not support deleteAutomation"
|
|
8454
|
+
};
|
|
8455
|
+
},
|
|
8456
|
+
archiveAutomationInboxItem: async (itemId) => {
|
|
8457
|
+
try {
|
|
8458
|
+
if (this.provider?.archiveAutomationInboxItem) return await this.provider.archiveAutomationInboxItem(itemId);
|
|
8459
|
+
this.logger?.warn("Provider does not support archiveAutomationInboxItem");
|
|
8460
|
+
} catch (error) {
|
|
8461
|
+
this.logger?.error("Failed to archive automation inbox item", error);
|
|
8462
|
+
return {
|
|
8463
|
+
success: false,
|
|
8464
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
8465
|
+
};
|
|
8466
|
+
}
|
|
8467
|
+
return {
|
|
8468
|
+
success: false,
|
|
8469
|
+
message: "Provider does not support archiveAutomationInboxItem"
|
|
8470
|
+
};
|
|
8471
|
+
},
|
|
8472
|
+
deleteAutomationInboxItem: async (itemId) => {
|
|
8473
|
+
try {
|
|
8474
|
+
if (this.provider?.deleteAutomationInboxItem) return await this.provider.deleteAutomationInboxItem(itemId);
|
|
8475
|
+
this.logger?.warn("Provider does not support deleteAutomationInboxItem");
|
|
8476
|
+
} catch (error) {
|
|
8477
|
+
this.logger?.error("Failed to delete automation inbox item", error);
|
|
8478
|
+
return {
|
|
8479
|
+
success: false,
|
|
8480
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
8481
|
+
};
|
|
8482
|
+
}
|
|
8483
|
+
return {
|
|
8484
|
+
success: false,
|
|
8485
|
+
message: "Provider does not support deleteAutomationInboxItem"
|
|
8486
|
+
};
|
|
8487
|
+
},
|
|
8488
|
+
testAutomation: async (id) => {
|
|
8489
|
+
try {
|
|
8490
|
+
if (this.provider?.testAutomation) return await this.provider.testAutomation(id);
|
|
8491
|
+
this.logger?.warn("Provider does not support testAutomation");
|
|
8492
|
+
} catch (error) {
|
|
8493
|
+
this.logger?.error("Failed to test automation", error);
|
|
8494
|
+
return {
|
|
8495
|
+
success: false,
|
|
8496
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
8497
|
+
};
|
|
8498
|
+
}
|
|
8499
|
+
return {
|
|
8500
|
+
success: false,
|
|
8501
|
+
message: "Provider does not support testAutomation"
|
|
8502
|
+
};
|
|
8503
|
+
},
|
|
7499
8504
|
on: (event, handler) => {
|
|
7500
8505
|
if (this.provider.on) this.provider.on(event, handler);
|
|
7501
8506
|
else this.logger?.warn(`Provider does not support event registration: ${String(event)}`);
|
|
@@ -7637,6 +8642,167 @@ var AgentClient = class {
|
|
|
7637
8642
|
};
|
|
7638
8643
|
}
|
|
7639
8644
|
},
|
|
8645
|
+
getSkillList: async (params) => {
|
|
8646
|
+
try {
|
|
8647
|
+
if (this.provider && this.provider.getSkillList) {
|
|
8648
|
+
const result = await this.provider.getSkillList(params);
|
|
8649
|
+
this.logger?.info("Skill list retrieved", {
|
|
8650
|
+
resultCount: result.results.length,
|
|
8651
|
+
hasError: !!result.error
|
|
8652
|
+
});
|
|
8653
|
+
return result;
|
|
8654
|
+
}
|
|
8655
|
+
return {
|
|
8656
|
+
results: [],
|
|
8657
|
+
error: "Provider does not support getSkillList"
|
|
8658
|
+
};
|
|
8659
|
+
} catch (error) {
|
|
8660
|
+
this.logger?.error("Failed to get skill list", error);
|
|
8661
|
+
return {
|
|
8662
|
+
results: [],
|
|
8663
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8664
|
+
};
|
|
8665
|
+
}
|
|
8666
|
+
},
|
|
8667
|
+
importSkill: async (params) => {
|
|
8668
|
+
try {
|
|
8669
|
+
if (this.provider && this.provider.importSkill) {
|
|
8670
|
+
const result = await this.provider.importSkill(params);
|
|
8671
|
+
this.logger?.info("Import skill completed", {
|
|
8672
|
+
success: result.success,
|
|
8673
|
+
hasError: !!result.error
|
|
8674
|
+
});
|
|
8675
|
+
return result;
|
|
8676
|
+
}
|
|
8677
|
+
return {
|
|
8678
|
+
success: false,
|
|
8679
|
+
error: "Provider does not support importSkill"
|
|
8680
|
+
};
|
|
8681
|
+
} catch (error) {
|
|
8682
|
+
this.logger?.error("Failed to import skill", error);
|
|
8683
|
+
return {
|
|
8684
|
+
success: false,
|
|
8685
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8686
|
+
};
|
|
8687
|
+
}
|
|
8688
|
+
},
|
|
8689
|
+
toggleSkill: async (params) => {
|
|
8690
|
+
try {
|
|
8691
|
+
if (this.provider && this.provider.toggleSkill) {
|
|
8692
|
+
const result = await this.provider.toggleSkill(params);
|
|
8693
|
+
this.logger?.info("Toggle skill completed", {
|
|
8694
|
+
success: result.success,
|
|
8695
|
+
hasError: !!result.error
|
|
8696
|
+
});
|
|
8697
|
+
return result;
|
|
8698
|
+
}
|
|
8699
|
+
return {
|
|
8700
|
+
success: false,
|
|
8701
|
+
error: "Provider does not support toggleSkill"
|
|
8702
|
+
};
|
|
8703
|
+
} catch (error) {
|
|
8704
|
+
this.logger?.error("Failed to toggle skill", error);
|
|
8705
|
+
return {
|
|
8706
|
+
success: false,
|
|
8707
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8708
|
+
};
|
|
8709
|
+
}
|
|
8710
|
+
},
|
|
8711
|
+
deleteSkill: async (params) => {
|
|
8712
|
+
try {
|
|
8713
|
+
if (this.provider && this.provider.deleteSkill) {
|
|
8714
|
+
const result = await this.provider.deleteSkill(params);
|
|
8715
|
+
this.logger?.info("Delete skill completed", {
|
|
8716
|
+
success: result.success,
|
|
8717
|
+
hasError: !!result.error
|
|
8718
|
+
});
|
|
8719
|
+
return result;
|
|
8720
|
+
}
|
|
8721
|
+
return {
|
|
8722
|
+
success: false,
|
|
8723
|
+
error: "Provider does not support deleteSkill"
|
|
8724
|
+
};
|
|
8725
|
+
} catch (error) {
|
|
8726
|
+
this.logger?.error("Failed to delete skill", error);
|
|
8727
|
+
return {
|
|
8728
|
+
success: false,
|
|
8729
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8730
|
+
};
|
|
8731
|
+
}
|
|
8732
|
+
},
|
|
8733
|
+
getSkillContent: async (params) => {
|
|
8734
|
+
try {
|
|
8735
|
+
if (this.provider && this.provider.getSkillContent) {
|
|
8736
|
+
const result = await this.provider.getSkillContent(params);
|
|
8737
|
+
this.logger?.info("Get skill content completed", { hasError: !!result.error });
|
|
8738
|
+
return result;
|
|
8739
|
+
}
|
|
8740
|
+
return {
|
|
8741
|
+
content: "",
|
|
8742
|
+
error: "Provider does not support getSkillContent"
|
|
8743
|
+
};
|
|
8744
|
+
} catch (error) {
|
|
8745
|
+
this.logger?.error("Failed to get skill content", error);
|
|
8746
|
+
return {
|
|
8747
|
+
content: "",
|
|
8748
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8749
|
+
};
|
|
8750
|
+
}
|
|
8751
|
+
},
|
|
8752
|
+
getMarketplaceSkills: async () => {
|
|
8753
|
+
try {
|
|
8754
|
+
if (this.provider && this.provider.getMarketplaceSkills) {
|
|
8755
|
+
const result = await this.provider.getMarketplaceSkills();
|
|
8756
|
+
this.logger?.info("Marketplace skills retrieved", {
|
|
8757
|
+
resultCount: result.results.length,
|
|
8758
|
+
hasError: !!result.error
|
|
8759
|
+
});
|
|
8760
|
+
return result;
|
|
8761
|
+
}
|
|
8762
|
+
return {
|
|
8763
|
+
results: [],
|
|
8764
|
+
error: "Provider does not support getMarketplaceSkills"
|
|
8765
|
+
};
|
|
8766
|
+
} catch (error) {
|
|
8767
|
+
this.logger?.error("Failed to get marketplace skills", error);
|
|
8768
|
+
return {
|
|
8769
|
+
results: [],
|
|
8770
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8771
|
+
};
|
|
8772
|
+
}
|
|
8773
|
+
},
|
|
8774
|
+
getMarketplaceSkillContent: async (params) => {
|
|
8775
|
+
try {
|
|
8776
|
+
if (this.provider && this.provider.getMarketplaceSkillContent) return await this.provider.getMarketplaceSkillContent(params);
|
|
8777
|
+
return {
|
|
8778
|
+
content: "",
|
|
8779
|
+
error: "Provider does not support getMarketplaceSkillContent"
|
|
8780
|
+
};
|
|
8781
|
+
} catch (error) {
|
|
8782
|
+
this.logger?.error("Failed to get marketplace skill content", error);
|
|
8783
|
+
return {
|
|
8784
|
+
content: "",
|
|
8785
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8786
|
+
};
|
|
8787
|
+
}
|
|
8788
|
+
},
|
|
8789
|
+
installMarketplaceSkill: async (params) => {
|
|
8790
|
+
try {
|
|
8791
|
+
if (this.provider && this.provider.installMarketplaceSkill) return await this.provider.installMarketplaceSkill(params);
|
|
8792
|
+
return {
|
|
8793
|
+
success: false,
|
|
8794
|
+
skillName: params.skillName,
|
|
8795
|
+
errorMessage: "Provider does not support installMarketplaceSkill"
|
|
8796
|
+
};
|
|
8797
|
+
} catch (error) {
|
|
8798
|
+
this.logger?.error("Failed to install marketplace skill", error);
|
|
8799
|
+
return {
|
|
8800
|
+
success: false,
|
|
8801
|
+
skillName: params.skillName,
|
|
8802
|
+
errorMessage: error instanceof Error ? error.message : "Unknown error"
|
|
8803
|
+
};
|
|
8804
|
+
}
|
|
8805
|
+
},
|
|
7640
8806
|
batchTogglePlugins: async (request) => {
|
|
7641
8807
|
try {
|
|
7642
8808
|
if (this.provider && this.provider.batchTogglePlugins) {
|
|
@@ -7681,10 +8847,10 @@ var AgentClient = class {
|
|
|
7681
8847
|
return [];
|
|
7682
8848
|
}
|
|
7683
8849
|
},
|
|
7684
|
-
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource) => {
|
|
8850
|
+
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath) => {
|
|
7685
8851
|
try {
|
|
7686
8852
|
if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
|
|
7687
|
-
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource);
|
|
8853
|
+
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath);
|
|
7688
8854
|
this.logger?.info("Install plugins", {
|
|
7689
8855
|
pluginNames,
|
|
7690
8856
|
marketplaceName,
|
|
@@ -7705,37 +8871,399 @@ var AgentClient = class {
|
|
|
7705
8871
|
};
|
|
7706
8872
|
}
|
|
7707
8873
|
},
|
|
7708
|
-
|
|
8874
|
+
uninstallPlugin: async (pluginName, marketplaceName, scope) => {
|
|
8875
|
+
try {
|
|
8876
|
+
if (this.provider && "uninstallPlugin" in this.provider && typeof this.provider.uninstallPlugin === "function") {
|
|
8877
|
+
const result = await this.provider.uninstallPlugin(pluginName, marketplaceName, scope);
|
|
8878
|
+
this.logger?.info("Uninstall plugin", {
|
|
8879
|
+
pluginName,
|
|
8880
|
+
marketplaceName,
|
|
8881
|
+
scope,
|
|
8882
|
+
success: result.success
|
|
8883
|
+
});
|
|
8884
|
+
return result;
|
|
8885
|
+
}
|
|
8886
|
+
this.logger?.warn("Provider does not support uninstallPlugin");
|
|
8887
|
+
return {
|
|
8888
|
+
success: false,
|
|
8889
|
+
error: "Provider does not support uninstallPlugin"
|
|
8890
|
+
};
|
|
8891
|
+
} catch (error) {
|
|
8892
|
+
this.logger?.error("Failed to uninstall plugin", error);
|
|
8893
|
+
return {
|
|
8894
|
+
success: false,
|
|
8895
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8896
|
+
};
|
|
8897
|
+
}
|
|
8898
|
+
},
|
|
8899
|
+
updatePlugin: async (pluginName, marketplaceName) => {
|
|
8900
|
+
try {
|
|
8901
|
+
if (this.provider && "updatePlugin" in this.provider && typeof this.provider.updatePlugin === "function") {
|
|
8902
|
+
const result = await this.provider.updatePlugin(pluginName, marketplaceName);
|
|
8903
|
+
this.logger?.info("Update plugin", {
|
|
8904
|
+
pluginName,
|
|
8905
|
+
marketplaceName,
|
|
8906
|
+
success: result.success
|
|
8907
|
+
});
|
|
8908
|
+
return result;
|
|
8909
|
+
}
|
|
8910
|
+
this.logger?.warn("Provider does not support updatePlugin");
|
|
8911
|
+
return {
|
|
8912
|
+
success: false,
|
|
8913
|
+
error: "Provider does not support updatePlugin"
|
|
8914
|
+
};
|
|
8915
|
+
} catch (error) {
|
|
8916
|
+
this.logger?.error("Failed to update plugin", error);
|
|
8917
|
+
return {
|
|
8918
|
+
success: false,
|
|
8919
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8920
|
+
};
|
|
8921
|
+
}
|
|
8922
|
+
},
|
|
8923
|
+
getPluginMarketplaces: async (forceRefresh) => {
|
|
8924
|
+
try {
|
|
8925
|
+
if (this.provider && "getPluginMarketplaces" in this.provider && typeof this.provider.getPluginMarketplaces === "function") {
|
|
8926
|
+
const result = await this.provider.getPluginMarketplaces(forceRefresh);
|
|
8927
|
+
this.logger?.info("Got plugin marketplaces", { count: result?.length ?? 0 });
|
|
8928
|
+
return result;
|
|
8929
|
+
}
|
|
8930
|
+
this.logger?.warn("Provider does not support getPluginMarketplaces");
|
|
8931
|
+
return [];
|
|
8932
|
+
} catch (error) {
|
|
8933
|
+
this.logger?.error("Failed to get plugin marketplaces", error);
|
|
8934
|
+
return [];
|
|
8935
|
+
}
|
|
8936
|
+
},
|
|
8937
|
+
getMarketplacePlugins: async (marketplaceName, forceRefresh, searchText) => {
|
|
8938
|
+
try {
|
|
8939
|
+
if (this.provider && "getMarketplacePlugins" in this.provider && typeof this.provider.getMarketplacePlugins === "function") {
|
|
8940
|
+
const result = await this.provider.getMarketplacePlugins(marketplaceName, forceRefresh, searchText);
|
|
8941
|
+
this.logger?.info("Got marketplace plugins", {
|
|
8942
|
+
marketplaceName,
|
|
8943
|
+
count: result?.length ?? 0
|
|
8944
|
+
});
|
|
8945
|
+
return result;
|
|
8946
|
+
}
|
|
8947
|
+
this.logger?.warn("Provider does not support getMarketplacePlugins");
|
|
8948
|
+
return [];
|
|
8949
|
+
} catch (error) {
|
|
8950
|
+
this.logger?.error("Failed to get marketplace plugins", error);
|
|
8951
|
+
return [];
|
|
8952
|
+
}
|
|
8953
|
+
},
|
|
8954
|
+
getPluginDetail: async (pluginName, marketplaceName) => {
|
|
8955
|
+
try {
|
|
8956
|
+
if (this.provider && "getPluginDetail" in this.provider && typeof this.provider.getPluginDetail === "function") {
|
|
8957
|
+
const result = await this.provider.getPluginDetail(pluginName, marketplaceName);
|
|
8958
|
+
this.logger?.info("Got plugin detail", {
|
|
8959
|
+
pluginName,
|
|
8960
|
+
marketplaceName
|
|
8961
|
+
});
|
|
8962
|
+
return result;
|
|
8963
|
+
}
|
|
8964
|
+
this.logger?.warn("Provider does not support getPluginDetail");
|
|
8965
|
+
return null;
|
|
8966
|
+
} catch (error) {
|
|
8967
|
+
this.logger?.error("Failed to get plugin detail", error);
|
|
8968
|
+
return null;
|
|
8969
|
+
}
|
|
8970
|
+
},
|
|
8971
|
+
addPluginMarketplace: async (source, name) => {
|
|
8972
|
+
try {
|
|
8973
|
+
if (this.provider && "addPluginMarketplace" in this.provider && typeof this.provider.addPluginMarketplace === "function") {
|
|
8974
|
+
const result = await this.provider.addPluginMarketplace(source, name);
|
|
8975
|
+
this.logger?.info("Add plugin marketplace", {
|
|
8976
|
+
source,
|
|
8977
|
+
name,
|
|
8978
|
+
success: result.success
|
|
8979
|
+
});
|
|
8980
|
+
return result;
|
|
8981
|
+
}
|
|
8982
|
+
this.logger?.warn("Provider does not support addPluginMarketplace");
|
|
8983
|
+
return {
|
|
8984
|
+
success: false,
|
|
8985
|
+
error: "Provider does not support addPluginMarketplace"
|
|
8986
|
+
};
|
|
8987
|
+
} catch (error) {
|
|
8988
|
+
this.logger?.error("Failed to add plugin marketplace", error);
|
|
8989
|
+
return {
|
|
8990
|
+
success: false,
|
|
8991
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
8992
|
+
};
|
|
8993
|
+
}
|
|
8994
|
+
},
|
|
8995
|
+
removePluginMarketplace: async (marketplaceName) => {
|
|
8996
|
+
try {
|
|
8997
|
+
if (this.provider && "removePluginMarketplace" in this.provider && typeof this.provider.removePluginMarketplace === "function") {
|
|
8998
|
+
const result = await this.provider.removePluginMarketplace(marketplaceName);
|
|
8999
|
+
this.logger?.info("Remove plugin marketplace", {
|
|
9000
|
+
marketplaceName,
|
|
9001
|
+
success: result.success
|
|
9002
|
+
});
|
|
9003
|
+
return result;
|
|
9004
|
+
}
|
|
9005
|
+
this.logger?.warn("Provider does not support removePluginMarketplace");
|
|
9006
|
+
return {
|
|
9007
|
+
success: false,
|
|
9008
|
+
error: "Provider does not support removePluginMarketplace"
|
|
9009
|
+
};
|
|
9010
|
+
} catch (error) {
|
|
9011
|
+
this.logger?.error("Failed to remove plugin marketplace", error);
|
|
9012
|
+
return {
|
|
9013
|
+
success: false,
|
|
9014
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
9015
|
+
};
|
|
9016
|
+
}
|
|
9017
|
+
},
|
|
9018
|
+
refreshPluginMarketplace: async (marketplaceName) => {
|
|
9019
|
+
try {
|
|
9020
|
+
if (this.provider && "refreshPluginMarketplace" in this.provider && typeof this.provider.refreshPluginMarketplace === "function") {
|
|
9021
|
+
const result = await this.provider.refreshPluginMarketplace(marketplaceName);
|
|
9022
|
+
this.logger?.info("Refresh plugin marketplace", {
|
|
9023
|
+
marketplaceName,
|
|
9024
|
+
success: result.success
|
|
9025
|
+
});
|
|
9026
|
+
return result;
|
|
9027
|
+
}
|
|
9028
|
+
this.logger?.warn("Provider does not support refreshPluginMarketplace");
|
|
9029
|
+
return {
|
|
9030
|
+
success: false,
|
|
9031
|
+
error: "Provider does not support refreshPluginMarketplace"
|
|
9032
|
+
};
|
|
9033
|
+
} catch (error) {
|
|
9034
|
+
this.logger?.error("Failed to refresh plugin marketplace", error);
|
|
9035
|
+
return {
|
|
9036
|
+
success: false,
|
|
9037
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
9038
|
+
};
|
|
9039
|
+
}
|
|
9040
|
+
},
|
|
9041
|
+
openFolderInNewWindow: async (folderPath) => {
|
|
9042
|
+
try {
|
|
9043
|
+
if (this.provider && "openFolderInNewWindow" in this.provider && typeof this.provider.openFolderInNewWindow === "function") {
|
|
9044
|
+
await this.provider.openFolderInNewWindow(folderPath);
|
|
9045
|
+
this.logger?.info("Opened folder in new window", { folderPath });
|
|
9046
|
+
} else {
|
|
9047
|
+
this.logger?.warn("Provider does not support openFolderInNewWindow");
|
|
9048
|
+
throw new Error("Provider does not support openFolderInNewWindow");
|
|
9049
|
+
}
|
|
9050
|
+
} catch (error) {
|
|
9051
|
+
this.logger?.error("Failed to open folder in new window", error);
|
|
9052
|
+
throw error;
|
|
9053
|
+
}
|
|
9054
|
+
},
|
|
9055
|
+
openFolder: async (folderPath) => {
|
|
7709
9056
|
try {
|
|
7710
|
-
if (this.provider && "
|
|
7711
|
-
const result = await this.provider.
|
|
7712
|
-
this.logger?.info("
|
|
9057
|
+
if (this.provider && "openFolder" in this.provider && typeof this.provider.openFolder === "function") {
|
|
9058
|
+
const result = await this.provider.openFolder(folderPath);
|
|
9059
|
+
this.logger?.info("Opened folder in system file manager", { folderPath });
|
|
7713
9060
|
return result;
|
|
9061
|
+
} else {
|
|
9062
|
+
this.logger?.warn("Provider does not support openFolder");
|
|
9063
|
+
throw new Error("Provider does not support openFolder");
|
|
7714
9064
|
}
|
|
9065
|
+
} catch (error) {
|
|
9066
|
+
this.logger?.error("Failed to open folder", error);
|
|
9067
|
+
throw error;
|
|
9068
|
+
}
|
|
9069
|
+
},
|
|
9070
|
+
getSupportScenes: async (locale) => {
|
|
9071
|
+
try {
|
|
9072
|
+
if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") return await this.provider.getSupportScenes(locale);
|
|
7715
9073
|
this.logger?.warn("Provider does not support getSupportScenes");
|
|
7716
9074
|
return [];
|
|
7717
9075
|
} catch (error) {
|
|
7718
|
-
this.logger?.error("Failed to get support scenes", error);
|
|
9076
|
+
this.logger?.error("Failed to get support scenes", error);
|
|
9077
|
+
return [];
|
|
9078
|
+
}
|
|
9079
|
+
},
|
|
9080
|
+
getProductScenes: async (locale) => {
|
|
9081
|
+
try {
|
|
9082
|
+
if (this.provider?.getProductScenes) {
|
|
9083
|
+
const result = await this.provider.getProductScenes(locale);
|
|
9084
|
+
this.logger?.info("Got product scenes", { count: result?.length ?? 0 });
|
|
9085
|
+
return result;
|
|
9086
|
+
}
|
|
9087
|
+
this.logger?.warn("Provider does not support getProductScenes");
|
|
9088
|
+
return [];
|
|
9089
|
+
} catch (error) {
|
|
9090
|
+
this.logger?.error("Failed to get product scenes", error);
|
|
7719
9091
|
return [];
|
|
7720
9092
|
}
|
|
7721
9093
|
},
|
|
7722
|
-
getAvailableCommands: async (
|
|
9094
|
+
getAvailableCommands: async (params) => {
|
|
7723
9095
|
try {
|
|
7724
9096
|
if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
|
|
7725
|
-
const result = await this.provider.getAvailableCommands(
|
|
9097
|
+
const result = await this.provider.getAvailableCommands(params);
|
|
7726
9098
|
this.logger?.info("Got available commands from provider", {
|
|
7727
|
-
sessionId: sessionId ?? "(default)",
|
|
9099
|
+
sessionId: params?.sessionId ?? "(default)",
|
|
7728
9100
|
count: result?.length ?? 0
|
|
7729
9101
|
});
|
|
7730
9102
|
return result;
|
|
7731
9103
|
}
|
|
7732
|
-
this.logger?.warn("Provider does not support getAvailableCommands", {
|
|
9104
|
+
this.logger?.warn("Provider does not support getAvailableCommands", { params });
|
|
7733
9105
|
return [];
|
|
7734
9106
|
} catch (error) {
|
|
7735
9107
|
this.logger?.error("Failed to get available commands", error);
|
|
7736
9108
|
return [];
|
|
7737
9109
|
}
|
|
7738
9110
|
},
|
|
9111
|
+
reportTelemetry: async (eventName, payload) => {
|
|
9112
|
+
try {
|
|
9113
|
+
if (this.provider?.reportTelemetry) await this.provider.reportTelemetry(eventName, payload);
|
|
9114
|
+
else this.logger?.warn("Provider does not support reportTelemetry");
|
|
9115
|
+
} catch (error) {
|
|
9116
|
+
this.logger?.error("Failed to report telemetry", error);
|
|
9117
|
+
}
|
|
9118
|
+
},
|
|
9119
|
+
getProductConfiguration: async () => {
|
|
9120
|
+
try {
|
|
9121
|
+
if (this.provider?.getProductConfiguration) return await this.provider.getProductConfiguration();
|
|
9122
|
+
this.logger?.warn("Provider does not support getProductConfiguration");
|
|
9123
|
+
return {};
|
|
9124
|
+
} catch (error) {
|
|
9125
|
+
this.logger?.error("Failed to get product configuration", error);
|
|
9126
|
+
return {};
|
|
9127
|
+
}
|
|
9128
|
+
},
|
|
9129
|
+
getUserInfo: async () => {
|
|
9130
|
+
this.logger?.info("[AgentClient.sessions] getUserInfo() called");
|
|
9131
|
+
try {
|
|
9132
|
+
if (this.provider?.getUserInfo) {
|
|
9133
|
+
const result = await this.provider.getUserInfo();
|
|
9134
|
+
this.logger?.info("[AgentClient.sessions] getUserInfo() result:", JSON.stringify(result));
|
|
9135
|
+
return result;
|
|
9136
|
+
}
|
|
9137
|
+
this.logger?.warn("Provider does not support getUserInfo");
|
|
9138
|
+
return {};
|
|
9139
|
+
} catch (error) {
|
|
9140
|
+
this.logger?.error("Failed to get user info", error);
|
|
9141
|
+
return {};
|
|
9142
|
+
}
|
|
9143
|
+
},
|
|
9144
|
+
respondToSampling: async (sessionId, response) => {
|
|
9145
|
+
try {
|
|
9146
|
+
if (this.provider?.respondToSampling) {
|
|
9147
|
+
await this.provider.respondToSampling(sessionId, response);
|
|
9148
|
+
this.logger?.info("Responded to sampling request", {
|
|
9149
|
+
sessionId,
|
|
9150
|
+
requestId: response.id,
|
|
9151
|
+
approved: response.approved
|
|
9152
|
+
});
|
|
9153
|
+
} else this.logger?.warn("Provider does not support respondToSampling");
|
|
9154
|
+
} catch (error) {
|
|
9155
|
+
this.logger?.error("Failed to respond to sampling request", error);
|
|
9156
|
+
throw error;
|
|
9157
|
+
}
|
|
9158
|
+
},
|
|
9159
|
+
respondToRoots: async (sessionId, response) => {
|
|
9160
|
+
try {
|
|
9161
|
+
if (this.provider?.respondToRoots) {
|
|
9162
|
+
await this.provider.respondToRoots(sessionId, response);
|
|
9163
|
+
this.logger?.info("Responded to roots request", {
|
|
9164
|
+
sessionId,
|
|
9165
|
+
requestId: response.id,
|
|
9166
|
+
approved: response.approved
|
|
9167
|
+
});
|
|
9168
|
+
} else this.logger?.warn("Provider does not support respondToRoots");
|
|
9169
|
+
} catch (error) {
|
|
9170
|
+
this.logger?.error("Failed to respond to roots request", error);
|
|
9171
|
+
throw error;
|
|
9172
|
+
}
|
|
9173
|
+
},
|
|
9174
|
+
subscribeSamplingRequests: (serverName, callback) => {
|
|
9175
|
+
if (this.provider?.subscribeSamplingRequests) {
|
|
9176
|
+
this.logger?.info("Subscribing to sampling requests", { serverName });
|
|
9177
|
+
return this.provider.subscribeSamplingRequests(serverName, callback);
|
|
9178
|
+
}
|
|
9179
|
+
this.logger?.warn("Provider does not support subscribeSamplingRequests");
|
|
9180
|
+
return () => {};
|
|
9181
|
+
},
|
|
9182
|
+
subscribeRootsRequests: (serverName, callback) => {
|
|
9183
|
+
if (this.provider?.subscribeRootsRequests) {
|
|
9184
|
+
this.logger?.info("Subscribing to roots requests", { serverName });
|
|
9185
|
+
return this.provider.subscribeRootsRequests(serverName, callback);
|
|
9186
|
+
}
|
|
9187
|
+
this.logger?.warn("Provider does not support subscribeRootsRequests");
|
|
9188
|
+
return () => {};
|
|
9189
|
+
},
|
|
9190
|
+
getMcpServers: async () => {
|
|
9191
|
+
if (this.provider?.getMcpServers) {
|
|
9192
|
+
this.logger?.info("Getting MCP servers list");
|
|
9193
|
+
return this.provider.getMcpServers();
|
|
9194
|
+
}
|
|
9195
|
+
this.logger?.warn("Provider does not support getMcpServers");
|
|
9196
|
+
return [];
|
|
9197
|
+
},
|
|
9198
|
+
toggleMcpServer: async (serverName, enabled) => {
|
|
9199
|
+
if (this.provider?.toggleMcpServer) {
|
|
9200
|
+
this.logger?.info("Toggling MCP server", {
|
|
9201
|
+
serverName,
|
|
9202
|
+
enabled
|
|
9203
|
+
});
|
|
9204
|
+
await this.provider.toggleMcpServer(serverName, enabled);
|
|
9205
|
+
} else {
|
|
9206
|
+
this.logger?.warn("Provider does not support toggleMcpServer");
|
|
9207
|
+
throw new Error("toggleMcpServer not supported by provider");
|
|
9208
|
+
}
|
|
9209
|
+
},
|
|
9210
|
+
reconnectMcpServer: async (serverName, forceHttpCallback) => {
|
|
9211
|
+
if (this.provider?.reconnectMcpServer) {
|
|
9212
|
+
this.logger?.info("Reconnecting MCP server", {
|
|
9213
|
+
serverName,
|
|
9214
|
+
forceHttpCallback
|
|
9215
|
+
});
|
|
9216
|
+
await this.provider.reconnectMcpServer(serverName, forceHttpCallback);
|
|
9217
|
+
} else {
|
|
9218
|
+
this.logger?.warn("Provider does not support reconnectMcpServer");
|
|
9219
|
+
throw new Error("reconnectMcpServer not supported by provider");
|
|
9220
|
+
}
|
|
9221
|
+
},
|
|
9222
|
+
deleteMcpServer: async (serverName) => {
|
|
9223
|
+
if (this.provider?.deleteMcpServer) {
|
|
9224
|
+
this.logger?.info("Deleting MCP server", { serverName });
|
|
9225
|
+
await this.provider.deleteMcpServer(serverName);
|
|
9226
|
+
} else {
|
|
9227
|
+
this.logger?.warn("Provider does not support deleteMcpServer");
|
|
9228
|
+
throw new Error("deleteMcpServer not supported by provider");
|
|
9229
|
+
}
|
|
9230
|
+
},
|
|
9231
|
+
openMcpConfig: async () => {
|
|
9232
|
+
if (this.provider?.openMcpConfig) {
|
|
9233
|
+
this.logger?.info("Opening MCP config");
|
|
9234
|
+
await this.provider.openMcpConfig();
|
|
9235
|
+
} else {
|
|
9236
|
+
this.logger?.warn("Provider does not support openMcpConfig");
|
|
9237
|
+
throw new Error("openMcpConfig not supported by provider");
|
|
9238
|
+
}
|
|
9239
|
+
},
|
|
9240
|
+
getMcpConfigContent: async () => {
|
|
9241
|
+
if (this.provider?.getMcpConfigContent) {
|
|
9242
|
+
this.logger?.info("Getting MCP config content");
|
|
9243
|
+
return await this.provider.getMcpConfigContent();
|
|
9244
|
+
} else {
|
|
9245
|
+
this.logger?.warn("Provider does not support getMcpConfigContent");
|
|
9246
|
+
throw new Error("getMcpConfigContent not supported by provider");
|
|
9247
|
+
}
|
|
9248
|
+
},
|
|
9249
|
+
saveMcpConfigContent: async (content) => {
|
|
9250
|
+
if (this.provider?.saveMcpConfigContent) {
|
|
9251
|
+
this.logger?.info("Saving MCP config content");
|
|
9252
|
+
await this.provider.saveMcpConfigContent(content);
|
|
9253
|
+
} else {
|
|
9254
|
+
this.logger?.warn("Provider does not support saveMcpConfigContent");
|
|
9255
|
+
throw new Error("saveMcpConfigContent not supported by provider");
|
|
9256
|
+
}
|
|
9257
|
+
},
|
|
9258
|
+
clipboardReadText: async () => {
|
|
9259
|
+
if (this.provider?.clipboardReadText) {
|
|
9260
|
+
this.logger?.info("Reading clipboard text");
|
|
9261
|
+
return await this.provider.clipboardReadText();
|
|
9262
|
+
} else {
|
|
9263
|
+
this.logger?.warn("Provider does not support clipboardReadText");
|
|
9264
|
+
throw new Error("clipboardReadText not supported by provider");
|
|
9265
|
+
}
|
|
9266
|
+
},
|
|
7739
9267
|
models: this.createModelsResource()
|
|
7740
9268
|
};
|
|
7741
9269
|
}
|
|
@@ -7961,10 +9489,6 @@ const oauthRepositoryService = new OAuthRepositoryService();
|
|
|
7961
9489
|
* 判断当前账号是否是 SSO 账号
|
|
7962
9490
|
* 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
|
|
7963
9491
|
*/
|
|
7964
|
-
const isSSODomain = () => {
|
|
7965
|
-
const { hostname } = window.location;
|
|
7966
|
-
return hostname.includes(".sso.copilot") || hostname.includes("sso.codebuddy.cn") || hostname.includes(".sso.copilot-staging") || hostname.includes(".staging-sso.codebuddy.cn");
|
|
7967
|
-
};
|
|
7968
9492
|
/**
|
|
7969
9493
|
* 根据路径获取完整 URL
|
|
7970
9494
|
* - SSO 账号需要跳转到对应的预发/生产域名
|
|
@@ -7972,16 +9496,7 @@ const isSSODomain = () => {
|
|
|
7972
9496
|
* @param path 路径,如 '/login'、'/logout'、'/home' 等
|
|
7973
9497
|
* @returns 完整的 URL 地址
|
|
7974
9498
|
*/
|
|
7975
|
-
const getFullUrl = (path) => {
|
|
7976
|
-
const { hostname, protocol } = window.location;
|
|
7977
|
-
if (isSSODomain()) {
|
|
7978
|
-
const isCodebuddy = hostname.includes("codebuddy.cn");
|
|
7979
|
-
const isStaging = hostname.includes("staging");
|
|
7980
|
-
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn${path}` : `${protocol}//www.codebuddy.cn${path}`;
|
|
7981
|
-
else return isStaging ? `${protocol}//staging-copilot.tencent.com${path}` : `${protocol}//copilot.tencent.com${path}`;
|
|
7982
|
-
}
|
|
7983
|
-
return `${window.location.origin}${path}`;
|
|
7984
|
-
};
|
|
9499
|
+
const getFullUrl = (path) => `${window.location.origin}${path}`;
|
|
7985
9500
|
/** 获取当前域名的账号选择页面 URL */
|
|
7986
9501
|
const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
|
|
7987
9502
|
/** localStorage 中存储选中账号 ID 的 key */
|
|
@@ -8014,16 +9529,34 @@ const getPackageName = (packageCode) => CommodityCodeText[packageCode] || "";
|
|
|
8014
9529
|
* 注意:getAgents 和 getModels 方法已废弃并移除,
|
|
8015
9530
|
* 请使用 IAgentAdapter 中的对应方法
|
|
8016
9531
|
*/
|
|
8017
|
-
var BackendProvider = class {
|
|
9532
|
+
var BackendProvider = class BackendProvider {
|
|
8018
9533
|
constructor(config) {
|
|
8019
9534
|
httpService.setBaseURL(config.baseUrl);
|
|
8020
9535
|
if (config.authToken) httpService.setAuthToken(config.authToken);
|
|
8021
|
-
httpService.onUnauthorized(() =>
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
9536
|
+
httpService.onUnauthorized(() => this.handleUnauthorized());
|
|
9537
|
+
}
|
|
9538
|
+
/**
|
|
9539
|
+
* 处理 401 未授权错误
|
|
9540
|
+
* 先尝试刷新 token,失败后再执行登出流程
|
|
9541
|
+
*
|
|
9542
|
+
* @throws 如果 token 刷新失败,抛出错误通知 HttpService 不要重试
|
|
9543
|
+
*/
|
|
9544
|
+
async handleUnauthorized() {
|
|
9545
|
+
console.log("[BackendProvider] User unauthorized (401), attempting token refresh first");
|
|
9546
|
+
try {
|
|
9547
|
+
if (await this.refreshToken()) {
|
|
9548
|
+
console.log("[BackendProvider] Token refresh successful after 401, user still logged in");
|
|
9549
|
+
return;
|
|
9550
|
+
}
|
|
9551
|
+
throw new Error("Token refresh returned null");
|
|
9552
|
+
} catch (error) {
|
|
9553
|
+
console.error("[BackendProvider] Token refresh failed after 401:", error);
|
|
9554
|
+
console.log("[BackendProvider] Token refresh failed, triggering logout");
|
|
9555
|
+
this.logout().catch((logoutError) => {
|
|
9556
|
+
console.error("[BackendProvider] Logout failed in 401 handler:", logoutError);
|
|
8025
9557
|
});
|
|
8026
|
-
|
|
9558
|
+
throw error;
|
|
9559
|
+
}
|
|
8027
9560
|
}
|
|
8028
9561
|
/**
|
|
8029
9562
|
* 获取当前账号信息
|
|
@@ -8287,10 +9820,11 @@ var BackendProvider = class {
|
|
|
8287
9820
|
if (!time) return 0;
|
|
8288
9821
|
return new Date(time).getTime();
|
|
8289
9822
|
};
|
|
8290
|
-
const dailyCredits = [CommodityCode.free
|
|
9823
|
+
const dailyCredits = [CommodityCode.free];
|
|
8291
9824
|
const planResources = resources.map((r) => {
|
|
8292
9825
|
const isDaily = dailyCredits.includes(r.PackageCode);
|
|
8293
9826
|
const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
|
|
9827
|
+
const refreshAt = parseTime(r.CycleEndTime) + 1e3;
|
|
8294
9828
|
return {
|
|
8295
9829
|
id: r.ResourceId,
|
|
8296
9830
|
name: isDaily ? "plan.addonCredits" : getPackageName(r.PackageCode),
|
|
@@ -8300,7 +9834,7 @@ var BackendProvider = class {
|
|
|
8300
9834
|
used: Math.max(0, Number(r.CycleCapacitySizePrecise) - Number(r.CycleCapacityRemainPrecise)) || 0,
|
|
8301
9835
|
left: Number(r.CycleCapacityRemainPrecise) || 0,
|
|
8302
9836
|
expireAt: parseTime(endTime),
|
|
8303
|
-
refreshAt: isDaily ? void 0 :
|
|
9837
|
+
refreshAt: isDaily ? void 0 : refreshAt
|
|
8304
9838
|
};
|
|
8305
9839
|
}).sort((a, b) => {
|
|
8306
9840
|
const getPriority = (code) => {
|
|
@@ -8308,10 +9842,11 @@ var BackendProvider = class {
|
|
|
8308
9842
|
CommodityCode.proMon,
|
|
8309
9843
|
CommodityCode.proMonPlus,
|
|
8310
9844
|
CommodityCode.proYear,
|
|
9845
|
+
CommodityCode.freeMon,
|
|
8311
9846
|
CommodityCode.extra
|
|
8312
9847
|
].includes(code)) return 1;
|
|
8313
9848
|
if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
|
|
8314
|
-
if ([CommodityCode.free
|
|
9849
|
+
if ([CommodityCode.free].includes(code)) return 3;
|
|
8315
9850
|
return 4;
|
|
8316
9851
|
};
|
|
8317
9852
|
return getPriority(a.packageCode) - getPriority(b.packageCode);
|
|
@@ -8436,34 +9971,65 @@ var BackendProvider = class {
|
|
|
8436
9971
|
}
|
|
8437
9972
|
/**
|
|
8438
9973
|
* 登出账号
|
|
8439
|
-
*
|
|
9974
|
+
*
|
|
9975
|
+
* 策略:
|
|
9976
|
+
* - IOA 企业:用 iframe 走 SSO/SAML SLO 登出链路(涉及跨域重定向),通过轮询 iframe URL 变化检测完成
|
|
9977
|
+
* - 非 IOA 企业:直接用 httpService 请求 /console/logout,速度快
|
|
8440
9978
|
*/
|
|
8441
9979
|
async logout() {
|
|
8442
|
-
const
|
|
9980
|
+
const account = accountService.getAccount();
|
|
9981
|
+
if (account?.enterpriseId && ["esoikz80kd8g", "etahzsqej0n4"].includes(account.enterpriseId)) await this.logoutViaIframe();
|
|
9982
|
+
else await this.logoutViaHttp();
|
|
9983
|
+
localStorage.removeItem(SELECTED_ACCOUNT_KEY);
|
|
9984
|
+
accountService.clearAccount();
|
|
9985
|
+
}
|
|
9986
|
+
/**
|
|
9987
|
+
* IOA 企业登出:通过 iframe 走 SSO/SAML SLO 登出链路
|
|
9988
|
+
* 轮询 iframe URL 变化检测完成,兜底超时 5 秒
|
|
9989
|
+
*/
|
|
9990
|
+
async logoutViaIframe() {
|
|
9991
|
+
const logoutUrl = `${httpService.getAxiosInstance().defaults.baseURL}/console/logout`;
|
|
8443
9992
|
try {
|
|
8444
9993
|
await new Promise((resolve) => {
|
|
8445
9994
|
const iframe = document.createElement("iframe");
|
|
8446
9995
|
iframe.style.cssText = "position:fixed;top:-9999px;left:-9999px;width:1px;height:1px;border:none;";
|
|
8447
|
-
iframe.src =
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
9996
|
+
iframe.src = logoutUrl;
|
|
9997
|
+
let pollTimer;
|
|
9998
|
+
let settled = false;
|
|
9999
|
+
const done = () => {
|
|
10000
|
+
if (settled) return;
|
|
10001
|
+
settled = true;
|
|
10002
|
+
clearInterval(pollTimer);
|
|
8453
10003
|
clearTimeout(timeout);
|
|
8454
10004
|
if (iframe.parentNode) iframe.parentNode.removeChild(iframe);
|
|
8455
|
-
};
|
|
8456
|
-
iframe.onerror = () => {
|
|
8457
|
-
cleanup();
|
|
8458
10005
|
resolve();
|
|
8459
10006
|
};
|
|
10007
|
+
let wasRedirecting = false;
|
|
10008
|
+
pollTimer = setInterval(() => {
|
|
10009
|
+
try {
|
|
10010
|
+
const href = iframe.contentWindow?.location?.href;
|
|
10011
|
+
if (wasRedirecting && href) done();
|
|
10012
|
+
} catch {
|
|
10013
|
+
wasRedirecting = true;
|
|
10014
|
+
}
|
|
10015
|
+
}, 100);
|
|
10016
|
+
const timeout = setTimeout(done, 5e3);
|
|
10017
|
+
iframe.onerror = done;
|
|
8460
10018
|
document.body.appendChild(iframe);
|
|
8461
10019
|
});
|
|
8462
10020
|
} catch (error) {
|
|
8463
|
-
console.error("[BackendProvider] logout failed:", error);
|
|
10021
|
+
console.error("[BackendProvider] logout via iframe failed:", error);
|
|
10022
|
+
}
|
|
10023
|
+
}
|
|
10024
|
+
/**
|
|
10025
|
+
* 非 IOA 企业登出:直接 HTTP 请求 /console/logout
|
|
10026
|
+
*/
|
|
10027
|
+
async logoutViaHttp() {
|
|
10028
|
+
try {
|
|
10029
|
+
await httpService.get("/console/logout");
|
|
10030
|
+
} catch (error) {
|
|
10031
|
+
console.error("[BackendProvider] logout via http failed:", error);
|
|
8464
10032
|
}
|
|
8465
|
-
localStorage.removeItem(SELECTED_ACCOUNT_KEY);
|
|
8466
|
-
accountService.clearAccount();
|
|
8467
10033
|
}
|
|
8468
10034
|
/**
|
|
8469
10035
|
* 批量切换插件状态
|
|
@@ -8541,6 +10107,132 @@ var BackendProvider = class {
|
|
|
8541
10107
|
async getRepositories(connector, page = 0, perPage = 100) {
|
|
8542
10108
|
return oauthRepositoryService.getRepositories(connector, page, perPage);
|
|
8543
10109
|
}
|
|
10110
|
+
/**
|
|
10111
|
+
* 保存待发送的输入内容到后端
|
|
10112
|
+
* API 端点: POST /api/v1/code-id
|
|
10113
|
+
*/
|
|
10114
|
+
async savePendingInput(code) {
|
|
10115
|
+
try {
|
|
10116
|
+
const result = await httpService.post("/api/v1/code-id", { code });
|
|
10117
|
+
return result?.codeId || result?.data?.codeId || null;
|
|
10118
|
+
} catch (e) {
|
|
10119
|
+
console.warn("[BackendProvider] savePendingInput failed:", e);
|
|
10120
|
+
return null;
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
/**
|
|
10124
|
+
* 从后端加载待发送的输入内容
|
|
10125
|
+
* API 端点: GET /api/v1/code?id=xxx
|
|
10126
|
+
*/
|
|
10127
|
+
async loadPendingInput(codeId) {
|
|
10128
|
+
try {
|
|
10129
|
+
const result = await httpService.get(`/api/v1/code?id=${encodeURIComponent(codeId)}`);
|
|
10130
|
+
return result?.code || result?.data?.code || null;
|
|
10131
|
+
} catch (e) {
|
|
10132
|
+
console.warn("[BackendProvider] loadPendingInput failed:", e);
|
|
10133
|
+
return null;
|
|
10134
|
+
}
|
|
10135
|
+
}
|
|
10136
|
+
/**
|
|
10137
|
+
* 获取每日签到状态
|
|
10138
|
+
* API 端点: POST /billing/meter/checkin-status
|
|
10139
|
+
*/
|
|
10140
|
+
async getCheckinStatus() {
|
|
10141
|
+
try {
|
|
10142
|
+
const result = await httpService.post("/billing/meter/checkin-status", {});
|
|
10143
|
+
if (result?.code === 0 && result?.data) return result.data;
|
|
10144
|
+
return null;
|
|
10145
|
+
} catch (error) {
|
|
10146
|
+
console.error("[BackendProvider] getCheckinStatus failed:", error);
|
|
10147
|
+
return null;
|
|
10148
|
+
}
|
|
10149
|
+
}
|
|
10150
|
+
/**
|
|
10151
|
+
* 执行每日签到
|
|
10152
|
+
* API 端点: POST /billing/meter/daily-checkin
|
|
10153
|
+
*/
|
|
10154
|
+
async claimDailyCheckin() {
|
|
10155
|
+
const result = await httpService.post("/billing/meter/daily-checkin", {});
|
|
10156
|
+
if (result?.code === 0 && result?.data) return result.data;
|
|
10157
|
+
throw new Error(result?.msg || "Checkin failed");
|
|
10158
|
+
}
|
|
10159
|
+
static {
|
|
10160
|
+
this.SKILLHUB_BASE_URL = "https://lightmake.site";
|
|
10161
|
+
}
|
|
10162
|
+
static {
|
|
10163
|
+
this.SKILLHUB_FETCH_TIMEOUT = 1e4;
|
|
10164
|
+
}
|
|
10165
|
+
async skillHubFetch(url, init) {
|
|
10166
|
+
const controller = new AbortController();
|
|
10167
|
+
const timer = setTimeout(() => controller.abort(), BackendProvider.SKILLHUB_FETCH_TIMEOUT);
|
|
10168
|
+
try {
|
|
10169
|
+
return await fetch(url, {
|
|
10170
|
+
...init,
|
|
10171
|
+
signal: controller.signal
|
|
10172
|
+
});
|
|
10173
|
+
} finally {
|
|
10174
|
+
clearTimeout(timer);
|
|
10175
|
+
}
|
|
10176
|
+
}
|
|
10177
|
+
async getSkillHubList(params = {}) {
|
|
10178
|
+
const qs = new URLSearchParams();
|
|
10179
|
+
if (params.page) qs.set("page", String(params.page));
|
|
10180
|
+
if (params.pageSize) qs.set("pageSize", String(params.pageSize));
|
|
10181
|
+
if (params.sortBy) qs.set("sortBy", params.sortBy);
|
|
10182
|
+
if (params.order) qs.set("order", params.order);
|
|
10183
|
+
if (params.keyword) qs.set("keyword", params.keyword);
|
|
10184
|
+
if (params.category) qs.set("category", params.category);
|
|
10185
|
+
const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/skills?${qs.toString()}`);
|
|
10186
|
+
if (!res.ok) throw new Error(`SkillHub list: ${res.status}`);
|
|
10187
|
+
return res.json();
|
|
10188
|
+
}
|
|
10189
|
+
async getSkillHubCategories() {
|
|
10190
|
+
const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/categories`);
|
|
10191
|
+
if (!res.ok) throw new Error(`SkillHub categories: ${res.status}`);
|
|
10192
|
+
return res.json();
|
|
10193
|
+
}
|
|
10194
|
+
async getSkillHubSearch(q, limit = 20) {
|
|
10195
|
+
const qs = new URLSearchParams({
|
|
10196
|
+
q,
|
|
10197
|
+
limit: String(limit)
|
|
10198
|
+
});
|
|
10199
|
+
const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/search?${qs.toString()}`);
|
|
10200
|
+
if (!res.ok) throw new Error(`SkillHub search: ${res.status}`);
|
|
10201
|
+
return res.json();
|
|
10202
|
+
}
|
|
10203
|
+
async getSkillHubDetail(slug) {
|
|
10204
|
+
const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}`);
|
|
10205
|
+
if (!res.ok) throw new Error(`SkillHub detail: ${res.status}`);
|
|
10206
|
+
return res.json();
|
|
10207
|
+
}
|
|
10208
|
+
async getSkillHubExists(slugs) {
|
|
10209
|
+
const res = await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/exists`, {
|
|
10210
|
+
method: "POST",
|
|
10211
|
+
headers: { "Content-Type": "application/json" },
|
|
10212
|
+
body: JSON.stringify({ slugs })
|
|
10213
|
+
});
|
|
10214
|
+
if (!res.ok) throw new Error(`SkillHub exists: ${res.status}`);
|
|
10215
|
+
return res.json();
|
|
10216
|
+
}
|
|
10217
|
+
async reportSkillHubStats(slug, inc) {
|
|
10218
|
+
try {
|
|
10219
|
+
await this.skillHubFetch(`${BackendProvider.SKILLHUB_BASE_URL}/api/v1/skills/${encodeURIComponent(slug)}/stats/inc`, {
|
|
10220
|
+
method: "POST",
|
|
10221
|
+
headers: { "Content-Type": "application/json" },
|
|
10222
|
+
body: JSON.stringify(inc)
|
|
10223
|
+
});
|
|
10224
|
+
} catch {}
|
|
10225
|
+
}
|
|
10226
|
+
async installSkillHubSkill(_slug, _version, _name) {
|
|
10227
|
+
return {
|
|
10228
|
+
success: false,
|
|
10229
|
+
skillName: _slug,
|
|
10230
|
+
errorMessage: "SkillHub install requires IDE mode (no IPC channel available)"
|
|
10231
|
+
};
|
|
10232
|
+
}
|
|
10233
|
+
async getSkillHubInstalledMetas() {
|
|
10234
|
+
return [];
|
|
10235
|
+
}
|
|
8544
10236
|
};
|
|
8545
10237
|
/**
|
|
8546
10238
|
* 创建 BackendProvider 实例
|
|
@@ -8579,10 +10271,26 @@ const BACKEND_REQUEST_TYPES = {
|
|
|
8579
10271
|
REVOKE_ALL: "backend:revoke-all",
|
|
8580
10272
|
GET_FILE: "backend:get-file",
|
|
8581
10273
|
RELOAD_WINDOW: "backend:reload-window",
|
|
10274
|
+
SAVE_LOCALE: "backend:save-locale",
|
|
8582
10275
|
CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
|
|
8583
10276
|
OPEN_EXTERNAL: "backend:open-external",
|
|
10277
|
+
OPEN_LOCAL_FILE: "backend:open-local-file",
|
|
10278
|
+
GET_LOCAL_CUSTOM_MODELS: "backend:get-local-custom-models",
|
|
10279
|
+
SAVE_LOCAL_CUSTOM_MODEL: "backend:save-local-custom-model",
|
|
10280
|
+
DELETE_LOCAL_CUSTOM_MODEL: "backend:delete-local-custom-model",
|
|
8584
10281
|
BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
|
|
8585
|
-
GET_SUPPORT_SCENES: "backend:get-support-scenes"
|
|
10282
|
+
GET_SUPPORT_SCENES: "backend:get-support-scenes",
|
|
10283
|
+
GET_ACCOUNT_USAGE: "backend:get-account-usage",
|
|
10284
|
+
GET_CHECKIN_STATUS: "backend:get-checkin-status",
|
|
10285
|
+
CLAIM_DAILY_CHECKIN: "backend:claim-daily-checkin",
|
|
10286
|
+
GET_ACTIVITY_BANNER: "backend:get-activity-banner",
|
|
10287
|
+
SKILLHUB_LIST: "backend:skillhub-list",
|
|
10288
|
+
SKILLHUB_CATEGORIES: "backend:skillhub-categories",
|
|
10289
|
+
SKILLHUB_SEARCH: "backend:skillhub-search",
|
|
10290
|
+
SKILLHUB_DETAIL: "backend:skillhub-detail",
|
|
10291
|
+
SKILLHUB_DOWNLOAD_URL: "backend:skillhub-download-url",
|
|
10292
|
+
SKILLHUB_EXISTS: "backend:skillhub-exists",
|
|
10293
|
+
SKILLHUB_REPORT_STATS: "backend:skillhub-report-stats"
|
|
8586
10294
|
};
|
|
8587
10295
|
/**
|
|
8588
10296
|
* 生成唯一请求 ID
|
|
@@ -8601,6 +10309,25 @@ var IPCBackendProvider = class {
|
|
|
8601
10309
|
this.debug = config.debug ?? false;
|
|
8602
10310
|
this.timeoutMs = config.timeoutMs ?? 3e4;
|
|
8603
10311
|
this.log("Initialized with IWidgetChannel");
|
|
10312
|
+
this.setupSessionChangeListener();
|
|
10313
|
+
}
|
|
10314
|
+
/**
|
|
10315
|
+
* 设置会话变化监听器
|
|
10316
|
+
* 监听来自 Extension Host (BackendBridgeService) 推送的 auth:session-changed 事件
|
|
10317
|
+
* 并更新本地 accountService
|
|
10318
|
+
*/
|
|
10319
|
+
setupSessionChangeListener() {
|
|
10320
|
+
this.log("Setting up session change listener");
|
|
10321
|
+
this.channel.on("auth:session-changed", (data) => {
|
|
10322
|
+
this.log("Received auth:session-changed event from Extension Host:", data);
|
|
10323
|
+
const account = data?.account || null;
|
|
10324
|
+
accountService.setAccount(account);
|
|
10325
|
+
this.log("Updated accountService with new session", {
|
|
10326
|
+
hasAccount: !!account,
|
|
10327
|
+
accountNickname: account?.nickname
|
|
10328
|
+
});
|
|
10329
|
+
});
|
|
10330
|
+
this.log("Session change listener setup complete");
|
|
8604
10331
|
}
|
|
8605
10332
|
/**
|
|
8606
10333
|
* 发送统一格式的后端请求
|
|
@@ -8629,12 +10356,14 @@ var IPCBackendProvider = class {
|
|
|
8629
10356
|
*/
|
|
8630
10357
|
async getAccount() {
|
|
8631
10358
|
this.log("Getting account via IPC");
|
|
10359
|
+
const startTime = performance.now();
|
|
8632
10360
|
try {
|
|
8633
10361
|
const account = await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT);
|
|
10362
|
+
this.log(`getAccount IPC completed in ${(performance.now() - startTime).toFixed(0)}ms`);
|
|
8634
10363
|
accountService.setAccount(account);
|
|
8635
10364
|
return account;
|
|
8636
10365
|
} catch (error) {
|
|
8637
|
-
this.log(
|
|
10366
|
+
this.log(`getAccount IPC failed after ${(performance.now() - startTime).toFixed(0)}ms:`, error);
|
|
8638
10367
|
accountService.setAccount(null);
|
|
8639
10368
|
return null;
|
|
8640
10369
|
}
|
|
@@ -8863,6 +10592,20 @@ var IPCBackendProvider = class {
|
|
|
8863
10592
|
}
|
|
8864
10593
|
}
|
|
8865
10594
|
/**
|
|
10595
|
+
* Save locale to argv.json without restarting the app.
|
|
10596
|
+
* The change takes effect on next manual restart.
|
|
10597
|
+
* @param params locale to save
|
|
10598
|
+
*/
|
|
10599
|
+
async saveLocale(params) {
|
|
10600
|
+
this.log("Saving locale to argv.json via IPC", params);
|
|
10601
|
+
try {
|
|
10602
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_LOCALE, params);
|
|
10603
|
+
} catch (error) {
|
|
10604
|
+
this.log("Save locale request failed:", error);
|
|
10605
|
+
throw error;
|
|
10606
|
+
}
|
|
10607
|
+
}
|
|
10608
|
+
/**
|
|
8866
10609
|
* 关闭 Agent Manager 面板
|
|
8867
10610
|
* IDE 环境: 通过 IPC 通知 IDE 关闭 Agent Manager(用于返回 IDE)
|
|
8868
10611
|
*/
|
|
@@ -8890,6 +10633,41 @@ var IPCBackendProvider = class {
|
|
|
8890
10633
|
}
|
|
8891
10634
|
}
|
|
8892
10635
|
/**
|
|
10636
|
+
* 打开本地文件
|
|
10637
|
+
* IDE 环境: 通过 IPC 通知 IDE 打开本地配置文件
|
|
10638
|
+
* @param filePath 要打开的文件路径
|
|
10639
|
+
*/
|
|
10640
|
+
async openLocalFile(filePath) {
|
|
10641
|
+
this.log("Opening local file via IPC:", filePath);
|
|
10642
|
+
try {
|
|
10643
|
+
if (!await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_LOCAL_FILE, { filePath })) throw new Error(`Failed to open local file: ${filePath}`);
|
|
10644
|
+
} catch (error) {
|
|
10645
|
+
this.log("Open local file request failed:", error);
|
|
10646
|
+
throw error;
|
|
10647
|
+
}
|
|
10648
|
+
}
|
|
10649
|
+
/**
|
|
10650
|
+
* 获取用户级本地自定义模型
|
|
10651
|
+
*/
|
|
10652
|
+
async getLocalCustomModels() {
|
|
10653
|
+
this.log("Getting local custom models via IPC");
|
|
10654
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_LOCAL_CUSTOM_MODELS);
|
|
10655
|
+
}
|
|
10656
|
+
/**
|
|
10657
|
+
* 保存用户级本地自定义模型
|
|
10658
|
+
*/
|
|
10659
|
+
async saveLocalCustomModel(request) {
|
|
10660
|
+
this.log("Saving local custom model via IPC:", request);
|
|
10661
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SAVE_LOCAL_CUSTOM_MODEL, request);
|
|
10662
|
+
}
|
|
10663
|
+
/**
|
|
10664
|
+
* 删除用户级本地自定义模型
|
|
10665
|
+
*/
|
|
10666
|
+
async deleteLocalCustomModel(id) {
|
|
10667
|
+
this.log("Deleting local custom model via IPC:", id);
|
|
10668
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.DELETE_LOCAL_CUSTOM_MODEL, { id });
|
|
10669
|
+
}
|
|
10670
|
+
/**
|
|
8893
10671
|
* 批量切换插件状态
|
|
8894
10672
|
* IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
|
|
8895
10673
|
*/
|
|
@@ -8923,6 +10701,187 @@ var IPCBackendProvider = class {
|
|
|
8923
10701
|
}
|
|
8924
10702
|
}
|
|
8925
10703
|
/**
|
|
10704
|
+
* 获取账号用量信息(积分/Credits)
|
|
10705
|
+
* IDE 环境: 通过 IPC 实时获取用量信息,每次打开菜单时调用
|
|
10706
|
+
*
|
|
10707
|
+
* 调用链:
|
|
10708
|
+
* 1. agent-ui: IPCBackendProvider.getAccountUsage()
|
|
10709
|
+
* 2. Agent Manager renderer: BackendService.getAccountUsage()
|
|
10710
|
+
* 3. Main Process: codebuddy:getAccountUsage IPC handler
|
|
10711
|
+
* 4. 返回 { usageLeft, usageTotal, editionType, refreshAt } 等字段
|
|
10712
|
+
*/
|
|
10713
|
+
async getAccountUsage() {
|
|
10714
|
+
this.log("Getting account usage via IPC");
|
|
10715
|
+
try {
|
|
10716
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACCOUNT_USAGE);
|
|
10717
|
+
} catch (error) {
|
|
10718
|
+
this.log("Get account usage failed:", error);
|
|
10719
|
+
return null;
|
|
10720
|
+
}
|
|
10721
|
+
}
|
|
10722
|
+
/**
|
|
10723
|
+
* 获取每日签到状态
|
|
10724
|
+
* IDE 环境: 通过 IPC 获取签到状态
|
|
10725
|
+
*/
|
|
10726
|
+
async getCheckinStatus() {
|
|
10727
|
+
this.log("Getting checkin status via IPC");
|
|
10728
|
+
try {
|
|
10729
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_CHECKIN_STATUS);
|
|
10730
|
+
} catch (error) {
|
|
10731
|
+
this.log("Get checkin status failed:", error);
|
|
10732
|
+
return null;
|
|
10733
|
+
}
|
|
10734
|
+
}
|
|
10735
|
+
/**
|
|
10736
|
+
* 执行每日签到
|
|
10737
|
+
* IDE 环境: 通过 IPC 执行签到
|
|
10738
|
+
*/
|
|
10739
|
+
async claimDailyCheckin() {
|
|
10740
|
+
this.log("Claiming daily checkin via IPC");
|
|
10741
|
+
try {
|
|
10742
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.CLAIM_DAILY_CHECKIN);
|
|
10743
|
+
} catch (error) {
|
|
10744
|
+
this.log("Claim daily checkin failed:", error);
|
|
10745
|
+
throw error;
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
/**
|
|
10749
|
+
* 获取活动 Banner
|
|
10750
|
+
* IDE 环境: 通过 IPC 获取活动 Banner
|
|
10751
|
+
*/
|
|
10752
|
+
async getActivityBanner() {
|
|
10753
|
+
this.log("Getting activity banner via IPC");
|
|
10754
|
+
try {
|
|
10755
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.GET_ACTIVITY_BANNER);
|
|
10756
|
+
} catch (error) {
|
|
10757
|
+
this.log("Get activity banner failed:", error);
|
|
10758
|
+
return null;
|
|
10759
|
+
}
|
|
10760
|
+
}
|
|
10761
|
+
/**
|
|
10762
|
+
* 获取 SkillHub 技能列表
|
|
10763
|
+
* IDE 环境: 通过 IPC 获取技能列表
|
|
10764
|
+
*/
|
|
10765
|
+
async getSkillHubList(params) {
|
|
10766
|
+
this.log("Getting SkillHub list via IPC", params);
|
|
10767
|
+
try {
|
|
10768
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_LIST, params);
|
|
10769
|
+
} catch (error) {
|
|
10770
|
+
this.log("Get SkillHub list failed:", error);
|
|
10771
|
+
throw error;
|
|
10772
|
+
}
|
|
10773
|
+
}
|
|
10774
|
+
/**
|
|
10775
|
+
* 获取 SkillHub 分类列表
|
|
10776
|
+
* IDE 环境: 通过 IPC 获取分类列表
|
|
10777
|
+
*/
|
|
10778
|
+
async getSkillHubCategories() {
|
|
10779
|
+
this.log("Getting SkillHub categories via IPC");
|
|
10780
|
+
try {
|
|
10781
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_CATEGORIES);
|
|
10782
|
+
} catch (error) {
|
|
10783
|
+
this.log("Get SkillHub categories failed:", error);
|
|
10784
|
+
throw error;
|
|
10785
|
+
}
|
|
10786
|
+
}
|
|
10787
|
+
/**
|
|
10788
|
+
* 搜索 SkillHub 技能
|
|
10789
|
+
* IDE 环境: 通过 IPC 搜索技能
|
|
10790
|
+
*/
|
|
10791
|
+
async getSkillHubSearch(q, limit = 20) {
|
|
10792
|
+
this.log("Searching SkillHub via IPC", {
|
|
10793
|
+
q,
|
|
10794
|
+
limit
|
|
10795
|
+
});
|
|
10796
|
+
try {
|
|
10797
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_SEARCH, {
|
|
10798
|
+
q,
|
|
10799
|
+
limit
|
|
10800
|
+
});
|
|
10801
|
+
} catch (error) {
|
|
10802
|
+
this.log("SkillHub search failed:", error);
|
|
10803
|
+
throw error;
|
|
10804
|
+
}
|
|
10805
|
+
}
|
|
10806
|
+
/**
|
|
10807
|
+
* 获取 SkillHub 技能详情
|
|
10808
|
+
* IDE 环境: 通过 IPC 获取技能详情
|
|
10809
|
+
*/
|
|
10810
|
+
async getSkillHubDetail(slug) {
|
|
10811
|
+
this.log("Getting SkillHub detail via IPC", { slug });
|
|
10812
|
+
try {
|
|
10813
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_DETAIL, { slug });
|
|
10814
|
+
} catch (error) {
|
|
10815
|
+
this.log("Get SkillHub detail failed:", error);
|
|
10816
|
+
throw error;
|
|
10817
|
+
}
|
|
10818
|
+
}
|
|
10819
|
+
/**
|
|
10820
|
+
* 批量检查 SkillHub 技能是否存在
|
|
10821
|
+
* IDE 环境: 通过 IPC 检查技能是否存在
|
|
10822
|
+
*/
|
|
10823
|
+
async getSkillHubExists(slugs) {
|
|
10824
|
+
this.log("Checking SkillHub exists via IPC", { slugs });
|
|
10825
|
+
try {
|
|
10826
|
+
return await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_EXISTS, { slugs });
|
|
10827
|
+
} catch (error) {
|
|
10828
|
+
this.log("SkillHub exists check failed:", error);
|
|
10829
|
+
throw error;
|
|
10830
|
+
}
|
|
10831
|
+
}
|
|
10832
|
+
/**
|
|
10833
|
+
* 上报 SkillHub 技能统计
|
|
10834
|
+
* IDE 环境: 通过 IPC 上报统计
|
|
10835
|
+
*/
|
|
10836
|
+
async reportSkillHubStats(slug, inc) {
|
|
10837
|
+
this.log("Reporting SkillHub stats via IPC", {
|
|
10838
|
+
slug,
|
|
10839
|
+
inc
|
|
10840
|
+
});
|
|
10841
|
+
try {
|
|
10842
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.SKILLHUB_REPORT_STATS, {
|
|
10843
|
+
slug,
|
|
10844
|
+
inc
|
|
10845
|
+
});
|
|
10846
|
+
} catch (error) {
|
|
10847
|
+
this.log("Report SkillHub stats failed:", error);
|
|
10848
|
+
}
|
|
10849
|
+
}
|
|
10850
|
+
/**
|
|
10851
|
+
* 安装 SkillHub 技能
|
|
10852
|
+
* IDE 环境: 通过 IPC 安装技能(下载 zip → 解压到本地)
|
|
10853
|
+
*/
|
|
10854
|
+
async installSkillHubSkill(slug, version, name) {
|
|
10855
|
+
this.log("Installing SkillHub skill via IPC", {
|
|
10856
|
+
slug,
|
|
10857
|
+
version,
|
|
10858
|
+
name
|
|
10859
|
+
});
|
|
10860
|
+
try {
|
|
10861
|
+
return await this.sendBackendRequest("backend:skillhub-install", {
|
|
10862
|
+
slug,
|
|
10863
|
+
version,
|
|
10864
|
+
name
|
|
10865
|
+
});
|
|
10866
|
+
} catch (error) {
|
|
10867
|
+
this.log("Install SkillHub skill failed:", error);
|
|
10868
|
+
throw error;
|
|
10869
|
+
}
|
|
10870
|
+
}
|
|
10871
|
+
/**
|
|
10872
|
+
* 获取本地已安装的 SkillHub 技能元信息
|
|
10873
|
+
* IDE 环境: 通过 IPC 获取元信息
|
|
10874
|
+
*/
|
|
10875
|
+
async getSkillHubInstalledMetas() {
|
|
10876
|
+
this.log("Getting SkillHub installed metas via IPC");
|
|
10877
|
+
try {
|
|
10878
|
+
return await this.sendBackendRequest("backend:skillhub-installed-metas");
|
|
10879
|
+
} catch (error) {
|
|
10880
|
+
this.log("Get SkillHub installed metas failed:", error);
|
|
10881
|
+
return [];
|
|
10882
|
+
}
|
|
10883
|
+
}
|
|
10884
|
+
/**
|
|
8926
10885
|
* 调试日志
|
|
8927
10886
|
*/
|
|
8928
10887
|
log(...args) {
|
|
@@ -8937,5 +10896,5 @@ function createIPCBackendProvider(config) {
|
|
|
8937
10896
|
}
|
|
8938
10897
|
|
|
8939
10898
|
//#endregion
|
|
8940
|
-
export { ActiveSessionImpl, AgentClient, BackendProvider, CloudAgentConnection, CloudAgentProvider, E2BFilesystem, HttpService, IPCBackendProvider, SessionManager, createBackendProvider, createIPCBackendProvider, httpService, isCloudAgentState };
|
|
10899
|
+
export { ActiveSessionImpl, AgentClient, BackendProvider, CloudAgentConnection, CloudAgentProvider, E2BFilesystem, HttpService, IPCBackendProvider, SessionError, SessionManager, createBackendProvider, createIPCBackendProvider, httpService, isCloudAgentState };
|
|
8941
10900
|
//# sourceMappingURL=index.mjs.map
|