@tencent-ai/cloud-agent-sdk 0.2.12 → 0.2.13-next.2bf8b02.20260209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +714 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +719 -100
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +719 -100
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +714 -140
- package/dist/index.mjs.map +1 -1
- package/dist/tencent-ai-cloud-agent-sdk-0.2.13-next.2bf8b02.20260209.tgz +0 -0
- package/package.json +4 -3
- package/dist/tencent-ai-cloud-agent-sdk-0.2.12.tgz +0 -0
package/dist/index.mjs
CHANGED
|
@@ -661,7 +661,8 @@ const ExtensionMethod = {
|
|
|
661
661
|
CHECKPOINT: "_codebuddy.ai/checkpoint",
|
|
662
662
|
USAGE: "_codebuddy.ai/usage",
|
|
663
663
|
COMMAND: "_codebuddy.ai/command",
|
|
664
|
-
AUTH_URL: "_codebuddy.ai/authUrl"
|
|
664
|
+
AUTH_URL: "_codebuddy.ai/authUrl",
|
|
665
|
+
FILE_HISTORY_SNAPSHOT: "_codebuddy.ai/file_history_snapshot"
|
|
665
666
|
};
|
|
666
667
|
/**
|
|
667
668
|
* All known extension methods
|
|
@@ -672,7 +673,8 @@ const KNOWN_EXTENSIONS = [
|
|
|
672
673
|
ExtensionMethod.CHECKPOINT,
|
|
673
674
|
ExtensionMethod.USAGE,
|
|
674
675
|
ExtensionMethod.COMMAND,
|
|
675
|
-
ExtensionMethod.AUTH_URL
|
|
676
|
+
ExtensionMethod.AUTH_URL,
|
|
677
|
+
ExtensionMethod.FILE_HISTORY_SNAPSHOT
|
|
676
678
|
];
|
|
677
679
|
|
|
678
680
|
//#endregion
|
|
@@ -2244,6 +2246,24 @@ var CloudAgentConnection = class {
|
|
|
2244
2246
|
},
|
|
2245
2247
|
onUsageUpdate: (usage) => {
|
|
2246
2248
|
this.emit("usageUpdate", usage);
|
|
2249
|
+
},
|
|
2250
|
+
onExtNotification: (method, params) => {
|
|
2251
|
+
console.log("[CloudConnection] Received extNotification:", {
|
|
2252
|
+
method,
|
|
2253
|
+
paramsKeys: Object.keys(params)
|
|
2254
|
+
});
|
|
2255
|
+
if (method === ExtensionMethod.COMMAND) {
|
|
2256
|
+
const action = params.action;
|
|
2257
|
+
const commandParams = params.params;
|
|
2258
|
+
console.log("[CloudConnection] Emitting command event:", {
|
|
2259
|
+
action,
|
|
2260
|
+
paramsKeys: commandParams ? Object.keys(commandParams) : []
|
|
2261
|
+
});
|
|
2262
|
+
this.emit("command", {
|
|
2263
|
+
action,
|
|
2264
|
+
params: commandParams
|
|
2265
|
+
});
|
|
2266
|
+
}
|
|
2247
2267
|
}
|
|
2248
2268
|
});
|
|
2249
2269
|
this.setupEventForwarding();
|
|
@@ -2372,7 +2392,7 @@ var CloudAgentConnection = class {
|
|
|
2372
2392
|
}
|
|
2373
2393
|
async createSession(params) {
|
|
2374
2394
|
return {
|
|
2375
|
-
...await this.client.
|
|
2395
|
+
...await this.client.createSession(this.cwd),
|
|
2376
2396
|
sessionId: this.agentId
|
|
2377
2397
|
};
|
|
2378
2398
|
}
|
|
@@ -2490,6 +2510,16 @@ var CloudAgentConnection = class {
|
|
|
2490
2510
|
get sessionConnectionInfo() {
|
|
2491
2511
|
return this._sessionConnectionInfo;
|
|
2492
2512
|
}
|
|
2513
|
+
async reportTelemetry(eventName, payload) {
|
|
2514
|
+
try {
|
|
2515
|
+
await this.client.extMethod("reportTelemetry", {
|
|
2516
|
+
eventName,
|
|
2517
|
+
payload
|
|
2518
|
+
});
|
|
2519
|
+
} catch (error) {
|
|
2520
|
+
console.warn("[CloudAgentConnection] reportTelemetry failed:", error);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2493
2523
|
async extMethod(method, params) {
|
|
2494
2524
|
return this.client.extMethod(method, params);
|
|
2495
2525
|
}
|
|
@@ -5253,7 +5283,7 @@ var axios_default = axios;
|
|
|
5253
5283
|
* 特性:
|
|
5254
5284
|
* - 单例模式,全局唯一实例,延迟初始化(首次使用时自动创建)
|
|
5255
5285
|
* - 支持拦截器注册(其他模块可注入 header)
|
|
5256
|
-
* - 统一 401
|
|
5286
|
+
* - 统一 401 处理(支持自动刷新 token 并重试)
|
|
5257
5287
|
* - 自动携带凭证(withCredentials)
|
|
5258
5288
|
* - 类型安全
|
|
5259
5289
|
*
|
|
@@ -5293,6 +5323,8 @@ var HttpService = class HttpService {
|
|
|
5293
5323
|
*/
|
|
5294
5324
|
constructor(config = {}) {
|
|
5295
5325
|
this.unauthorizedCallbacks = /* @__PURE__ */ new Set();
|
|
5326
|
+
this.isRefreshing = false;
|
|
5327
|
+
this.refreshSubscribers = [];
|
|
5296
5328
|
this.config = config;
|
|
5297
5329
|
this.axiosInstance = axios_default.create({
|
|
5298
5330
|
baseURL: config.baseURL?.replace(/\/$/, "") || "",
|
|
@@ -5333,18 +5365,54 @@ var HttpService = class HttpService {
|
|
|
5333
5365
|
}, (error) => Promise.reject(error));
|
|
5334
5366
|
}
|
|
5335
5367
|
/**
|
|
5336
|
-
* 注册默认响应拦截器(处理 401
|
|
5368
|
+
* 注册默认响应拦截器(处理 401,支持自动重试)
|
|
5337
5369
|
*/
|
|
5338
5370
|
registerDefaultResponseInterceptor() {
|
|
5339
|
-
this.axiosInstance.interceptors.response.use((response) => response, (error) => {
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5371
|
+
this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
|
|
5372
|
+
const originalRequest = error.config;
|
|
5373
|
+
if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
|
|
5374
|
+
if (originalRequest.url?.includes("/console/accounts")) {
|
|
5375
|
+
console.warn("[HttpService] Unauthorized 401 on refresh endpoint, not retrying");
|
|
5376
|
+
return Promise.reject(error);
|
|
5377
|
+
}
|
|
5378
|
+
console.warn("[HttpService] Unauthorized 401, attempting token refresh and retry");
|
|
5379
|
+
originalRequest._retry = true;
|
|
5380
|
+
if (this.isRefreshing) return new Promise((resolve, reject) => {
|
|
5381
|
+
this.refreshSubscribers.push((success) => {
|
|
5382
|
+
if (success) this.axiosInstance.request(originalRequest).then(resolve).catch(reject);
|
|
5383
|
+
else reject(error);
|
|
5384
|
+
});
|
|
5385
|
+
});
|
|
5386
|
+
this.isRefreshing = true;
|
|
5387
|
+
try {
|
|
5388
|
+
await this.triggerUnauthorizedCallbacks();
|
|
5389
|
+
this.onRefreshSuccess();
|
|
5390
|
+
return this.axiosInstance.request(originalRequest);
|
|
5391
|
+
} catch (refreshError) {
|
|
5392
|
+
this.onRefreshFailure();
|
|
5393
|
+
return Promise.reject(error);
|
|
5394
|
+
} finally {
|
|
5395
|
+
this.isRefreshing = false;
|
|
5396
|
+
}
|
|
5343
5397
|
}
|
|
5344
5398
|
return Promise.reject(error);
|
|
5345
5399
|
});
|
|
5346
5400
|
}
|
|
5347
5401
|
/**
|
|
5402
|
+
* token 刷新成功,通知所有等待的请求
|
|
5403
|
+
*/
|
|
5404
|
+
onRefreshSuccess() {
|
|
5405
|
+
this.refreshSubscribers.forEach((callback) => callback(true));
|
|
5406
|
+
this.refreshSubscribers = [];
|
|
5407
|
+
}
|
|
5408
|
+
/**
|
|
5409
|
+
* token 刷新失败,通知所有等待的请求
|
|
5410
|
+
*/
|
|
5411
|
+
onRefreshFailure() {
|
|
5412
|
+
this.refreshSubscribers.forEach((callback) => callback(false));
|
|
5413
|
+
this.refreshSubscribers = [];
|
|
5414
|
+
}
|
|
5415
|
+
/**
|
|
5348
5416
|
* 注册请求拦截器
|
|
5349
5417
|
* @param onFulfilled 请求成功拦截器
|
|
5350
5418
|
* @param onRejected 请求失败拦截器
|
|
@@ -5421,16 +5489,18 @@ var HttpService = class HttpService {
|
|
|
5421
5489
|
this.unauthorizedCallbacks.delete(callback);
|
|
5422
5490
|
}
|
|
5423
5491
|
/**
|
|
5424
|
-
* 触发所有 401
|
|
5492
|
+
* 触发所有 401 回调并等待完成
|
|
5493
|
+
* @returns Promise,等待所有回调完成
|
|
5494
|
+
* @throws 如果任何回调失败,则抛出错误
|
|
5425
5495
|
*/
|
|
5426
|
-
triggerUnauthorizedCallbacks() {
|
|
5427
|
-
this.unauthorizedCallbacks
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
}
|
|
5496
|
+
async triggerUnauthorizedCallbacks() {
|
|
5497
|
+
const callbacks = Array.from(this.unauthorizedCallbacks);
|
|
5498
|
+
const failedResults = (await Promise.allSettled(callbacks.map((callback) => callback()))).filter((r) => r.status === "rejected");
|
|
5499
|
+
if (failedResults.length > 0) {
|
|
5500
|
+
const errors = failedResults.map((r) => r.reason);
|
|
5501
|
+
console.error("[HttpService] Some unauthorized callbacks failed:", errors);
|
|
5502
|
+
throw errors[0];
|
|
5503
|
+
}
|
|
5434
5504
|
}
|
|
5435
5505
|
/**
|
|
5436
5506
|
* 更新 authToken
|
|
@@ -5542,6 +5612,7 @@ var AccountService = class {
|
|
|
5542
5612
|
this.initPromise = null;
|
|
5543
5613
|
this.initResolve = null;
|
|
5544
5614
|
this.requestInterceptorId = null;
|
|
5615
|
+
this.crossTabBroadcaster = null;
|
|
5545
5616
|
this.initPromise = new Promise((resolve) => {
|
|
5546
5617
|
this.initResolve = resolve;
|
|
5547
5618
|
});
|
|
@@ -5590,15 +5661,34 @@ var AccountService = class {
|
|
|
5590
5661
|
this.initialized = true;
|
|
5591
5662
|
this.initResolve?.(account);
|
|
5592
5663
|
}
|
|
5593
|
-
if (!wasInitialized || prev?.uid !== account?.uid)
|
|
5664
|
+
if (!wasInitialized || prev?.uid !== account?.uid) {
|
|
5665
|
+
this.notifyListeners();
|
|
5666
|
+
if (account && this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogin();
|
|
5667
|
+
}
|
|
5594
5668
|
}
|
|
5595
5669
|
/**
|
|
5596
5670
|
* 清除账号(登出)
|
|
5671
|
+
* 先广播登出消息,再清除本地账号
|
|
5597
5672
|
*/
|
|
5598
5673
|
clearAccount() {
|
|
5674
|
+
if (this.crossTabBroadcaster) this.crossTabBroadcaster.broadcastLogout();
|
|
5675
|
+
this.setAccount(null);
|
|
5676
|
+
}
|
|
5677
|
+
/**
|
|
5678
|
+
* 静默清除账号(不广播)
|
|
5679
|
+
* 用于收到其他标签页 logout 消息时,避免循环广播
|
|
5680
|
+
*/
|
|
5681
|
+
clearAccountSilently() {
|
|
5599
5682
|
this.setAccount(null);
|
|
5600
5683
|
}
|
|
5601
5684
|
/**
|
|
5685
|
+
* 设置跨标签页认证同步广播器
|
|
5686
|
+
* 应在应用初始化时由上层(如 agent-ui)调用
|
|
5687
|
+
*/
|
|
5688
|
+
setCrossTabBroadcaster(broadcaster) {
|
|
5689
|
+
this.crossTabBroadcaster = broadcaster;
|
|
5690
|
+
}
|
|
5691
|
+
/**
|
|
5602
5692
|
* 订阅账号变化
|
|
5603
5693
|
* @param callback 变化时的回调函数
|
|
5604
5694
|
* @returns 取消订阅函数
|
|
@@ -5663,6 +5753,11 @@ var AccountService = class {
|
|
|
5663
5753
|
* 导出单例实例
|
|
5664
5754
|
*/
|
|
5665
5755
|
const accountService = new AccountService();
|
|
5756
|
+
/**
|
|
5757
|
+
* 暴露给全局,供 Agent Manager 直接调用 setAccount 刷新 Widget 状态
|
|
5758
|
+
* 这是为了解决 IDE 环境中 IPC 事件无法直接触发 Widget 账号刷新的问题
|
|
5759
|
+
*/
|
|
5760
|
+
if (typeof window !== "undefined") window.__genieAccountService = accountService;
|
|
5666
5761
|
|
|
5667
5762
|
//#endregion
|
|
5668
5763
|
//#region ../agent-provider/src/common/utils/concurrency.ts
|
|
@@ -5765,20 +5860,32 @@ var CosUploadService = class {
|
|
|
5765
5860
|
* 上传单个文件到 COS
|
|
5766
5861
|
*
|
|
5767
5862
|
* @param file - 要上传的文件
|
|
5863
|
+
* @param abortSignal - 可选的 AbortSignal,用于取消上传
|
|
5768
5864
|
* @returns 上传结果,包含访问 URL 或错误信息
|
|
5769
5865
|
*/
|
|
5770
|
-
async uploadFile(file) {
|
|
5866
|
+
async uploadFile(file, abortSignal) {
|
|
5771
5867
|
const filename = file.name;
|
|
5772
5868
|
this.logger?.info(`[CosUploadService] Uploading file: ${filename}`);
|
|
5773
5869
|
try {
|
|
5870
|
+
if (abortSignal?.aborted) return {
|
|
5871
|
+
success: false,
|
|
5872
|
+
error: "Upload cancelled",
|
|
5873
|
+
aborted: true
|
|
5874
|
+
};
|
|
5774
5875
|
const objectKey = this.generateObjectKey(filename);
|
|
5775
5876
|
this.logger?.debug(`[CosUploadService] Generated objectKey: ${objectKey}`);
|
|
5776
5877
|
const presignedItem = (await this.getPresignedUrls([objectKey])).items[0];
|
|
5777
5878
|
if (!presignedItem) throw new Error("No presigned URL item returned");
|
|
5879
|
+
if (abortSignal?.aborted) return {
|
|
5880
|
+
success: false,
|
|
5881
|
+
error: "Upload cancelled",
|
|
5882
|
+
aborted: true
|
|
5883
|
+
};
|
|
5778
5884
|
const uploadResponse = await fetch(presignedItem.upload_url, {
|
|
5779
5885
|
method: "PUT",
|
|
5780
5886
|
body: file,
|
|
5781
|
-
headers: { "Content-Type": file.type || "application/octet-stream" }
|
|
5887
|
+
headers: { "Content-Type": file.type || "application/octet-stream" },
|
|
5888
|
+
signal: abortSignal
|
|
5782
5889
|
});
|
|
5783
5890
|
if (!uploadResponse.ok) {
|
|
5784
5891
|
const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
|
|
@@ -5792,6 +5899,11 @@ var CosUploadService = class {
|
|
|
5792
5899
|
objectKey
|
|
5793
5900
|
};
|
|
5794
5901
|
} catch (error) {
|
|
5902
|
+
if (error instanceof Error && error.name === "AbortError") return {
|
|
5903
|
+
success: false,
|
|
5904
|
+
error: "Upload cancelled",
|
|
5905
|
+
aborted: true
|
|
5906
|
+
};
|
|
5795
5907
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
5796
5908
|
this.logger?.error(`[CosUploadService] Upload failed: ${filename}`, error);
|
|
5797
5909
|
return {
|
|
@@ -5806,14 +5918,25 @@ var CosUploadService = class {
|
|
|
5806
5918
|
* 使用并发控制,限制同时上传的文件数量
|
|
5807
5919
|
*
|
|
5808
5920
|
* @param files - 要上传的文件数组
|
|
5921
|
+
* @param abortSignal - 可选的 AbortSignal,用于取消上传
|
|
5809
5922
|
* @returns 所有文件的上传结果
|
|
5810
5923
|
*/
|
|
5811
|
-
async uploadFiles(files) {
|
|
5924
|
+
async uploadFiles(files, abortSignal) {
|
|
5812
5925
|
if (files.length === 0) return {
|
|
5813
5926
|
success: true,
|
|
5814
5927
|
urls: [],
|
|
5815
5928
|
results: []
|
|
5816
5929
|
};
|
|
5930
|
+
if (abortSignal?.aborted) return {
|
|
5931
|
+
success: false,
|
|
5932
|
+
error: "Upload cancelled",
|
|
5933
|
+
aborted: true,
|
|
5934
|
+
results: files.map(() => ({
|
|
5935
|
+
success: false,
|
|
5936
|
+
error: "Upload cancelled",
|
|
5937
|
+
aborted: true
|
|
5938
|
+
}))
|
|
5939
|
+
};
|
|
5817
5940
|
this.logger?.info(`[CosUploadService] Uploading ${files.length} file(s) with concurrency ${this.uploadConcurrency}`);
|
|
5818
5941
|
try {
|
|
5819
5942
|
const fileInfos = files.map((file) => ({
|
|
@@ -5825,6 +5948,12 @@ var CosUploadService = class {
|
|
|
5825
5948
|
this.logger?.debug(`[CosUploadService] Got ${presignedResponse.items.length} presigned URLs`);
|
|
5826
5949
|
if (presignedResponse.items.length !== fileInfos.length) throw new Error(`Expected ${fileInfos.length} presigned URLs, got ${presignedResponse.items.length}`);
|
|
5827
5950
|
const results = (await runWithConcurrencySettled(fileInfos.map(({ file }, index) => async () => {
|
|
5951
|
+
if (abortSignal?.aborted) return {
|
|
5952
|
+
success: false,
|
|
5953
|
+
error: "Upload cancelled",
|
|
5954
|
+
aborted: true,
|
|
5955
|
+
objectKey: fileInfos[index].objectKey
|
|
5956
|
+
};
|
|
5828
5957
|
const presignedItem = presignedResponse.items[index];
|
|
5829
5958
|
if (!presignedItem) return {
|
|
5830
5959
|
success: false,
|
|
@@ -5835,7 +5964,8 @@ var CosUploadService = class {
|
|
|
5835
5964
|
const uploadResponse = await fetch(presignedItem.upload_url, {
|
|
5836
5965
|
method: "PUT",
|
|
5837
5966
|
body: file,
|
|
5838
|
-
headers: { "Content-Type": file.type || "application/octet-stream" }
|
|
5967
|
+
headers: { "Content-Type": file.type || "application/octet-stream" },
|
|
5968
|
+
signal: abortSignal
|
|
5839
5969
|
});
|
|
5840
5970
|
if (!uploadResponse.ok) {
|
|
5841
5971
|
const errorText = await uploadResponse.text().catch(() => uploadResponse.statusText);
|
|
@@ -5852,6 +5982,12 @@ var CosUploadService = class {
|
|
|
5852
5982
|
objectKey: presignedItem.object_key
|
|
5853
5983
|
};
|
|
5854
5984
|
} catch (error) {
|
|
5985
|
+
if (error instanceof Error && error.name === "AbortError") return {
|
|
5986
|
+
success: false,
|
|
5987
|
+
error: "Upload cancelled",
|
|
5988
|
+
aborted: true,
|
|
5989
|
+
objectKey: presignedItem.object_key
|
|
5990
|
+
};
|
|
5855
5991
|
return {
|
|
5856
5992
|
success: false,
|
|
5857
5993
|
error: error instanceof Error ? error.message : "Unknown error",
|
|
@@ -6252,15 +6388,9 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6252
6388
|
const url = this.buildGetUrl("/console/as/conversations/", params);
|
|
6253
6389
|
const apiResponse = await httpService.get(url);
|
|
6254
6390
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
6255
|
-
const agents = apiResponse.data.conversations.map((a) => this.toAgentState(a));
|
|
6256
|
-
const pagination = apiResponse.data.pagination;
|
|
6257
|
-
console.log("[CloudAgentProvider] API response:", {
|
|
6258
|
-
agentsCount: agents.length,
|
|
6259
|
-
pagination
|
|
6260
|
-
});
|
|
6261
6391
|
return {
|
|
6262
|
-
agents,
|
|
6263
|
-
pagination
|
|
6392
|
+
agents: apiResponse.data.conversations.map((a) => this.toAgentState(a)),
|
|
6393
|
+
pagination: apiResponse.data.pagination
|
|
6264
6394
|
};
|
|
6265
6395
|
} catch (error) {
|
|
6266
6396
|
this.logger?.error("Failed to list agents:", error);
|
|
@@ -6270,13 +6400,21 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6270
6400
|
/**
|
|
6271
6401
|
* Create a new conversation
|
|
6272
6402
|
* POST {endpoint}/console/as/conversations
|
|
6403
|
+
* @param params - Session params containing cwd and optional configuration
|
|
6273
6404
|
*/
|
|
6274
|
-
async create() {
|
|
6405
|
+
async create(params) {
|
|
6275
6406
|
try {
|
|
6276
|
-
const
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
});
|
|
6407
|
+
const { options = {} } = params;
|
|
6408
|
+
const codebuddyMeta = options._meta?.["codebuddy.ai"];
|
|
6409
|
+
const tagsObj = options.tags || codebuddyMeta?.tags;
|
|
6410
|
+
const tagsArray = tagsObj ? Object.entries(tagsObj).map(([key, value]) => `${key}:${value}`) : void 0;
|
|
6411
|
+
const createPayload = {
|
|
6412
|
+
prompt: (options.prompt || "").slice(0, 100),
|
|
6413
|
+
model: options.model || "deepseek-r1",
|
|
6414
|
+
...tagsArray && tagsArray.length > 0 ? { tags: tagsArray } : {}
|
|
6415
|
+
};
|
|
6416
|
+
console.log("[CloudAgentProvider] Creating conversation with payload:", createPayload);
|
|
6417
|
+
const apiResponse = await httpService.post("/console/as/conversations/", createPayload);
|
|
6280
6418
|
if (!apiResponse.data) throw new Error("No data in API response");
|
|
6281
6419
|
this.logger?.info(`Created conversation: ${apiResponse.data.id}`);
|
|
6282
6420
|
return apiResponse.data.id;
|
|
@@ -6476,9 +6614,12 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6476
6614
|
this.logger?.warn("[CloudAgentProvider] No data in config response, returning empty models");
|
|
6477
6615
|
return [];
|
|
6478
6616
|
}
|
|
6479
|
-
const
|
|
6480
|
-
|
|
6481
|
-
|
|
6617
|
+
const productConfig = apiResponse.data;
|
|
6618
|
+
const allModels = productConfig.models ?? [];
|
|
6619
|
+
const cliModelIds = (productConfig.agents ?? []).find((agent) => agent.name === "cli")?.models ?? [];
|
|
6620
|
+
const filteredModels = cliModelIds.length > 0 ? allModels.filter((model) => cliModelIds.includes(model.id)) : allModels;
|
|
6621
|
+
this.logger?.info(`[CloudAgentProvider] Retrieved ${filteredModels.length} models for cli agent (total: ${allModels.length})`);
|
|
6622
|
+
return filteredModels.map((model) => ({
|
|
6482
6623
|
id: model.id,
|
|
6483
6624
|
name: model.name ?? model.id,
|
|
6484
6625
|
description: model.description,
|
|
@@ -6582,7 +6723,7 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6582
6723
|
/**
|
|
6583
6724
|
* Upload files to cloud storage via COS presigned URL
|
|
6584
6725
|
*
|
|
6585
|
-
* @param params - files array (File objects in browser)
|
|
6726
|
+
* @param params - files array (File objects in browser), optional abortSignal
|
|
6586
6727
|
* @returns Response with corresponding cloud URLs
|
|
6587
6728
|
*/
|
|
6588
6729
|
async uploadFile(params) {
|
|
@@ -6592,12 +6733,13 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6592
6733
|
success: false,
|
|
6593
6734
|
error: "No valid File objects provided"
|
|
6594
6735
|
};
|
|
6595
|
-
const result = await this.cosUploadService.uploadFiles(files);
|
|
6736
|
+
const result = await this.cosUploadService.uploadFiles(files, params.abortSignal);
|
|
6596
6737
|
return {
|
|
6597
6738
|
success: result.success,
|
|
6598
6739
|
urls: result.urls,
|
|
6599
6740
|
expireSeconds: result.expireSeconds,
|
|
6600
|
-
error: result.error
|
|
6741
|
+
error: result.error,
|
|
6742
|
+
aborted: result.aborted
|
|
6601
6743
|
};
|
|
6602
6744
|
}
|
|
6603
6745
|
/**
|
|
@@ -6639,20 +6781,22 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6639
6781
|
}
|
|
6640
6782
|
/**
|
|
6641
6783
|
* 获取支持的场景列表
|
|
6642
|
-
* API 端点: GET /
|
|
6784
|
+
* API 端点: GET /v2/as/support/scenes (不鉴权)
|
|
6643
6785
|
* 用于 Welcome 页面的 QuickActions 快捷操作
|
|
6644
6786
|
*
|
|
6787
|
+
* @param locale - 可选,语言环境(如 'zh-CN', 'en-US'),用于获取对应语言的场景数据
|
|
6645
6788
|
* @returns Promise<SupportScene[]> 支持的场景列表
|
|
6646
6789
|
*/
|
|
6647
|
-
async getSupportScenes() {
|
|
6790
|
+
async getSupportScenes(locale) {
|
|
6648
6791
|
try {
|
|
6649
|
-
const
|
|
6792
|
+
const url = this.buildGetUrl("/v2/as/support/scenes", locale ? { locale } : void 0);
|
|
6793
|
+
const apiResponse = await httpService.get(url);
|
|
6650
6794
|
if (!apiResponse.data) {
|
|
6651
6795
|
this.logger?.warn("[CloudAgentProvider] No data in support scenes response");
|
|
6652
6796
|
return [];
|
|
6653
6797
|
}
|
|
6654
6798
|
const scenes = apiResponse.data.scenes || [];
|
|
6655
|
-
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes`);
|
|
6799
|
+
this.logger?.info(`[CloudAgentProvider] Retrieved ${scenes.length} support scenes${locale ? ` for locale: ${locale}` : ""}`);
|
|
6656
6800
|
return scenes;
|
|
6657
6801
|
} catch (error) {
|
|
6658
6802
|
this.logger?.error("[CloudAgentProvider] Failed to get support scenes:", error);
|
|
@@ -6668,7 +6812,8 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6668
6812
|
type: "cloud",
|
|
6669
6813
|
status,
|
|
6670
6814
|
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
6671
|
-
capabilities: this.options.clientCapabilities
|
|
6815
|
+
capabilities: this.options.clientCapabilities,
|
|
6816
|
+
isUserDefinedTitle: data.isUserDefinedTitle
|
|
6672
6817
|
};
|
|
6673
6818
|
}
|
|
6674
6819
|
/**
|
|
@@ -6684,6 +6829,23 @@ var CloudAgentProvider = class CloudAgentProvider {
|
|
|
6684
6829
|
const queryString = searchParams.toString();
|
|
6685
6830
|
return queryString ? `${path}?${queryString}` : path;
|
|
6686
6831
|
}
|
|
6832
|
+
/**
|
|
6833
|
+
* 上报 telemetry 事件(Cloud 模式)
|
|
6834
|
+
* 通过 HTTP POST 发送到 /v2/report
|
|
6835
|
+
*/
|
|
6836
|
+
async reportTelemetry(eventName, payload) {
|
|
6837
|
+
try {
|
|
6838
|
+
const events = [{
|
|
6839
|
+
eventCode: eventName,
|
|
6840
|
+
timestamp: Date.now(),
|
|
6841
|
+
reportDelay: 0,
|
|
6842
|
+
...payload
|
|
6843
|
+
}];
|
|
6844
|
+
await httpService.post("/v2/report", events);
|
|
6845
|
+
} catch (error) {
|
|
6846
|
+
this.logger?.warn("reportTelemetry() failed:", error);
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6687
6849
|
};
|
|
6688
6850
|
|
|
6689
6851
|
//#endregion
|
|
@@ -6722,6 +6884,7 @@ var ActiveSessionImpl = class {
|
|
|
6722
6884
|
this._availableCommands = [];
|
|
6723
6885
|
this.listeners = /* @__PURE__ */ new Map();
|
|
6724
6886
|
this.onceListeners = /* @__PURE__ */ new Map();
|
|
6887
|
+
this.connectionListeners = [];
|
|
6725
6888
|
this._id = sessionId;
|
|
6726
6889
|
this._agentId = agentId;
|
|
6727
6890
|
this.connection = connection;
|
|
@@ -6747,6 +6910,18 @@ var ActiveSessionImpl = class {
|
|
|
6747
6910
|
return this._agentId;
|
|
6748
6911
|
}
|
|
6749
6912
|
/**
|
|
6913
|
+
* Actual workspace path (set from newSession response _meta)
|
|
6914
|
+
*/
|
|
6915
|
+
get cwd() {
|
|
6916
|
+
return this._cwd;
|
|
6917
|
+
}
|
|
6918
|
+
/**
|
|
6919
|
+
* Set actual workspace path (called by SessionManager after createSession)
|
|
6920
|
+
*/
|
|
6921
|
+
setCwd(cwd) {
|
|
6922
|
+
this._cwd = cwd;
|
|
6923
|
+
}
|
|
6924
|
+
/**
|
|
6750
6925
|
* Agent state (live connection state)
|
|
6751
6926
|
* Returns LocalAgentState or CloudAgentState based on transport type
|
|
6752
6927
|
*/
|
|
@@ -6963,8 +7138,8 @@ var ActiveSessionImpl = class {
|
|
|
6963
7138
|
* await session.setMode('architect');
|
|
6964
7139
|
* ```
|
|
6965
7140
|
*/
|
|
6966
|
-
async setMode(modeId) {
|
|
6967
|
-
if (this._availableModes) {
|
|
7141
|
+
async setMode(modeId, skipAvailableChecker) {
|
|
7142
|
+
if (this._availableModes && !skipAvailableChecker) {
|
|
6968
7143
|
if (!this._availableModes.some((m) => m.id === modeId)) {
|
|
6969
7144
|
const availableIds = this._availableModes.map((m) => m.id).join(", ");
|
|
6970
7145
|
throw new Error(`Invalid modeId: "${modeId}". Available modes: ${availableIds}`);
|
|
@@ -7064,6 +7239,7 @@ var ActiveSessionImpl = class {
|
|
|
7064
7239
|
* Disconnect from the session/agent
|
|
7065
7240
|
*/
|
|
7066
7241
|
disconnect() {
|
|
7242
|
+
this.removeConnectionListeners();
|
|
7067
7243
|
this.connection.disconnect();
|
|
7068
7244
|
this.removeAllListeners();
|
|
7069
7245
|
this.logger?.info(`Session ${this._id}: Disconnected`);
|
|
@@ -7087,60 +7263,80 @@ var ActiveSessionImpl = class {
|
|
|
7087
7263
|
if (!this.connection.isInitialized) throw new Error(`Session ${this._id}: Connection not initialized.`);
|
|
7088
7264
|
return this.connection;
|
|
7089
7265
|
}
|
|
7266
|
+
/**
|
|
7267
|
+
* 在 connection 上注册 listener 并保存引用,便于 disconnect 时移除
|
|
7268
|
+
*/
|
|
7269
|
+
addConnectionListener(connection, event, listener) {
|
|
7270
|
+
connection.on(event, listener);
|
|
7271
|
+
this.connectionListeners.push({
|
|
7272
|
+
event,
|
|
7273
|
+
listener
|
|
7274
|
+
});
|
|
7275
|
+
}
|
|
7276
|
+
/**
|
|
7277
|
+
* 从 connection 上移除所有本 session 注册的 listener
|
|
7278
|
+
*/
|
|
7279
|
+
removeConnectionListeners() {
|
|
7280
|
+
for (const { event, listener } of this.connectionListeners) this.connection.off(event, listener);
|
|
7281
|
+
this.connectionListeners = [];
|
|
7282
|
+
}
|
|
7090
7283
|
setupConnectionEvents(connection) {
|
|
7091
|
-
|
|
7284
|
+
this.addConnectionListener(connection, "connected", () => {
|
|
7092
7285
|
this.emit("connected", void 0);
|
|
7093
7286
|
});
|
|
7094
|
-
|
|
7287
|
+
this.addConnectionListener(connection, "disconnected", () => {
|
|
7095
7288
|
this.emit("disconnected", void 0);
|
|
7096
7289
|
});
|
|
7097
|
-
|
|
7290
|
+
this.addConnectionListener(connection, "error", (error) => {
|
|
7098
7291
|
this.emit("error", error);
|
|
7099
7292
|
});
|
|
7100
|
-
|
|
7293
|
+
this.addConnectionListener(connection, "sessionUpdate", (update) => {
|
|
7101
7294
|
this.emit("sessionUpdate", update);
|
|
7102
7295
|
});
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
artifactUri: artifact.uri,
|
|
7106
|
-
artifactType: artifact.type
|
|
7107
|
-
});
|
|
7296
|
+
this.addConnectionListener(connection, "artifactCreated", (artifact) => {
|
|
7297
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7108
7298
|
this.emit("artifactCreated", artifact);
|
|
7109
7299
|
});
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
artifactUri: artifact.uri,
|
|
7113
|
-
artifactType: artifact.type
|
|
7114
|
-
});
|
|
7300
|
+
this.addConnectionListener(connection, "artifactUpdated", (artifact) => {
|
|
7301
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7115
7302
|
this.emit("artifactUpdated", artifact);
|
|
7116
7303
|
});
|
|
7117
|
-
|
|
7118
|
-
|
|
7304
|
+
this.addConnectionListener(connection, "artifactDeleted", (artifact) => {
|
|
7305
|
+
if (!this.shouldForwardArtifact(artifact)) return;
|
|
7119
7306
|
this.emit("artifactDeleted", artifact);
|
|
7120
7307
|
});
|
|
7121
|
-
|
|
7308
|
+
this.addConnectionListener(connection, "permissionRequest", (request) => {
|
|
7122
7309
|
this.emit("permissionRequest", request);
|
|
7123
7310
|
});
|
|
7124
|
-
|
|
7311
|
+
this.addConnectionListener(connection, "questionRequest", (request) => {
|
|
7125
7312
|
this.emit("questionRequest", request);
|
|
7126
7313
|
});
|
|
7127
|
-
|
|
7314
|
+
this.addConnectionListener(connection, "questionCancelled", () => {
|
|
7128
7315
|
this.prompts.cancel();
|
|
7129
7316
|
});
|
|
7130
|
-
|
|
7317
|
+
this.addConnectionListener(connection, "usageUpdate", (usage) => {
|
|
7131
7318
|
this.emit("usageUpdate", usage);
|
|
7132
7319
|
});
|
|
7133
|
-
|
|
7320
|
+
this.addConnectionListener(connection, "checkpointCreated", (checkpoint) => {
|
|
7321
|
+
const originSessionId = checkpoint.__sessionId;
|
|
7322
|
+
if (originSessionId && originSessionId !== this._id) return;
|
|
7134
7323
|
this.emit("checkpointCreated", checkpoint);
|
|
7135
7324
|
});
|
|
7136
|
-
|
|
7325
|
+
this.addConnectionListener(connection, "checkpointUpdated", (checkpoint) => {
|
|
7326
|
+
const originSessionId = checkpoint.__sessionId;
|
|
7327
|
+
if (originSessionId && originSessionId !== this._id) return;
|
|
7137
7328
|
this.emit("checkpointUpdated", checkpoint);
|
|
7138
7329
|
});
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7330
|
+
this.addConnectionListener(connection, "command", (command) => {
|
|
7331
|
+
const originSessionId = command.__sessionId;
|
|
7332
|
+
if (originSessionId && originSessionId !== this._id) {
|
|
7333
|
+
console.log("[Session] Command not forwarded:", {
|
|
7334
|
+
command,
|
|
7335
|
+
originSessionId,
|
|
7336
|
+
sessionId: this._id
|
|
7337
|
+
});
|
|
7338
|
+
return;
|
|
7339
|
+
}
|
|
7144
7340
|
this.emit("command", command);
|
|
7145
7341
|
});
|
|
7146
7342
|
}
|
|
@@ -7150,19 +7346,38 @@ var ActiveSessionImpl = class {
|
|
|
7150
7346
|
_meta: response._meta ?? void 0
|
|
7151
7347
|
};
|
|
7152
7348
|
}
|
|
7349
|
+
/**
|
|
7350
|
+
* 判断 artifact 是否应该转发给当前 session
|
|
7351
|
+
* - media 类型:按 cwd 路径隔离(同 cwd 下不同 session 可共享 media)
|
|
7352
|
+
* - 其余类型:按 __sessionId 严格隔离
|
|
7353
|
+
*/
|
|
7354
|
+
shouldForwardArtifact(artifact) {
|
|
7355
|
+
const originSessionId = artifact.__sessionId;
|
|
7356
|
+
console.log("[Session] shouldForwardArtifact:", {
|
|
7357
|
+
artifact,
|
|
7358
|
+
originSessionId,
|
|
7359
|
+
sessionId: this._id,
|
|
7360
|
+
cwd: this.connection?.cwd
|
|
7361
|
+
});
|
|
7362
|
+
if (artifact.type === "media") {
|
|
7363
|
+
const cwd = this.connection?.cwd;
|
|
7364
|
+
const uri = artifact?.uri;
|
|
7365
|
+
if (cwd && uri) {
|
|
7366
|
+
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
7367
|
+
const uriPath = toPosix(uri.replace(/^(?:file|agent):\/\//, ""));
|
|
7368
|
+
const posixCwd = toPosix(cwd);
|
|
7369
|
+
const normalizedCwd = posixCwd.endsWith("/") ? posixCwd : posixCwd + "/";
|
|
7370
|
+
return uriPath.startsWith(normalizedCwd);
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
if (originSessionId && originSessionId !== this._id) return false;
|
|
7374
|
+
return true;
|
|
7375
|
+
}
|
|
7153
7376
|
};
|
|
7154
7377
|
|
|
7155
7378
|
//#endregion
|
|
7156
7379
|
//#region ../agent-provider/src/common/client/session-manager.ts
|
|
7157
7380
|
/**
|
|
7158
|
-
* SessionManager - Manages session lifecycle and connections
|
|
7159
|
-
*
|
|
7160
|
-
* Provides the core implementation for session-centric API operations:
|
|
7161
|
-
* - list() - Lists sessions (mapped from agents)
|
|
7162
|
-
* - createSession() - Creates new session (auto-creates agent)
|
|
7163
|
-
* - loadSession() - Loads existing session (finds agent by sessionId)
|
|
7164
|
-
*/
|
|
7165
|
-
/**
|
|
7166
7381
|
* SessionManager - Session lifecycle management
|
|
7167
7382
|
*
|
|
7168
7383
|
* This class manages the relationship between sessions and agents.
|
|
@@ -7212,7 +7427,8 @@ var SessionManager = class {
|
|
|
7212
7427
|
createdAt: agent.createdAt,
|
|
7213
7428
|
lastActivityAt: agent.updatedAt,
|
|
7214
7429
|
cwd: agent.type === "local" ? agent.cwd : void 0,
|
|
7215
|
-
isPlayground: agent.isPlayground
|
|
7430
|
+
isPlayground: agent.isPlayground,
|
|
7431
|
+
isUserDefinedTitle: agent.isUserDefinedTitle
|
|
7216
7432
|
}));
|
|
7217
7433
|
console.log("[SessionManager] Returning sessions:", {
|
|
7218
7434
|
count: sessions.length,
|
|
@@ -7239,13 +7455,26 @@ var SessionManager = class {
|
|
|
7239
7455
|
if (this.provider.create) {
|
|
7240
7456
|
agentId = await this.provider.create(params);
|
|
7241
7457
|
this.logger?.debug(`Created new agent: ${agentId}`);
|
|
7458
|
+
if (params.options?.onSessionPrepared) {
|
|
7459
|
+
const initialPrompt = params.options?.prompt;
|
|
7460
|
+
const initialTitle = initialPrompt?.slice(0, 50) || "";
|
|
7461
|
+
params.options.onSessionPrepared({
|
|
7462
|
+
id: agentId,
|
|
7463
|
+
agentId,
|
|
7464
|
+
name: initialTitle + (initialPrompt && initialPrompt.length > 50 ? "..." : ""),
|
|
7465
|
+
status: "connecting",
|
|
7466
|
+
cwd: params.cwd || "",
|
|
7467
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
7468
|
+
});
|
|
7469
|
+
this.logger?.debug(`Called onSessionPrepared for: ${agentId}`);
|
|
7470
|
+
}
|
|
7242
7471
|
} else throw new Error("Provider does not support creating agents. Use sessions.load() with an existing sessionId.");
|
|
7243
7472
|
const connection = await this.provider.connect(agentId);
|
|
7244
7473
|
this.logger?.debug(`Connected to agent: ${agentId}`);
|
|
7245
7474
|
const response = await connection.createSession({
|
|
7246
|
-
_meta: params._meta,
|
|
7475
|
+
_meta: params.options?._meta,
|
|
7247
7476
|
cwd: params.cwd,
|
|
7248
|
-
mcpServers: params.mcpServers
|
|
7477
|
+
mcpServers: params.options?.mcpServers
|
|
7249
7478
|
});
|
|
7250
7479
|
if (this.provider.registerSession) {
|
|
7251
7480
|
this.provider.registerSession(response.sessionId, agentId);
|
|
@@ -7258,14 +7487,10 @@ var SessionManager = class {
|
|
|
7258
7487
|
connectionInfo
|
|
7259
7488
|
});
|
|
7260
7489
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
description: m.description ?? void 0
|
|
7266
|
-
}));
|
|
7267
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
7268
|
-
}
|
|
7490
|
+
const availableModels = this.extractAvailableModels(response);
|
|
7491
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
7492
|
+
const responseCwd = response._meta?.["codebuddy.ai"]?.cwd;
|
|
7493
|
+
if (responseCwd) session.setCwd(responseCwd);
|
|
7269
7494
|
this.logger?.info(`Session created: ${response.sessionId}`);
|
|
7270
7495
|
return session;
|
|
7271
7496
|
}
|
|
@@ -7301,17 +7526,31 @@ var SessionManager = class {
|
|
|
7301
7526
|
mcpServers: params.mcpServers
|
|
7302
7527
|
});
|
|
7303
7528
|
session.setModes(response.modes?.availableModes, response.modes?.currentModeId);
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
id: m.modelId,
|
|
7307
|
-
name: m.name,
|
|
7308
|
-
description: m.description ?? void 0
|
|
7309
|
-
}));
|
|
7310
|
-
session.setModels(localModels, response.models?.currentModelId);
|
|
7311
|
-
}
|
|
7529
|
+
const availableModels = this.extractAvailableModels(response);
|
|
7530
|
+
if (availableModels) session.setModels(availableModels, response.models?.currentModelId);
|
|
7312
7531
|
this.logger?.info(`Session loaded: ${params.sessionId}`);
|
|
7313
7532
|
return session;
|
|
7314
7533
|
}
|
|
7534
|
+
/**
|
|
7535
|
+
* 从 ACP response 中提取可用模型列表
|
|
7536
|
+
*
|
|
7537
|
+
* 优先级:
|
|
7538
|
+
* 1. response.models._meta?.['codebuddy.ai']?.availableModels - 包含完整的模型信息(字段名为 'id')
|
|
7539
|
+
* 2. response.models?.availableModels - 只包含基本信息(字段名为 'modelId')
|
|
7540
|
+
* 3. undefined - 都没有时返回 undefined
|
|
7541
|
+
*
|
|
7542
|
+
* @param response - ACP 响应对象
|
|
7543
|
+
* @returns ModelInfo[] | undefined
|
|
7544
|
+
*/
|
|
7545
|
+
extractAvailableModels(response) {
|
|
7546
|
+
const metaModels = (response.models?._meta?.["codebuddy.ai"])?.availableModels;
|
|
7547
|
+
if (metaModels && Array.isArray(metaModels) && metaModels.length > 0) return metaModels;
|
|
7548
|
+
const availableModels = response.models?.availableModels;
|
|
7549
|
+
if (availableModels && Array.isArray(availableModels) && availableModels.length > 0) return availableModels.map((model) => ({
|
|
7550
|
+
...model,
|
|
7551
|
+
...model._meta?.["codebuddy.ai"] || {}
|
|
7552
|
+
}));
|
|
7553
|
+
}
|
|
7315
7554
|
};
|
|
7316
7555
|
|
|
7317
7556
|
//#endregion
|
|
@@ -7584,6 +7823,28 @@ var AgentClient = class {
|
|
|
7584
7823
|
};
|
|
7585
7824
|
}
|
|
7586
7825
|
},
|
|
7826
|
+
getSubagentList: async (params) => {
|
|
7827
|
+
try {
|
|
7828
|
+
if (this.provider && this.provider.getSubagentList) {
|
|
7829
|
+
const result = await this.provider.getSubagentList(params);
|
|
7830
|
+
this.logger?.info("Subagent list retrieved", {
|
|
7831
|
+
resultCount: result.results.length,
|
|
7832
|
+
hasError: !!result.error
|
|
7833
|
+
});
|
|
7834
|
+
return result;
|
|
7835
|
+
}
|
|
7836
|
+
return {
|
|
7837
|
+
results: [],
|
|
7838
|
+
error: "Provider does not support getSubagentList"
|
|
7839
|
+
};
|
|
7840
|
+
} catch (error) {
|
|
7841
|
+
this.logger?.error("Failed to get subagent list", error);
|
|
7842
|
+
return {
|
|
7843
|
+
results: [],
|
|
7844
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
7845
|
+
};
|
|
7846
|
+
}
|
|
7847
|
+
},
|
|
7587
7848
|
batchTogglePlugins: async (request) => {
|
|
7588
7849
|
try {
|
|
7589
7850
|
if (this.provider && this.provider.batchTogglePlugins) {
|
|
@@ -7628,10 +7889,10 @@ var AgentClient = class {
|
|
|
7628
7889
|
return [];
|
|
7629
7890
|
}
|
|
7630
7891
|
},
|
|
7631
|
-
installPlugins: async (pluginNames, marketplaceName, installScope) => {
|
|
7892
|
+
installPlugins: async (pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath) => {
|
|
7632
7893
|
try {
|
|
7633
7894
|
if (this.provider && "installPlugins" in this.provider && typeof this.provider.installPlugins === "function") {
|
|
7634
|
-
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope);
|
|
7895
|
+
const result = await this.provider.installPlugins(pluginNames, marketplaceName, installScope, marketplaceSource, workspacePath);
|
|
7635
7896
|
this.logger?.info("Install plugins", {
|
|
7636
7897
|
pluginNames,
|
|
7637
7898
|
marketplaceName,
|
|
@@ -7652,13 +7913,9 @@ var AgentClient = class {
|
|
|
7652
7913
|
};
|
|
7653
7914
|
}
|
|
7654
7915
|
},
|
|
7655
|
-
getSupportScenes: async () => {
|
|
7916
|
+
getSupportScenes: async (locale) => {
|
|
7656
7917
|
try {
|
|
7657
|
-
if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function")
|
|
7658
|
-
const result = await this.provider.getSupportScenes();
|
|
7659
|
-
this.logger?.info("Got support scenes", { count: result?.length ?? 0 });
|
|
7660
|
-
return result;
|
|
7661
|
-
}
|
|
7918
|
+
if (this.provider && "getSupportScenes" in this.provider && typeof this.provider.getSupportScenes === "function") return await this.provider.getSupportScenes(locale);
|
|
7662
7919
|
this.logger?.warn("Provider does not support getSupportScenes");
|
|
7663
7920
|
return [];
|
|
7664
7921
|
} catch (error) {
|
|
@@ -7666,6 +7923,94 @@ var AgentClient = class {
|
|
|
7666
7923
|
return [];
|
|
7667
7924
|
}
|
|
7668
7925
|
},
|
|
7926
|
+
getProductScenes: async (locale) => {
|
|
7927
|
+
try {
|
|
7928
|
+
const hasMethod = this.provider && "getProductScenes" in this.provider;
|
|
7929
|
+
const isFunction = hasMethod && typeof this.provider.getProductScenes === "function";
|
|
7930
|
+
this.logger?.warn(`[getProductScenes] provider=${!!this.provider}, hasMethod=${hasMethod}, isFunction=${isFunction}, providerType=${this.provider?.constructor?.name}`);
|
|
7931
|
+
if (isFunction) {
|
|
7932
|
+
const result = await this.provider.getProductScenes(locale);
|
|
7933
|
+
this.logger?.warn(`[getProductScenes] got ${result?.length ?? 0} scenes`);
|
|
7934
|
+
return result;
|
|
7935
|
+
}
|
|
7936
|
+
this.logger?.warn("Provider does not support getProductScenes");
|
|
7937
|
+
return [];
|
|
7938
|
+
} catch (error) {
|
|
7939
|
+
this.logger?.error("Failed to get product scenes", error);
|
|
7940
|
+
return [];
|
|
7941
|
+
}
|
|
7942
|
+
},
|
|
7943
|
+
getAvailableCommands: async (params) => {
|
|
7944
|
+
try {
|
|
7945
|
+
if (this.provider && "getAvailableCommands" in this.provider && typeof this.provider.getAvailableCommands === "function") {
|
|
7946
|
+
const result = await this.provider.getAvailableCommands(params);
|
|
7947
|
+
this.logger?.info("Got available commands from provider", {
|
|
7948
|
+
sessionId: params?.sessionId ?? "(default)",
|
|
7949
|
+
count: result?.length ?? 0
|
|
7950
|
+
});
|
|
7951
|
+
return result;
|
|
7952
|
+
}
|
|
7953
|
+
this.logger?.warn("Provider does not support getAvailableCommands", { params });
|
|
7954
|
+
return [];
|
|
7955
|
+
} catch (error) {
|
|
7956
|
+
this.logger?.error("Failed to get available commands", error);
|
|
7957
|
+
return [];
|
|
7958
|
+
}
|
|
7959
|
+
},
|
|
7960
|
+
reportTelemetry: async (eventName, payload) => {
|
|
7961
|
+
try {
|
|
7962
|
+
if (this.provider?.reportTelemetry) await this.provider.reportTelemetry(eventName, payload);
|
|
7963
|
+
else this.logger?.warn("Provider does not support reportTelemetry");
|
|
7964
|
+
} catch (error) {
|
|
7965
|
+
this.logger?.error("Failed to report telemetry", error);
|
|
7966
|
+
}
|
|
7967
|
+
},
|
|
7968
|
+
respondToSampling: async (sessionId, response) => {
|
|
7969
|
+
try {
|
|
7970
|
+
if (this.provider?.respondToSampling) {
|
|
7971
|
+
await this.provider.respondToSampling(sessionId, response);
|
|
7972
|
+
this.logger?.info("Responded to sampling request", {
|
|
7973
|
+
sessionId,
|
|
7974
|
+
requestId: response.id,
|
|
7975
|
+
approved: response.approved
|
|
7976
|
+
});
|
|
7977
|
+
} else this.logger?.warn("Provider does not support respondToSampling");
|
|
7978
|
+
} catch (error) {
|
|
7979
|
+
this.logger?.error("Failed to respond to sampling request", error);
|
|
7980
|
+
throw error;
|
|
7981
|
+
}
|
|
7982
|
+
},
|
|
7983
|
+
respondToRoots: async (sessionId, response) => {
|
|
7984
|
+
try {
|
|
7985
|
+
if (this.provider?.respondToRoots) {
|
|
7986
|
+
await this.provider.respondToRoots(sessionId, response);
|
|
7987
|
+
this.logger?.info("Responded to roots request", {
|
|
7988
|
+
sessionId,
|
|
7989
|
+
requestId: response.id,
|
|
7990
|
+
approved: response.approved
|
|
7991
|
+
});
|
|
7992
|
+
} else this.logger?.warn("Provider does not support respondToRoots");
|
|
7993
|
+
} catch (error) {
|
|
7994
|
+
this.logger?.error("Failed to respond to roots request", error);
|
|
7995
|
+
throw error;
|
|
7996
|
+
}
|
|
7997
|
+
},
|
|
7998
|
+
subscribeSamplingRequests: (serverName, callback) => {
|
|
7999
|
+
if (this.provider?.subscribeSamplingRequests) {
|
|
8000
|
+
this.logger?.info("Subscribing to sampling requests", { serverName });
|
|
8001
|
+
return this.provider.subscribeSamplingRequests(serverName, callback);
|
|
8002
|
+
}
|
|
8003
|
+
this.logger?.warn("Provider does not support subscribeSamplingRequests");
|
|
8004
|
+
return () => {};
|
|
8005
|
+
},
|
|
8006
|
+
subscribeRootsRequests: (serverName, callback) => {
|
|
8007
|
+
if (this.provider?.subscribeRootsRequests) {
|
|
8008
|
+
this.logger?.info("Subscribing to roots requests", { serverName });
|
|
8009
|
+
return this.provider.subscribeRootsRequests(serverName, callback);
|
|
8010
|
+
}
|
|
8011
|
+
this.logger?.warn("Provider does not support subscribeRootsRequests");
|
|
8012
|
+
return () => {};
|
|
8013
|
+
},
|
|
7669
8014
|
models: this.createModelsResource()
|
|
7670
8015
|
};
|
|
7671
8016
|
}
|
|
@@ -7732,6 +8077,154 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
7732
8077
|
return AccountStatus;
|
|
7733
8078
|
}({});
|
|
7734
8079
|
|
|
8080
|
+
//#endregion
|
|
8081
|
+
//#region ../agent-provider/src/backend/service/oauth-repository-service.ts
|
|
8082
|
+
/**
|
|
8083
|
+
* OAuth Repository Service
|
|
8084
|
+
*
|
|
8085
|
+
* 封装 OAuth 连接器相关的仓库和分支操作
|
|
8086
|
+
*/
|
|
8087
|
+
/**
|
|
8088
|
+
* OAuth Repository Service
|
|
8089
|
+
*
|
|
8090
|
+
* 提供仓库和分支的查询操作
|
|
8091
|
+
*/
|
|
8092
|
+
var OAuthRepositoryService = class {
|
|
8093
|
+
/**
|
|
8094
|
+
* 获取仓库分支列表
|
|
8095
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
8096
|
+
*
|
|
8097
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8098
|
+
* @param params 平台特定的查询参数
|
|
8099
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8100
|
+
* @param perPage 每页数量,最大100
|
|
8101
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
8102
|
+
*
|
|
8103
|
+
* @example
|
|
8104
|
+
* ```typescript
|
|
8105
|
+
* // GitHub
|
|
8106
|
+
* const branches = await service.getBranches('github', {
|
|
8107
|
+
* owner: 'CodeBuddy-Official-Account',
|
|
8108
|
+
* repo: 'CodeBuddyIDE'
|
|
8109
|
+
* });
|
|
8110
|
+
*
|
|
8111
|
+
* // Gongfeng
|
|
8112
|
+
* const branches = await service.getBranches('gongfeng', {
|
|
8113
|
+
* project_id: '1611499'
|
|
8114
|
+
* });
|
|
8115
|
+
*
|
|
8116
|
+
* // CNB
|
|
8117
|
+
* const branches = await service.getBranches('cnb', {
|
|
8118
|
+
* repo: 'genie/genie-ide'
|
|
8119
|
+
* });
|
|
8120
|
+
* ```
|
|
8121
|
+
*/
|
|
8122
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
8123
|
+
try {
|
|
8124
|
+
const url = `/console/as/connector/oauth/${connector}/branches?${this.buildBranchQueryParams(connector, params, page, perPage).toString()}`;
|
|
8125
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
8126
|
+
const apiResponse = await httpService.get(url);
|
|
8127
|
+
if (!apiResponse.data) {
|
|
8128
|
+
console.warn(`[OAuthRepositoryService] No data in branches response for ${connector}`);
|
|
8129
|
+
return [];
|
|
8130
|
+
}
|
|
8131
|
+
const branches = apiResponse.data.branches || [];
|
|
8132
|
+
console.log(`[OAuthRepositoryService] Retrieved ${branches.length} branches from ${connector}`);
|
|
8133
|
+
return branches;
|
|
8134
|
+
} catch (error) {
|
|
8135
|
+
console.error(`[OAuthRepositoryService] Failed to get branches from ${connector}:`, error);
|
|
8136
|
+
throw error;
|
|
8137
|
+
}
|
|
8138
|
+
}
|
|
8139
|
+
/**
|
|
8140
|
+
* 获取仓库列表
|
|
8141
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
8142
|
+
*
|
|
8143
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
8144
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
8145
|
+
*
|
|
8146
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8147
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8148
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
8149
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
8150
|
+
* @param perPage 每页数量,最大100
|
|
8151
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
8152
|
+
*
|
|
8153
|
+
* @example
|
|
8154
|
+
* ```typescript
|
|
8155
|
+
* // GitHub - 必须传 page=0 获取全量数据
|
|
8156
|
+
* const response = await service.getRepositories('github', 0, 100);
|
|
8157
|
+
* // response.github_repos 是 map: installation_id => repo[]
|
|
8158
|
+
*
|
|
8159
|
+
* // Gongfeng
|
|
8160
|
+
* const response = await service.getRepositories('gongfeng', 0, 100);
|
|
8161
|
+
* // response.gongfeng_repos 是数组
|
|
8162
|
+
*
|
|
8163
|
+
* // CNB
|
|
8164
|
+
* const response = await service.getRepositories('cnb', 0, 100);
|
|
8165
|
+
* // response.cnb_repos 是数组
|
|
8166
|
+
* ```
|
|
8167
|
+
*/
|
|
8168
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
8169
|
+
try {
|
|
8170
|
+
const queryParams = new URLSearchParams();
|
|
8171
|
+
queryParams.append("page", String(page));
|
|
8172
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
8173
|
+
const url = `/console/as/connector/oauth/${connector}/repos?${queryParams.toString()}`;
|
|
8174
|
+
console.log(`[OAuthRepositoryService] GET ${url}`);
|
|
8175
|
+
const apiResponse = await httpService.get(url);
|
|
8176
|
+
if (!apiResponse.data) {
|
|
8177
|
+
console.warn(`[OAuthRepositoryService] No data in repos response for ${connector}`);
|
|
8178
|
+
return {};
|
|
8179
|
+
}
|
|
8180
|
+
const response = apiResponse.data;
|
|
8181
|
+
this.logRepositoryCounts(response);
|
|
8182
|
+
return response;
|
|
8183
|
+
} catch (error) {
|
|
8184
|
+
console.error(`[OAuthRepositoryService] Failed to get repos from ${connector}:`, error);
|
|
8185
|
+
throw error;
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
/**
|
|
8189
|
+
* 构建分支查询参数
|
|
8190
|
+
*/
|
|
8191
|
+
buildBranchQueryParams(connector, params, page, perPage) {
|
|
8192
|
+
const queryParams = new URLSearchParams();
|
|
8193
|
+
queryParams.append("page", String(page));
|
|
8194
|
+
queryParams.append("per_page", String(Math.min(perPage, 100)));
|
|
8195
|
+
if (connector === "github") {
|
|
8196
|
+
const githubParams = params;
|
|
8197
|
+
if (!githubParams.owner || !githubParams.repo) throw new Error("GitHub requires owner and repo parameters");
|
|
8198
|
+
queryParams.append("owner", githubParams.owner);
|
|
8199
|
+
queryParams.append("repo", githubParams.repo);
|
|
8200
|
+
} else if (connector === "gongfeng") {
|
|
8201
|
+
const gongfengParams = params;
|
|
8202
|
+
if (!gongfengParams.project_id) throw new Error("Gongfeng requires project_id parameter");
|
|
8203
|
+
queryParams.append("project_id", gongfengParams.project_id);
|
|
8204
|
+
} else if (connector === "cnb") {
|
|
8205
|
+
const cnbParams = params;
|
|
8206
|
+
if (!cnbParams.repo) throw new Error("CNB requires repo parameter");
|
|
8207
|
+
queryParams.append("repo", cnbParams.repo);
|
|
8208
|
+
} else throw new Error(`Unknown connector: ${connector}`);
|
|
8209
|
+
return queryParams;
|
|
8210
|
+
}
|
|
8211
|
+
/**
|
|
8212
|
+
* 记录仓库数量日志
|
|
8213
|
+
*/
|
|
8214
|
+
logRepositoryCounts(response) {
|
|
8215
|
+
if (response.github_repos) {
|
|
8216
|
+
const totalCount = Object.values(response.github_repos).reduce((sum, repos) => sum + repos.length, 0);
|
|
8217
|
+
console.log(`[OAuthRepositoryService] Retrieved ${totalCount} GitHub repos across ${Object.keys(response.github_repos).length} installations`);
|
|
8218
|
+
}
|
|
8219
|
+
if (response.gongfeng_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.gongfeng_repos.length} Gongfeng repos`);
|
|
8220
|
+
if (response.cnb_repos) console.log(`[OAuthRepositoryService] Retrieved ${response.cnb_repos.length} CNB repos`);
|
|
8221
|
+
}
|
|
8222
|
+
};
|
|
8223
|
+
/**
|
|
8224
|
+
* OAuth Repository Service 单例实例
|
|
8225
|
+
*/
|
|
8226
|
+
const oauthRepositoryService = new OAuthRepositoryService();
|
|
8227
|
+
|
|
7735
8228
|
//#endregion
|
|
7736
8229
|
//#region ../agent-provider/src/backend/backend-provider.ts
|
|
7737
8230
|
/**
|
|
@@ -7740,28 +8233,24 @@ let AccountStatus = /* @__PURE__ */ function(AccountStatus) {
|
|
|
7740
8233
|
* 封装与后端 API 的 HTTP 通信
|
|
7741
8234
|
*/
|
|
7742
8235
|
/**
|
|
7743
|
-
*
|
|
7744
|
-
*
|
|
8236
|
+
* 判断当前账号是否是 SSO 账号
|
|
8237
|
+
* 通过 account.accountType === 'sso' 来判断,这种不行,因为未登录之前account 为空
|
|
7745
8238
|
*/
|
|
7746
|
-
const
|
|
7747
|
-
|
|
7748
|
-
|
|
8239
|
+
const safeParseJSON = (jsonString) => {
|
|
8240
|
+
try {
|
|
8241
|
+
return JSON.parse(jsonString);
|
|
8242
|
+
} catch (error) {
|
|
8243
|
+
return {};
|
|
8244
|
+
}
|
|
7749
8245
|
};
|
|
7750
8246
|
/**
|
|
7751
|
-
*
|
|
7752
|
-
* - SSO
|
|
7753
|
-
* - 非 SSO
|
|
8247
|
+
* 根据路径获取完整 URL
|
|
8248
|
+
* - SSO 账号需要跳转到对应的预发/生产域名
|
|
8249
|
+
* - 非 SSO 账号直接使用当前域名
|
|
8250
|
+
* @param path 路径,如 '/login'、'/logout'、'/home' 等
|
|
8251
|
+
* @returns 完整的 URL 地址
|
|
7754
8252
|
*/
|
|
7755
|
-
const
|
|
7756
|
-
const { hostname, protocol } = window.location;
|
|
7757
|
-
if (isSSODomain()) {
|
|
7758
|
-
const isCodebuddy = hostname.includes("codebuddy.cn");
|
|
7759
|
-
const isStaging = hostname.includes("staging");
|
|
7760
|
-
if (isCodebuddy) return isStaging ? `${protocol}//staging.codebuddy.cn/login` : `${protocol}//www.codebuddy.cn/login`;
|
|
7761
|
-
else return isStaging ? `${protocol}//staging-copilot.tencent.com/login` : `${protocol}//copilot.tencent.com/login`;
|
|
7762
|
-
}
|
|
7763
|
-
return `${window.location.origin}/login`;
|
|
7764
|
-
};
|
|
8253
|
+
const getFullUrl = (path) => `${window.location.origin}${path}`;
|
|
7765
8254
|
/** 获取当前域名的账号选择页面 URL */
|
|
7766
8255
|
const getSelectAccountUrl = () => `${window.location.origin}/login/select`;
|
|
7767
8256
|
/** localStorage 中存储选中账号 ID 的 key */
|
|
@@ -7798,12 +8287,30 @@ var BackendProvider = class {
|
|
|
7798
8287
|
constructor(config) {
|
|
7799
8288
|
httpService.setBaseURL(config.baseUrl);
|
|
7800
8289
|
if (config.authToken) httpService.setAuthToken(config.authToken);
|
|
7801
|
-
httpService.onUnauthorized(() =>
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
8290
|
+
httpService.onUnauthorized(() => this.handleUnauthorized());
|
|
8291
|
+
}
|
|
8292
|
+
/**
|
|
8293
|
+
* 处理 401 未授权错误
|
|
8294
|
+
* 先尝试刷新 token,失败后再执行登出流程
|
|
8295
|
+
*
|
|
8296
|
+
* @throws 如果 token 刷新失败,抛出错误通知 HttpService 不要重试
|
|
8297
|
+
*/
|
|
8298
|
+
async handleUnauthorized() {
|
|
8299
|
+
console.log("[BackendProvider] User unauthorized (401), attempting token refresh first");
|
|
8300
|
+
try {
|
|
8301
|
+
if (await this.refreshToken()) {
|
|
8302
|
+
console.log("[BackendProvider] Token refresh successful after 401, user still logged in");
|
|
8303
|
+
return;
|
|
8304
|
+
}
|
|
8305
|
+
throw new Error("Token refresh returned null");
|
|
8306
|
+
} catch (error) {
|
|
8307
|
+
console.error("[BackendProvider] Token refresh failed after 401:", error);
|
|
8308
|
+
console.log("[BackendProvider] Token refresh failed, triggering logout");
|
|
8309
|
+
this.logout().catch((logoutError) => {
|
|
8310
|
+
console.error("[BackendProvider] Logout failed in 401 handler:", logoutError);
|
|
7805
8311
|
});
|
|
7806
|
-
|
|
8312
|
+
throw error;
|
|
8313
|
+
}
|
|
7807
8314
|
}
|
|
7808
8315
|
/**
|
|
7809
8316
|
* 获取当前账号信息
|
|
@@ -7848,7 +8355,7 @@ var BackendProvider = class {
|
|
|
7848
8355
|
return account;
|
|
7849
8356
|
}
|
|
7850
8357
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
7851
|
-
window.location.href = `${getSelectAccountUrl()}?platform=
|
|
8358
|
+
window.location.href = `${getSelectAccountUrl()}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
7852
8359
|
accountService.setAccount(null);
|
|
7853
8360
|
return null;
|
|
7854
8361
|
} catch (error) {
|
|
@@ -7871,7 +8378,8 @@ var BackendProvider = class {
|
|
|
7871
8378
|
activeStatus: connector.active_status,
|
|
7872
8379
|
displayName: connector.display_name,
|
|
7873
8380
|
oauthClientId: connector.oauth_client_id,
|
|
7874
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
8381
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
8382
|
+
oauthAppName: connector.oauth_app_name
|
|
7875
8383
|
})) };
|
|
7876
8384
|
}
|
|
7877
8385
|
throw result;
|
|
@@ -7953,7 +8461,8 @@ var BackendProvider = class {
|
|
|
7953
8461
|
connectStatus: connector.connect_status,
|
|
7954
8462
|
displayName: connector.display_name,
|
|
7955
8463
|
oauthClientId: connector.oauth_client_id,
|
|
7956
|
-
oauthRedirectUrl: connector.oauth_redirect_url
|
|
8464
|
+
oauthRedirectUrl: connector.oauth_redirect_url,
|
|
8465
|
+
oauthAppName: connector.oauth_app_name
|
|
7957
8466
|
})) };
|
|
7958
8467
|
}
|
|
7959
8468
|
throw result;
|
|
@@ -8044,6 +8553,9 @@ var BackendProvider = class {
|
|
|
8044
8553
|
PackageCode: void 0,
|
|
8045
8554
|
name: ""
|
|
8046
8555
|
};
|
|
8556
|
+
const productFeatures = typeof window !== "undefined" && window.PRODUCT_FEATURES ? safeParseJSON(window.PRODUCT_FEATURES) : {};
|
|
8557
|
+
console.log("[PRODUCT_FEATURES]", productFeatures);
|
|
8558
|
+
if (!productFeatures.billing) return defaultPlan;
|
|
8047
8559
|
try {
|
|
8048
8560
|
const now = /* @__PURE__ */ new Date();
|
|
8049
8561
|
const futureDate = new Date(now.getTime() + 101 * 365 * 24 * 60 * 60 * 1e3);
|
|
@@ -8065,7 +8577,7 @@ var BackendProvider = class {
|
|
|
8065
8577
|
if (!time) return 0;
|
|
8066
8578
|
return new Date(time).getTime();
|
|
8067
8579
|
};
|
|
8068
|
-
const dailyCredits = [CommodityCode.free
|
|
8580
|
+
const dailyCredits = [CommodityCode.free];
|
|
8069
8581
|
const planResources = resources.map((r) => {
|
|
8070
8582
|
const isDaily = dailyCredits.includes(r.PackageCode);
|
|
8071
8583
|
const endTime = isDaily ? r.CycleEndTime : r.DeductionEndTime;
|
|
@@ -8086,10 +8598,11 @@ var BackendProvider = class {
|
|
|
8086
8598
|
CommodityCode.proMon,
|
|
8087
8599
|
CommodityCode.proMonPlus,
|
|
8088
8600
|
CommodityCode.proYear,
|
|
8601
|
+
CommodityCode.freeMon,
|
|
8089
8602
|
CommodityCode.extra
|
|
8090
8603
|
].includes(code)) return 1;
|
|
8091
8604
|
if ([CommodityCode.gift, CommodityCode.activity].includes(code)) return 2;
|
|
8092
|
-
if ([CommodityCode.free
|
|
8605
|
+
if ([CommodityCode.free].includes(code)) return 3;
|
|
8093
8606
|
return 4;
|
|
8094
8607
|
};
|
|
8095
8608
|
return getPriority(a.packageCode) - getPriority(b.packageCode);
|
|
@@ -8210,7 +8723,7 @@ var BackendProvider = class {
|
|
|
8210
8723
|
*/
|
|
8211
8724
|
async login() {
|
|
8212
8725
|
const redirectUrl = encodeURIComponent(window.location.href);
|
|
8213
|
-
window.location.href = `${
|
|
8726
|
+
window.location.href = `${getFullUrl("/login")}?platform=agents&state=0&redirect_uri=${redirectUrl}`;
|
|
8214
8727
|
}
|
|
8215
8728
|
/**
|
|
8216
8729
|
* 登出账号
|
|
@@ -8273,6 +8786,52 @@ var BackendProvider = class {
|
|
|
8273
8786
|
return null;
|
|
8274
8787
|
}
|
|
8275
8788
|
}
|
|
8789
|
+
/**
|
|
8790
|
+
* 刷新 Token
|
|
8791
|
+
* 通过调用 getAccount 刷新 cookie,适用于 Cloud 场景下页面切换回来时刷新登录态
|
|
8792
|
+
* @returns Promise<Account | null> 刷新后的账号信息
|
|
8793
|
+
*/
|
|
8794
|
+
async refreshToken() {
|
|
8795
|
+
console.log("[BackendProvider] Refreshing token...");
|
|
8796
|
+
try {
|
|
8797
|
+
const account = await this.getAccount();
|
|
8798
|
+
console.log("[BackendProvider] Token refreshed, account:", account?.uid);
|
|
8799
|
+
return account;
|
|
8800
|
+
} catch (error) {
|
|
8801
|
+
console.error("[BackendProvider] refreshToken failed:", error);
|
|
8802
|
+
return null;
|
|
8803
|
+
}
|
|
8804
|
+
}
|
|
8805
|
+
/**
|
|
8806
|
+
* 获取仓库分支列表
|
|
8807
|
+
* API 端点: GET /console/as/connector/oauth/{name}/branches
|
|
8808
|
+
*
|
|
8809
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8810
|
+
* @param params 平台特定的查询参数
|
|
8811
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8812
|
+
* @param perPage 每页数量,最大100
|
|
8813
|
+
* @returns Promise<OauthBranch[]> 分支列表
|
|
8814
|
+
*/
|
|
8815
|
+
async getBranches(connector, params, page = 0, perPage = 100) {
|
|
8816
|
+
return oauthRepositoryService.getBranches(connector, params, page, perPage);
|
|
8817
|
+
}
|
|
8818
|
+
/**
|
|
8819
|
+
* 获取仓库列表
|
|
8820
|
+
* API 端点: GET /console/as/connector/oauth/{name}/repos
|
|
8821
|
+
*
|
|
8822
|
+
* Note: 由于工蜂原生支持的 Search 能力会匹配 path/name/description 部分,
|
|
8823
|
+
* 且不支持定制,不满足产品要求(只按 name 匹配),因此前端拉取全量数据后做筛选。
|
|
8824
|
+
*
|
|
8825
|
+
* @param connector 连接器名称 ('github' | 'gongfeng' | 'cnb')
|
|
8826
|
+
* @param page 页码,从1开始,0表示不分页获取全部
|
|
8827
|
+
* - GitHub 只支持全量数据,必须传 0
|
|
8828
|
+
* - 工蜂和 CNB 依据前端逻辑而定
|
|
8829
|
+
* @param perPage 每页数量,最大100
|
|
8830
|
+
* @returns Promise<ListReposResponse> 仓库列表响应
|
|
8831
|
+
*/
|
|
8832
|
+
async getRepositories(connector, page = 0, perPage = 100) {
|
|
8833
|
+
return oauthRepositoryService.getRepositories(connector, page, perPage);
|
|
8834
|
+
}
|
|
8276
8835
|
};
|
|
8277
8836
|
/**
|
|
8278
8837
|
* 创建 BackendProvider 实例
|
|
@@ -8312,6 +8871,7 @@ const BACKEND_REQUEST_TYPES = {
|
|
|
8312
8871
|
GET_FILE: "backend:get-file",
|
|
8313
8872
|
RELOAD_WINDOW: "backend:reload-window",
|
|
8314
8873
|
CLOSE_AGENT_MANAGER: "backend:close-agent-manager",
|
|
8874
|
+
OPEN_EXTERNAL: "backend:open-external",
|
|
8315
8875
|
BATCH_TOGGLE_PLUGINS: "backend:batch-toggle-plugins",
|
|
8316
8876
|
GET_SUPPORT_SCENES: "backend:get-support-scenes"
|
|
8317
8877
|
};
|
|
@@ -8607,6 +9167,20 @@ var IPCBackendProvider = class {
|
|
|
8607
9167
|
}
|
|
8608
9168
|
}
|
|
8609
9169
|
/**
|
|
9170
|
+
* 在外部浏览器中打开链接
|
|
9171
|
+
* IDE 环境: 通过 IPC 通知 IDE 使用 vscode.env.openExternal 打开 URL
|
|
9172
|
+
* @param url 要打开的 URL
|
|
9173
|
+
*/
|
|
9174
|
+
async openExternal(url) {
|
|
9175
|
+
this.log("Opening external URL via IPC:", url);
|
|
9176
|
+
try {
|
|
9177
|
+
await this.sendBackendRequest(BACKEND_REQUEST_TYPES.OPEN_EXTERNAL, { url });
|
|
9178
|
+
} catch (error) {
|
|
9179
|
+
this.log("Open external request failed:", error);
|
|
9180
|
+
throw error;
|
|
9181
|
+
}
|
|
9182
|
+
}
|
|
9183
|
+
/**
|
|
8610
9184
|
* 批量切换插件状态
|
|
8611
9185
|
* IDE 环境: 通过 IPC 调用 Extension Host 的 PluginService
|
|
8612
9186
|
*/
|