keepwork-sdk 1.0.2 → 1.0.3
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-npm/keepwork-sdk.js +1759 -389
- package/dist-npm/keepwork-sdk.js.map +1 -1
- package/dist-npm/types/index.d.ts +3 -1
- package/dist-npm/types/index.d.ts.map +1 -1
- package/dist-npm/types/src/ai-chat/AIChat.core.d.ts +21 -3
- package/dist-npm/types/src/ai-chat/AIChat.core.d.ts.map +1 -1
- package/dist-npm/types/src/ai-chat/AIChat.session.d.ts +6 -5
- package/dist-npm/types/src/ai-chat/AIChat.session.d.ts.map +1 -1
- package/dist-npm/types/src/ai-chat/AIGenerators.base.d.ts +57 -3
- package/dist-npm/types/src/ai-chat/AIGenerators.base.d.ts.map +1 -1
- package/dist-npm/types/src/ai-chat/AIGenerators.media.d.ts.map +1 -1
- package/dist-npm/types/src/core/keepworkSDK.core.d.ts +8 -12
- package/dist-npm/types/src/core/keepworkSDK.core.d.ts.map +1 -1
- package/dist-npm/types/src/core/keepworkSDK.d.ts +35 -28
- package/dist-npm/types/src/core/keepworkSDK.d.ts.map +1 -1
- package/dist-npm/types/src/core/keepworkSDK.pages.d.ts.map +1 -1
- package/dist-npm/types/src/digital-human/DigitalHuman.d.ts +30 -1
- package/dist-npm/types/src/digital-human/DigitalHuman.d.ts.map +1 -1
- package/dist-npm/types/src/digital-human/DigitalHumanFrame.d.ts +25 -2
- package/dist-npm/types/src/digital-human/DigitalHumanFrame.d.ts.map +1 -1
- package/dist-npm/types/src/rtc/AIChatRTC.session.d.ts +2 -1
- package/dist-npm/types/src/rtc/AIChatRTC.session.d.ts.map +1 -1
- package/dist-npm/types/src/rtc/LocalRTC.d.ts +146 -25
- package/dist-npm/types/src/rtc/LocalRTC.d.ts.map +1 -1
- package/dist-npm/types/src/rtc/LocalRTCController.d.ts +244 -0
- package/dist-npm/types/src/rtc/LocalRTCController.d.ts.map +1 -0
- package/dist-npm/types/src/tools/MinigameTools.d.ts +13 -0
- package/dist-npm/types/src/tools/MinigameTools.d.ts.map +1 -1
- package/dist-npm/types/src/types/api.d.ts +306 -0
- package/dist-npm/types/src/types/api.d.ts.map +1 -0
- package/dist-npm/types/src/ui/LocalAPIKeySettings.d.ts.map +1 -1
- package/dist-npm/types/src/ui/LoginWindow.d.ts.map +1 -1
- package/dist-npm/types/src/user/SocialFriends.d.ts +6 -5
- package/dist-npm/types/src/user/SocialFriends.d.ts.map +1 -1
- package/dist-npm/types/src/user/UserWorks.d.ts +18 -17
- package/dist-npm/types/src/user/UserWorks.d.ts.map +1 -1
- package/package.json +6 -2
package/dist-npm/keepwork-sdk.js
CHANGED
|
@@ -887,7 +887,7 @@ if (typeof window !== "undefined") {
|
|
|
887
887
|
window.LocalStorageUtil = LocalStorageUtil;
|
|
888
888
|
window.StorageUtil = StorageUtil;
|
|
889
889
|
}
|
|
890
|
-
const console$
|
|
890
|
+
const console$q = SDKLogger.createModuleConsole("PersonalPageStore");
|
|
891
891
|
class PersonalPageStoreBase {
|
|
892
892
|
constructor(sdk) {
|
|
893
893
|
// ──────────────────── 字段 ────────────────────
|
|
@@ -970,7 +970,7 @@ class PersonalPageStoreBase {
|
|
|
970
970
|
try {
|
|
971
971
|
handler(...args);
|
|
972
972
|
} catch (e) {
|
|
973
|
-
console$
|
|
973
|
+
console$q.warn(`PersonalPageStore: listener for '${event}' threw:`, e);
|
|
974
974
|
}
|
|
975
975
|
}
|
|
976
976
|
}
|
|
@@ -1087,7 +1087,7 @@ class PersonalPageStoreBase {
|
|
|
1087
1087
|
if (typeof mountedFolder === "string") {
|
|
1088
1088
|
const parts = mountedFolder.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
1089
1089
|
if (parts.length < 2) {
|
|
1090
|
-
console$
|
|
1090
|
+
console$q.warn("PersonalPageStore: mountedFolder path requires at least username/workspace");
|
|
1091
1091
|
return null;
|
|
1092
1092
|
}
|
|
1093
1093
|
const username = parts[0];
|
|
@@ -1098,7 +1098,7 @@ class PersonalPageStoreBase {
|
|
|
1098
1098
|
if (typeof mountedFolder === "object" && mountedFolder !== null) {
|
|
1099
1099
|
const m = mountedFolder;
|
|
1100
1100
|
if (!m["username"] || !m["workspace"]) {
|
|
1101
|
-
console$
|
|
1101
|
+
console$q.warn("PersonalPageStore: mountedFolder object requires username and workspace");
|
|
1102
1102
|
return null;
|
|
1103
1103
|
}
|
|
1104
1104
|
return {
|
|
@@ -1107,7 +1107,7 @@ class PersonalPageStoreBase {
|
|
|
1107
1107
|
remoteStorePath: m["remoteStorePath"] ?? this.remoteStorePath
|
|
1108
1108
|
};
|
|
1109
1109
|
}
|
|
1110
|
-
console$
|
|
1110
|
+
console$q.warn("PersonalPageStore: mountedFolder must be a path string, object, or null");
|
|
1111
1111
|
return null;
|
|
1112
1112
|
}
|
|
1113
1113
|
// ──────────────────── SearchPath ────────────────────
|
|
@@ -1127,10 +1127,10 @@ class PersonalPageStoreBase {
|
|
|
1127
1127
|
if (existing) {
|
|
1128
1128
|
existing.baseUrl = normalizedBaseUrl;
|
|
1129
1129
|
existing.isReadonly = isReadonly;
|
|
1130
|
-
console$
|
|
1130
|
+
console$q.log(`[PersonalPageStore] Updated search path: ${normalizedPrefix} -> ${normalizedBaseUrl} (readonly=${isReadonly})`);
|
|
1131
1131
|
} else {
|
|
1132
1132
|
this._searchPaths.push({ prefix: normalizedPrefix, baseUrl: normalizedBaseUrl, isReadonly });
|
|
1133
|
-
console$
|
|
1133
|
+
console$q.log(`[PersonalPageStore] Added search path: ${normalizedPrefix} -> ${normalizedBaseUrl} (readonly=${isReadonly})`);
|
|
1134
1134
|
}
|
|
1135
1135
|
}
|
|
1136
1136
|
/**
|
|
@@ -1184,7 +1184,7 @@ class PersonalPageStoreBase {
|
|
|
1184
1184
|
if (!resp.ok) continue;
|
|
1185
1185
|
const text = await resp.text();
|
|
1186
1186
|
if (text != null) {
|
|
1187
|
-
console$
|
|
1187
|
+
console$q.log(`[PersonalPageStore] SearchPath found: ${effectiveName} -> ${fileUrl}`);
|
|
1188
1188
|
const pageKey = this._toInternalPageKey(pageName);
|
|
1189
1189
|
this.personalPageData[pageKey] = this.personalPageData[pageKey] ?? {};
|
|
1190
1190
|
this.setValueByPath(this.personalPageData[pageKey], "content", text);
|
|
@@ -1193,7 +1193,7 @@ class PersonalPageStoreBase {
|
|
|
1193
1193
|
} catch {
|
|
1194
1194
|
}
|
|
1195
1195
|
}
|
|
1196
|
-
console$
|
|
1196
|
+
console$q.log(`[PersonalPageStore] SearchPath not found: ${effectiveName}`);
|
|
1197
1197
|
this._searchPathNotFound.add(effectiveName);
|
|
1198
1198
|
return null;
|
|
1199
1199
|
}
|
|
@@ -1457,7 +1457,7 @@ class PersonalPageStoreBase {
|
|
|
1457
1457
|
const newUsername = username || null;
|
|
1458
1458
|
if (this.overrideUsername !== newUsername) this.reset();
|
|
1459
1459
|
this.overrideUsername = newUsername;
|
|
1460
|
-
console$
|
|
1460
|
+
console$q.log(`PersonalPageStore: Override username set to: ${this.overrideUsername ?? "current user"}`);
|
|
1461
1461
|
}
|
|
1462
1462
|
/**
|
|
1463
1463
|
* 获取当前使用的用户名(override 或当前登录用户)。
|
|
@@ -1503,7 +1503,7 @@ class PersonalPageStoreBase {
|
|
|
1503
1503
|
if (this.userProfileLoaded) return;
|
|
1504
1504
|
try {
|
|
1505
1505
|
if (!this.sdk.token) {
|
|
1506
|
-
console$
|
|
1506
|
+
console$q.log("personalPageStore: No token set, using anonymous mode");
|
|
1507
1507
|
return;
|
|
1508
1508
|
}
|
|
1509
1509
|
await ((_b2 = (_a2 = this.sdk).getUserProfile) == null ? void 0 : _b2.call(_a2, { useCache: true }));
|
|
@@ -4579,7 +4579,7 @@ class AudioEngine {
|
|
|
4579
4579
|
};
|
|
4580
4580
|
}
|
|
4581
4581
|
}
|
|
4582
|
-
const console$
|
|
4582
|
+
const console$p = SDKLogger.createModuleConsole("Speech");
|
|
4583
4583
|
let _md5 = null;
|
|
4584
4584
|
async function getMd5() {
|
|
4585
4585
|
if (_md5) return _md5;
|
|
@@ -4651,7 +4651,7 @@ class Speech {
|
|
|
4651
4651
|
if (valid.includes(mode)) {
|
|
4652
4652
|
this.fallbackMode = mode;
|
|
4653
4653
|
} else {
|
|
4654
|
-
console$
|
|
4654
|
+
console$p.warn(`Invalid fallbackMode "${mode}", expected one of: ${valid.join(", ")}`);
|
|
4655
4655
|
}
|
|
4656
4656
|
}
|
|
4657
4657
|
/** 获取共享 AudioEngine 实例(优先 sdk.audioEngine,否则 AudioEngine.getShared())。 */
|
|
@@ -4684,7 +4684,7 @@ class Speech {
|
|
|
4684
4684
|
}
|
|
4685
4685
|
const OfflineCtx = typeof window !== "undefined" ? window.OfflineAudioContext || window.webkitOfflineAudioContext : null;
|
|
4686
4686
|
if (!OfflineCtx) {
|
|
4687
|
-
console$
|
|
4687
|
+
console$p.warn("当前浏览器不支持 OfflineAudioContext,返回原始采样率音频");
|
|
4688
4688
|
return audioBuffer;
|
|
4689
4689
|
}
|
|
4690
4690
|
const frameCount = Math.max(1, Math.ceil(audioBuffer.duration * nextSampleRate));
|
|
@@ -5013,7 +5013,7 @@ class Speech {
|
|
|
5013
5013
|
}
|
|
5014
5014
|
});
|
|
5015
5015
|
} catch (error) {
|
|
5016
|
-
console$
|
|
5016
|
+
console$p.error("停止音频播放时发生错误:", error);
|
|
5017
5017
|
}
|
|
5018
5018
|
}
|
|
5019
5019
|
/** 停止所有音频(stopAllAudio 的别名)。 */
|
|
@@ -5038,10 +5038,10 @@ class Speech {
|
|
|
5038
5038
|
audio.src = audioUrl;
|
|
5039
5039
|
void ((_b2 = (_a2 = this.resumeSharedAudioEngine()) == null ? void 0 : _a2.finally) == null ? void 0 : _b2.call(_a2, () => {
|
|
5040
5040
|
const p = audio.play();
|
|
5041
|
-
if (p) p.catch((err) => console$
|
|
5041
|
+
if (p) p.catch((err) => console$p.error("Error playing YouDao audio:", err));
|
|
5042
5042
|
}));
|
|
5043
5043
|
} catch (e) {
|
|
5044
|
-
console$
|
|
5044
|
+
console$p.error("Error with YouDao API:", e);
|
|
5045
5045
|
}
|
|
5046
5046
|
}
|
|
5047
5047
|
// ──────────────────── 语音转文字(STT)────────────────────
|
|
@@ -5058,10 +5058,10 @@ class Speech {
|
|
|
5058
5058
|
maxDuration: 60,
|
|
5059
5059
|
sampleRate: 16e3,
|
|
5060
5060
|
format: "wav",
|
|
5061
|
-
onStart: () => console$
|
|
5062
|
-
onStop: () => console$
|
|
5063
|
-
onError: (e) => console$
|
|
5064
|
-
onResult: (r) => console$
|
|
5061
|
+
onStart: () => console$p.log("录音开始"),
|
|
5062
|
+
onStop: () => console$p.log("录音停止"),
|
|
5063
|
+
onError: (e) => console$p.error("录音错误:", e),
|
|
5064
|
+
onResult: (r) => console$p.log("识别结果:", r),
|
|
5065
5065
|
...options
|
|
5066
5066
|
};
|
|
5067
5067
|
if (!((_a2 = navigator.mediaDevices) == null ? void 0 : _a2.getUserMedia)) throw new Error("当前浏览器不支持录音功能,请使用现代浏览器并确保在HTTPS环境下访问");
|
|
@@ -5295,7 +5295,7 @@ class Speech {
|
|
|
5295
5295
|
});
|
|
5296
5296
|
}
|
|
5297
5297
|
}
|
|
5298
|
-
const console$
|
|
5298
|
+
const console$o = SDKLogger.createModuleConsole("MqttManager");
|
|
5299
5299
|
class MqttManager {
|
|
5300
5300
|
constructor() {
|
|
5301
5301
|
__publicField(this, "client", null);
|
|
@@ -5367,11 +5367,11 @@ class MqttManager {
|
|
|
5367
5367
|
}
|
|
5368
5368
|
}
|
|
5369
5369
|
} catch (e) {
|
|
5370
|
-
console$
|
|
5370
|
+
console$o.error("Failed to load MQTT config from storage:", e);
|
|
5371
5371
|
}
|
|
5372
5372
|
}
|
|
5373
5373
|
if (!effectiveConfig) {
|
|
5374
|
-
console$
|
|
5374
|
+
console$o.error("MQTT connect: No config provided and no stored config");
|
|
5375
5375
|
this.status = "error";
|
|
5376
5376
|
this.emit("statusChange", this.status);
|
|
5377
5377
|
return;
|
|
@@ -5379,7 +5379,7 @@ class MqttManager {
|
|
|
5379
5379
|
try {
|
|
5380
5380
|
await this.LoadMQTT();
|
|
5381
5381
|
} catch (e) {
|
|
5382
|
-
console$
|
|
5382
|
+
console$o.error("Failed to load MQTT library:", e);
|
|
5383
5383
|
this.status = "error";
|
|
5384
5384
|
this.emit("statusChange", this.status);
|
|
5385
5385
|
return;
|
|
@@ -5403,7 +5403,7 @@ class MqttManager {
|
|
|
5403
5403
|
reconnectPeriod: 5e3,
|
|
5404
5404
|
connectTimeout: 30 * 1e3
|
|
5405
5405
|
};
|
|
5406
|
-
console$
|
|
5406
|
+
console$o.log("Connecting to MQTT with options:", connectOptions);
|
|
5407
5407
|
try {
|
|
5408
5408
|
this.client = mqtt.connect(connectOptions);
|
|
5409
5409
|
this.client.on("connect", () => {
|
|
@@ -5411,7 +5411,7 @@ class MqttManager {
|
|
|
5411
5411
|
topics == null ? void 0 : topics.forEach((topic) => this.subscribe(topic));
|
|
5412
5412
|
});
|
|
5413
5413
|
this.client.on("error", (err) => {
|
|
5414
|
-
console$
|
|
5414
|
+
console$o.error("MQTT Error:", err);
|
|
5415
5415
|
this.status = "error";
|
|
5416
5416
|
this.emit("statusChange", this.status);
|
|
5417
5417
|
this.emit("error", err);
|
|
@@ -5425,7 +5425,7 @@ class MqttManager {
|
|
|
5425
5425
|
this.client.on("reconnect", () => {
|
|
5426
5426
|
var _a3;
|
|
5427
5427
|
this.retryCount++;
|
|
5428
|
-
console$
|
|
5428
|
+
console$o.log(`MQTT Reconnecting... (${this.retryCount}/${this.maxRetries})`);
|
|
5429
5429
|
if (this.retryCount > this.maxRetries) {
|
|
5430
5430
|
(_a3 = this.client) == null ? void 0 : _a3.end();
|
|
5431
5431
|
this.status = "error";
|
|
@@ -5434,21 +5434,21 @@ class MqttManager {
|
|
|
5434
5434
|
}
|
|
5435
5435
|
});
|
|
5436
5436
|
} catch (e) {
|
|
5437
|
-
console$
|
|
5437
|
+
console$o.error("MQTT Connection Exception:", e);
|
|
5438
5438
|
this.status = "error";
|
|
5439
5439
|
this.emit("statusChange", this.status);
|
|
5440
5440
|
}
|
|
5441
5441
|
}
|
|
5442
5442
|
/** @private 连接成功回调。 */
|
|
5443
5443
|
OnConnect() {
|
|
5444
|
-
console$
|
|
5444
|
+
console$o.log("MQTT Connected");
|
|
5445
5445
|
this.status = "connected";
|
|
5446
5446
|
this.retryCount = 0;
|
|
5447
5447
|
this.emit("statusChange", this.status);
|
|
5448
5448
|
}
|
|
5449
5449
|
/** @private 连接关闭回调。 */
|
|
5450
5450
|
OnClose() {
|
|
5451
|
-
console$
|
|
5451
|
+
console$o.log("MQTT Closed");
|
|
5452
5452
|
if (this.status !== "disconnected") {
|
|
5453
5453
|
this.status = "disconnected";
|
|
5454
5454
|
this.emit("statusChange", this.status);
|
|
@@ -5459,7 +5459,7 @@ class MqttManager {
|
|
|
5459
5459
|
*/
|
|
5460
5460
|
OnMessage(topic, message) {
|
|
5461
5461
|
const msgStr = String(message);
|
|
5462
|
-
console$
|
|
5462
|
+
console$o.log(`message ${msgStr}
|
|
5463
5463
|
On topic: ${topic}`);
|
|
5464
5464
|
localStorage.setItem(`mqtt_msg_${topic}`, msgStr);
|
|
5465
5465
|
this.emit("message", { topic, message: msgStr });
|
|
@@ -5486,7 +5486,7 @@ On topic: ${topic}`);
|
|
|
5486
5486
|
var _a2;
|
|
5487
5487
|
if ((_a2 = this.client) == null ? void 0 : _a2.connected) {
|
|
5488
5488
|
this.client.subscribe(topic, (err) => {
|
|
5489
|
-
if (!err) console$
|
|
5489
|
+
if (!err) console$o.log(`Subscribed to ${topic}`);
|
|
5490
5490
|
});
|
|
5491
5491
|
}
|
|
5492
5492
|
}
|
|
@@ -6282,7 +6282,7 @@ class SandboxToolEnv {
|
|
|
6282
6282
|
});
|
|
6283
6283
|
}
|
|
6284
6284
|
}
|
|
6285
|
-
const console$
|
|
6285
|
+
const console$n = SDKLogger.createModuleConsole("AgentTool");
|
|
6286
6286
|
class AgentTool {
|
|
6287
6287
|
constructor(sdk) {
|
|
6288
6288
|
__publicField(this, "sdk");
|
|
@@ -6322,7 +6322,7 @@ class AgentTool {
|
|
|
6322
6322
|
} = args;
|
|
6323
6323
|
if (!task) return "Failed: 'task' is a required parameter.";
|
|
6324
6324
|
const resolvedAgentName = agentName || this.currentAgentName(session);
|
|
6325
|
-
console$
|
|
6325
|
+
console$n.log(`[CopilotTools] runAsyncAgentTask session='${session.name ?? "root"}' target='${resolvedAgentName}' callbackMode=${callbackMode ?? "delay"} task=${this.summarizeDebugValue(task)}`);
|
|
6326
6326
|
const expandedTask = await this.expandTemplate(session, task, "task");
|
|
6327
6327
|
const expandedSystemPrompt = await this.expandTemplate(session, systemPrompt, "systemPrompt");
|
|
6328
6328
|
const router = (_a2 = this.sdk) == null ? void 0 : _a2.agentRouter;
|
|
@@ -6447,11 +6447,11 @@ class AgentTool {
|
|
|
6447
6447
|
if (!value.includes("${") && !/^\s*\/\S+/.test(value)) return value;
|
|
6448
6448
|
try {
|
|
6449
6449
|
const expanded = await session.sandbox.processTemplate(value);
|
|
6450
|
-
console$
|
|
6450
|
+
console$n.log(`[CopilotTools] runAsyncAgentTask ${label} expanded via sandbox: ${this.summarizeDebugValue(expanded)}`);
|
|
6451
6451
|
return expanded;
|
|
6452
6452
|
} catch (e) {
|
|
6453
6453
|
if (e && e["isRestartAgentSignal"]) throw e;
|
|
6454
|
-
console$
|
|
6454
|
+
console$n.warn(`[CopilotTools] runAsyncAgentTask: ${label} template expansion failed. Error: ${e.message}`);
|
|
6455
6455
|
return value;
|
|
6456
6456
|
}
|
|
6457
6457
|
}
|
|
@@ -6493,7 +6493,7 @@ ${resultText}`;
|
|
|
6493
6493
|
try {
|
|
6494
6494
|
await ((_a3 = target == null ? void 0 : target["sendMessage"]) == null ? void 0 : _a3.call(target, payload));
|
|
6495
6495
|
} catch (e) {
|
|
6496
|
-
console$
|
|
6496
|
+
console$n.error(`[CopilotTools] ${targetLabel}.sendMessage failed:`, e);
|
|
6497
6497
|
}
|
|
6498
6498
|
}).catch(async (e) => {
|
|
6499
6499
|
var _a3;
|
|
@@ -6501,7 +6501,7 @@ ${resultText}`;
|
|
|
6501
6501
|
try {
|
|
6502
6502
|
await ((_a3 = target == null ? void 0 : target["sendMessage"]) == null ? void 0 : _a3.call(target, payload));
|
|
6503
6503
|
} catch (e2) {
|
|
6504
|
-
console$
|
|
6504
|
+
console$n.error(`[CopilotTools] ${targetLabel}.sendMessage failed:`, e2);
|
|
6505
6505
|
}
|
|
6506
6506
|
});
|
|
6507
6507
|
return `Task submitted to agent '${agentName}'. The agent is working in a brand-new background session. Results will be delivered as a message via ${targetLabel} when complete.`;
|
|
@@ -6587,7 +6587,7 @@ __publicField(AgentTool, "definitions", [
|
|
|
6587
6587
|
}
|
|
6588
6588
|
}
|
|
6589
6589
|
]);
|
|
6590
|
-
const console$
|
|
6590
|
+
const console$m = SDKLogger.createModuleConsole("PersonalPageTool");
|
|
6591
6591
|
class PersonalPageTool {
|
|
6592
6592
|
constructor(sdk) {
|
|
6593
6593
|
__publicField(this, "sdk");
|
|
@@ -6630,19 +6630,19 @@ class PersonalPageTool {
|
|
|
6630
6630
|
}
|
|
6631
6631
|
if (name === "personal_page_load") {
|
|
6632
6632
|
try {
|
|
6633
|
-
console$
|
|
6633
|
+
console$m.log(`[PersonalPageTool] Loading data from file '${filePageName}', key '${storageKey}'`);
|
|
6634
6634
|
if (!this.sdk.personalPageStore) throw new Error("SDK PersonalPageStore not available");
|
|
6635
6635
|
const data = storageKey ? await this.sdk.personalPageStore.loadPageData(filePageName, storageKey) : await this.sdk.personalPageStore.loadPageData(filePageName);
|
|
6636
6636
|
return JSON.stringify(data);
|
|
6637
6637
|
} catch (e) {
|
|
6638
|
-
console$
|
|
6638
|
+
console$m.error("[PersonalPageTool] Load failed:", e);
|
|
6639
6639
|
return `Failed to load data: ${e.message}`;
|
|
6640
6640
|
}
|
|
6641
6641
|
}
|
|
6642
6642
|
if (name === "personal_page_save") {
|
|
6643
6643
|
const { data, bForceFlush } = args;
|
|
6644
6644
|
try {
|
|
6645
|
-
console$
|
|
6645
|
+
console$m.log(`[PersonalPageTool] Saving data to file '${filePageName}', key '${storageKey}'`, data);
|
|
6646
6646
|
if (!this.sdk.personalPageStore) throw new Error("SDK PersonalPageStore not available");
|
|
6647
6647
|
await this.sdk.personalPageStore.savePageData(
|
|
6648
6648
|
filePageName,
|
|
@@ -6652,7 +6652,7 @@ class PersonalPageTool {
|
|
|
6652
6652
|
);
|
|
6653
6653
|
return "Data saved successfully.";
|
|
6654
6654
|
} catch (e) {
|
|
6655
|
-
console$
|
|
6655
|
+
console$m.error("[PersonalPageTool] Save failed:", e);
|
|
6656
6656
|
return `Failed to save data: ${e.message}`;
|
|
6657
6657
|
}
|
|
6658
6658
|
}
|
|
@@ -6712,7 +6712,7 @@ __publicField(PersonalPageTool, "definitions", [
|
|
|
6712
6712
|
}
|
|
6713
6713
|
}
|
|
6714
6714
|
]);
|
|
6715
|
-
const console$
|
|
6715
|
+
const console$l = SDKLogger.createModuleConsole("ExecuteTool");
|
|
6716
6716
|
const AsyncFunction = Object.getPrototypeOf(async function() {
|
|
6717
6717
|
}).constructor;
|
|
6718
6718
|
class ExecuteTool {
|
|
@@ -6762,7 +6762,7 @@ class ExecuteTool {
|
|
|
6762
6762
|
async runAppCmd(code, config = {}) {
|
|
6763
6763
|
const logs = [];
|
|
6764
6764
|
try {
|
|
6765
|
-
const originalConsole = console$
|
|
6765
|
+
const originalConsole = console$l;
|
|
6766
6766
|
const wrappedConsole = Object.create(originalConsole);
|
|
6767
6767
|
const consoleMethods = ["log", "info", "warn", "error", "debug"];
|
|
6768
6768
|
for (const level of consoleMethods) {
|
|
@@ -7901,7 +7901,7 @@ __publicField(AppTools, "definitions", [
|
|
|
7901
7901
|
}
|
|
7902
7902
|
}
|
|
7903
7903
|
]);
|
|
7904
|
-
const console$
|
|
7904
|
+
const console$k = SDKLogger.createModuleConsole("AIChat");
|
|
7905
7905
|
class AIChat {
|
|
7906
7906
|
constructor(sdk) {
|
|
7907
7907
|
__publicField(this, "sdk");
|
|
@@ -7993,7 +7993,7 @@ class AIChat {
|
|
|
7993
7993
|
try {
|
|
7994
7994
|
token = window.localStorage.getItem("token");
|
|
7995
7995
|
} catch (e) {
|
|
7996
|
-
console$
|
|
7996
|
+
console$k.warn("Failed to get token from localStorage:", e);
|
|
7997
7997
|
}
|
|
7998
7998
|
}
|
|
7999
7999
|
if (token) headers["authorization"] = `Bearer ${token}`;
|
|
@@ -8107,7 +8107,7 @@ class AIChat {
|
|
|
8107
8107
|
const session = options._session;
|
|
8108
8108
|
for (const toolCall of toolCalls) {
|
|
8109
8109
|
if (session == null ? void 0 : session._restartSignal) {
|
|
8110
|
-
console$
|
|
8110
|
+
console$k.log("[AIChat] _restartSignal detected, aborting tool loop");
|
|
8111
8111
|
break;
|
|
8112
8112
|
}
|
|
8113
8113
|
const fnName = (_d = toolCall.function) == null ? void 0 : _d.name;
|
|
@@ -8120,14 +8120,14 @@ class AIChat {
|
|
|
8120
8120
|
if (session) session["_restartSignal"] = error;
|
|
8121
8121
|
throw error;
|
|
8122
8122
|
}
|
|
8123
|
-
console$
|
|
8123
|
+
console$k.error("Tool call execution failed:", error);
|
|
8124
8124
|
const errorResult = { error: error.message ?? "Tool execution failed" };
|
|
8125
8125
|
toolResults.push({ tool_call_id: toolCall.id, result: errorResult });
|
|
8126
8126
|
(_f = options.onToolResult) == null ? void 0 : _f.call(options, { name: fnName, toolCallId: toolCall.id, result: errorResult });
|
|
8127
8127
|
}
|
|
8128
8128
|
}
|
|
8129
8129
|
if (session == null ? void 0 : session._restartSignal) {
|
|
8130
|
-
console$
|
|
8130
|
+
console$k.log("[AIChat] _restartSignal detected, aborting chat recursion");
|
|
8131
8131
|
return assistantContent ?? "";
|
|
8132
8132
|
}
|
|
8133
8133
|
for (const toolResult of toolResults) {
|
|
@@ -8204,7 +8204,7 @@ class AIChat {
|
|
|
8204
8204
|
throw new Error("createSession not yet initialized — ensure AIChat.session.ts is imported");
|
|
8205
8205
|
}
|
|
8206
8206
|
}
|
|
8207
|
-
const console$
|
|
8207
|
+
const console$j = SDKLogger.createModuleConsole("ChildSessionMixin");
|
|
8208
8208
|
function _generateUUID() {
|
|
8209
8209
|
if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
|
|
8210
8210
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
@@ -8275,7 +8275,7 @@ const childSessionMethods = {
|
|
|
8275
8275
|
if (this.sandbox) childSession["sandbox"] = this.sandbox;
|
|
8276
8276
|
const entry = { session: childSession, queue: [], isRunning: false };
|
|
8277
8277
|
this._childSessions[name] = entry;
|
|
8278
|
-
console$
|
|
8278
|
+
console$j.log(`[ChildSessionMixin] Child agent '${name}' created`);
|
|
8279
8279
|
return entry;
|
|
8280
8280
|
},
|
|
8281
8281
|
/**
|
|
@@ -8302,7 +8302,7 @@ const childSessionMethods = {
|
|
|
8302
8302
|
2. ${task}`;
|
|
8303
8303
|
if (tools) last.tools = [.../* @__PURE__ */ new Set([...last.tools, ...tools])];
|
|
8304
8304
|
last.maxIterations = Math.max(last.maxIterations, maxIterations);
|
|
8305
|
-
console$
|
|
8305
|
+
console$j.log(`[ChildSessionMixin] Merged task into queue for child '${name}'`);
|
|
8306
8306
|
return last.promise;
|
|
8307
8307
|
}
|
|
8308
8308
|
let resolve;
|
|
@@ -8377,15 +8377,15 @@ const childSessionMethods = {
|
|
|
8377
8377
|
const result = typeof response === "string" ? response : (response == null ? void 0 : response["result"]) ?? "";
|
|
8378
8378
|
const taskSummary = taskObj.description ?? (taskObj.task.length > 80 ? taskObj.task.slice(0, 80) + "..." : taskObj.task);
|
|
8379
8379
|
this._pendingChildResults.push({ agentName: name, taskId: taskObj.id, taskSummary, result });
|
|
8380
|
-
console$
|
|
8380
|
+
console$j.log(`[ChildSessionMixin] Child '${name}' completed task ${taskObj.id}; pendingChildResults=${this._pendingChildResults.length}; result=${_summarize(result)}`);
|
|
8381
8381
|
(_h = self._handleChildCallback) == null ? void 0 : _h.call(self, taskObj.callbackMode, taskObj.debounceSeconds);
|
|
8382
8382
|
taskObj.resolve(result);
|
|
8383
8383
|
} catch (e) {
|
|
8384
|
-
console$
|
|
8384
|
+
console$j.error(`[ChildSessionMixin] Child '${name}' task ${taskObj.id} failed:`, e);
|
|
8385
8385
|
const errorResult = { error: e.message ?? "Child agent task failed" };
|
|
8386
8386
|
const taskSummary = taskObj.description ?? (taskObj.task.length > 80 ? taskObj.task.slice(0, 80) + "..." : taskObj.task);
|
|
8387
8387
|
this._pendingChildResults.push({ agentName: name, taskId: taskObj.id, taskSummary, result: errorResult });
|
|
8388
|
-
console$
|
|
8388
|
+
console$j.warn(`[ChildSessionMixin] Child '${name}' failure queued; taskId=${taskObj.id}; pendingChildResults=${this._pendingChildResults.length}; result=${_summarize(errorResult)}`);
|
|
8389
8389
|
(_i = self._handleChildCallback) == null ? void 0 : _i.call(self, taskObj.callbackMode, taskObj.debounceSeconds);
|
|
8390
8390
|
taskObj.reject(e);
|
|
8391
8391
|
}
|
|
@@ -8415,7 +8415,7 @@ const childSessionMethods = {
|
|
|
8415
8415
|
try {
|
|
8416
8416
|
this.onChildStream(event);
|
|
8417
8417
|
} catch (e) {
|
|
8418
|
-
console$
|
|
8418
|
+
console$j.warn("[ChildSessionMixin] onChildStream callback error:", e);
|
|
8419
8419
|
}
|
|
8420
8420
|
}
|
|
8421
8421
|
},
|
|
@@ -8435,7 +8435,7 @@ const childSessionMethods = {
|
|
|
8435
8435
|
const results = this._pendingChildResults;
|
|
8436
8436
|
this._pendingChildResults = [];
|
|
8437
8437
|
if (results.length > 0) {
|
|
8438
|
-
console$
|
|
8438
|
+
console$j.log(
|
|
8439
8439
|
`[ChildSessionMixin] _consumePendingChildResults session='${this.name ?? "root"}' consumed ${results.length} result(s): ` + results.map((item) => `${item.agentName}:${item.taskId}:${_summarize(item.result, 80)}`).join(" | ")
|
|
8440
8440
|
);
|
|
8441
8441
|
}
|
|
@@ -8452,7 +8452,7 @@ const childSessionMethods = {
|
|
|
8452
8452
|
*/
|
|
8453
8453
|
_handleChildCallback(mode, debounceSeconds) {
|
|
8454
8454
|
var _a2, _b2;
|
|
8455
|
-
console$
|
|
8455
|
+
console$j.log(
|
|
8456
8456
|
`[ChildSessionMixin] _handleChildCallback session='${this.name ?? "root"}' mode=${mode ?? "delay"} debounceSeconds=${debounceSeconds ?? 5} pendingChildResults=${this._pendingChildResults.length}`
|
|
8457
8457
|
);
|
|
8458
8458
|
const selfCb = this;
|
|
@@ -8468,7 +8468,7 @@ const childSessionMethods = {
|
|
|
8468
8468
|
* @private
|
|
8469
8469
|
*/
|
|
8470
8470
|
async _triggerImmediateCallback() {
|
|
8471
|
-
console$
|
|
8471
|
+
console$j.warn("[ChildSessionMixin] _triggerImmediateCallback not overridden — child results will accumulate until next send.");
|
|
8472
8472
|
},
|
|
8473
8473
|
/**
|
|
8474
8474
|
* 延迟执行 `_triggerImmediateCallback`(用于 debounce 模式)。
|
|
@@ -8481,7 +8481,7 @@ const childSessionMethods = {
|
|
|
8481
8481
|
await this._triggerImmediateCallback();
|
|
8482
8482
|
}, seconds * 1e3);
|
|
8483
8483
|
this._debounceTimers.push(timerId);
|
|
8484
|
-
console$
|
|
8484
|
+
console$j.log(`[ChildSessionMixin] Debounce callback set: ${seconds}s pendingChildResults=${this._pendingChildResults.length}`);
|
|
8485
8485
|
},
|
|
8486
8486
|
/**
|
|
8487
8487
|
* 取消所有待处理的 debounce 定时器。
|
|
@@ -8535,7 +8535,137 @@ const childSessionMethods = {
|
|
|
8535
8535
|
this._pendingChildResults = [];
|
|
8536
8536
|
}
|
|
8537
8537
|
};
|
|
8538
|
-
|
|
8538
|
+
function detectFormat(url) {
|
|
8539
|
+
if (!url || typeof url !== "string") return null;
|
|
8540
|
+
const path = url.split(/[?#]/)[0].toLowerCase();
|
|
8541
|
+
if (path.endsWith(".json")) return "json";
|
|
8542
|
+
if (path.endsWith(".yml") || path.endsWith(".yaml")) return "yml";
|
|
8543
|
+
if (path.endsWith(".md")) return "md";
|
|
8544
|
+
return null;
|
|
8545
|
+
}
|
|
8546
|
+
function normalize(config) {
|
|
8547
|
+
if (!config || typeof config !== "object") return config;
|
|
8548
|
+
if (config.content && !config.system_prompt) {
|
|
8549
|
+
const body = String(config.content).trim();
|
|
8550
|
+
if (body) config.system_prompt = body;
|
|
8551
|
+
}
|
|
8552
|
+
delete config.content;
|
|
8553
|
+
if (config.workspace) {
|
|
8554
|
+
if (!config.tools) config.tools = {};
|
|
8555
|
+
if (!config.tools.fileOps) config.tools.fileOps = { enabled: false };
|
|
8556
|
+
if (!config.tools.fileOps.workspace) {
|
|
8557
|
+
config.tools.fileOps.workspace = config.workspace;
|
|
8558
|
+
}
|
|
8559
|
+
}
|
|
8560
|
+
if (config.mountFolder) {
|
|
8561
|
+
if (!config.tools) config.tools = {};
|
|
8562
|
+
if (!config.tools.fileOps) config.tools.fileOps = { enabled: false };
|
|
8563
|
+
if (!config.tools.fileOps.mountFolder) {
|
|
8564
|
+
config.tools.fileOps.mountFolder = config.mountFolder;
|
|
8565
|
+
}
|
|
8566
|
+
}
|
|
8567
|
+
if (config.history_length !== void 0 && config.historyLength === void 0) {
|
|
8568
|
+
config.historyLength = config.history_length;
|
|
8569
|
+
}
|
|
8570
|
+
delete config.history_length;
|
|
8571
|
+
return config;
|
|
8572
|
+
}
|
|
8573
|
+
function parseTable(tableText) {
|
|
8574
|
+
if (!tableText || typeof tableText !== "string") return {};
|
|
8575
|
+
const lines = tableText.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("|"));
|
|
8576
|
+
if (lines.length < 2) return {};
|
|
8577
|
+
const headerCells = lines[0].split("|").map((c) => c.trim()).filter(Boolean);
|
|
8578
|
+
const dataLines = lines.slice(2);
|
|
8579
|
+
const rows = dataLines.map((line) => {
|
|
8580
|
+
const cells = line.split("|").map((c) => c.trim()).filter(Boolean);
|
|
8581
|
+
const row = {};
|
|
8582
|
+
headerCells.forEach((h, i) => {
|
|
8583
|
+
row[h] = cells[i] !== void 0 ? cells[i] : "";
|
|
8584
|
+
});
|
|
8585
|
+
return row;
|
|
8586
|
+
});
|
|
8587
|
+
if (headerCells.length === 2) {
|
|
8588
|
+
const [keyCol, valCol] = headerCells;
|
|
8589
|
+
const isKV = keyCol.toLowerCase() === "key" && valCol.toLowerCase() === "value";
|
|
8590
|
+
if (isKV) {
|
|
8591
|
+
const obj = {};
|
|
8592
|
+
for (const row of rows) {
|
|
8593
|
+
const k = row[keyCol];
|
|
8594
|
+
if (k) obj[k] = _coerceValue(row[valCol]);
|
|
8595
|
+
}
|
|
8596
|
+
return obj;
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
return rows;
|
|
8600
|
+
}
|
|
8601
|
+
function _coerceValue(v) {
|
|
8602
|
+
if (v === "true") return true;
|
|
8603
|
+
if (v === "false") return false;
|
|
8604
|
+
if (v === "null" || v === "") return null;
|
|
8605
|
+
const n = Number(v);
|
|
8606
|
+
if (!isNaN(n) && v.trim() !== "") return n;
|
|
8607
|
+
return v;
|
|
8608
|
+
}
|
|
8609
|
+
function parse(text, formatHint) {
|
|
8610
|
+
if (!text || typeof text !== "string") return {};
|
|
8611
|
+
const trimmed = text.trim();
|
|
8612
|
+
if (formatHint === "json" || trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
8613
|
+
return normalize(JSON.parse(trimmed));
|
|
8614
|
+
}
|
|
8615
|
+
if (trimmed.startsWith("---\n") || trimmed.startsWith("---\r\n")) {
|
|
8616
|
+
const YML = _getYMLParser();
|
|
8617
|
+
if (YML) return normalize(YML.yamlToObject(trimmed, true));
|
|
8618
|
+
}
|
|
8619
|
+
const firstLine = trimmed.split("\n").find((l) => l.trim());
|
|
8620
|
+
if (firstLine && firstLine.trim().startsWith("|")) {
|
|
8621
|
+
return normalize(parseTable(trimmed));
|
|
8622
|
+
}
|
|
8623
|
+
try {
|
|
8624
|
+
return normalize(JSON.parse(trimmed));
|
|
8625
|
+
} catch {
|
|
8626
|
+
const YML = _getYMLParser();
|
|
8627
|
+
if (YML) return normalize(YML.yamlToObject(trimmed, true));
|
|
8628
|
+
}
|
|
8629
|
+
return {};
|
|
8630
|
+
}
|
|
8631
|
+
async function fetchConfig(source) {
|
|
8632
|
+
if (source && typeof source === "object") {
|
|
8633
|
+
return normalize({ ...source });
|
|
8634
|
+
}
|
|
8635
|
+
if (typeof source !== "string" || !source.trim()) {
|
|
8636
|
+
throw new Error("AgentConfig.fetch: source must be a non-empty string or object");
|
|
8637
|
+
}
|
|
8638
|
+
const trimmed = source.trim();
|
|
8639
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
8640
|
+
return normalize(JSON.parse(trimmed));
|
|
8641
|
+
}
|
|
8642
|
+
const resp = await fetch(trimmed);
|
|
8643
|
+
if (!resp.ok) {
|
|
8644
|
+
throw new Error(`AgentConfig.fetch: fetch failed (${resp.status}) for ${trimmed}`);
|
|
8645
|
+
}
|
|
8646
|
+
let text = await resp.text();
|
|
8647
|
+
text = text.replace(
|
|
8648
|
+
/<script[^>]*\/___vscode_livepreview_injected_script[^>]*><\/script>\s*/gi,
|
|
8649
|
+
""
|
|
8650
|
+
);
|
|
8651
|
+
const format = detectFormat(trimmed);
|
|
8652
|
+
return parse(text, format);
|
|
8653
|
+
}
|
|
8654
|
+
function _getYMLParser() {
|
|
8655
|
+
if (typeof YMLParser !== "undefined") return YMLParser;
|
|
8656
|
+
if (typeof window !== "undefined" && window.YMLParser) {
|
|
8657
|
+
return window.YMLParser;
|
|
8658
|
+
}
|
|
8659
|
+
return null;
|
|
8660
|
+
}
|
|
8661
|
+
const AgentConfig = {
|
|
8662
|
+
detectFormat,
|
|
8663
|
+
normalize,
|
|
8664
|
+
parse,
|
|
8665
|
+
parseTable,
|
|
8666
|
+
fetch: fetchConfig
|
|
8667
|
+
};
|
|
8668
|
+
const console$i = SDKLogger.createModuleConsole("ImageUtils");
|
|
8539
8669
|
const DEFAULT_MAX_BYTES = 32 * 1024;
|
|
8540
8670
|
function base64ByteSize(base64) {
|
|
8541
8671
|
const len = base64.length;
|
|
@@ -8578,7 +8708,7 @@ async function compressBase64Image(inputBase64, options = {}) {
|
|
|
8578
8708
|
for (const quality of QUALITY_STEPS) {
|
|
8579
8709
|
const result = canvasToBase64(img, width, height, quality);
|
|
8580
8710
|
if (result.byteSize <= maxBytes) {
|
|
8581
|
-
console$
|
|
8711
|
+
console$i.log(
|
|
8582
8712
|
`[ImageUtils] Compressed image: ${width}x${height} q=${quality} → ${(result.byteSize / 1024).toFixed(1)} KB`
|
|
8583
8713
|
);
|
|
8584
8714
|
return result.base64;
|
|
@@ -8588,7 +8718,7 @@ async function compressBase64Image(inputBase64, options = {}) {
|
|
|
8588
8718
|
height = Math.max(1, Math.floor(height / 2));
|
|
8589
8719
|
}
|
|
8590
8720
|
const final = canvasToBase64(img, width, height, 0.2);
|
|
8591
|
-
console$
|
|
8721
|
+
console$i.warn(
|
|
8592
8722
|
`[ImageUtils] Could not compress below ${maxBytes} bytes; final size ${final.byteSize}`
|
|
8593
8723
|
);
|
|
8594
8724
|
return final.base64;
|
|
@@ -8658,7 +8788,7 @@ async function uploadTempVisionImage(base64OrDataURI, options = {}) {
|
|
|
8658
8788
|
try {
|
|
8659
8789
|
const headResp = await fetch(cdnUrl, { method: "HEAD" });
|
|
8660
8790
|
if (headResp.ok) {
|
|
8661
|
-
console$
|
|
8791
|
+
console$i.log(`[ImageUtils] File already exists at ${cdnUrl}, skipping upload`);
|
|
8662
8792
|
return cdnUrl;
|
|
8663
8793
|
}
|
|
8664
8794
|
} catch {
|
|
@@ -8686,7 +8816,7 @@ async function uploadTempVisionImage(base64OrDataURI, options = {}) {
|
|
|
8686
8816
|
if (!uploadResp.ok) {
|
|
8687
8817
|
throw new Error(`[ImageUtils] Qiniu upload failed: HTTP ${uploadResp.status}`);
|
|
8688
8818
|
}
|
|
8689
|
-
console$
|
|
8819
|
+
console$i.log(`[ImageUtils] Uploaded to ${cdnUrl} (${(blob.size / 1024).toFixed(1)} KB)`);
|
|
8690
8820
|
return cdnUrl;
|
|
8691
8821
|
}
|
|
8692
8822
|
let _cachedMd5 = null;
|
|
@@ -8706,7 +8836,7 @@ async function _getMd5() {
|
|
|
8706
8836
|
}
|
|
8707
8837
|
return _cachedMd5;
|
|
8708
8838
|
}
|
|
8709
|
-
const console$
|
|
8839
|
+
const console$h = SDKLogger.createModuleConsole("AIChat");
|
|
8710
8840
|
class ChatSession {
|
|
8711
8841
|
constructor(aiChat, options = {}) {
|
|
8712
8842
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -8795,7 +8925,7 @@ class ChatSession {
|
|
|
8795
8925
|
if (router) {
|
|
8796
8926
|
this._registeredAsAgent = ((_b2 = router.register) == null ? void 0 : _b2.call(router, this.name, this)) ?? false;
|
|
8797
8927
|
if (!this._registeredAsAgent) {
|
|
8798
|
-
console$
|
|
8928
|
+
console$h.warn(`[ChatSession] Failed to register agent '${this.name}' — name may already be taken.`);
|
|
8799
8929
|
}
|
|
8800
8930
|
}
|
|
8801
8931
|
}
|
|
@@ -8844,7 +8974,7 @@ class ChatSession {
|
|
|
8844
8974
|
this._workspaceExplicitlySet = true;
|
|
8845
8975
|
this.workspace = nextWorkspace;
|
|
8846
8976
|
if (this.sandbox) this.sandbox.workspace = nextSandboxWorkspace;
|
|
8847
|
-
console$
|
|
8977
|
+
console$h.log(`[ChatSession] Workspace set to: ${this.workspace ?? "(none)"}`);
|
|
8848
8978
|
}
|
|
8849
8979
|
/**
|
|
8850
8980
|
* 设置只读回退层的 mountFolder 配置。
|
|
@@ -8853,7 +8983,7 @@ class ChatSession {
|
|
|
8853
8983
|
setMountFolder(mountFolderConfig) {
|
|
8854
8984
|
this.mountFolder = mountFolderConfig ?? null;
|
|
8855
8985
|
if (this.sandbox) this.sandbox.mountFolder = this.mountFolder;
|
|
8856
|
-
console$
|
|
8986
|
+
console$h.log(`[ChatSession] MountFolder set to: ${this.mountFolder ?? "(none)"}`);
|
|
8857
8987
|
}
|
|
8858
8988
|
/** 设置 API 缓存 Key(传递给 aiGenerators.chat)。 */
|
|
8859
8989
|
setAPICacheKey(key) {
|
|
@@ -8922,7 +9052,7 @@ class ChatSession {
|
|
|
8922
9052
|
const s = typeof v === "string" ? v : JSON.stringify(v);
|
|
8923
9053
|
return s.length > 180 ? s.slice(0, 180) + "..." : s;
|
|
8924
9054
|
};
|
|
8925
|
-
console$
|
|
9055
|
+
console$h.log(`[ChatSession.send] start session='${this.name ?? "root"}' userMessage=${summarizeDebugValue2(userMessage)}`);
|
|
8926
9056
|
try {
|
|
8927
9057
|
let resolvedUserMessage = userMessage;
|
|
8928
9058
|
const effectiveOptions = {
|
|
@@ -8934,11 +9064,11 @@ class ChatSession {
|
|
|
8934
9064
|
const shouldProcessTemplate = effectiveOptions.runCode === true && typeof userMessage === "string";
|
|
8935
9065
|
if (shouldProcessTemplate) {
|
|
8936
9066
|
resolvedUserMessage = await this.sandbox.processTemplate(userMessage);
|
|
8937
|
-
console$
|
|
9067
|
+
console$h.log(`[ChatSession.send] runCode resolved userMessage=${summarizeDebugValue2(resolvedUserMessage)}`);
|
|
8938
9068
|
}
|
|
8939
9069
|
const childResults = ((_b2 = this._consumePendingChildResults) == null ? void 0 : _b2.call(this)) ?? [];
|
|
8940
9070
|
if (childResults.length > 0) {
|
|
8941
|
-
console$
|
|
9071
|
+
console$h.log(`[ChatSession.send] injecting ${childResults.length} pending child result(s) into session='${this.name ?? "root"}'`);
|
|
8942
9072
|
const toolCalls = childResults.map((cr) => ({
|
|
8943
9073
|
id: cr.taskId,
|
|
8944
9074
|
type: "function",
|
|
@@ -8960,7 +9090,7 @@ class ChatSession {
|
|
|
8960
9090
|
else if (Array.isArray(resolvedUserMessage)) resolvedUserMessage = [{ type: "text", text: contextPrefix }, ...resolvedUserMessage];
|
|
8961
9091
|
}
|
|
8962
9092
|
if (effectiveOptions.skipIfMessageTextEmpty === true && shouldProcessTemplate && typeof resolvedUserMessage === "string" && resolvedUserMessage.trim() === "" && childResults.length === 0) {
|
|
8963
|
-
console$
|
|
9093
|
+
console$h.log(`[ChatSession.send] skipped empty runCode result in session='${this.name ?? "root"}'`);
|
|
8964
9094
|
return "";
|
|
8965
9095
|
}
|
|
8966
9096
|
if (Array.isArray(resolvedUserMessage)) {
|
|
@@ -8978,7 +9108,7 @@ class ChatSession {
|
|
|
8978
9108
|
try {
|
|
8979
9109
|
effectiveOptions.onUserMessage(userMessageEntry);
|
|
8980
9110
|
} catch (e) {
|
|
8981
|
-
console$
|
|
9111
|
+
console$h.warn("[ChatSession.send] onUserMessage callback failed:", e);
|
|
8982
9112
|
}
|
|
8983
9113
|
}
|
|
8984
9114
|
}
|
|
@@ -8988,7 +9118,7 @@ class ChatSession {
|
|
|
8988
9118
|
this._evictExcessImages(effectiveOptions.imageConfig.maxImageHistoryCount);
|
|
8989
9119
|
}
|
|
8990
9120
|
this._lastSendOptions = effectiveOptions;
|
|
8991
|
-
console$
|
|
9121
|
+
console$h.log("[ChatSession.send] options:", effectiveOptions);
|
|
8992
9122
|
let currentGptChatId;
|
|
8993
9123
|
const response = await this.aiChat.chat({
|
|
8994
9124
|
...effectiveOptions,
|
|
@@ -9035,11 +9165,11 @@ class ChatSession {
|
|
|
9035
9165
|
if (history) this.historyId = history.id;
|
|
9036
9166
|
}
|
|
9037
9167
|
} catch (e) {
|
|
9038
|
-
console$
|
|
9168
|
+
console$h.warn("Failed to fetch chat history", e);
|
|
9039
9169
|
}
|
|
9040
9170
|
}
|
|
9041
9171
|
} catch (e) {
|
|
9042
|
-
console$
|
|
9172
|
+
console$h.error("Failed to save chat history", e);
|
|
9043
9173
|
}
|
|
9044
9174
|
return response;
|
|
9045
9175
|
} finally {
|
|
@@ -9062,10 +9192,10 @@ class ChatSession {
|
|
|
9062
9192
|
if (!url || !url.startsWith("data:")) return item;
|
|
9063
9193
|
try {
|
|
9064
9194
|
const cdnUrl = await uploadTempVisionImage(url, { sdk: this.aiChat.sdk });
|
|
9065
|
-
console$
|
|
9195
|
+
console$h.log("[ChatSession] Uploaded inline image to CDN:", cdnUrl);
|
|
9066
9196
|
return { ...item, image_url: { ...item.image_url, url: cdnUrl } };
|
|
9067
9197
|
} catch (e) {
|
|
9068
|
-
console$
|
|
9198
|
+
console$h.warn("[ChatSession] Failed to upload inline image, keeping data-URI:", e);
|
|
9069
9199
|
return item;
|
|
9070
9200
|
}
|
|
9071
9201
|
})
|
|
@@ -9090,7 +9220,7 @@ class ChatSession {
|
|
|
9090
9220
|
const keepFrom = roundStarts[roundStarts.length - limit];
|
|
9091
9221
|
const evicted = keepFrom - systemEnd;
|
|
9092
9222
|
this.messages = [...this.messages.slice(0, systemEnd), ...this.messages.slice(keepFrom)];
|
|
9093
|
-
console$
|
|
9223
|
+
console$h.log(`[ChatSession] Evicted ${evicted} message(s), kept ${limit} round(s)`);
|
|
9094
9224
|
}
|
|
9095
9225
|
/**
|
|
9096
9226
|
* 从历史中移除超出 maxCount 限制的旧图片,
|
|
@@ -9118,7 +9248,7 @@ class ChatSession {
|
|
|
9118
9248
|
msg.content[partIdx] = { type: "text", text: "(user_image)" };
|
|
9119
9249
|
removedCount++;
|
|
9120
9250
|
}
|
|
9121
|
-
if (removedCount > 0) console$
|
|
9251
|
+
if (removedCount > 0) console$h.log(`[ChatSession] Evicted ${removedCount} image(s) from history, kept ${maxCount}`);
|
|
9122
9252
|
}
|
|
9123
9253
|
// ──────────────────── 历史管理 ────────────────────
|
|
9124
9254
|
/** 清空对话历史(仅清空 messages 数组)。 */
|
|
@@ -9145,7 +9275,7 @@ class ChatSession {
|
|
|
9145
9275
|
*/
|
|
9146
9276
|
async restartAgent(promptFile, tools, _options) {
|
|
9147
9277
|
var _a2, _b2, _c, _d, _e, _f;
|
|
9148
|
-
console$
|
|
9278
|
+
console$h.log(`[ChatSession] restartAgent session='${this.name ?? "root"}' promptFile=${promptFile ?? "(none)"}`);
|
|
9149
9279
|
const normalizedTools = Array.isArray(tools) ? tools.filter((t) => typeof t === "string" && t.trim()) : [];
|
|
9150
9280
|
const cleanupFn = this["_cleanupChildSessions"];
|
|
9151
9281
|
cleanupFn == null ? void 0 : cleanupFn.call(this);
|
|
@@ -9161,18 +9291,17 @@ class ChatSession {
|
|
|
9161
9291
|
const hasPromptFile = !!(promptFile && typeof promptFile === "string" && promptFile.trim());
|
|
9162
9292
|
if (hasPromptFile) {
|
|
9163
9293
|
try {
|
|
9164
|
-
|
|
9165
|
-
loadedConfig = await AgentConfig2.fetch(promptFile.trim());
|
|
9294
|
+
loadedConfig = await AgentConfig.fetch(promptFile.trim());
|
|
9166
9295
|
} catch (e) {
|
|
9167
|
-
console$
|
|
9296
|
+
console$h.warn(`[ChatSession] restartAgent failed to load '${promptFile}': ${e.message}`);
|
|
9168
9297
|
}
|
|
9169
9298
|
}
|
|
9170
9299
|
const systemPrompt = loadedConfig ? loadedConfig["system_prompt"] ?? loadedConfig["systemPrompt"] ?? defaults.systemPrompt : defaults.systemPrompt;
|
|
9171
9300
|
if (hasPromptFile && loadedConfig) {
|
|
9172
9301
|
this._savedMessages = this.messages.filter((m) => m.role !== "system");
|
|
9173
|
-
console$
|
|
9302
|
+
console$h.log(`[ChatSession] restartAgent: saved ${this._savedMessages.length} history messages`);
|
|
9174
9303
|
} else if (!hasPromptFile && this._savedMessages) {
|
|
9175
|
-
console$
|
|
9304
|
+
console$h.log(`[ChatSession] restartAgent: keeping ${this._savedMessages.length} saved history messages for summarizer`);
|
|
9176
9305
|
}
|
|
9177
9306
|
this.messages = [];
|
|
9178
9307
|
if (systemPrompt) this.messages.push({ role: "system", content: systemPrompt });
|
|
@@ -9213,7 +9342,7 @@ function installAIChatSessionFactory() {
|
|
|
9213
9342
|
Object.assign(ChatSession.prototype, childSessionMethods);
|
|
9214
9343
|
Object.assign(ChatSession.prototype, {
|
|
9215
9344
|
async _triggerImmediateCallback() {
|
|
9216
|
-
console$
|
|
9345
|
+
console$h.log(
|
|
9217
9346
|
`[ChatSession] _triggerImmediateCallback session='${this.name ?? "root"}' pendingChildResults=${this._pendingChildResults.length} isSending=${this._isSending}`
|
|
9218
9347
|
);
|
|
9219
9348
|
if (this._isSending) {
|
|
@@ -9226,11 +9355,11 @@ function installAIChatSessionFactory() {
|
|
|
9226
9355
|
});
|
|
9227
9356
|
}
|
|
9228
9357
|
if (this._pendingChildResults.length === 0) return;
|
|
9229
|
-
console$
|
|
9358
|
+
console$h.log("[ChatSession] Immediate callback: sending child results to parent");
|
|
9230
9359
|
try {
|
|
9231
9360
|
await this.send(null, this._lastSendOptions);
|
|
9232
9361
|
} catch (e) {
|
|
9233
|
-
console$
|
|
9362
|
+
console$h.error("[ChatSession] Immediate callback send failed:", e);
|
|
9234
9363
|
}
|
|
9235
9364
|
}
|
|
9236
9365
|
});
|
|
@@ -9242,7 +9371,7 @@ function installAIChatSessionFactory() {
|
|
|
9242
9371
|
}
|
|
9243
9372
|
installAIChatSessionFactory();
|
|
9244
9373
|
installAIChatSessionFactory();
|
|
9245
|
-
const console$
|
|
9374
|
+
const console$g = SDKLogger.createModuleConsole("SummarizeTool");
|
|
9246
9375
|
const _SummarizeTool = class _SummarizeTool {
|
|
9247
9376
|
constructor() {
|
|
9248
9377
|
__publicField(this, "config", {});
|
|
@@ -9318,7 +9447,7 @@ const _SummarizeTool = class _SummarizeTool {
|
|
|
9318
9447
|
};
|
|
9319
9448
|
const filtered = this.filterSessionMessages(session, filters);
|
|
9320
9449
|
const result = filtered.slice(-count);
|
|
9321
|
-
console$
|
|
9450
|
+
console$g.log(`[SummarizeTool] get_history_messages: ${result.length}/${filtered.length} messages (count=${count})`);
|
|
9322
9451
|
return JSON.stringify(
|
|
9323
9452
|
result.map((msg) => ({
|
|
9324
9453
|
role: msg.role,
|
|
@@ -9338,7 +9467,7 @@ const _SummarizeTool = class _SummarizeTool {
|
|
|
9338
9467
|
const filters = args["filters"] ?? null;
|
|
9339
9468
|
const filtered = this.filterSessionMessages(session, filters);
|
|
9340
9469
|
const total = Array.isArray(session.messages) ? session.messages.length : Array.isArray(session._history) ? session._history.length : 0;
|
|
9341
|
-
console$
|
|
9470
|
+
console$g.log(`[SummarizeTool] get_history_messages_count: ${filtered.length}/${total}`);
|
|
9342
9471
|
return JSON.stringify({ count: filtered.length, total });
|
|
9343
9472
|
}
|
|
9344
9473
|
/**
|
|
@@ -9388,7 +9517,7 @@ ${result.summary}`;
|
|
|
9388
9517
|
const messageBased = _SummarizeTool.isMessageBased(session);
|
|
9389
9518
|
if (isAsync) {
|
|
9390
9519
|
if (session._isSummarizing) {
|
|
9391
|
-
console$
|
|
9520
|
+
console$g.log("[SummarizeTool] Async summarization already running, merging");
|
|
9392
9521
|
return { summary: "", removedCount: 0, remainingCount: messages.length, status: "merged" };
|
|
9393
9522
|
}
|
|
9394
9523
|
session._isSummarizing = true;
|
|
@@ -9399,7 +9528,7 @@ ${result.summary}`;
|
|
|
9399
9528
|
}
|
|
9400
9529
|
const sdk = session.sdk ?? ((_a2 = session.aiChat) == null ? void 0 : _a2.sdk);
|
|
9401
9530
|
if (!(sdk == null ? void 0 : sdk.aiChat)) {
|
|
9402
|
-
console$
|
|
9531
|
+
console$g.error("[SummarizeTool] No SDK instance available on session");
|
|
9403
9532
|
return { summary: "", removedCount: 0, remainingCount: messages.length };
|
|
9404
9533
|
}
|
|
9405
9534
|
const keepRecentRounds = Number(options.keepRecentRounds) || 3;
|
|
@@ -9445,7 +9574,7 @@ ${result.summary}`;
|
|
|
9445
9574
|
}
|
|
9446
9575
|
return result;
|
|
9447
9576
|
} catch (e) {
|
|
9448
|
-
console$
|
|
9577
|
+
console$g.error("[SummarizeTool] Summarization failed:", e);
|
|
9449
9578
|
return { summary: "", removedCount: 0, remainingCount: messages.length };
|
|
9450
9579
|
} finally {
|
|
9451
9580
|
agent.destroy();
|
|
@@ -9464,10 +9593,10 @@ ${result.summary}`;
|
|
|
9464
9593
|
taskSummary: "Conversation summarization",
|
|
9465
9594
|
result: result.summary
|
|
9466
9595
|
});
|
|
9467
|
-
console$
|
|
9596
|
+
console$g.log(`[SummarizeTool] Async summary queued as pending result (taskId=${taskId})`);
|
|
9468
9597
|
}
|
|
9469
9598
|
} catch (e) {
|
|
9470
|
-
console$
|
|
9599
|
+
console$g.error("[SummarizeTool] Async summarization failed:", e);
|
|
9471
9600
|
} finally {
|
|
9472
9601
|
session._isSummarizing = false;
|
|
9473
9602
|
}
|
|
@@ -9628,7 +9757,7 @@ class SummarizeAgent {
|
|
|
9628
9757
|
*/
|
|
9629
9758
|
async loadConfig(config, { skipCopilotToolsOverride = false } = {}) {
|
|
9630
9759
|
this._config = config;
|
|
9631
|
-
console$
|
|
9760
|
+
console$g.log("[SummarizeAgent] Config loaded:", Object.keys(config).join(", "));
|
|
9632
9761
|
if (this.session) await this._createAgentSession();
|
|
9633
9762
|
if (!skipCopilotToolsOverride) this._overrideCopilotToolsExecutor();
|
|
9634
9763
|
return config;
|
|
@@ -9646,7 +9775,7 @@ class SummarizeAgent {
|
|
|
9646
9775
|
this._timer = setInterval(() => {
|
|
9647
9776
|
void this._onTick();
|
|
9648
9777
|
}, interval * 1e3);
|
|
9649
|
-
console$
|
|
9778
|
+
console$g.log(`[SummarizeAgent] Silent-tick timer started (${interval}s)`);
|
|
9650
9779
|
}
|
|
9651
9780
|
/** 停止静默计时器。 */
|
|
9652
9781
|
stopTimer() {
|
|
@@ -9688,7 +9817,7 @@ class SummarizeAgent {
|
|
|
9688
9817
|
}
|
|
9689
9818
|
this._checkAndTriggerRunning = true;
|
|
9690
9819
|
this._autoTriggerSignature = signature;
|
|
9691
|
-
console$
|
|
9820
|
+
console$g.log(`[SummarizeAgent] Auto-summarization triggered: ${roundCount} rounds, ${totalTextLength} chars`);
|
|
9692
9821
|
try {
|
|
9693
9822
|
if (this._config) {
|
|
9694
9823
|
try {
|
|
@@ -9697,7 +9826,7 @@ class SummarizeAgent {
|
|
|
9697
9826
|
this._onEvent("summarized", { summary: result.summary, removedCount: result.removedCount, remainingCount: result.remainingCount, trigger: "auto", mode: result.mode, summarizeBeginTime: result.summarizeBeginTime });
|
|
9698
9827
|
}
|
|
9699
9828
|
} catch (e) {
|
|
9700
|
-
console$
|
|
9829
|
+
console$g.error("[SummarizeAgent] Auto-summarization (agent) failed:", e);
|
|
9701
9830
|
}
|
|
9702
9831
|
return;
|
|
9703
9832
|
}
|
|
@@ -9711,7 +9840,7 @@ class SummarizeAgent {
|
|
|
9711
9840
|
this._onEvent("summarized", { summary: result.summary, removedCount: result.removedCount, remainingCount: result.remainingCount, trigger: "auto", mode: result.mode, summarizeBeginTime: result.summarizeBeginTime });
|
|
9712
9841
|
}
|
|
9713
9842
|
} catch (e) {
|
|
9714
|
-
console$
|
|
9843
|
+
console$g.error("[SummarizeAgent] Auto-summarization fallback failed:", e);
|
|
9715
9844
|
}
|
|
9716
9845
|
} finally {
|
|
9717
9846
|
this._checkAndTriggerRunning = false;
|
|
@@ -9727,7 +9856,7 @@ class SummarizeAgent {
|
|
|
9727
9856
|
async run(options = {}) {
|
|
9728
9857
|
var _a2, _b2, _c, _d, _e, _f;
|
|
9729
9858
|
if (this._running) {
|
|
9730
|
-
console$
|
|
9859
|
+
console$g.log("[SummarizeAgent] Already running, skipping");
|
|
9731
9860
|
return { summary: "", removedCount: 0, remainingCount: ((_b2 = (_a2 = this.session) == null ? void 0 : _a2.messages) == null ? void 0 : _b2.length) ?? 0 };
|
|
9732
9861
|
}
|
|
9733
9862
|
const session = this.session;
|
|
@@ -9735,7 +9864,7 @@ class SummarizeAgent {
|
|
|
9735
9864
|
if (!this._config) return { summary: "", removedCount: 0, remainingCount: session.messages.length };
|
|
9736
9865
|
if (!this._agentSession) await this._createAgentSession();
|
|
9737
9866
|
if (!this._agentSession) {
|
|
9738
|
-
console$
|
|
9867
|
+
console$g.error("[SummarizeAgent] Failed to create agent session");
|
|
9739
9868
|
return { summary: "", removedCount: 0, remainingCount: session.messages.length };
|
|
9740
9869
|
}
|
|
9741
9870
|
const opts = this._getOptions();
|
|
@@ -9744,11 +9873,11 @@ class SummarizeAgent {
|
|
|
9744
9873
|
const summarizeBeginTime = Date.now();
|
|
9745
9874
|
const conversationMessages = session.messages.filter((m) => m.role !== "system");
|
|
9746
9875
|
if (conversationMessages.length < 2) {
|
|
9747
|
-
console$
|
|
9876
|
+
console$g.log("[SummarizeAgent] Not enough messages to summarize");
|
|
9748
9877
|
return { summary: "", removedCount: 0, remainingCount: session.messages.length };
|
|
9749
9878
|
}
|
|
9750
9879
|
this._running = true;
|
|
9751
|
-
console$
|
|
9880
|
+
console$g.log(`[SummarizeAgent] Running: ${conversationMessages.length} messages, mode=${mode}`);
|
|
9752
9881
|
try {
|
|
9753
9882
|
const agentSession = this._agentSession;
|
|
9754
9883
|
const agentConfig = this._config;
|
|
@@ -9757,7 +9886,7 @@ class SummarizeAgent {
|
|
|
9757
9886
|
try {
|
|
9758
9887
|
systemPrompt = ((_c = agentSession.sandbox) == null ? void 0 : _c.processTemplate) ? await agentSession.sandbox.processTemplate(rawPrompt) : rawPrompt;
|
|
9759
9888
|
} catch (e) {
|
|
9760
|
-
console$
|
|
9889
|
+
console$g.warn("[SummarizeAgent] Prompt template failed, using raw:", e);
|
|
9761
9890
|
systemPrompt = rawPrompt;
|
|
9762
9891
|
}
|
|
9763
9892
|
const serialized = SummarizeTool.serializeMessages(conversationMessages);
|
|
@@ -9786,7 +9915,7 @@ class SummarizeAgent {
|
|
|
9786
9915
|
);
|
|
9787
9916
|
const summaryText = (lastAssistant == null ? void 0 : lastAssistant.content) ?? "";
|
|
9788
9917
|
if (!summaryText) {
|
|
9789
|
-
console$
|
|
9918
|
+
console$g.warn("[SummarizeAgent] Empty summary returned");
|
|
9790
9919
|
return { summary: "", removedCount: 0, remainingCount: session.messages.length };
|
|
9791
9920
|
}
|
|
9792
9921
|
const cleanedMessages = session.messages.filter(
|
|
@@ -9800,17 +9929,17 @@ class SummarizeAgent {
|
|
|
9800
9929
|
await ((_f = aiChat == null ? void 0 : aiChat.updateChatHistory) == null ? void 0 : _f.call(aiChat, session.historyId, { id: session.historyId, chatId: session.chatId, modId: session.modId, model: session.model, messages: cleanedMessages }));
|
|
9801
9930
|
}
|
|
9802
9931
|
} catch (e) {
|
|
9803
|
-
console$
|
|
9932
|
+
console$g.warn("[SummarizeAgent] Failed to persist summarized history:", e);
|
|
9804
9933
|
}
|
|
9805
9934
|
if (mode === "replace") {
|
|
9806
9935
|
session.messages = cleanedMessages;
|
|
9807
9936
|
this.syncHistoryToRTC();
|
|
9808
9937
|
}
|
|
9809
9938
|
const remainingCount = session.messages.length;
|
|
9810
|
-
console$
|
|
9939
|
+
console$g.log(`[SummarizeAgent] ${mode} mode: removed ${removedCount} from history, session ${mode === "replace" ? "updated" : "unchanged"}`);
|
|
9811
9940
|
return { summary: summaryText, removedCount, remainingCount, mode, summarizeBeginTime };
|
|
9812
9941
|
} catch (e) {
|
|
9813
|
-
console$
|
|
9942
|
+
console$g.error("[SummarizeAgent] Failed:", e);
|
|
9814
9943
|
return { summary: "", removedCount: 0, remainingCount: session.messages.length };
|
|
9815
9944
|
} finally {
|
|
9816
9945
|
this._running = false;
|
|
@@ -9832,7 +9961,7 @@ class SummarizeAgent {
|
|
|
9832
9961
|
newHistory.push({ role: msg.role, text, roundId: null });
|
|
9833
9962
|
}
|
|
9834
9963
|
vcSession._history = newHistory;
|
|
9835
|
-
console$
|
|
9964
|
+
console$g.log(`[SummarizeAgent] Synced history to RTC (${newHistory.length} entries)`);
|
|
9836
9965
|
}
|
|
9837
9966
|
/** 完全销毁 agent:停止计时器,清除所有状态。 */
|
|
9838
9967
|
destroy() {
|
|
@@ -9896,7 +10025,7 @@ class SummarizeAgent {
|
|
|
9896
10025
|
}
|
|
9897
10026
|
this._tickSummarizing = true;
|
|
9898
10027
|
this._autoTriggerSignature = signature;
|
|
9899
|
-
console$
|
|
10028
|
+
console$g.log(`[SummarizeAgent] Silent-tick triggered: ${roundCount} rounds, ${totalTextLength} chars`);
|
|
9900
10029
|
try {
|
|
9901
10030
|
let result;
|
|
9902
10031
|
if (this._config) {
|
|
@@ -9909,7 +10038,7 @@ class SummarizeAgent {
|
|
|
9909
10038
|
this._onEvent("summarized", { summary: result.summary, removedCount: result.removedCount, remainingCount: result.remainingCount, trigger: "silentTick", mode: result.mode, summarizeBeginTime: result.summarizeBeginTime });
|
|
9910
10039
|
}
|
|
9911
10040
|
} catch (e) {
|
|
9912
|
-
console$
|
|
10041
|
+
console$g.error("[SummarizeAgent] Silent-tick failed:", e);
|
|
9913
10042
|
} finally {
|
|
9914
10043
|
this._tickSummarizing = false;
|
|
9915
10044
|
if (this._pendingAutoCheck) this._drainPendingAutoCheck();
|
|
@@ -9934,7 +10063,7 @@ class SummarizeAgent {
|
|
|
9934
10063
|
this._agentSession = sdk.aiChat.createSession({ model, workspace, mountFolder, enableTools, skipHistory: true });
|
|
9935
10064
|
if ((_e = this.session) == null ? void 0 : _e.sandbox) this._agentSession["sandbox"] = this.session.sandbox;
|
|
9936
10065
|
this._registerHistoryAPIsOnSandbox(this._agentSession["sandbox"]);
|
|
9937
|
-
console$
|
|
10066
|
+
console$g.log(`[SummarizeAgent] Agent session created (model=${model}, tools=${enableTools.join(",")})`);
|
|
9938
10067
|
return this._agentSession;
|
|
9939
10068
|
}
|
|
9940
10069
|
/** @private 覆盖 CopilotTools 的 summarize 分类 executor,使其通过 agent 执行。 */
|
|
@@ -9963,7 +10092,7 @@ class SummarizeAgent {
|
|
|
9963
10092
|
definitions: mergedDefs,
|
|
9964
10093
|
executor: async (fnName, fnArgs, config) => {
|
|
9965
10094
|
if (fnName === "summarize_conversation") {
|
|
9966
|
-
console$
|
|
10095
|
+
console$g.log(`[SummarizeAgent] summarize_conversation tool called: ${(fnArgs == null ? void 0 : fnArgs["reason"]) ?? "(no reason)"}`);
|
|
9967
10096
|
try {
|
|
9968
10097
|
const result = await agent.run();
|
|
9969
10098
|
if (result.summary) {
|
|
@@ -9975,7 +10104,7 @@ ${result.summary}`;
|
|
|
9975
10104
|
}
|
|
9976
10105
|
return "No summarization needed — conversation is short enough.";
|
|
9977
10106
|
} catch (e) {
|
|
9978
|
-
console$
|
|
10107
|
+
console$g.error("[SummarizeAgent] summarize_conversation tool failed:", e);
|
|
9979
10108
|
return `Summarization failed: ${e.message}`;
|
|
9980
10109
|
}
|
|
9981
10110
|
}
|
|
@@ -9984,7 +10113,7 @@ ${result.summary}`;
|
|
|
9984
10113
|
}
|
|
9985
10114
|
});
|
|
9986
10115
|
this._registerHistoryAPIsOnSandbox((_f = this.session) == null ? void 0 : _f.sandbox);
|
|
9987
|
-
console$
|
|
10116
|
+
console$g.log("[SummarizeAgent] Overrode CopilotTools summarize executor");
|
|
9988
10117
|
}
|
|
9989
10118
|
/**
|
|
9990
10119
|
* @private 在 sandbox 上注册 get_history_messages / get_history_messages_count 自定义 API,
|
|
@@ -10004,7 +10133,7 @@ ${result.summary}`;
|
|
|
10004
10133
|
});
|
|
10005
10134
|
}
|
|
10006
10135
|
}
|
|
10007
|
-
const console$
|
|
10136
|
+
const console$f = SDKLogger.createModuleConsole("CopilotTools");
|
|
10008
10137
|
class CopilotTools {
|
|
10009
10138
|
constructor(sdk) {
|
|
10010
10139
|
/** 工具分类注册表 */
|
|
@@ -10163,7 +10292,7 @@ class CopilotTools {
|
|
|
10163
10292
|
const sessionName = (sessionObj == null ? void 0 : sessionObj["name"]) || (sessionObj == null ? void 0 : sessionObj["workspace"]) || "direct";
|
|
10164
10293
|
const source = (config == null ? void 0 : config["_proxied"]) ? "proxied" : "local";
|
|
10165
10294
|
const routerId = ((_c = (_b2 = (_a2 = this.sdk) == null ? void 0 : _a2.agentRouter) == null ? void 0 : _b2.instanceId) == null ? void 0 : _c.slice(0, 8)) || (typeof window !== "undefined" && window.parent === window ? "parent" : "iframe");
|
|
10166
|
-
console$
|
|
10295
|
+
console$f.log(`[CopilotTools|${routerId}] ${source} execute: ${fnName} [category: ${categoryName}, session: ${sessionName}]`);
|
|
10167
10296
|
return this._registry[categoryName].executor(fnName, fnArgs, config);
|
|
10168
10297
|
}
|
|
10169
10298
|
/**
|
|
@@ -10296,7 +10425,7 @@ class CopilotTools {
|
|
|
10296
10425
|
/** AppTools 类引用(供外部访问) */
|
|
10297
10426
|
__publicField(CopilotTools, "AppTools");
|
|
10298
10427
|
CopilotTools.AppTools = AppTools;
|
|
10299
|
-
const console$
|
|
10428
|
+
const console$e = SDKLogger.createModuleConsole("WxLaunchApp");
|
|
10300
10429
|
class WxLaunchApp {
|
|
10301
10430
|
constructor(sdk) {
|
|
10302
10431
|
__publicField(this, "sdk");
|
|
@@ -10395,27 +10524,27 @@ class WxLaunchApp {
|
|
|
10395
10524
|
/** 在容器中创建唤起按钮,返回按钮元素 id(失败返回 null)。 */
|
|
10396
10525
|
createLaunchButton(container, options = {}) {
|
|
10397
10526
|
if (!container) {
|
|
10398
|
-
console$
|
|
10527
|
+
console$e.error("Container element is required");
|
|
10399
10528
|
return null;
|
|
10400
10529
|
}
|
|
10401
10530
|
if (!this.isConfigured) {
|
|
10402
|
-
console$
|
|
10403
|
-
console$
|
|
10531
|
+
console$e.warn("WeChat SDK not configured. Please call initialize() first, or the button may not work properly.");
|
|
10532
|
+
console$e.warn('Example: await wxLaunchApp.initialize({ appId: "your-appid" })');
|
|
10404
10533
|
if (options.autoInit && options.appId) {
|
|
10405
|
-
console$
|
|
10534
|
+
console$e.log("Attempting auto-initialization...");
|
|
10406
10535
|
this.initialize({
|
|
10407
10536
|
appId: options.appId,
|
|
10408
10537
|
url: options.url,
|
|
10409
10538
|
debug: options.debug
|
|
10410
10539
|
}).then((result) => {
|
|
10411
10540
|
if (result.success) {
|
|
10412
|
-
console$
|
|
10541
|
+
console$e.log("Auto-initialization successful, recreating button...");
|
|
10413
10542
|
this.createLaunchButton(container, { ...options, autoInit: false });
|
|
10414
10543
|
} else {
|
|
10415
|
-
console$
|
|
10544
|
+
console$e.error("Auto-initialization failed:", result.message);
|
|
10416
10545
|
}
|
|
10417
10546
|
}).catch((err) => {
|
|
10418
|
-
console$
|
|
10547
|
+
console$e.error("Auto-initialization error:", err);
|
|
10419
10548
|
});
|
|
10420
10549
|
return null;
|
|
10421
10550
|
}
|
|
@@ -10497,7 +10626,7 @@ class WxLaunchApp {
|
|
|
10497
10626
|
this.downloadUrl = url;
|
|
10498
10627
|
}
|
|
10499
10628
|
}
|
|
10500
|
-
const console$
|
|
10629
|
+
const console$d = SDKLogger.createModuleConsole("WxAuth");
|
|
10501
10630
|
const DEFAULT_CONFIG = {
|
|
10502
10631
|
appId: "wx7935c49369d421c1",
|
|
10503
10632
|
// 默认微信 App ID
|
|
@@ -10558,7 +10687,7 @@ class WxAuth {
|
|
|
10558
10687
|
*/
|
|
10559
10688
|
authorize(options = {}) {
|
|
10560
10689
|
if (typeof window === "undefined") {
|
|
10561
|
-
console$
|
|
10690
|
+
console$d.warn("WxAuth.authorize: Not in browser environment");
|
|
10562
10691
|
return;
|
|
10563
10692
|
}
|
|
10564
10693
|
const appId = options.appId || this.appId;
|
|
@@ -10612,7 +10741,7 @@ class WxAuth {
|
|
|
10612
10741
|
}
|
|
10613
10742
|
const res = await response.json();
|
|
10614
10743
|
if (appId === this.maisiAppId) {
|
|
10615
|
-
console$
|
|
10744
|
+
console$d.log("Using Maisi App ID for wxCodeToToken");
|
|
10616
10745
|
onSuccess(res);
|
|
10617
10746
|
return { success: true, data: res, isMaisi: true };
|
|
10618
10747
|
}
|
|
@@ -14248,6 +14377,7 @@ const SERVICE_PRESETS = {
|
|
|
14248
14377
|
{ name: "openrouter-gpt-5.5", modelId: "openai/gpt-5.5", category: "Chat" },
|
|
14249
14378
|
{ name: "openrouter-claude-opus-4-8", modelId: "anthropic/claude-4.8-opus", category: "Chat" },
|
|
14250
14379
|
{ name: "openrouter-claude", modelId: "anthropic/claude-4.8-opus", category: "Chat" },
|
|
14380
|
+
{ name: "openrouter-claude-fable-5", modelId: "anthropic/claude-fable-5", category: "Chat" },
|
|
14251
14381
|
{ name: "openrouter-claude-sonnet", modelId: "anthropic/claude-4.6-sonnet", category: "Chat" },
|
|
14252
14382
|
{ name: "openrouter-gemini-3.1-flash-image-preview", modelId: "google/gemini-3.1-flash-image-preview", category: "Image" },
|
|
14253
14383
|
{ name: "openrouter-gemini-3-pro-image-preview", modelId: "google/gemini-3-pro-image-preview", category: "Image" },
|
|
@@ -14726,6 +14856,7 @@ class LocalAPIKeySettings {
|
|
|
14726
14856
|
}
|
|
14727
14857
|
}
|
|
14728
14858
|
async save() {
|
|
14859
|
+
var _a2;
|
|
14729
14860
|
const data = this._serializeData();
|
|
14730
14861
|
try {
|
|
14731
14862
|
if (this.storageMode === "personalPageStore") {
|
|
@@ -14736,6 +14867,14 @@ class LocalAPIKeySettings {
|
|
|
14736
14867
|
} else {
|
|
14737
14868
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(data, null, 2));
|
|
14738
14869
|
}
|
|
14870
|
+
const onSave = (_a2 = this._showOptions) == null ? void 0 : _a2.onSave;
|
|
14871
|
+
if (typeof onSave === "function") {
|
|
14872
|
+
try {
|
|
14873
|
+
onSave();
|
|
14874
|
+
} catch (e) {
|
|
14875
|
+
console.warn("[LocalAPIKeySettings] onSave callback failed:", e);
|
|
14876
|
+
}
|
|
14877
|
+
}
|
|
14739
14878
|
} catch (e) {
|
|
14740
14879
|
console.warn("[LocalAPIKeySettings] Failed to save settings:", e);
|
|
14741
14880
|
}
|
|
@@ -15872,7 +16011,7 @@ class LocalAPIKeySettings {
|
|
|
15872
16011
|
return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>`;
|
|
15873
16012
|
}
|
|
15874
16013
|
}
|
|
15875
|
-
const console$
|
|
16014
|
+
const console$c = SDKLogger.createModuleConsole("AIGenerators");
|
|
15876
16015
|
const DEFAULT_CHAT_MODEL = "keepwork-flash";
|
|
15877
16016
|
const DEFAULT_IMAGE_MODEL = "keepwork-image";
|
|
15878
16017
|
const DEFAULT_VIDEO_MODEL = "keepwork-video";
|
|
@@ -15962,6 +16101,41 @@ class AIGeneratorsBase {
|
|
|
15962
16101
|
var _a2;
|
|
15963
16102
|
return ((_a2 = this.sdk.localAPIKeySettings) == null ? void 0 : _a2.resolveModelSettings(model ?? "", { provider })) ?? { model: model ?? "" };
|
|
15964
16103
|
}
|
|
16104
|
+
/**
|
|
16105
|
+
* 判断某个模型当前是否「可能可用」(potentially usable):
|
|
16106
|
+
* - 本地 API key 功能已启用(localAPIKeySettings.enabled):模型必须能解析出 apiKey,
|
|
16107
|
+
* 跳过没有配置 key 的模型。
|
|
16108
|
+
* - 未启用:请求走 Keepwork proxy,跳过必须依赖本地 key 直连的模型
|
|
16109
|
+
* (如 OpenRouter `provider/model` 格式),其余模型视为可用。
|
|
16110
|
+
*
|
|
16111
|
+
* @param model - 模型名字符串,或带 name/modelId/enabled 字段的配置对象
|
|
16112
|
+
* (如 `localAPIKeySettings.listModels()` 的条目)。enabled === false 的条目直接视为不可用。
|
|
16113
|
+
* 传入空字符串 / null / undefined 时按默认聊天模型(DEFAULT_CHAT_MODEL)判断,
|
|
16114
|
+
* 与 chat() 缺省 model 的行为一致。
|
|
16115
|
+
*/
|
|
16116
|
+
isModelUsable(model) {
|
|
16117
|
+
if (model == null || model === "") return this.isModelUsable(DEFAULT_CHAT_MODEL);
|
|
16118
|
+
const isObj = typeof model === "object";
|
|
16119
|
+
if (isObj && model.enabled === false) return false;
|
|
16120
|
+
const name = isObj ? model.name || model.modelId || "" : String(model).trim();
|
|
16121
|
+
if (!name) return false;
|
|
16122
|
+
const localSettings = this.sdk.localAPIKeySettings;
|
|
16123
|
+
const resolved = this._resolveLocalModelSettings(name);
|
|
16124
|
+
if (localSettings == null ? void 0 : localSettings.enabled) {
|
|
16125
|
+
return !!resolved.apiKey;
|
|
16126
|
+
}
|
|
16127
|
+
const modelId = isObj && model.modelId || resolved.model || name;
|
|
16128
|
+
const provider = this._detectProvider(String(modelId));
|
|
16129
|
+
return provider !== "openrouter" && !String(modelId).includes("/");
|
|
16130
|
+
}
|
|
16131
|
+
/**
|
|
16132
|
+
* 过滤出「可能可用」的模型列表(规则见 isModelUsable)。
|
|
16133
|
+
* 支持字符串数组或 `localAPIKeySettings.listModels()` 返回的配置对象数组。
|
|
16134
|
+
*/
|
|
16135
|
+
filterUsableModels(models) {
|
|
16136
|
+
if (!Array.isArray(models)) return [];
|
|
16137
|
+
return models.filter((m) => this.isModelUsable(m));
|
|
16138
|
+
}
|
|
15965
16139
|
/** 判断是否应优先使用直连路由。 */
|
|
15966
16140
|
_shouldPreferDirect(localModelSettings, opts = {}) {
|
|
15967
16141
|
if (opts["directOnly"]) return true;
|
|
@@ -16135,6 +16309,16 @@ class AIGeneratorsBase {
|
|
|
16135
16309
|
if (this._shouldDisableReasoning(model)) return false;
|
|
16136
16310
|
return reasoning;
|
|
16137
16311
|
}
|
|
16312
|
+
/**
|
|
16313
|
+
* 解析 maxTokens 选项:同时接受 camelCase `maxTokens` 与下划线 `max_tokens`,
|
|
16314
|
+
* 返回正整数或 undefined(不传)。
|
|
16315
|
+
*/
|
|
16316
|
+
_resolveMaxTokens(options) {
|
|
16317
|
+
const raw = (options == null ? void 0 : options.maxTokens) ?? (options == null ? void 0 : options.max_tokens);
|
|
16318
|
+
const value = Number(raw);
|
|
16319
|
+
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
16320
|
+
return Math.floor(value);
|
|
16321
|
+
}
|
|
16138
16322
|
_buildReasoningBodyField(provider, reasoning) {
|
|
16139
16323
|
if (reasoning === void 0) return null;
|
|
16140
16324
|
if (provider === "openrouter") {
|
|
@@ -16198,7 +16382,7 @@ class AIGeneratorsBase {
|
|
|
16198
16382
|
* 支持流式和非流式两种模式,统一发出 AIChat 兼容的回调。
|
|
16199
16383
|
*/
|
|
16200
16384
|
async chatViaProxy(options = {}) {
|
|
16201
|
-
const { messages = [], stream = true, reasoning, knowledgeBaseCodes = [], apiCacheKey, abortController, extraHeaders, onMessage, onReasoning, onToolCall, onComplete, onError } = options;
|
|
16385
|
+
const { messages = [], stream = true, reasoning, knowledgeBaseCodes = [], apiCacheKey, abortController, extraHeaders, onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete, onError } = options;
|
|
16202
16386
|
const requestedModel = options["model"] ?? "keepwork-pro";
|
|
16203
16387
|
const tools = options["tools"] ?? [];
|
|
16204
16388
|
if (!messages || messages.length === 0) throw new Error("Messages array is required and cannot be empty");
|
|
@@ -16211,6 +16395,8 @@ class AIGeneratorsBase {
|
|
|
16211
16395
|
if (extraHeaders) Object.assign(headers, extraHeaders);
|
|
16212
16396
|
const requestBody = { messages, model, stream };
|
|
16213
16397
|
if (localModelSettings.apiKey) requestBody["apiKey"] = localModelSettings.apiKey;
|
|
16398
|
+
const maxTokens = this._resolveMaxTokens(options);
|
|
16399
|
+
if (maxTokens !== void 0) requestBody["max_tokens"] = maxTokens;
|
|
16214
16400
|
const reasoningOpt = this._normalizeReasoningOption(model, reasoning);
|
|
16215
16401
|
if (reasoningOpt !== void 0) requestBody["reasoning"] = reasoningOpt;
|
|
16216
16402
|
if ((knowledgeBaseCodes == null ? void 0 : knowledgeBaseCodes.length) > 0) requestBody["knowledgeBaseCodes"] = knowledgeBaseCodes;
|
|
@@ -16227,7 +16413,7 @@ class AIGeneratorsBase {
|
|
|
16227
16413
|
const msg = response.status === 429 ? "请求频率过高,请稍后重试" : `请求失败: ${response.status} ${response.statusText}`;
|
|
16228
16414
|
throw new Error(msg);
|
|
16229
16415
|
}
|
|
16230
|
-
if (stream) return await this._readKeepworkProxySSE(response, { onMessage, onReasoning, onToolCall, onComplete });
|
|
16416
|
+
if (stream) return await this._readKeepworkProxySSE(response, { onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete });
|
|
16231
16417
|
const result = await response.json();
|
|
16232
16418
|
const fullResultText = typeof result["result"] === "string" ? result["result"] : "";
|
|
16233
16419
|
const reasoningText = typeof result["reasoning_content"] === "string" ? result["reasoning_content"] : "";
|
|
@@ -16236,21 +16422,21 @@ class AIGeneratorsBase {
|
|
|
16236
16422
|
try {
|
|
16237
16423
|
onReasoning(reasoningText, reasoningText, result);
|
|
16238
16424
|
} catch (e) {
|
|
16239
|
-
console$
|
|
16425
|
+
console$c.warn("onReasoning failed:", e);
|
|
16240
16426
|
}
|
|
16241
16427
|
}
|
|
16242
16428
|
if (onToolCall) for (const tc of toolCalls) {
|
|
16243
16429
|
try {
|
|
16244
16430
|
onToolCall(tc);
|
|
16245
16431
|
} catch (e) {
|
|
16246
|
-
console$
|
|
16432
|
+
console$c.warn("onToolCall failed:", e);
|
|
16247
16433
|
}
|
|
16248
16434
|
}
|
|
16249
16435
|
if (onMessage && (fullResultText || reasoningText)) {
|
|
16250
16436
|
try {
|
|
16251
16437
|
onMessage(fullResultText, { result: fullResultText, reasoning_content: reasoningText, tool_calls: toolCalls });
|
|
16252
16438
|
} catch (e) {
|
|
16253
|
-
console$
|
|
16439
|
+
console$c.warn("onMessage failed:", e);
|
|
16254
16440
|
}
|
|
16255
16441
|
}
|
|
16256
16442
|
if (onComplete) onComplete(fullResultText, { result: fullResultText, reasoning_content: reasoningText, tool_calls: toolCalls, raw: result, headers: Object.fromEntries(response.headers.entries()) });
|
|
@@ -16260,56 +16446,174 @@ class AIGeneratorsBase {
|
|
|
16260
16446
|
throw error;
|
|
16261
16447
|
}
|
|
16262
16448
|
}
|
|
16263
|
-
/**
|
|
16264
|
-
|
|
16449
|
+
/**
|
|
16450
|
+
* @private 解析 Keepwork proxy SSE 流,返回累积文本。
|
|
16451
|
+
*
|
|
16452
|
+
* 增量式设计(性能关键):每条 `data:` 行只解析一次,缓冲区只保留未收完的尾行。
|
|
16453
|
+
* 此前的实现把全部已收数据留在缓冲区、每次网络读取都重新 split + JSON.parse 所有行——
|
|
16454
|
+
* create_file 把整页 HTML 拆成数千条小 delta 行传输时,这会变成 O(n²) 的主线程占用,
|
|
16455
|
+
* 浏览器完全没机会绘制(UI 卡死、CSS 动画停帧、工具调用 chip 直到流结束才出现)。
|
|
16456
|
+
*/
|
|
16457
|
+
async _readKeepworkProxySSE(response, { onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete } = {}) {
|
|
16265
16458
|
var _a2;
|
|
16266
16459
|
const reader = (_a2 = response.body) == null ? void 0 : _a2.getReader();
|
|
16267
16460
|
const decoder = new TextDecoder("utf-8");
|
|
16268
|
-
let
|
|
16269
|
-
let emittedReasoningLen = 0;
|
|
16461
|
+
let buffer = "", fullResult = "", fullReasoningContent = "";
|
|
16270
16462
|
const toolCalls = [];
|
|
16463
|
+
const deltaToolCallsByIndex = /* @__PURE__ */ new Map();
|
|
16464
|
+
const announcedDelta = /* @__PURE__ */ new Set();
|
|
16465
|
+
const announceDeltaToolCalls = () => {
|
|
16466
|
+
var _a3;
|
|
16467
|
+
for (const entry of deltaToolCallsByIndex.values()) {
|
|
16468
|
+
if (!((_a3 = entry.function) == null ? void 0 : _a3.name) || announcedDelta.has(entry)) continue;
|
|
16469
|
+
announcedDelta.add(entry);
|
|
16470
|
+
if (onToolCall) {
|
|
16471
|
+
try {
|
|
16472
|
+
onToolCall(entry);
|
|
16473
|
+
} catch (e) {
|
|
16474
|
+
console$c.warn("onToolCall failed:", e);
|
|
16475
|
+
}
|
|
16476
|
+
}
|
|
16477
|
+
}
|
|
16478
|
+
};
|
|
16271
16479
|
if (!reader) {
|
|
16272
16480
|
if (onComplete) onComplete("", { result: "", reasoning_content: "", tool_calls: [] });
|
|
16273
16481
|
return "";
|
|
16274
16482
|
}
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16483
|
+
const consumePayload = (json) => {
|
|
16484
|
+
var _a3, _b2, _c, _d;
|
|
16485
|
+
let textChanged = false;
|
|
16486
|
+
if (typeof json["result"] === "string" && json["result"]) {
|
|
16487
|
+
fullResult += json["result"];
|
|
16488
|
+
textChanged = true;
|
|
16489
|
+
}
|
|
16490
|
+
if (typeof json["reasoning_content"] === "string" && json["reasoning_content"]) {
|
|
16491
|
+
fullReasoningContent += json["reasoning_content"];
|
|
16492
|
+
textChanged = true;
|
|
16493
|
+
if (onReasoning) {
|
|
16494
|
+
try {
|
|
16495
|
+
onReasoning(fullReasoningContent, json["reasoning_content"]);
|
|
16496
|
+
} catch (e) {
|
|
16497
|
+
console$c.warn("onReasoning failed:", e);
|
|
16498
|
+
}
|
|
16499
|
+
}
|
|
16280
16500
|
}
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
|
|
16287
|
-
|
|
16288
|
-
|
|
16289
|
-
|
|
16290
|
-
|
|
16291
|
-
toolCalls.push(toolCall);
|
|
16292
|
-
if (onToolCall) onToolCall(toolCall);
|
|
16501
|
+
if (Array.isArray(json["tool_calls"])) {
|
|
16502
|
+
for (const toolCall of json["tool_calls"]) {
|
|
16503
|
+
const existing = toolCalls.find((tc) => tc.id === toolCall.id);
|
|
16504
|
+
if (!existing) {
|
|
16505
|
+
toolCalls.push(toolCall);
|
|
16506
|
+
if (onToolCallChunk) {
|
|
16507
|
+
try {
|
|
16508
|
+
onToolCallChunk(toolCall);
|
|
16509
|
+
} catch (e) {
|
|
16510
|
+
console$c.warn("onToolCallChunk failed:", e);
|
|
16293
16511
|
}
|
|
16294
|
-
}
|
|
16512
|
+
}
|
|
16513
|
+
if (onToolCall) {
|
|
16514
|
+
try {
|
|
16515
|
+
onToolCall(toolCall);
|
|
16516
|
+
} catch (e) {
|
|
16517
|
+
console$c.warn("onToolCall failed:", e);
|
|
16518
|
+
}
|
|
16519
|
+
}
|
|
16520
|
+
} else {
|
|
16521
|
+
const nextArgs = (_a3 = toolCall.function) == null ? void 0 : _a3.arguments;
|
|
16522
|
+
if (typeof nextArgs === "string" && nextArgs.length > (((_c = (_b2 = existing.function) == null ? void 0 : _b2.arguments) == null ? void 0 : _c.length) ?? 0)) {
|
|
16523
|
+
if (!existing.function) existing.function = { name: ((_d = toolCall.function) == null ? void 0 : _d.name) ?? "", arguments: "" };
|
|
16524
|
+
existing.function.arguments = nextArgs;
|
|
16525
|
+
if (onToolCallChunk) {
|
|
16526
|
+
try {
|
|
16527
|
+
onToolCallChunk(existing);
|
|
16528
|
+
} catch (e) {
|
|
16529
|
+
console$c.warn("onToolCallChunk failed:", e);
|
|
16530
|
+
}
|
|
16531
|
+
}
|
|
16532
|
+
}
|
|
16295
16533
|
}
|
|
16296
|
-
}
|
|
16297
|
-
|
|
16298
|
-
|
|
16299
|
-
|
|
16300
|
-
const
|
|
16301
|
-
|
|
16534
|
+
}
|
|
16535
|
+
}
|
|
16536
|
+
if (Array.isArray(json["tool_calls_delta"])) {
|
|
16537
|
+
for (const frag of json["tool_calls_delta"]) {
|
|
16538
|
+
const idx = frag["index"] ?? 0;
|
|
16539
|
+
let entry = deltaToolCallsByIndex.get(idx);
|
|
16540
|
+
if (!entry) {
|
|
16541
|
+
entry = { id: "", type: "function", function: { name: "", arguments: "" }, index: idx };
|
|
16542
|
+
deltaToolCallsByIndex.set(idx, entry);
|
|
16543
|
+
toolCalls.push(entry);
|
|
16544
|
+
}
|
|
16545
|
+
if (typeof frag["id"] === "string" && frag["id"]) entry.id = frag["id"];
|
|
16546
|
+
if (typeof frag["type"] === "string" && frag["type"]) entry.type = frag["type"];
|
|
16547
|
+
const fn = frag["function"];
|
|
16548
|
+
let tcChanged = false;
|
|
16549
|
+
if (typeof (fn == null ? void 0 : fn["name"]) === "string" && fn["name"]) {
|
|
16550
|
+
entry.function.name += fn["name"];
|
|
16551
|
+
tcChanged = true;
|
|
16552
|
+
}
|
|
16553
|
+
if (typeof (fn == null ? void 0 : fn["arguments"]) === "string" && fn["arguments"]) {
|
|
16554
|
+
entry.function.arguments += fn["arguments"];
|
|
16555
|
+
tcChanged = true;
|
|
16556
|
+
}
|
|
16557
|
+
if (tcChanged && entry.function.name && onToolCallChunk) {
|
|
16558
|
+
try {
|
|
16559
|
+
onToolCallChunk(entry);
|
|
16560
|
+
} catch (e) {
|
|
16561
|
+
console$c.warn("onToolCallChunk failed:", e);
|
|
16562
|
+
}
|
|
16563
|
+
}
|
|
16564
|
+
}
|
|
16565
|
+
}
|
|
16566
|
+
return textChanged;
|
|
16567
|
+
};
|
|
16568
|
+
const consumeTail = () => {
|
|
16569
|
+
const line = buffer.trim();
|
|
16570
|
+
buffer = "";
|
|
16571
|
+
if (!line.startsWith("data: {")) return false;
|
|
16572
|
+
try {
|
|
16573
|
+
return consumePayload(JSON.parse(line.substring("data: ".length)));
|
|
16574
|
+
} catch (_) {
|
|
16575
|
+
return false;
|
|
16576
|
+
}
|
|
16577
|
+
};
|
|
16578
|
+
while (true) {
|
|
16579
|
+
const { done, value } = await reader.read();
|
|
16580
|
+
if (done) {
|
|
16581
|
+
const tailChanged = consumeTail();
|
|
16582
|
+
if (tailChanged && onMessage) {
|
|
16302
16583
|
try {
|
|
16303
|
-
|
|
16584
|
+
onMessage(fullResult, { result: fullResult, reasoning_content: fullReasoningContent, tool_calls: toolCalls });
|
|
16304
16585
|
} catch (e) {
|
|
16305
|
-
console$
|
|
16586
|
+
console$c.warn("onMessage failed:", e);
|
|
16306
16587
|
}
|
|
16307
16588
|
}
|
|
16308
|
-
|
|
16589
|
+
announceDeltaToolCalls();
|
|
16590
|
+
if (onComplete) onComplete(fullResult, { result: fullResult, reasoning_content: fullReasoningContent, tool_calls: toolCalls, headers: Object.fromEntries(response.headers.entries()) });
|
|
16591
|
+
break;
|
|
16592
|
+
}
|
|
16593
|
+
buffer += decoder.decode(value, { stream: true });
|
|
16594
|
+
const lines = buffer.split("\n");
|
|
16595
|
+
buffer = lines.pop() ?? "";
|
|
16596
|
+
let textChanged = false;
|
|
16597
|
+
for (const line of lines) {
|
|
16598
|
+
if (!line.startsWith("data: {")) continue;
|
|
16599
|
+
let json;
|
|
16600
|
+
try {
|
|
16601
|
+
json = JSON.parse(line.substring("data: ".length));
|
|
16602
|
+
} catch (_) {
|
|
16603
|
+
continue;
|
|
16604
|
+
}
|
|
16605
|
+
try {
|
|
16606
|
+
if (consumePayload(json)) textChanged = true;
|
|
16607
|
+
} catch (e) {
|
|
16608
|
+
console$c.warn("Error consuming stream payload:", e);
|
|
16609
|
+
}
|
|
16610
|
+
}
|
|
16611
|
+
if (textChanged && onMessage) {
|
|
16612
|
+
try {
|
|
16309
16613
|
onMessage(fullResult, { result: fullResult, reasoning_content: fullReasoningContent, tool_calls: toolCalls });
|
|
16614
|
+
} catch (e) {
|
|
16615
|
+
console$c.warn("onMessage failed:", e);
|
|
16310
16616
|
}
|
|
16311
|
-
} catch (e) {
|
|
16312
|
-
console$b.warn("Error parsing stream response:", e);
|
|
16313
16617
|
}
|
|
16314
16618
|
}
|
|
16315
16619
|
return fullResult;
|
|
@@ -16320,7 +16624,7 @@ class AIGeneratorsBase {
|
|
|
16320
16624
|
*/
|
|
16321
16625
|
async chatCompletion(options = {}) {
|
|
16322
16626
|
var _a2, _b2, _c;
|
|
16323
|
-
const { messages, prompt, stream = false, temperature, responseFormat, abortController, extraHeaders, onMessage, onReasoning, onToolCall, onComplete, onError } = options;
|
|
16627
|
+
const { messages, prompt, stream = false, temperature, responseFormat, abortController, extraHeaders, onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete, onError } = options;
|
|
16324
16628
|
const requestedModel = options["model"] ?? DEFAULT_CHAT_MODEL;
|
|
16325
16629
|
const tools = options["tools"];
|
|
16326
16630
|
try {
|
|
@@ -16333,11 +16637,12 @@ class AIGeneratorsBase {
|
|
|
16333
16637
|
}
|
|
16334
16638
|
if (!apiKey) throw new Error(`Direct chat requires API key for provider: ${provider ?? "unknown"}`);
|
|
16335
16639
|
const normalizedMessages = this._normalizeMessages(messages, prompt);
|
|
16640
|
+
const maxTokens = this._resolveMaxTokens(options);
|
|
16336
16641
|
const isGemini = provider === "gemini" || provider === "google";
|
|
16337
16642
|
if (isGemini && (tools == null ? void 0 : tools.length)) throw new Error("Direct chat with tools is not supported for provider: gemini");
|
|
16338
16643
|
if (isGemini) {
|
|
16339
16644
|
const wrappedOnMessage = stream && onMessage ? (fullText, _delta, raw) => onMessage(fullText, { result: fullText, reasoning_content: "", tool_calls: [] }, raw) : void 0;
|
|
16340
|
-
const result = await this._callGoogleLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, responseFormat, onMessage: wrappedOnMessage, abortController, extraHeaders });
|
|
16645
|
+
const result = await this._callGoogleLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, maxTokens, responseFormat, onMessage: wrappedOnMessage, abortController, extraHeaders });
|
|
16341
16646
|
const res = result;
|
|
16342
16647
|
if (stream) {
|
|
16343
16648
|
if (onComplete) onComplete(res.text, { result: res.text, reasoning_content: "", tool_calls: [] });
|
|
@@ -16358,6 +16663,7 @@ class AIGeneratorsBase {
|
|
|
16358
16663
|
if (extraHeaders) Object.assign(headers, extraHeaders);
|
|
16359
16664
|
const body = { model, messages: this._normalizeOpenAIChatMessages(normalizedMessages), stream };
|
|
16360
16665
|
if (temperature !== void 0) body["temperature"] = temperature;
|
|
16666
|
+
if (maxTokens !== void 0) body["max_tokens"] = maxTokens;
|
|
16361
16667
|
if (responseFormat) body["response_format"] = typeof responseFormat === "string" ? { type: responseFormat } : responseFormat;
|
|
16362
16668
|
if (tools == null ? void 0 : tools.length) body["tools"] = tools;
|
|
16363
16669
|
const reasoningOpt = this._normalizeReasoningOption(model, options["reasoning"]);
|
|
@@ -16383,35 +16689,35 @@ class AIGeneratorsBase {
|
|
|
16383
16689
|
try {
|
|
16384
16690
|
onReasoning(reasoningText, reasoningText, data);
|
|
16385
16691
|
} catch (e) {
|
|
16386
|
-
console$
|
|
16692
|
+
console$c.warn("onReasoning failed:", e);
|
|
16387
16693
|
}
|
|
16388
16694
|
}
|
|
16389
16695
|
if (onToolCall) for (const tc of tCalls) {
|
|
16390
16696
|
try {
|
|
16391
16697
|
onToolCall(tc);
|
|
16392
16698
|
} catch (e) {
|
|
16393
|
-
console$
|
|
16699
|
+
console$c.warn("onToolCall failed:", e);
|
|
16394
16700
|
}
|
|
16395
16701
|
}
|
|
16396
16702
|
if (onMessage && (text || reasoningText)) {
|
|
16397
16703
|
try {
|
|
16398
16704
|
onMessage(text, { result: text, reasoning_content: reasoningText, tool_calls: tCalls });
|
|
16399
16705
|
} catch (e) {
|
|
16400
|
-
console$
|
|
16706
|
+
console$c.warn("onMessage failed:", e);
|
|
16401
16707
|
}
|
|
16402
16708
|
}
|
|
16403
16709
|
if (onComplete) onComplete(text, { result: text, reasoning_content: reasoningText, tool_calls: tCalls, raw: data, headers: Object.fromEntries(response.headers.entries()) });
|
|
16404
16710
|
return text;
|
|
16405
16711
|
}
|
|
16406
|
-
return await this._readChatCompletionSSE(response, { onMessage, onReasoning, onToolCall, onComplete });
|
|
16712
|
+
return await this._readChatCompletionSSE(response, { onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete });
|
|
16407
16713
|
} catch (error) {
|
|
16408
16714
|
if (onError) onError(error);
|
|
16409
16715
|
throw error;
|
|
16410
16716
|
}
|
|
16411
16717
|
}
|
|
16412
16718
|
/** @private 解析 OpenAI/OpenRouter chat-completion SSE,返回累积文本。 */
|
|
16413
|
-
async _readChatCompletionSSE(response, { onMessage, onReasoning, onToolCall, onComplete } = {}) {
|
|
16414
|
-
var _a2, _b2, _c;
|
|
16719
|
+
async _readChatCompletionSSE(response, { onMessage, onReasoning, onToolCall, onToolCallChunk, onComplete } = {}) {
|
|
16720
|
+
var _a2, _b2, _c, _d;
|
|
16415
16721
|
const reader = (_a2 = response.body) == null ? void 0 : _a2.getReader();
|
|
16416
16722
|
if (!reader) {
|
|
16417
16723
|
if (onComplete) onComplete("", { result: "", reasoning_content: "", tool_calls: [] });
|
|
@@ -16473,7 +16779,7 @@ class AIGeneratorsBase {
|
|
|
16473
16779
|
try {
|
|
16474
16780
|
onReasoning(fullReasoningContent, rPiece, json);
|
|
16475
16781
|
} catch (e) {
|
|
16476
|
-
console$
|
|
16782
|
+
console$c.warn("onReasoning failed:", e);
|
|
16477
16783
|
}
|
|
16478
16784
|
}
|
|
16479
16785
|
}
|
|
@@ -16488,8 +16794,22 @@ class AIGeneratorsBase {
|
|
|
16488
16794
|
if (tc["id"]) entry.id = tc["id"];
|
|
16489
16795
|
if (tc["type"]) entry.type = tc["type"];
|
|
16490
16796
|
const fn = tc["function"];
|
|
16491
|
-
|
|
16492
|
-
if (fn == null ? void 0 : fn["
|
|
16797
|
+
let tcChanged = false;
|
|
16798
|
+
if (fn == null ? void 0 : fn["name"]) {
|
|
16799
|
+
entry.function.name += fn["name"];
|
|
16800
|
+
tcChanged = true;
|
|
16801
|
+
}
|
|
16802
|
+
if (fn == null ? void 0 : fn["arguments"]) {
|
|
16803
|
+
entry.function.arguments += fn["arguments"];
|
|
16804
|
+
tcChanged = true;
|
|
16805
|
+
}
|
|
16806
|
+
if (tcChanged && onToolCallChunk && ((_d = entry.function) == null ? void 0 : _d.name)) {
|
|
16807
|
+
try {
|
|
16808
|
+
onToolCallChunk(entry);
|
|
16809
|
+
} catch (e) {
|
|
16810
|
+
console$c.warn("onToolCallChunk failed:", e);
|
|
16811
|
+
}
|
|
16812
|
+
}
|
|
16493
16813
|
}
|
|
16494
16814
|
}
|
|
16495
16815
|
if (choice["finish_reason"] === "tool_calls") announce();
|
|
@@ -16511,22 +16831,24 @@ class AIGeneratorsBase {
|
|
|
16511
16831
|
const provider = this._directProvider(localModelSettings, { ...options, model });
|
|
16512
16832
|
if (!apiKey) throw new Error("Direct provider API key is required");
|
|
16513
16833
|
const normalizedMessages = this._normalizeMessages(messages, prompt);
|
|
16834
|
+
const maxTokens = this._resolveMaxTokens(options);
|
|
16514
16835
|
let result;
|
|
16515
16836
|
if (provider === "gemini" || provider === "google") {
|
|
16516
|
-
result = await this._callGoogleLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16837
|
+
result = await this._callGoogleLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, maxTokens, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16517
16838
|
} else if (provider === "openai") {
|
|
16518
|
-
result = await this._callOpenAILLM({ model, apiKey, messages: normalizedMessages, stream, temperature, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16839
|
+
result = await this._callOpenAILLM({ model, apiKey, messages: normalizedMessages, stream, temperature, maxTokens, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16519
16840
|
} else if (provider === "openrouter") {
|
|
16520
|
-
result = await this._callOpenRouterLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16841
|
+
result = await this._callOpenRouterLLM({ model, apiKey, messages: normalizedMessages, stream, temperature, maxTokens, responseFormat, onMessage, onReasoning, abortController, extraHeaders });
|
|
16521
16842
|
} else {
|
|
16522
16843
|
throw new Error(`Direct provider is not supported: ${provider ?? "unknown"}`);
|
|
16523
16844
|
}
|
|
16524
16845
|
return returnRaw ? result : result == null ? void 0 : result.text;
|
|
16525
16846
|
}
|
|
16526
16847
|
async _callOpenAILLM(opts) {
|
|
16527
|
-
const { model, apiKey, messages, stream = false, temperature, responseFormat, onMessage, onReasoning, abortController, extraHeaders } = opts;
|
|
16848
|
+
const { model, apiKey, messages, stream = false, temperature, maxTokens, responseFormat, onMessage, onReasoning, abortController, extraHeaders } = opts;
|
|
16528
16849
|
const body = { model, messages, stream };
|
|
16529
16850
|
if (temperature !== void 0) body["temperature"] = temperature;
|
|
16851
|
+
if (maxTokens !== void 0) body["max_tokens"] = maxTokens;
|
|
16530
16852
|
if (responseFormat) body["response_format"] = typeof responseFormat === "string" ? { type: responseFormat } : responseFormat;
|
|
16531
16853
|
const resp = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
16532
16854
|
method: "POST",
|
|
@@ -16540,9 +16862,10 @@ class AIGeneratorsBase {
|
|
|
16540
16862
|
return { text: this._extractOpenAIText(data), data };
|
|
16541
16863
|
}
|
|
16542
16864
|
async _callOpenRouterLLM(opts) {
|
|
16543
|
-
const { model, apiKey, messages, stream = false, temperature, responseFormat, onMessage, onReasoning, onImage, abortController, extraHeaders, extraBody } = opts;
|
|
16865
|
+
const { model, apiKey, messages, stream = false, temperature, maxTokens, responseFormat, onMessage, onReasoning, onImage, abortController, extraHeaders, extraBody } = opts;
|
|
16544
16866
|
const body = { model, messages, stream };
|
|
16545
16867
|
if (temperature !== void 0) body["temperature"] = temperature;
|
|
16868
|
+
if (maxTokens !== void 0) body["max_tokens"] = maxTokens;
|
|
16546
16869
|
if (responseFormat) body["response_format"] = typeof responseFormat === "string" ? { type: responseFormat } : responseFormat;
|
|
16547
16870
|
if (extraBody) Object.assign(body, extraBody);
|
|
16548
16871
|
const resp = await fetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
@@ -16563,9 +16886,10 @@ class AIGeneratorsBase {
|
|
|
16563
16886
|
return { text: this._extractOpenAIText(data), data };
|
|
16564
16887
|
}
|
|
16565
16888
|
async _callGoogleLLM(opts) {
|
|
16566
|
-
const { model, apiKey, messages, stream = false, temperature, responseFormat, onMessage, onReasoning, abortController, extraHeaders } = opts;
|
|
16889
|
+
const { model, apiKey, messages, stream = false, temperature, maxTokens, responseFormat, onMessage, onReasoning, abortController, extraHeaders } = opts;
|
|
16567
16890
|
const generationConfig = {};
|
|
16568
16891
|
if (temperature !== void 0) generationConfig["temperature"] = temperature;
|
|
16892
|
+
if (maxTokens !== void 0) generationConfig["maxOutputTokens"] = maxTokens;
|
|
16569
16893
|
if (responseFormat === "json_object" || (responseFormat == null ? void 0 : responseFormat["type"]) === "json_object") generationConfig["responseMimeType"] = "application/json";
|
|
16570
16894
|
const body = { contents: this._messagesToGeminiContents(messages) };
|
|
16571
16895
|
if (Object.keys(generationConfig).length > 0) body["generationConfig"] = generationConfig;
|
|
@@ -16599,7 +16923,7 @@ class AIGeneratorsBase {
|
|
|
16599
16923
|
try {
|
|
16600
16924
|
json = JSON.parse(payload);
|
|
16601
16925
|
} catch (err) {
|
|
16602
|
-
console$
|
|
16926
|
+
console$c.warn("[AIGenerators] Ignoring malformed SSE payload:", payload, err);
|
|
16603
16927
|
return;
|
|
16604
16928
|
}
|
|
16605
16929
|
sawChunk = true;
|
|
@@ -16622,7 +16946,7 @@ class AIGeneratorsBase {
|
|
|
16622
16946
|
result = await reader.read();
|
|
16623
16947
|
} catch (err) {
|
|
16624
16948
|
if (fullText || reasoningText || sawChunk) {
|
|
16625
|
-
console$
|
|
16949
|
+
console$c.warn("[AIGenerators] SSE stream ended with read error after content:", err);
|
|
16626
16950
|
return fullText || reasoningText;
|
|
16627
16951
|
}
|
|
16628
16952
|
throw err;
|
|
@@ -16654,7 +16978,7 @@ class AIGeneratorsBase {
|
|
|
16654
16978
|
try {
|
|
16655
16979
|
json = JSON.parse(payload);
|
|
16656
16980
|
} catch (err) {
|
|
16657
|
-
console$
|
|
16981
|
+
console$c.warn("[AIGenerators] Ignoring malformed image SSE payload:", payload, err);
|
|
16658
16982
|
return;
|
|
16659
16983
|
}
|
|
16660
16984
|
lastData = json;
|
|
@@ -18966,7 +19290,7 @@ function applyPagesMixin(TargetClass) {
|
|
|
18966
19290
|
return this.get(`/sites/${siteId}`);
|
|
18967
19291
|
};
|
|
18968
19292
|
}
|
|
18969
|
-
const console$
|
|
19293
|
+
const console$b = SDKLogger.createModuleConsole("AgentRouter");
|
|
18970
19294
|
const MSG$1 = {
|
|
18971
19295
|
REGISTER: "agent_register",
|
|
18972
19296
|
REGISTER_ACK: "agent_register_ack",
|
|
@@ -19069,11 +19393,11 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19069
19393
|
register(agentName, session) {
|
|
19070
19394
|
if (!agentName) return false;
|
|
19071
19395
|
if (this.localAgents.has(agentName) || this.routeTable.has(agentName)) {
|
|
19072
|
-
console$
|
|
19396
|
+
console$b.warn(`[AgentRouter] Agent '${agentName}' already registered.`);
|
|
19073
19397
|
return false;
|
|
19074
19398
|
}
|
|
19075
19399
|
this.localAgents.set(agentName, { session });
|
|
19076
|
-
console$
|
|
19400
|
+
console$b.log(`[AgentRouter] Registered local agent '${agentName}'`);
|
|
19077
19401
|
this._broadcast({ is_agent_router: true, type: MSG$1.REGISTER, agentName, instanceId: this.instanceId }, null);
|
|
19078
19402
|
return true;
|
|
19079
19403
|
}
|
|
@@ -19084,7 +19408,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19084
19408
|
unregister(agentName) {
|
|
19085
19409
|
if (!this.localAgents.has(agentName)) return;
|
|
19086
19410
|
this.localAgents.delete(agentName);
|
|
19087
|
-
console$
|
|
19411
|
+
console$b.log(`[AgentRouter] Unregistered local agent '${agentName}'`);
|
|
19088
19412
|
this._broadcast({ is_agent_router: true, type: MSG$1.UNREGISTER, agentName, instanceId: this.instanceId }, null);
|
|
19089
19413
|
}
|
|
19090
19414
|
/**
|
|
@@ -19133,7 +19457,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19133
19457
|
submitTask(agentName, payload, callbacks = {}) {
|
|
19134
19458
|
const route = this.routeTable.get(agentName);
|
|
19135
19459
|
if (!route) {
|
|
19136
|
-
console$
|
|
19460
|
+
console$b.warn(`[AgentRouter] submitTask failed: no route to '${agentName}'`);
|
|
19137
19461
|
return Promise.reject(new Error(`No route to remote agent '${agentName}'`));
|
|
19138
19462
|
}
|
|
19139
19463
|
const taskId = generateUUID();
|
|
@@ -19216,7 +19540,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19216
19540
|
*/
|
|
19217
19541
|
attachNPLJS(npljs, options = {}) {
|
|
19218
19542
|
if (!npljs) {
|
|
19219
|
-
console$
|
|
19543
|
+
console$b.warn("[AgentRouter] attachNPLJS: npljs instance is required");
|
|
19220
19544
|
return this;
|
|
19221
19545
|
}
|
|
19222
19546
|
const sendEventName = options.sendEventName ?? "@webparacraft_backgroundAgent";
|
|
@@ -19236,7 +19560,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19236
19560
|
this._onMessage({ data: msg, source: proxy });
|
|
19237
19561
|
});
|
|
19238
19562
|
this.addChildWindow(proxy);
|
|
19239
|
-
console$
|
|
19563
|
+
console$b.log(`[AgentRouter] attachNPLJS: send=${sendEventName} recv=${recvEventName}`);
|
|
19240
19564
|
return this;
|
|
19241
19565
|
}
|
|
19242
19566
|
/**
|
|
@@ -19250,7 +19574,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19250
19574
|
if (npljs && this._nplRecvEventName) npljs.OffMsg(this._nplRecvEventName);
|
|
19251
19575
|
this._nplWindowProxy = null;
|
|
19252
19576
|
this._nplRecvEventName = null;
|
|
19253
|
-
console$
|
|
19577
|
+
console$b.log("[AgentRouter] detachNPLJS: bridge removed");
|
|
19254
19578
|
}
|
|
19255
19579
|
// ─────────────────────── 传输帮助 ───────────────────────
|
|
19256
19580
|
/**
|
|
@@ -19266,7 +19590,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19266
19590
|
}
|
|
19267
19591
|
windowRef.postMessage(msg, "*");
|
|
19268
19592
|
} catch (e) {
|
|
19269
|
-
console$
|
|
19593
|
+
console$b.warn("[AgentRouter] _sendTo failed:", e);
|
|
19270
19594
|
}
|
|
19271
19595
|
}
|
|
19272
19596
|
/**
|
|
@@ -19350,7 +19674,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19350
19674
|
}
|
|
19351
19675
|
this.routeTable.set(agentName, { windowRef: sourceWindow, sourceInstanceId: instanceId, learnedFrom: sourceWindow, updatedAt: Date.now() });
|
|
19352
19676
|
this._indexWindowAgent(sourceWindow, agentName);
|
|
19353
|
-
console$
|
|
19677
|
+
console$b.log(`[AgentRouter] Discovered remote agent '${agentName}' via instance ${instanceId}`);
|
|
19354
19678
|
if (sourceWindow !== window.parent) this.connectedWindows.add(sourceWindow);
|
|
19355
19679
|
if (!syncBackfill) {
|
|
19356
19680
|
this._sendTo(sourceWindow, { is_agent_router: true, type: MSG$1.REGISTER_ACK, agentName, instanceId: this.instanceId });
|
|
@@ -19360,14 +19684,14 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19360
19684
|
}
|
|
19361
19685
|
/** @private 处理 agent_register_ack(当前仅记录日志)。 */
|
|
19362
19686
|
_handleRegisterAck(msg) {
|
|
19363
|
-
console$
|
|
19687
|
+
console$b.log(`[AgentRouter] Registration of '${msg.agentName}' acknowledged by instance ${msg.instanceId}`);
|
|
19364
19688
|
}
|
|
19365
19689
|
/** @private 处理 agent_register_reject(回滚本地乐观注册)。 */
|
|
19366
19690
|
_handleRegisterReject(msg) {
|
|
19367
|
-
console$
|
|
19691
|
+
console$b.warn(`[AgentRouter] Registration of '${msg.agentName}' rejected: ${msg.reason}`);
|
|
19368
19692
|
if (this.localAgents.has(msg.agentName ?? "")) {
|
|
19369
19693
|
this.localAgents.delete(msg.agentName ?? "");
|
|
19370
|
-
console$
|
|
19694
|
+
console$b.warn(`[AgentRouter] Rolled back local registration of '${msg.agentName}'`);
|
|
19371
19695
|
}
|
|
19372
19696
|
}
|
|
19373
19697
|
/** @private 处理 agent_unregister(验证来源后删除路由,防止劫持)。 */
|
|
@@ -19377,7 +19701,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19377
19701
|
const existing = this.routeTable.get(agentName);
|
|
19378
19702
|
if (existing) {
|
|
19379
19703
|
if (existing.windowRef !== sourceWindow || existing.sourceInstanceId !== instanceId) {
|
|
19380
|
-
console$
|
|
19704
|
+
console$b.warn(`[AgentRouter] _handleUnregister ignored stale unregister for '${agentName}'`);
|
|
19381
19705
|
return;
|
|
19382
19706
|
}
|
|
19383
19707
|
this.routeTable.delete(agentName);
|
|
@@ -19407,7 +19731,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19407
19731
|
this._createRelayTask(taskId, agentName, route.windowRef, sourceWindow);
|
|
19408
19732
|
return;
|
|
19409
19733
|
}
|
|
19410
|
-
console$
|
|
19734
|
+
console$b.warn(`[AgentRouter] _handleTask no route found for agent='${agentName}' taskId=${taskId}`);
|
|
19411
19735
|
this._sendTo(sourceWindow, {
|
|
19412
19736
|
is_agent_router: true,
|
|
19413
19737
|
type: MSG$1.TASK_RESULT,
|
|
@@ -19461,7 +19785,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19461
19785
|
const result = typeof response === "string" ? response : (response == null ? void 0 : response["result"]) ?? "";
|
|
19462
19786
|
this._sendTo(replyWindow, { is_agent_router: true, type: MSG$1.TASK_RESULT, taskId, result, error: null, sourceInstanceId: this.instanceId });
|
|
19463
19787
|
} catch (e) {
|
|
19464
|
-
console$
|
|
19788
|
+
console$b.error("[AgentRouter] Local task execution failed:", e);
|
|
19465
19789
|
this._sendTo(replyWindow, {
|
|
19466
19790
|
is_agent_router: true,
|
|
19467
19791
|
type: MSG$1.TASK_RESULT,
|
|
@@ -19528,11 +19852,11 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19528
19852
|
const { taskId = "", result, error } = msg;
|
|
19529
19853
|
const record = this.taskRegistry.get(taskId);
|
|
19530
19854
|
if (!record) {
|
|
19531
|
-
console$
|
|
19855
|
+
console$b.warn(`[AgentRouter] _handleTaskResult dropped taskId=${taskId}: no task record`);
|
|
19532
19856
|
return;
|
|
19533
19857
|
}
|
|
19534
19858
|
if (!this._isExpectedTaskSource(record, sourceWindow)) {
|
|
19535
|
-
console$
|
|
19859
|
+
console$b.warn(`[AgentRouter] _handleTaskResult dropped taskId=${taskId}: unexpected source`);
|
|
19536
19860
|
return;
|
|
19537
19861
|
}
|
|
19538
19862
|
if (record.kind === "origin") {
|
|
@@ -19558,7 +19882,7 @@ const _AgentRouter = class _AgentRouter {
|
|
|
19558
19882
|
const { taskId = "" } = msg;
|
|
19559
19883
|
const record = this.taskRegistry.get(taskId);
|
|
19560
19884
|
if (!record) {
|
|
19561
|
-
console$
|
|
19885
|
+
console$b.warn(`[AgentRouter] _handleStream dropped taskId=${taskId}: no task record`);
|
|
19562
19886
|
return;
|
|
19563
19887
|
}
|
|
19564
19888
|
if (!this._isExpectedTaskSource(record, sourceWindow)) return;
|
|
@@ -20048,6 +20372,10 @@ const _KeepworkSDK = class _KeepworkSDK {
|
|
|
20048
20372
|
* 因此 npm 包中 `API_KEYS.maisi` 为 `''`;如需鉴权请通过 `setUserApiKey()` 自行提供。
|
|
20049
20373
|
*/
|
|
20050
20374
|
__publicField(_KeepworkSDK, "API_KEYS", {
|
|
20375
|
+
// 正常情况下 `__MAISI_API_KEY__` 由 Vite `define` 在构建/转译期替换为字符串字面量。
|
|
20376
|
+
// 但当源码 `.ts` 被裸服务(如 maisi dev server 直接以 ESM 提供未做 define 替换的文件)时,
|
|
20377
|
+
// 该全局并不存在,直接引用会抛 ReferenceError 导致整个 SDK 加载失败。
|
|
20378
|
+
// 用 typeof 守卫做安全回退:缺失时退化为空串(与 npm 构建一致),不再抛错。
|
|
20051
20379
|
maisi: ""
|
|
20052
20380
|
});
|
|
20053
20381
|
/** bundle 自身 URL(由 index.ts 在加载时写入,供 DigitalHumanFrame 等推导 CDN 路径)。 */
|
|
@@ -20561,7 +20889,7 @@ function normalizeRTCMessageContent(content) {
|
|
|
20561
20889
|
if (content === null || content === void 0) return null;
|
|
20562
20890
|
return typeof content === "string" ? content : JSON.stringify(content);
|
|
20563
20891
|
}
|
|
20564
|
-
const console$
|
|
20892
|
+
const console$a = SDKLogger.createModuleConsole("AIChatRTC");
|
|
20565
20893
|
class RTCChatSession {
|
|
20566
20894
|
/**
|
|
20567
20895
|
* @param {AIChatRTC} aiChatRTC - Parent AIChatRTC instance
|
|
@@ -20679,7 +21007,7 @@ class RTCChatSession {
|
|
|
20679
21007
|
try {
|
|
20680
21008
|
fn(data);
|
|
20681
21009
|
} catch (e) {
|
|
20682
|
-
console$
|
|
21010
|
+
console$a.warn(`[RTCChatSession] Event '${event}' listener error:`, e);
|
|
20683
21011
|
}
|
|
20684
21012
|
}
|
|
20685
21013
|
}
|
|
@@ -20778,7 +21106,7 @@ class RTCChatSession {
|
|
|
20778
21106
|
taskId: this.taskId
|
|
20779
21107
|
});
|
|
20780
21108
|
} catch (e) {
|
|
20781
|
-
console$
|
|
21109
|
+
console$a.warn("[RTCChatSession] stop voiceChat warning:", e == null ? void 0 : e.message);
|
|
20782
21110
|
}
|
|
20783
21111
|
}
|
|
20784
21112
|
this._cleanup();
|
|
@@ -20842,7 +21170,7 @@ class RTCChatSession {
|
|
|
20842
21170
|
this.rtcEngine.leaveRoom();
|
|
20843
21171
|
VERTC.destroyEngine(this.rtcEngine);
|
|
20844
21172
|
} catch (e) {
|
|
20845
|
-
console$
|
|
21173
|
+
console$a.warn("[RTCChatSession] cleanup warning:", e == null ? void 0 : e.message);
|
|
20846
21174
|
}
|
|
20847
21175
|
this.rtcEngine = null;
|
|
20848
21176
|
}
|
|
@@ -21194,7 +21522,7 @@ class RTCChatSession {
|
|
|
21194
21522
|
*/
|
|
21195
21523
|
async restartAgent(promptFile, tools) {
|
|
21196
21524
|
var _a2, _b2;
|
|
21197
|
-
console$
|
|
21525
|
+
console$a.log(`[RTCChatSession] restartAgent promptFile=${promptFile || "(none)"}`);
|
|
21198
21526
|
const normalizedTools = Array.isArray(tools) ? tools.filter((t) => typeof t === "string" && t.trim()) : [];
|
|
21199
21527
|
if (typeof this._cleanupChildSessions === "function") {
|
|
21200
21528
|
this._cleanupChildSessions();
|
|
@@ -21207,10 +21535,9 @@ class RTCChatSession {
|
|
|
21207
21535
|
let loadedConfig = null;
|
|
21208
21536
|
if (promptFile && typeof promptFile === "string" && promptFile.trim()) {
|
|
21209
21537
|
try {
|
|
21210
|
-
|
|
21211
|
-
loadedConfig = await AgentConfig2.fetch(promptFile.trim());
|
|
21538
|
+
loadedConfig = await AgentConfig.fetch(promptFile.trim());
|
|
21212
21539
|
} catch (e) {
|
|
21213
|
-
console$
|
|
21540
|
+
console$a.warn(`[RTCChatSession] restartAgent failed to load '${promptFile}': ${e == null ? void 0 : e.message}`);
|
|
21214
21541
|
}
|
|
21215
21542
|
}
|
|
21216
21543
|
if (loadedConfig) {
|
|
@@ -21558,7 +21885,7 @@ class RTCChatSession {
|
|
|
21558
21885
|
for (const toolCall of toolCalls) {
|
|
21559
21886
|
const funcName = (_a2 = toolCall.function) == null ? void 0 : _a2.name;
|
|
21560
21887
|
if (!funcName) {
|
|
21561
|
-
console$
|
|
21888
|
+
console$a.warn("[AIChatRTC] Skipping tool call with empty function name", toolCall == null ? void 0 : toolCall.id);
|
|
21562
21889
|
if (this.rtcEngine && toolCall.id) {
|
|
21563
21890
|
await this._sendFuncResultChunked(toolCall.id, "OK", "unknown");
|
|
21564
21891
|
}
|
|
@@ -21579,7 +21906,7 @@ class RTCChatSession {
|
|
|
21579
21906
|
if (e && e.isRestartAgentSignal) {
|
|
21580
21907
|
const dh = this._digitalHuman;
|
|
21581
21908
|
if (dh && typeof dh.restartAgent === "function") {
|
|
21582
|
-
console$
|
|
21909
|
+
console$a.log(`[AIChatRTC] RestartAgentSignal caught in _handleFunctionCall, restarting with '${e.promptFile}'`);
|
|
21583
21910
|
if (this.rtcEngine && toolCall.id) {
|
|
21584
21911
|
await this._sendFuncResultChunked(toolCall.id, "Agent restarting...", funcName);
|
|
21585
21912
|
}
|
|
@@ -21589,7 +21916,7 @@ class RTCChatSession {
|
|
|
21589
21916
|
try {
|
|
21590
21917
|
await dh.restartAgent(promptFile, tools);
|
|
21591
21918
|
} catch (err) {
|
|
21592
|
-
console$
|
|
21919
|
+
console$a.error("[AIChatRTC] deferred restartAgent failed:", err == null ? void 0 : err.message);
|
|
21593
21920
|
dh.emit("error", { error: err, stage: "restartAgent" });
|
|
21594
21921
|
}
|
|
21595
21922
|
}, 0);
|
|
@@ -21845,7 +22172,7 @@ function installRTCChatSessionMixin() {
|
|
|
21845
22172
|
try {
|
|
21846
22173
|
await this.send(null, this._lastSendOptions);
|
|
21847
22174
|
} catch (e) {
|
|
21848
|
-
console$
|
|
22175
|
+
console$a.error("[RTCChatSession] Immediate callback send failed:", e);
|
|
21849
22176
|
}
|
|
21850
22177
|
};
|
|
21851
22178
|
}
|
|
@@ -21909,7 +22236,7 @@ let AIChatRTC$1 = (_a = class {
|
|
|
21909
22236
|
return new RTCChatSession(this, config);
|
|
21910
22237
|
}
|
|
21911
22238
|
}, __publicField(_a, "AGENT_STATE", AGENT_STATE), __publicField(_a, "AGENT_STATE_LABELS", AGENT_STATE_LABELS), __publicField(_a, "COMMAND", COMMAND), _a);
|
|
21912
|
-
const console$
|
|
22239
|
+
const console$9 = SDKLogger.createModuleConsole("AIChatRTCLocal");
|
|
21913
22240
|
const _win = typeof window !== "undefined" ? window : {};
|
|
21914
22241
|
const DEFAULT_VAD_CDN = {
|
|
21915
22242
|
ortUrl: "https://cdn.keepwork.com/keepwork/cdn/voice/ort.min.js",
|
|
@@ -23116,7 +23443,7 @@ class WebSpeechASRBackend extends BaseASRBackend {
|
|
|
23116
23443
|
};
|
|
23117
23444
|
this._recognition.onerror = (event) => {
|
|
23118
23445
|
if (event.error === "no-speech" || event.error === "aborted") return;
|
|
23119
|
-
console$
|
|
23446
|
+
console$9.warn("[LocalRTCSession] SpeechRecognition error:", event.error);
|
|
23120
23447
|
const message = event.error === "not-allowed" ? "Microphone permission denied for speech recognition" : `SpeechRecognition error: ${event.error}`;
|
|
23121
23448
|
this.session._handleASRError(message, { fatal: false });
|
|
23122
23449
|
};
|
|
@@ -24086,7 +24413,7 @@ class LocalNeuralTTSBackend extends BaseTTSBackend {
|
|
|
24086
24413
|
if (Number.isFinite(this._numSpeakers) && this._numSpeakers > 0) {
|
|
24087
24414
|
if (speakerId < 0 || speakerId >= this._numSpeakers) {
|
|
24088
24415
|
const fallbackSpeakerId = ((_b2 = this._resolvedConfig) == null ? void 0 : _b2.defaultSpeakerId) || 0;
|
|
24089
|
-
console$
|
|
24416
|
+
console$9.warn(`[LocalNeuralTTS] Speaker ${speakerId} is out of range for preset ${((_d = (_c = this._resolvedConfig) == null ? void 0 : _c.activePreset) == null ? void 0 : _d.id) || "unknown"} (numSpeakers=${this._numSpeakers}); using ${fallbackSpeakerId} instead.`);
|
|
24090
24417
|
speakerId = fallbackSpeakerId >= 0 && fallbackSpeakerId < this._numSpeakers ? fallbackSpeakerId : 0;
|
|
24091
24418
|
}
|
|
24092
24419
|
}
|
|
@@ -24143,7 +24470,7 @@ class LocalNeuralTTSBackend extends BaseTTSBackend {
|
|
|
24143
24470
|
}
|
|
24144
24471
|
}
|
|
24145
24472
|
const SENTENCE_END_RE = /[。!?!?\n]+/;
|
|
24146
|
-
const console$
|
|
24473
|
+
const console$8 = SDKLogger.createModuleConsole("AIChatRTCLocal");
|
|
24147
24474
|
class LocalRTCSession {
|
|
24148
24475
|
/**
|
|
24149
24476
|
* @param {AIChatRTCLocal} parent - Parent AIChatRTCLocal instance
|
|
@@ -24217,7 +24544,7 @@ class LocalRTCSession {
|
|
|
24217
24544
|
fn(data);
|
|
24218
24545
|
} catch (eRaw) {
|
|
24219
24546
|
const e = eRaw;
|
|
24220
|
-
console$
|
|
24547
|
+
console$8.warn(`[LocalRTCSession] Event '${event}' listener error:`, e);
|
|
24221
24548
|
}
|
|
24222
24549
|
}
|
|
24223
24550
|
}
|
|
@@ -24518,10 +24845,10 @@ class LocalRTCSession {
|
|
|
24518
24845
|
}
|
|
24519
24846
|
});
|
|
24520
24847
|
this._micVAD.start();
|
|
24521
|
-
console$
|
|
24848
|
+
console$8.log("[LocalRTCSession] Silero VAD started (single-thread)");
|
|
24522
24849
|
} catch (eRaw) {
|
|
24523
24850
|
const e = eRaw;
|
|
24524
|
-
console$
|
|
24851
|
+
console$8.warn("[LocalRTCSession] Silero VAD init failed, falling back to energy VAD:", e.message);
|
|
24525
24852
|
this.parent._vadAvailable = false;
|
|
24526
24853
|
await this._initEnergyVAD();
|
|
24527
24854
|
}
|
|
@@ -24577,7 +24904,7 @@ class LocalRTCSession {
|
|
|
24577
24904
|
this._silenceStart = 0;
|
|
24578
24905
|
}
|
|
24579
24906
|
}, ENERGY_VAD.SAMPLE_INTERVAL);
|
|
24580
|
-
console$
|
|
24907
|
+
console$8.log("[LocalRTCSession] Energy VAD started (fallback)");
|
|
24581
24908
|
}
|
|
24582
24909
|
_onSpeechStart() {
|
|
24583
24910
|
if (this._isTTSSpeaking || this._isLLMStreaming) {
|
|
@@ -24734,7 +25061,7 @@ class LocalRTCSession {
|
|
|
24734
25061
|
_notifyMediaStreamChanged(stream) {
|
|
24735
25062
|
if (!this._asrBackend || typeof this._asrBackend.attachMediaStream !== "function") return;
|
|
24736
25063
|
this._asrBackend.attachMediaStream(stream).catch((error) => {
|
|
24737
|
-
console$
|
|
25064
|
+
console$8.warn("[LocalRTCSession] Failed to rebind ASR media stream:", (error == null ? void 0 : error.message) || error);
|
|
24738
25065
|
});
|
|
24739
25066
|
}
|
|
24740
25067
|
_beginRecognitionRound() {
|
|
@@ -24850,7 +25177,7 @@ class LocalRTCSession {
|
|
|
24850
25177
|
var _a2, _b2;
|
|
24851
25178
|
const MAX_ITERATIONS = 10;
|
|
24852
25179
|
if (iteration >= MAX_ITERATIONS) {
|
|
24853
|
-
console$
|
|
25180
|
+
console$8.warn("[LocalRTCSession] Max tool-call iterations reached");
|
|
24854
25181
|
if (this.isActive && !this.isMuted) this._setState(AGENT_STATE.LISTENING);
|
|
24855
25182
|
return;
|
|
24856
25183
|
}
|
|
@@ -24894,7 +25221,7 @@ class LocalRTCSession {
|
|
|
24894
25221
|
},
|
|
24895
25222
|
onError: (error) => {
|
|
24896
25223
|
if (error.name === "AbortError") return;
|
|
24897
|
-
console$
|
|
25224
|
+
console$8.error("[LocalRTCSession] LLM error:", error.message);
|
|
24898
25225
|
this.emit("error", { error: error.message || "LLM request failed" });
|
|
24899
25226
|
}
|
|
24900
25227
|
});
|
|
@@ -24902,7 +25229,7 @@ class LocalRTCSession {
|
|
|
24902
25229
|
const error = errorRaw;
|
|
24903
25230
|
this._isLLMStreaming = false;
|
|
24904
25231
|
if (error.name === "AbortError") return;
|
|
24905
|
-
console$
|
|
25232
|
+
console$8.error("[LocalRTCSession] LLM error:", error.message);
|
|
24906
25233
|
this.emit("error", { error: error.message || "LLM request failed" });
|
|
24907
25234
|
if (this.isActive && !this.isMuted) this._setState(AGENT_STATE.LISTENING);
|
|
24908
25235
|
return;
|
|
@@ -25038,7 +25365,7 @@ class LocalRTCSession {
|
|
|
25038
25365
|
if ((error == null ? void 0 : error.name) === "AbortError" || this._ttsToken !== drainToken) {
|
|
25039
25366
|
break;
|
|
25040
25367
|
}
|
|
25041
|
-
console$
|
|
25368
|
+
console$8.warn("[LocalRTCSession] TTS error:", (error == null ? void 0 : error.message) || error);
|
|
25042
25369
|
this._emitTTSStatus("error", {
|
|
25043
25370
|
provider: this.ttsBackendName,
|
|
25044
25371
|
message: (error == null ? void 0 : error.message) || String(error)
|
|
@@ -25145,7 +25472,7 @@ Result: ${resultText}`;
|
|
|
25145
25472
|
};
|
|
25146
25473
|
}
|
|
25147
25474
|
installLocalRTCSessionMixin();
|
|
25148
|
-
const console$
|
|
25475
|
+
const console$7 = SDKLogger.createModuleConsole("AIChatRTCLocal");
|
|
25149
25476
|
installLocalRTCSessionMixin();
|
|
25150
25477
|
let AIChatRTCLocal$1 = (_b = class {
|
|
25151
25478
|
/**
|
|
@@ -25193,12 +25520,12 @@ let AIChatRTCLocal$1 = (_b = class {
|
|
|
25193
25520
|
this._loadPromise = this._loadScripts().then(() => {
|
|
25194
25521
|
this._vadAvailable = !!(typeof vad !== "undefined" && vad.MicVAD);
|
|
25195
25522
|
if (this._vadAvailable) {
|
|
25196
|
-
console$
|
|
25523
|
+
console$7.log("[AIChatRTCLocal] Silero VAD loaded");
|
|
25197
25524
|
} else {
|
|
25198
|
-
console$
|
|
25525
|
+
console$7.warn("[AIChatRTCLocal] VAD bundle loaded but vad.MicVAD not found — using energy fallback");
|
|
25199
25526
|
}
|
|
25200
25527
|
}).catch(() => {
|
|
25201
|
-
console$
|
|
25528
|
+
console$7.warn("[AIChatRTCLocal] Failed to load Silero VAD — using energy fallback");
|
|
25202
25529
|
this._vadAvailable = false;
|
|
25203
25530
|
this._loadPromise = null;
|
|
25204
25531
|
});
|
|
@@ -25269,7 +25596,7 @@ let AIChatRTCLocal$1 = (_b = class {
|
|
|
25269
25596
|
return this._rememberBlobURL(cacheKey, cached);
|
|
25270
25597
|
}
|
|
25271
25598
|
} catch (error) {
|
|
25272
|
-
console$
|
|
25599
|
+
console$7.warn(`[AIChatRTCLocal] IndexedDB cache read failed for ${fileName}:`, (error == null ? void 0 : error.message) || error);
|
|
25273
25600
|
}
|
|
25274
25601
|
try {
|
|
25275
25602
|
const response = await fetch(remoteUrl);
|
|
@@ -25284,7 +25611,7 @@ let AIChatRTCLocal$1 = (_b = class {
|
|
|
25284
25611
|
});
|
|
25285
25612
|
return this._rememberBlobURL(cacheKey, blob);
|
|
25286
25613
|
} catch (error) {
|
|
25287
|
-
console$
|
|
25614
|
+
console$7.warn(`[AIChatRTCLocal] Failed to cache ${fileName}:`, (error == null ? void 0 : error.message) || error);
|
|
25288
25615
|
return null;
|
|
25289
25616
|
}
|
|
25290
25617
|
}
|
|
@@ -25361,6 +25688,886 @@ let AIChatRTCLocal$1 = (_b = class {
|
|
|
25361
25688
|
AIChatRTCLocal$1.DEFAULT_MODEL_CDN = DEFAULT_KEEPWORK_MODEL_CDN;
|
|
25362
25689
|
AIChatRTCLocal$1.DEFAULT_MODEL_BASE = getDefaultModelAssetBase();
|
|
25363
25690
|
const AIChatRTCLocal = AIChatRTCLocal$1;
|
|
25691
|
+
const LocalRTC = typeof window !== "undefined" && window.SherpaOnnxLocalRTC || null;
|
|
25692
|
+
const console$6 = SDKLogger.createModuleConsole("LocalRTCController");
|
|
25693
|
+
const SHERPA_DEFAULT_BASE = "https://cdn.keepwork.com/npm/sherpaonnx-full-js/";
|
|
25694
|
+
function normalizeText(text) {
|
|
25695
|
+
return String(text || "").replace(/[\s\r\n\t.,,。!!??、]+/g, "");
|
|
25696
|
+
}
|
|
25697
|
+
function waitForSherpaGlobal(timeoutMs = 15e3) {
|
|
25698
|
+
if (typeof window === "undefined") return Promise.resolve(false);
|
|
25699
|
+
const w = window;
|
|
25700
|
+
if (w.SherpaOnnxLocalRTC) return Promise.resolve(true);
|
|
25701
|
+
return new Promise((resolve) => {
|
|
25702
|
+
const start = Date.now();
|
|
25703
|
+
const tick = () => {
|
|
25704
|
+
if (w.SherpaOnnxLocalRTC) return resolve(true);
|
|
25705
|
+
if (Date.now() - start >= timeoutMs) return resolve(false);
|
|
25706
|
+
setTimeout(tick, 50);
|
|
25707
|
+
};
|
|
25708
|
+
tick();
|
|
25709
|
+
});
|
|
25710
|
+
}
|
|
25711
|
+
function loadScript$1(src) {
|
|
25712
|
+
return new Promise((resolve, reject) => {
|
|
25713
|
+
if (typeof document === "undefined") {
|
|
25714
|
+
resolve();
|
|
25715
|
+
return;
|
|
25716
|
+
}
|
|
25717
|
+
if (document.querySelector(`script[src^="${src.split("?")[0]}"]`)) {
|
|
25718
|
+
resolve();
|
|
25719
|
+
return;
|
|
25720
|
+
}
|
|
25721
|
+
const s = document.createElement("script");
|
|
25722
|
+
s.src = src;
|
|
25723
|
+
s.async = false;
|
|
25724
|
+
s.onload = () => resolve();
|
|
25725
|
+
s.onerror = () => reject(new Error(`Failed to load ${src}`));
|
|
25726
|
+
document.head.appendChild(s);
|
|
25727
|
+
});
|
|
25728
|
+
}
|
|
25729
|
+
class LocalRTCController {
|
|
25730
|
+
constructor(options) {
|
|
25731
|
+
// ── 运行时引用 ──
|
|
25732
|
+
__publicField(this, "host");
|
|
25733
|
+
__publicField(this, "config");
|
|
25734
|
+
__publicField(this, "hooks");
|
|
25735
|
+
/** SherpaOnnxLocalRTC 实例 */
|
|
25736
|
+
__publicField(this, "_rtc", null);
|
|
25737
|
+
/** LocalRTC 类 */
|
|
25738
|
+
__publicField(this, "_LocalRTC", null);
|
|
25739
|
+
/** 预加载是否已完成 */
|
|
25740
|
+
__publicField(this, "_preloaded", false);
|
|
25741
|
+
/** 预加载 Promise(防止并发重复预加载) */
|
|
25742
|
+
__publicField(this, "_preloadPromise", null);
|
|
25743
|
+
__publicField(this, "_sherpaBase", "");
|
|
25744
|
+
__publicField(this, "_sherpaVersion", "");
|
|
25745
|
+
// ── 加载进度 ──
|
|
25746
|
+
__publicField(this, "_loadProgress", {
|
|
25747
|
+
phase: "未开始",
|
|
25748
|
+
wasm: 0,
|
|
25749
|
+
kws: 0,
|
|
25750
|
+
asr: 0,
|
|
25751
|
+
source: "",
|
|
25752
|
+
done: false,
|
|
25753
|
+
error: ""
|
|
25754
|
+
});
|
|
25755
|
+
// ── 本地语音会话状态 ──
|
|
25756
|
+
__publicField(this, "_localVcActive", false);
|
|
25757
|
+
__publicField(this, "_localVcProcessing", false);
|
|
25758
|
+
__publicField(this, "_localTtsPlaying", false);
|
|
25759
|
+
__publicField(this, "_localTtsEndTime", 0);
|
|
25760
|
+
__publicField(this, "_localAsrEndTime", 0);
|
|
25761
|
+
__publicField(this, "_wakeViaKwsLocalAsr", false);
|
|
25762
|
+
__publicField(this, "_currentTtsText", "");
|
|
25763
|
+
__publicField(this, "_localAsrPausedForTts", false);
|
|
25764
|
+
__publicField(this, "_savedBargeInThreshold", null);
|
|
25765
|
+
__publicField(this, "_ttsVersion", 0);
|
|
25766
|
+
__publicField(this, "_lastSentAsrText", "");
|
|
25767
|
+
// ── textSpeech 事件订阅句柄(destroy 时解绑)──
|
|
25768
|
+
__publicField(this, "_onTtsStartBound", null);
|
|
25769
|
+
__publicField(this, "_onTtsEndBound", null);
|
|
25770
|
+
__publicField(this, "_onTtsCanceledBound", null);
|
|
25771
|
+
if (!(options == null ? void 0 : options.host)) throw new Error("LocalRTCController requires a host");
|
|
25772
|
+
this.host = options.host;
|
|
25773
|
+
this.config = options.config || {};
|
|
25774
|
+
this.hooks = options.hooks || {};
|
|
25775
|
+
this._LocalRTC = options.localRTCClass || null;
|
|
25776
|
+
this._onTtsStartBound = () => {
|
|
25777
|
+
void this.onTtsStart();
|
|
25778
|
+
};
|
|
25779
|
+
this._onTtsEndBound = () => {
|
|
25780
|
+
void this.onTtsEnd();
|
|
25781
|
+
};
|
|
25782
|
+
this._onTtsCanceledBound = () => {
|
|
25783
|
+
void this.onTtsCanceled();
|
|
25784
|
+
};
|
|
25785
|
+
this.host.on("textSpeechStart", this._onTtsStartBound);
|
|
25786
|
+
this.host.on("textSpeechEnd", this._onTtsEndBound);
|
|
25787
|
+
this.host.on("textSpeechCanceled", this._onTtsCanceledBound);
|
|
25788
|
+
}
|
|
25789
|
+
// =================== 公共状态查询 ===================
|
|
25790
|
+
/** 当前是否处于本地 ASR 活跃会话 */
|
|
25791
|
+
isLocalVcActive() {
|
|
25792
|
+
return this._localVcActive;
|
|
25793
|
+
}
|
|
25794
|
+
/** 当前 RTC 实例(供调试 / 高级用法) */
|
|
25795
|
+
getRtc() {
|
|
25796
|
+
return this._rtc;
|
|
25797
|
+
}
|
|
25798
|
+
/** 读取当前加载进度快照 */
|
|
25799
|
+
getLoadProgress() {
|
|
25800
|
+
return { ...this._loadProgress };
|
|
25801
|
+
}
|
|
25802
|
+
/** 内部:合并更新进度并通知钩子 */
|
|
25803
|
+
_setProgress(patch) {
|
|
25804
|
+
var _a2, _b2;
|
|
25805
|
+
this._loadProgress = { ...this._loadProgress, ...patch };
|
|
25806
|
+
const snap = this.getLoadProgress();
|
|
25807
|
+
try {
|
|
25808
|
+
(_b2 = (_a2 = this.hooks).onLoadProgress) == null ? void 0 : _b2.call(_a2, snap);
|
|
25809
|
+
} catch {
|
|
25810
|
+
}
|
|
25811
|
+
}
|
|
25812
|
+
_emitStatus(text) {
|
|
25813
|
+
var _a2, _b2;
|
|
25814
|
+
try {
|
|
25815
|
+
(_b2 = (_a2 = this.hooks).onStatus) == null ? void 0 : _b2.call(_a2, text);
|
|
25816
|
+
} catch {
|
|
25817
|
+
}
|
|
25818
|
+
}
|
|
25819
|
+
_isLocalAsrEnabled() {
|
|
25820
|
+
var _a2, _b2;
|
|
25821
|
+
try {
|
|
25822
|
+
return !!((_b2 = (_a2 = this.hooks).isLocalAsrEnabled) == null ? void 0 : _b2.call(_a2));
|
|
25823
|
+
} catch {
|
|
25824
|
+
return false;
|
|
25825
|
+
}
|
|
25826
|
+
}
|
|
25827
|
+
/** 获取打断(barge-in)配置:是否允许 TTS 播放时被打断 */
|
|
25828
|
+
_getInterruptionEnabled() {
|
|
25829
|
+
var _a2, _b2;
|
|
25830
|
+
return ((_b2 = (_a2 = this.config) == null ? void 0 : _a2.interruption) == null ? void 0 : _b2.enabled) !== false;
|
|
25831
|
+
}
|
|
25832
|
+
/** 是否为 android 原生 ASR 运行时(决定是否走「伪 KWS」方案) */
|
|
25833
|
+
_isAndroidRuntime() {
|
|
25834
|
+
const cfg = this.config || {};
|
|
25835
|
+
const asrRuntime = cfg.asrRuntime || (cfg.runtime === "android" ? "android" : "wasm");
|
|
25836
|
+
return asrRuntime === "android";
|
|
25837
|
+
}
|
|
25838
|
+
// =================== 解析 LocalRTC 类 ===================
|
|
25839
|
+
_resolveLocalRTCClass() {
|
|
25840
|
+
if (this._LocalRTC) return this._LocalRTC;
|
|
25841
|
+
if (LocalRTC) return LocalRTC;
|
|
25842
|
+
const w = typeof window !== "undefined" ? window : null;
|
|
25843
|
+
return w && w.SherpaOnnxLocalRTC || null;
|
|
25844
|
+
}
|
|
25845
|
+
// =================== 预加载 ===================
|
|
25846
|
+
/**
|
|
25847
|
+
* 预加载本地 RTC 资源并构造 SherpaOnnxLocalRTC 实例。
|
|
25848
|
+
* 幂等:重复调用返回同一个 Promise。
|
|
25849
|
+
* @returns rtc 实例或 null(不可用)
|
|
25850
|
+
*/
|
|
25851
|
+
async preload() {
|
|
25852
|
+
if (this.config.enabled === false) return null;
|
|
25853
|
+
if (this._preloaded) return this._rtc;
|
|
25854
|
+
if (this._preloadPromise) return this._preloadPromise;
|
|
25855
|
+
this._setProgress({ phase: "开始预加载...", done: false, error: "" });
|
|
25856
|
+
this._preloadPromise = this._doPreload().then((rtc) => {
|
|
25857
|
+
this._preloaded = true;
|
|
25858
|
+
this._preloadPromise = null;
|
|
25859
|
+
return rtc;
|
|
25860
|
+
}).catch((e) => {
|
|
25861
|
+
this._preloadPromise = null;
|
|
25862
|
+
this._setProgress({ phase: "加载失败", error: String((e == null ? void 0 : e.message) || e) });
|
|
25863
|
+
console$6.warn("[LocalRTCController] 预加载失败:", e);
|
|
25864
|
+
this._emitStatus("本地语音不可用");
|
|
25865
|
+
return null;
|
|
25866
|
+
});
|
|
25867
|
+
return this._preloadPromise;
|
|
25868
|
+
}
|
|
25869
|
+
async _doPreload() {
|
|
25870
|
+
var _a2, _b2, _c, _d, _e, _f, _g;
|
|
25871
|
+
const cfg = this.config;
|
|
25872
|
+
const w = typeof window !== "undefined" ? window : {};
|
|
25873
|
+
const base = cfg.baseUrl || w.sherpaonnxBase || SHERPA_DEFAULT_BASE;
|
|
25874
|
+
w.sherpaonnxBase = base;
|
|
25875
|
+
this._sherpaBase = base;
|
|
25876
|
+
this._sherpaVersion = cfg.version || "";
|
|
25877
|
+
const echo = cfg.echoGuard || {};
|
|
25878
|
+
if (echo.prefixRatio != null) w._echoPrefixRatio = echo.prefixRatio;
|
|
25879
|
+
if (echo.bigramRatio != null) w._echoBigramRatio = echo.bigramRatio;
|
|
25880
|
+
if (!w.SherpaOnnxLocalRTC) {
|
|
25881
|
+
this._setProgress({ phase: "加载 sherpa-onnx-local-rtc.js..." });
|
|
25882
|
+
await loadScript$1(base + "sherpa-onnx-local-rtc.js").catch(
|
|
25883
|
+
(e) => console$6.warn("[LocalRTCController] local-rtc 脚本加载失败", e)
|
|
25884
|
+
);
|
|
25885
|
+
}
|
|
25886
|
+
const ready = await waitForSherpaGlobal();
|
|
25887
|
+
if (!ready) {
|
|
25888
|
+
throw new Error("window.SherpaOnnxLocalRTC 未就绪(sherpa-onnx-local-rtc.js 加载失败?)");
|
|
25889
|
+
}
|
|
25890
|
+
await Promise.all([
|
|
25891
|
+
loadScript$1(base + "sherpa-onnx-kws.js").catch((e) => console$6.warn("[LocalRTCController] kws 脚本加载失败", e))
|
|
25892
|
+
]);
|
|
25893
|
+
const LocalRTC2 = this._resolveLocalRTCClass();
|
|
25894
|
+
if (!LocalRTC2) {
|
|
25895
|
+
throw new Error("LocalRTC 类不可用");
|
|
25896
|
+
}
|
|
25897
|
+
this._LocalRTC = LocalRTC2;
|
|
25898
|
+
const asrRuntime = cfg.asrRuntime || (cfg.runtime === "android" ? "android" : "wasm");
|
|
25899
|
+
const rtc = new LocalRTC2({
|
|
25900
|
+
baseUrl: base,
|
|
25901
|
+
asrRuntime,
|
|
25902
|
+
minAudioRms: cfg.minAudioRms ?? 0.015,
|
|
25903
|
+
audioSource: ((_a2 = cfg.audio) == null ? void 0 : _a2.source) || "voice_communication",
|
|
25904
|
+
aecEnabled: ((_b2 = cfg.audio) == null ? void 0 : _b2.aecEnabled) !== false,
|
|
25905
|
+
vadConfig: ((_c = cfg.vad) == null ? void 0 : _c.enabled) !== false ? cfg.vad || void 0 : void 0,
|
|
25906
|
+
kwsKeywords: ((_d = cfg.kws) == null ? void 0 : _d.keywords) || [],
|
|
25907
|
+
kwsThreshold: ((_e = cfg.kws) == null ? void 0 : _e.threshold) ?? 0.25,
|
|
25908
|
+
bargeInThreshold: ((_f = cfg.bargeIn) == null ? void 0 : _f.threshold) ?? 0.04,
|
|
25909
|
+
bargeInMinFrames: ((_g = cfg.bargeIn) == null ? void 0 : _g.minFrames) ?? 2,
|
|
25910
|
+
onLog: (msg) => console$6.log(msg),
|
|
25911
|
+
onError: (msg) => console$6.warn("ERROR " + msg),
|
|
25912
|
+
onStateChange: (state, old) => console$6.log(`State: ${old} -> ${state}`),
|
|
25913
|
+
onKwsDetected: (keyword, action) => this._handleKwsDetected(keyword, action),
|
|
25914
|
+
onAsrPartial: (text) => this._handleAsrPartial(text),
|
|
25915
|
+
onAsrResult: (text, all) => this._handleAsrResult(text, all),
|
|
25916
|
+
onProgress: (label, pct, source) => {
|
|
25917
|
+
const key = String(label || "").toLowerCase().includes("asr") ? "asr" : "kws";
|
|
25918
|
+
this._setProgress({ [key]: Math.round(pct), source: source || this._loadProgress.source, phase: `加载${label} ${Math.round(pct)}%` });
|
|
25919
|
+
}
|
|
25920
|
+
});
|
|
25921
|
+
this._rtc = rtc;
|
|
25922
|
+
w.localRTC = rtc;
|
|
25923
|
+
this._setProgress({ phase: "加载 WASM 运行时...", wasm: 5 });
|
|
25924
|
+
console$6.log("Calling init()...");
|
|
25925
|
+
await rtc.init();
|
|
25926
|
+
this._setProgress({ phase: "WASM 就绪", wasm: 100 });
|
|
25927
|
+
console$6.log("WASM runtime ready");
|
|
25928
|
+
const tasks = [
|
|
25929
|
+
rtc.preloadKws().then(() => {
|
|
25930
|
+
this._setProgress({ kws: 100 });
|
|
25931
|
+
console$6.log("KWS preloaded");
|
|
25932
|
+
}).catch((e) => {
|
|
25933
|
+
this._setProgress({ error: "KWS:" + ((e == null ? void 0 : e.message) || e) });
|
|
25934
|
+
console$6.warn("KWS preload failed: " + ((e == null ? void 0 : e.message) || e));
|
|
25935
|
+
})
|
|
25936
|
+
];
|
|
25937
|
+
if (cfg.preloadAsr) {
|
|
25938
|
+
tasks.push(
|
|
25939
|
+
rtc.preloadAsr().then(() => {
|
|
25940
|
+
this._setProgress({ asr: 100 });
|
|
25941
|
+
console$6.log("ASR preloaded");
|
|
25942
|
+
}).catch((e) => {
|
|
25943
|
+
this._setProgress({ error: "ASR:" + ((e == null ? void 0 : e.message) || e) });
|
|
25944
|
+
console$6.warn("ASR preload failed: " + ((e == null ? void 0 : e.message) || e));
|
|
25945
|
+
})
|
|
25946
|
+
);
|
|
25947
|
+
} else {
|
|
25948
|
+
this._setProgress({ asr: -1 });
|
|
25949
|
+
}
|
|
25950
|
+
await Promise.all(tasks);
|
|
25951
|
+
this._setProgress({ phase: "就绪", done: true });
|
|
25952
|
+
await this._startKwsWithRetry();
|
|
25953
|
+
return rtc;
|
|
25954
|
+
}
|
|
25955
|
+
/**
|
|
25956
|
+
* 启动 WASM KWS,失败时重试若干次。
|
|
25957
|
+
* "Could not start audio source" 多为麦克风被上一次会话/其它进程残留占用。
|
|
25958
|
+
*/
|
|
25959
|
+
async _startKwsWithRetry(maxAttempts = 3, delayMs = 500) {
|
|
25960
|
+
var _a2;
|
|
25961
|
+
const rtc = this._rtc;
|
|
25962
|
+
if (!rtc) return false;
|
|
25963
|
+
for (let i = 1; i <= maxAttempts; i++) {
|
|
25964
|
+
try {
|
|
25965
|
+
await rtc.start();
|
|
25966
|
+
console$6.log(`WASM KWS listening started${i > 1 ? `(第 ${i} 次尝试成功)` : ""}`);
|
|
25967
|
+
return true;
|
|
25968
|
+
} catch (e) {
|
|
25969
|
+
const msg = (e == null ? void 0 : e.message) || e;
|
|
25970
|
+
console$6.warn(`start() 第 ${i}/${maxAttempts} 次失败: ${msg}`);
|
|
25971
|
+
if (i < maxAttempts) {
|
|
25972
|
+
try {
|
|
25973
|
+
(_a2 = rtc.stop) == null ? void 0 : _a2.call(rtc);
|
|
25974
|
+
} catch {
|
|
25975
|
+
}
|
|
25976
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
25977
|
+
} else {
|
|
25978
|
+
this._emitStatus("麦克风被占用,唤醒启动失败");
|
|
25979
|
+
console$6.warn("WASM KWS 启动最终失败:麦克风可能被其它应用/会话占用");
|
|
25980
|
+
}
|
|
25981
|
+
}
|
|
25982
|
+
}
|
|
25983
|
+
return false;
|
|
25984
|
+
}
|
|
25985
|
+
// =================== 唤醒待机 / 麦克风让渡 ===================
|
|
25986
|
+
/**
|
|
25987
|
+
* 对话结束后重启 WASM KWS 唤醒监听(web/android 统一),回到「待唤醒」状态。
|
|
25988
|
+
*/
|
|
25989
|
+
async resumeKws() {
|
|
25990
|
+
const rtc = this._rtc;
|
|
25991
|
+
if (!rtc) return false;
|
|
25992
|
+
if (this._localVcActive) return false;
|
|
25993
|
+
const ok = await this._startKwsWithRetry();
|
|
25994
|
+
if (ok) {
|
|
25995
|
+
this._emitStatus("待唤醒...");
|
|
25996
|
+
console$6.log("对话已结束,WASM KWS 已重启(待唤醒)");
|
|
25997
|
+
}
|
|
25998
|
+
return ok;
|
|
25999
|
+
}
|
|
26000
|
+
/**
|
|
26001
|
+
* 启动云端 RTC 前,停掉 WASM KWS 释放麦克风(+短延迟确保设备真正释放)。
|
|
26002
|
+
*/
|
|
26003
|
+
async releaseMicForCloud() {
|
|
26004
|
+
const rtc = this._rtc;
|
|
26005
|
+
if (!(rtc == null ? void 0 : rtc.stop)) return;
|
|
26006
|
+
try {
|
|
26007
|
+
rtc.stop();
|
|
26008
|
+
console$6.log("云端启动前:已停止 WASM KWS 并释放麦克风");
|
|
26009
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
26010
|
+
} catch (e) {
|
|
26011
|
+
console$6.warn("releaseMicForCloud error: " + ((e == null ? void 0 : e.message) || e));
|
|
26012
|
+
}
|
|
26013
|
+
}
|
|
26014
|
+
// =================== 热切换:本地 ASR ⇄ 云端 ===================
|
|
26015
|
+
/**
|
|
26016
|
+
* 开启本地 ASR(从云端切换到本地,或直接启动本地语音会话)。
|
|
26017
|
+
* @returns 是否成功
|
|
26018
|
+
*/
|
|
26019
|
+
async enableLocalAsr(opts = {}) {
|
|
26020
|
+
const skipSwitchToAsr = opts.skipSwitchToAsr === true || this._wakeViaKwsLocalAsr === true;
|
|
26021
|
+
this._wakeViaKwsLocalAsr = false;
|
|
26022
|
+
const rtc = this._rtc;
|
|
26023
|
+
if (!rtc) {
|
|
26024
|
+
console$6.warn("LocalRTC not available");
|
|
26025
|
+
this._emitStatus("本地语音不可用");
|
|
26026
|
+
return false;
|
|
26027
|
+
}
|
|
26028
|
+
if (this._localVcActive) {
|
|
26029
|
+
console$6.log("enableLocalAsr 忽略:已处于本地对话中");
|
|
26030
|
+
return true;
|
|
26031
|
+
}
|
|
26032
|
+
console$6.log(`Starting local voice chat (ASR -> LLM -> TTS)...${skipSwitchToAsr ? "(switchToAsr 交给 SDK 自动)" : ""}`);
|
|
26033
|
+
this._localVcActive = true;
|
|
26034
|
+
let asrOk = false;
|
|
26035
|
+
if (skipSwitchToAsr) {
|
|
26036
|
+
asrOk = true;
|
|
26037
|
+
} else {
|
|
26038
|
+
if (this._localAsrEndTime) {
|
|
26039
|
+
const sinceEnd = Date.now() - this._localAsrEndTime;
|
|
26040
|
+
const minGap = 600;
|
|
26041
|
+
if (sinceEnd >= 0 && sinceEnd < minGap) {
|
|
26042
|
+
const wait = minGap - sinceEnd;
|
|
26043
|
+
console$6.log(`距上次本地 ASR 结束 ${sinceEnd}ms,等 ${wait}ms 供原生 AudioRecord 重初始化`);
|
|
26044
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
26045
|
+
}
|
|
26046
|
+
}
|
|
26047
|
+
try {
|
|
26048
|
+
asrOk = await rtc.switchToAsr();
|
|
26049
|
+
} catch (e) {
|
|
26050
|
+
console$6.warn("switchToAsr error: " + ((e == null ? void 0 : e.message) || e));
|
|
26051
|
+
}
|
|
26052
|
+
}
|
|
26053
|
+
if (!asrOk) {
|
|
26054
|
+
console$6.log("ASR not available (no native bridge?). Cannot start local voice chat.");
|
|
26055
|
+
this._localVcActive = false;
|
|
26056
|
+
this._emitStatus("本地 ASR 不可用");
|
|
26057
|
+
return false;
|
|
26058
|
+
}
|
|
26059
|
+
this._localTtsEndTime = Date.now();
|
|
26060
|
+
this._localTtsPlaying = false;
|
|
26061
|
+
this._currentTtsText = "";
|
|
26062
|
+
this._emitStatus("本地:聆听中...");
|
|
26063
|
+
console$6.log("Now using local ASR");
|
|
26064
|
+
return true;
|
|
26065
|
+
}
|
|
26066
|
+
/**
|
|
26067
|
+
* 关闭本地 ASR。
|
|
26068
|
+
* @param opts.resumeKws 结束后是否回到 WASM KWS 待唤醒(true=结束对话;false=热切换到云端)
|
|
26069
|
+
*/
|
|
26070
|
+
async disableLocalAsr(opts = {}) {
|
|
26071
|
+
var _a2, _b2, _c, _d;
|
|
26072
|
+
const resumeKws = opts.resumeKws !== false;
|
|
26073
|
+
this._localVcActive = false;
|
|
26074
|
+
this._lastSentAsrText = "";
|
|
26075
|
+
this._localAsrEndTime = Date.now();
|
|
26076
|
+
this._localTtsPlaying = false;
|
|
26077
|
+
this._localAsrPausedForTts = false;
|
|
26078
|
+
this._restoreBargeIn();
|
|
26079
|
+
if (!resumeKws) {
|
|
26080
|
+
try {
|
|
26081
|
+
if ((_a2 = this._rtc) == null ? void 0 : _a2.stopAsr) {
|
|
26082
|
+
this._rtc.stopAsr();
|
|
26083
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
26084
|
+
}
|
|
26085
|
+
(_c = (_b2 = this._rtc) == null ? void 0 : _b2.stop) == null ? void 0 : _c.call(_b2);
|
|
26086
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
26087
|
+
console$6.log("本地 ASR 已结束(热切换到云端:原生 ASR 已停、麦克风已释放,不重启 KWS)");
|
|
26088
|
+
} catch (e) {
|
|
26089
|
+
console$6.warn("disableLocalAsr(stop for cloud) error: " + ((e == null ? void 0 : e.message) || e));
|
|
26090
|
+
}
|
|
26091
|
+
return;
|
|
26092
|
+
}
|
|
26093
|
+
try {
|
|
26094
|
+
if ((_d = this._rtc) == null ? void 0 : _d.stopAsr) {
|
|
26095
|
+
this._rtc.stopAsr();
|
|
26096
|
+
this._emitStatus("待唤醒...");
|
|
26097
|
+
console$6.log("本地 ASR 已结束(stopAsr → 自动回到 KWS 待唤醒)");
|
|
26098
|
+
return;
|
|
26099
|
+
}
|
|
26100
|
+
} catch (e) {
|
|
26101
|
+
console$6.warn("disableLocalAsr stopAsr error: " + ((e == null ? void 0 : e.message) || e));
|
|
26102
|
+
}
|
|
26103
|
+
void this.resumeKws();
|
|
26104
|
+
}
|
|
26105
|
+
// =================== TTS 生命周期联动(内置订阅 host 事件) ===================
|
|
26106
|
+
/** host textSpeechStart:TTS 开始播放 */
|
|
26107
|
+
async onTtsStart() {
|
|
26108
|
+
if (!this._localVcActive || !this._rtc || !this._isLocalAsrEnabled()) return;
|
|
26109
|
+
this._localTtsPlaying = true;
|
|
26110
|
+
this._currentTtsText = "";
|
|
26111
|
+
if (this._getInterruptionEnabled()) {
|
|
26112
|
+
this._localAsrPausedForTts = false;
|
|
26113
|
+
console$6.log("TTS 开始 — 打断模式,ASR 保持活跃(AEC + echo guard)");
|
|
26114
|
+
} else {
|
|
26115
|
+
try {
|
|
26116
|
+
const alreadyPaused = this._rtc.isAsrPaused && this._rtc.isAsrPaused();
|
|
26117
|
+
if (alreadyPaused) {
|
|
26118
|
+
this._localAsrPausedForTts = true;
|
|
26119
|
+
this._suppressBargeIn();
|
|
26120
|
+
console$6.log("TTS 开始 — ASR 已处于暂停状态,保持暂停");
|
|
26121
|
+
} else if (this._rtc.getState && this._rtc.getState() === "ASR_LISTENING") {
|
|
26122
|
+
this._suppressBargeIn();
|
|
26123
|
+
await this._rtc.pauseAsr();
|
|
26124
|
+
this._localAsrPausedForTts = true;
|
|
26125
|
+
console$6.log("TTS 开始 — ASR 已暂停(pauseAsr,能量打断已禁用)");
|
|
26126
|
+
} else {
|
|
26127
|
+
this._localAsrPausedForTts = false;
|
|
26128
|
+
}
|
|
26129
|
+
} catch (e) {
|
|
26130
|
+
console$6.warn("onTtsStart error: " + ((e == null ? void 0 : e.message) || e));
|
|
26131
|
+
}
|
|
26132
|
+
}
|
|
26133
|
+
}
|
|
26134
|
+
/** host textSpeechEnd:TTS 播放结束 */
|
|
26135
|
+
async onTtsEnd() {
|
|
26136
|
+
if (!this._localVcActive || !this._isLocalAsrEnabled()) return;
|
|
26137
|
+
this._localTtsPlaying = false;
|
|
26138
|
+
this._localTtsEndTime = Date.now();
|
|
26139
|
+
if (!this._localAsrPausedForTts) {
|
|
26140
|
+
console$6.log("TTS 结束 — ASR 未曾暂停");
|
|
26141
|
+
this._emitStatus("本地:聆听中...");
|
|
26142
|
+
return;
|
|
26143
|
+
}
|
|
26144
|
+
this._localAsrPausedForTts = false;
|
|
26145
|
+
this._restoreBargeIn();
|
|
26146
|
+
if (this._localVcActive && !this._localVcProcessing && this._rtc) {
|
|
26147
|
+
try {
|
|
26148
|
+
await this._rtc.resumeAsr();
|
|
26149
|
+
console$6.log("TTS 结束 — ASR 已恢复(resumeAsr)");
|
|
26150
|
+
this._emitStatus("本地:聆听中...");
|
|
26151
|
+
} catch (e) {
|
|
26152
|
+
console$6.warn("resumeAsr after TTS error: " + ((e == null ? void 0 : e.message) || e));
|
|
26153
|
+
}
|
|
26154
|
+
}
|
|
26155
|
+
}
|
|
26156
|
+
/** host textSpeechCanceled:TTS 被打断/取消 */
|
|
26157
|
+
async onTtsCanceled() {
|
|
26158
|
+
if (!this._localVcActive || !this._isLocalAsrEnabled()) return;
|
|
26159
|
+
this._localTtsPlaying = false;
|
|
26160
|
+
this._localTtsEndTime = Date.now();
|
|
26161
|
+
if (!this._localAsrPausedForTts) {
|
|
26162
|
+
console$6.log("TTS 取消 — ASR 未曾暂停");
|
|
26163
|
+
this._emitStatus("本地:聆听中...");
|
|
26164
|
+
return;
|
|
26165
|
+
}
|
|
26166
|
+
this._localAsrPausedForTts = false;
|
|
26167
|
+
if (this._localVcProcessing) {
|
|
26168
|
+
console$6.log("TTS 取消(新 LLM 调用进行中,ASR 保持暂停)");
|
|
26169
|
+
return;
|
|
26170
|
+
}
|
|
26171
|
+
this._restoreBargeIn();
|
|
26172
|
+
if (this._localVcActive && !this._localVcProcessing && this._rtc) {
|
|
26173
|
+
try {
|
|
26174
|
+
await this._rtc.resumeAsr();
|
|
26175
|
+
console$6.log("TTS 取消 — ASR 已恢复(resumeAsr)");
|
|
26176
|
+
this._emitStatus("本地:聆听中...");
|
|
26177
|
+
} catch (e) {
|
|
26178
|
+
console$6.warn("resumeAsr after cancel error: " + ((e == null ? void 0 : e.message) || e));
|
|
26179
|
+
}
|
|
26180
|
+
}
|
|
26181
|
+
}
|
|
26182
|
+
/** 非打断模式:禁用 barge-in 能量检测(阈值推到 Infinity)。幂等。 */
|
|
26183
|
+
_suppressBargeIn() {
|
|
26184
|
+
const rtc = this._rtc;
|
|
26185
|
+
if (!rtc || this._savedBargeInThreshold != null) return;
|
|
26186
|
+
if (typeof rtc._bargeInThreshold === "number") {
|
|
26187
|
+
this._savedBargeInThreshold = rtc._bargeInThreshold;
|
|
26188
|
+
rtc._bargeInThreshold = Infinity;
|
|
26189
|
+
}
|
|
26190
|
+
}
|
|
26191
|
+
/** 恢复被 _suppressBargeIn 暂存的 barge-in 能量阈值。 */
|
|
26192
|
+
_restoreBargeIn() {
|
|
26193
|
+
const rtc = this._rtc;
|
|
26194
|
+
if (!rtc || this._savedBargeInThreshold == null) return;
|
|
26195
|
+
rtc._bargeInThreshold = this._savedBargeInThreshold;
|
|
26196
|
+
this._savedBargeInThreshold = null;
|
|
26197
|
+
}
|
|
26198
|
+
// =================== LocalRTC 回调 ===================
|
|
26199
|
+
_handleKwsDetected(keyword, action) {
|
|
26200
|
+
var _a2, _b2;
|
|
26201
|
+
console$6.log(`KWS "${keyword}" (${action})`);
|
|
26202
|
+
if (action === "start") {
|
|
26203
|
+
void this._wakeAndStartChat();
|
|
26204
|
+
} else if (action === "stop") {
|
|
26205
|
+
(_b2 = (_a2 = this.hooks).onToggleVoiceChat) == null ? void 0 : _b2.call(_a2, "stop");
|
|
26206
|
+
}
|
|
26207
|
+
}
|
|
26208
|
+
/**
|
|
26209
|
+
* 唤醒命中后启动对话。按模式区分麦克风处理。
|
|
26210
|
+
*/
|
|
26211
|
+
async _wakeAndStartChat() {
|
|
26212
|
+
var _a2, _b2, _c, _d;
|
|
26213
|
+
const localAsr = this._isLocalAsrEnabled();
|
|
26214
|
+
if (!localAsr) {
|
|
26215
|
+
try {
|
|
26216
|
+
(_b2 = (_a2 = this._rtc) == null ? void 0 : _a2.stop) == null ? void 0 : _b2.call(_a2);
|
|
26217
|
+
console$6.log("唤醒命中(云端):已同步停止 KWS(阻止 SDK 自动 switchToAsr)并释放麦克风");
|
|
26218
|
+
} catch (e) {
|
|
26219
|
+
console$6.warn("唤醒命中云端 stop 失败: " + ((e == null ? void 0 : e.message) || e));
|
|
26220
|
+
}
|
|
26221
|
+
} else {
|
|
26222
|
+
this._wakeViaKwsLocalAsr = true;
|
|
26223
|
+
console$6.log("唤醒命中(localASR):由 SDK 自动 switchToAsr,回调不重复切换");
|
|
26224
|
+
}
|
|
26225
|
+
(_d = (_c = this.hooks).onToggleVoiceChat) == null ? void 0 : _d.call(_c, "start");
|
|
26226
|
+
}
|
|
26227
|
+
_isLikelyEcho(text) {
|
|
26228
|
+
const w = typeof window !== "undefined" ? window : {};
|
|
26229
|
+
const Cls = this._LocalRTC || w.SherpaOnnxLocalRTC;
|
|
26230
|
+
if (!(Cls == null ? void 0 : Cls.isLikelyEcho)) return false;
|
|
26231
|
+
return Cls.isLikelyEcho(text, this._currentTtsText, {
|
|
26232
|
+
prefixRatio: w._echoPrefixRatio,
|
|
26233
|
+
bigramRatio: w._echoBigramRatio
|
|
26234
|
+
});
|
|
26235
|
+
}
|
|
26236
|
+
_handleAsrPartial(text) {
|
|
26237
|
+
console$6.log(`ASR partial: ${text}`);
|
|
26238
|
+
if (!this._localVcActive || !String(text || "").trim()) return;
|
|
26239
|
+
this._emitStatus(`本地:${String(text).slice(0, 30)}...`);
|
|
26240
|
+
if (this._localTtsPlaying && this._getInterruptionEnabled()) {
|
|
26241
|
+
if (!this._isLikelyEcho(text)) {
|
|
26242
|
+
console$6.log(`[Barge-in partial] 取消 TTS+LLM:"${text}"`);
|
|
26243
|
+
this._localTtsPlaying = false;
|
|
26244
|
+
try {
|
|
26245
|
+
void this.host.cancelSend("barge-in");
|
|
26246
|
+
} catch (e) {
|
|
26247
|
+
console$6.warn("cancelSend error: " + ((e == null ? void 0 : e.message) || e));
|
|
26248
|
+
}
|
|
26249
|
+
}
|
|
26250
|
+
}
|
|
26251
|
+
}
|
|
26252
|
+
async _handleAsrResult(text, _all) {
|
|
26253
|
+
var _a2, _b2, _c, _d, _e, _f;
|
|
26254
|
+
const trimmed = normalizeText(text);
|
|
26255
|
+
const keywords = ((_b2 = (_a2 = this.config) == null ? void 0 : _a2.kws) == null ? void 0 : _b2.keywords) || [];
|
|
26256
|
+
const stopKeywords = keywords.filter((k) => k.type === "stop").map((k) => k.keyword);
|
|
26257
|
+
const startKeywords = keywords.filter((k) => k.type === "start").map((k) => k.keyword);
|
|
26258
|
+
const matches = (list) => list.some(
|
|
26259
|
+
(kw) => trimmed === kw || trimmed.endsWith(kw) || trimmed.includes(kw) && trimmed.length <= kw.length + 2
|
|
26260
|
+
);
|
|
26261
|
+
if (matches(stopKeywords)) {
|
|
26262
|
+
console$6.log("Stop keyword in ASR — hanging up");
|
|
26263
|
+
(_d = (_c = this.hooks).onToggleVoiceChat) == null ? void 0 : _d.call(_c, "stop");
|
|
26264
|
+
return;
|
|
26265
|
+
}
|
|
26266
|
+
if (!this._localVcActive) {
|
|
26267
|
+
console$6.log(`未在对话中,忽略 ASR:"${trimmed}"`);
|
|
26268
|
+
return;
|
|
26269
|
+
}
|
|
26270
|
+
if (matches(startKeywords)) {
|
|
26271
|
+
console$6.log(`Start keyword in ASR — ignoring: "${trimmed}"`);
|
|
26272
|
+
return;
|
|
26273
|
+
}
|
|
26274
|
+
console$6.log(`ASR result: ${text}`);
|
|
26275
|
+
if (this._localTtsPlaying) {
|
|
26276
|
+
if (this._isLikelyEcho(text)) {
|
|
26277
|
+
console$6.log(`[Echo Guard] 忽略 TTS 期间回声: ${text}`);
|
|
26278
|
+
return;
|
|
26279
|
+
}
|
|
26280
|
+
if (this._getInterruptionEnabled()) {
|
|
26281
|
+
console$6.log(`[Barge-in] 用户打断 TTS(final): ${text}`);
|
|
26282
|
+
this._localTtsPlaying = false;
|
|
26283
|
+
} else {
|
|
26284
|
+
console$6.log(`[非打断] 忽略 TTS 期间 ASR 结果: ${text}`);
|
|
26285
|
+
return;
|
|
26286
|
+
}
|
|
26287
|
+
}
|
|
26288
|
+
if (this._localTtsEndTime && Date.now() - this._localTtsEndTime < 1500) {
|
|
26289
|
+
if (this._isLikelyEcho(text)) {
|
|
26290
|
+
console$6.log(`[Echo Guard] 忽略 TTS 后回声 (${Date.now() - this._localTtsEndTime}ms): ${text}`);
|
|
26291
|
+
return;
|
|
26292
|
+
}
|
|
26293
|
+
}
|
|
26294
|
+
if (this._lastSentAsrText && trimmed === normalizeText(this._lastSentAsrText)) {
|
|
26295
|
+
console$6.log(`忽略重复 ASR: ${text}`);
|
|
26296
|
+
this._lastSentAsrText = "";
|
|
26297
|
+
return;
|
|
26298
|
+
}
|
|
26299
|
+
if (this._localVcActive && String(text).trim()) {
|
|
26300
|
+
this._ttsVersion++;
|
|
26301
|
+
const myVersion = this._ttsVersion;
|
|
26302
|
+
this._localVcProcessing = true;
|
|
26303
|
+
this._lastSentAsrText = text;
|
|
26304
|
+
try {
|
|
26305
|
+
(_f = (_e = this.hooks).onUserSpeech) == null ? void 0 : _f.call(_e, String(text).trim());
|
|
26306
|
+
} catch (e) {
|
|
26307
|
+
console$6.warn("onUserSpeech error: " + ((e == null ? void 0 : e.message) || e));
|
|
26308
|
+
}
|
|
26309
|
+
this._emitStatus("本地:思考中...");
|
|
26310
|
+
try {
|
|
26311
|
+
await this.host.cancelSend("barge-in");
|
|
26312
|
+
const result = await this.host.sendMessage(text, { textToSpeech: true });
|
|
26313
|
+
const reply = (result == null ? void 0 : result.finalText) || "";
|
|
26314
|
+
console$6.log(
|
|
26315
|
+
`LLM reply v${myVersion} (${reply.length} chars)` + (myVersion !== this._ttsVersion ? " [superseded]" : "")
|
|
26316
|
+
);
|
|
26317
|
+
if (reply && this._localVcActive) {
|
|
26318
|
+
this._emitStatus("本地:等待 TTS...");
|
|
26319
|
+
}
|
|
26320
|
+
} catch (e) {
|
|
26321
|
+
console$6.warn("Local VC error: " + ((e == null ? void 0 : e.message) || e));
|
|
26322
|
+
if (this._localVcActive && myVersion === this._ttsVersion) {
|
|
26323
|
+
this._emitStatus("本地:聆听中...");
|
|
26324
|
+
}
|
|
26325
|
+
} finally {
|
|
26326
|
+
this._localVcProcessing = false;
|
|
26327
|
+
}
|
|
26328
|
+
}
|
|
26329
|
+
}
|
|
26330
|
+
// =================== 调试 API(下沉自 silvermind 调试面板) ===================
|
|
26331
|
+
/** 读取当前 LocalRTC 相关属性快照(供调试面板展示)。 */
|
|
26332
|
+
getDebugConfig() {
|
|
26333
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
26334
|
+
const cfg = this.config || {};
|
|
26335
|
+
const rtc = this._rtc;
|
|
26336
|
+
const w = typeof window !== "undefined" ? window : {};
|
|
26337
|
+
return {
|
|
26338
|
+
runtime: cfg.runtime || "-",
|
|
26339
|
+
asrRuntime: cfg.asrRuntime || (cfg.runtime === "android" ? "android" : "wasm"),
|
|
26340
|
+
state: (rtc == null ? void 0 : rtc.getState) ? rtc.getState() : "-",
|
|
26341
|
+
localVcActive: this._localVcActive,
|
|
26342
|
+
localAsrEnabled: this._isLocalAsrEnabled(),
|
|
26343
|
+
isAndroid: this._isAndroidRuntime(),
|
|
26344
|
+
loadProgress: this.getLoadProgress(),
|
|
26345
|
+
sherpa: (() => {
|
|
26346
|
+
const base = this._sherpaBase || cfg.baseUrl || w.sherpaonnxBase || SHERPA_DEFAULT_BASE;
|
|
26347
|
+
const version = this._sherpaVersion || cfg.version || (rtc == null ? void 0 : rtc._version) || "";
|
|
26348
|
+
return {
|
|
26349
|
+
base,
|
|
26350
|
+
version: version || "latest",
|
|
26351
|
+
isDefaultCdn: base === SHERPA_DEFAULT_BASE,
|
|
26352
|
+
coreUrl: base + "sherpa-onnx-local-rtc.js",
|
|
26353
|
+
wasmUrl: base + "sherpa-onnx-wasm-full.wasm",
|
|
26354
|
+
kwsUrl: base + "sherpa-onnx-kws.js"
|
|
26355
|
+
};
|
|
26356
|
+
})(),
|
|
26357
|
+
interruptionEnabled: ((_a2 = cfg.interruption) == null ? void 0 : _a2.enabled) !== false,
|
|
26358
|
+
minAudioRms: (rtc == null ? void 0 : rtc._minAudioRms) != null ? rtc._minAudioRms : cfg.minAudioRms ?? 0.015,
|
|
26359
|
+
bargeInThreshold: this._savedBargeInThreshold != null ? this._savedBargeInThreshold : (rtc == null ? void 0 : rtc._bargeInThreshold) != null && Number.isFinite(rtc._bargeInThreshold) ? rtc._bargeInThreshold : ((_b2 = cfg.bargeIn) == null ? void 0 : _b2.threshold) ?? 0.04,
|
|
26360
|
+
bargeInMinFrames: (rtc == null ? void 0 : rtc._bargeInMinFrames) != null ? rtc._bargeInMinFrames : ((_c = cfg.bargeIn) == null ? void 0 : _c.minFrames) ?? 2,
|
|
26361
|
+
kwsThreshold: (rtc == null ? void 0 : rtc._kwsThreshold) != null ? rtc._kwsThreshold : ((_d = cfg.kws) == null ? void 0 : _d.threshold) ?? 0.25,
|
|
26362
|
+
kwsKeywords: (Array.isArray(rtc == null ? void 0 : rtc._kwsKeywords) && rtc._kwsKeywords.length ? rtc._kwsKeywords : (_e = cfg.kws) == null ? void 0 : _e.keywords) || [],
|
|
26363
|
+
echoPrefixRatio: w._echoPrefixRatio ?? ((_f = cfg.echoGuard) == null ? void 0 : _f.prefixRatio) ?? 0.8,
|
|
26364
|
+
echoBigramRatio: w._echoBigramRatio ?? ((_g = cfg.echoGuard) == null ? void 0 : _g.bigramRatio) ?? 0.5,
|
|
26365
|
+
audioSource: (rtc == null ? void 0 : rtc._audioSource) ?? ((_h = cfg.audio) == null ? void 0 : _h.source) ?? "voice_communication",
|
|
26366
|
+
aecEnabled: (rtc == null ? void 0 : rtc.getAecEnabled) ? rtc.getAecEnabled() : ((_i = cfg.audio) == null ? void 0 : _i.aecEnabled) !== false,
|
|
26367
|
+
vadEnabled: ((_j = rtc == null ? void 0 : rtc._vadConfig) == null ? void 0 : _j.enabled) ?? ((_k = cfg.vad) == null ? void 0 : _k.enabled) !== false,
|
|
26368
|
+
vadThreshold: ((_l = rtc == null ? void 0 : rtc._vadConfig) == null ? void 0 : _l.threshold) ?? ((_m = cfg.vad) == null ? void 0 : _m.threshold) ?? 0.3,
|
|
26369
|
+
vadMinSilence: ((_n = rtc == null ? void 0 : rtc._vadConfig) == null ? void 0 : _n.minSilenceDuration) ?? ((_o = cfg.vad) == null ? void 0 : _o.minSilenceDuration) ?? 0.4,
|
|
26370
|
+
vadMinSpeech: ((_p = rtc == null ? void 0 : rtc._vadConfig) == null ? void 0 : _p.minSpeechDuration) ?? ((_q = cfg.vad) == null ? void 0 : _q.minSpeechDuration) ?? 0.1
|
|
26371
|
+
};
|
|
26372
|
+
}
|
|
26373
|
+
/** 组装当前 VAD 配置对象。 */
|
|
26374
|
+
_buildVadConfig() {
|
|
26375
|
+
const cfg = this.config || {};
|
|
26376
|
+
const rtc = this._rtc;
|
|
26377
|
+
const cur = (rtc == null ? void 0 : rtc._vadConfig) || cfg.vad || {};
|
|
26378
|
+
return {
|
|
26379
|
+
enabled: cur.enabled !== false,
|
|
26380
|
+
threshold: cur.threshold ?? 0.3,
|
|
26381
|
+
minSilenceDuration: cur.minSilenceDuration ?? 0.4,
|
|
26382
|
+
minSpeechDuration: cur.minSpeechDuration ?? 0.1
|
|
26383
|
+
};
|
|
26384
|
+
}
|
|
26385
|
+
/** 把 VAD 配置热更新到 rtc 实例 + 原生桥接(live 生效)。 */
|
|
26386
|
+
_applyVadConfig(vad2) {
|
|
26387
|
+
const cfg = this.config || (this.config = {});
|
|
26388
|
+
cfg.vad = { ...cfg.vad || {}, ...vad2 };
|
|
26389
|
+
const rtc = this._rtc;
|
|
26390
|
+
if (rtc) rtc._vadConfig = { ...vad2 };
|
|
26391
|
+
try {
|
|
26392
|
+
const w = typeof window !== "undefined" ? window : {};
|
|
26393
|
+
const bridge = w.SherpaOnnxAsrBridge || w.AndroidAsrBridge || null;
|
|
26394
|
+
if (bridge && typeof bridge.configureVad === "function") {
|
|
26395
|
+
bridge.configureVad(JSON.stringify(vad2));
|
|
26396
|
+
}
|
|
26397
|
+
} catch (e) {
|
|
26398
|
+
console$6.warn("configureVad error: " + ((e == null ? void 0 : e.message) || e));
|
|
26399
|
+
}
|
|
26400
|
+
}
|
|
26401
|
+
/** 热更新单个 LocalRTC 属性(仅内存,不持久化)。 */
|
|
26402
|
+
applyDebugSetting(key, value) {
|
|
26403
|
+
var _a2, _b2, _c, _d;
|
|
26404
|
+
const cfg = this.config || (this.config = {});
|
|
26405
|
+
const rtc = this._rtc;
|
|
26406
|
+
const w = typeof window !== "undefined" ? window : {};
|
|
26407
|
+
switch (key) {
|
|
26408
|
+
case "interruptionEnabled": {
|
|
26409
|
+
if (!cfg.interruption) cfg.interruption = {};
|
|
26410
|
+
cfg.interruption.enabled = !!value;
|
|
26411
|
+
if (value && this._savedBargeInThreshold != null) this._restoreBargeIn();
|
|
26412
|
+
console$6.log(`[Debug] interruption.enabled = ${!!value}`);
|
|
26413
|
+
break;
|
|
26414
|
+
}
|
|
26415
|
+
case "minAudioRms": {
|
|
26416
|
+
cfg.minAudioRms = value;
|
|
26417
|
+
try {
|
|
26418
|
+
(_a2 = rtc == null ? void 0 : rtc.setMinAudioRms) == null ? void 0 : _a2.call(rtc, value);
|
|
26419
|
+
} catch (e) {
|
|
26420
|
+
console$6.warn("setMinAudioRms error: " + ((e == null ? void 0 : e.message) || e));
|
|
26421
|
+
}
|
|
26422
|
+
console$6.log(`[Debug] minAudioRms = ${value}`);
|
|
26423
|
+
break;
|
|
26424
|
+
}
|
|
26425
|
+
case "bargeInThreshold": {
|
|
26426
|
+
if (!cfg.bargeIn) cfg.bargeIn = {};
|
|
26427
|
+
cfg.bargeIn.threshold = value;
|
|
26428
|
+
if (this._savedBargeInThreshold != null) this._savedBargeInThreshold = value;
|
|
26429
|
+
else if (rtc) rtc._bargeInThreshold = value;
|
|
26430
|
+
console$6.log(`[Debug] bargeIn.threshold = ${value}`);
|
|
26431
|
+
break;
|
|
26432
|
+
}
|
|
26433
|
+
case "bargeInMinFrames": {
|
|
26434
|
+
if (!cfg.bargeIn) cfg.bargeIn = {};
|
|
26435
|
+
cfg.bargeIn.minFrames = value;
|
|
26436
|
+
if (rtc) rtc._bargeInMinFrames = value;
|
|
26437
|
+
console$6.log(`[Debug] bargeIn.minFrames = ${value}`);
|
|
26438
|
+
break;
|
|
26439
|
+
}
|
|
26440
|
+
case "kwsThreshold": {
|
|
26441
|
+
if (!cfg.kws) cfg.kws = {};
|
|
26442
|
+
cfg.kws.threshold = value;
|
|
26443
|
+
try {
|
|
26444
|
+
(_b2 = rtc == null ? void 0 : rtc.setKwsThreshold) == null ? void 0 : _b2.call(rtc, value);
|
|
26445
|
+
} catch (e) {
|
|
26446
|
+
console$6.warn("setKwsThreshold error: " + ((e == null ? void 0 : e.message) || e));
|
|
26447
|
+
}
|
|
26448
|
+
console$6.log(`[Debug] kws.threshold = ${value}`);
|
|
26449
|
+
break;
|
|
26450
|
+
}
|
|
26451
|
+
case "echoPrefixRatio": {
|
|
26452
|
+
if (!cfg.echoGuard) cfg.echoGuard = {};
|
|
26453
|
+
cfg.echoGuard.prefixRatio = value;
|
|
26454
|
+
w._echoPrefixRatio = value;
|
|
26455
|
+
console$6.log(`[Debug] echoGuard.prefixRatio = ${value}`);
|
|
26456
|
+
break;
|
|
26457
|
+
}
|
|
26458
|
+
case "echoBigramRatio": {
|
|
26459
|
+
if (!cfg.echoGuard) cfg.echoGuard = {};
|
|
26460
|
+
cfg.echoGuard.bigramRatio = value;
|
|
26461
|
+
w._echoBigramRatio = value;
|
|
26462
|
+
console$6.log(`[Debug] echoGuard.bigramRatio = ${value}`);
|
|
26463
|
+
break;
|
|
26464
|
+
}
|
|
26465
|
+
case "audioSource": {
|
|
26466
|
+
if (!cfg.audio) cfg.audio = {};
|
|
26467
|
+
cfg.audio.source = value;
|
|
26468
|
+
if (rtc) rtc._audioSource = value;
|
|
26469
|
+
try {
|
|
26470
|
+
const bridge = w.SherpaOnnxAsrBridge || w.AndroidAsrBridge || null;
|
|
26471
|
+
(_c = bridge == null ? void 0 : bridge.configureAudioSource) == null ? void 0 : _c.call(bridge, JSON.stringify({ source: value }));
|
|
26472
|
+
} catch (e) {
|
|
26473
|
+
console$6.warn("configureAudioSource error: " + ((e == null ? void 0 : e.message) || e));
|
|
26474
|
+
}
|
|
26475
|
+
console$6.log(`[Debug] audio.source = ${value}(下次录音生效)`);
|
|
26476
|
+
break;
|
|
26477
|
+
}
|
|
26478
|
+
case "aecEnabled": {
|
|
26479
|
+
if (!cfg.audio) cfg.audio = {};
|
|
26480
|
+
cfg.audio.aecEnabled = !!value;
|
|
26481
|
+
try {
|
|
26482
|
+
(_d = rtc == null ? void 0 : rtc.setAecEnabled) == null ? void 0 : _d.call(rtc, !!value);
|
|
26483
|
+
} catch (e) {
|
|
26484
|
+
console$6.warn("setAecEnabled error: " + ((e == null ? void 0 : e.message) || e));
|
|
26485
|
+
}
|
|
26486
|
+
console$6.log(`[Debug] audio.aecEnabled = ${!!value}`);
|
|
26487
|
+
break;
|
|
26488
|
+
}
|
|
26489
|
+
case "vadEnabled": {
|
|
26490
|
+
const vad2 = this._buildVadConfig();
|
|
26491
|
+
vad2.enabled = !!value;
|
|
26492
|
+
this._applyVadConfig(vad2);
|
|
26493
|
+
console$6.log(`[Debug] vad.enabled = ${!!value}`);
|
|
26494
|
+
break;
|
|
26495
|
+
}
|
|
26496
|
+
case "vadThreshold": {
|
|
26497
|
+
const vad2 = this._buildVadConfig();
|
|
26498
|
+
vad2.threshold = value;
|
|
26499
|
+
this._applyVadConfig(vad2);
|
|
26500
|
+
console$6.log(`[Debug] vad.threshold = ${value}`);
|
|
26501
|
+
break;
|
|
26502
|
+
}
|
|
26503
|
+
case "vadMinSilence": {
|
|
26504
|
+
const vad2 = this._buildVadConfig();
|
|
26505
|
+
vad2.minSilenceDuration = value;
|
|
26506
|
+
this._applyVadConfig(vad2);
|
|
26507
|
+
console$6.log(`[Debug] vad.minSilenceDuration = ${value}`);
|
|
26508
|
+
break;
|
|
26509
|
+
}
|
|
26510
|
+
case "vadMinSpeech": {
|
|
26511
|
+
const vad2 = this._buildVadConfig();
|
|
26512
|
+
vad2.minSpeechDuration = value;
|
|
26513
|
+
this._applyVadConfig(vad2);
|
|
26514
|
+
console$6.log(`[Debug] vad.minSpeechDuration = ${value}`);
|
|
26515
|
+
break;
|
|
26516
|
+
}
|
|
26517
|
+
default:
|
|
26518
|
+
console$6.warn(`[Debug] 未知属性: ${key}`);
|
|
26519
|
+
}
|
|
26520
|
+
}
|
|
26521
|
+
/** 查询 Android 音频效果状态(AEC/NS/AGC),需原生桥接支持。 */
|
|
26522
|
+
async queryAudioEffects() {
|
|
26523
|
+
const rtc = this._rtc;
|
|
26524
|
+
if (!rtc || typeof rtc.getAudioEffectsInfo !== "function") {
|
|
26525
|
+
return { error: "getAudioEffectsInfo 不可用(需 Android 原生桥接)" };
|
|
26526
|
+
}
|
|
26527
|
+
try {
|
|
26528
|
+
return await rtc.getAudioEffectsInfo();
|
|
26529
|
+
} catch (e) {
|
|
26530
|
+
return { error: String((e == null ? void 0 : e.message) || e) };
|
|
26531
|
+
}
|
|
26532
|
+
}
|
|
26533
|
+
// =================== 销毁 ===================
|
|
26534
|
+
/** 销毁控制器(页面卸载/auth 切换/host destroy 时)。 */
|
|
26535
|
+
async destroy() {
|
|
26536
|
+
var _a2, _b2, _c, _d;
|
|
26537
|
+
try {
|
|
26538
|
+
if (this._onTtsStartBound) this.host.off("textSpeechStart", this._onTtsStartBound);
|
|
26539
|
+
if (this._onTtsEndBound) this.host.off("textSpeechEnd", this._onTtsEndBound);
|
|
26540
|
+
if (this._onTtsCanceledBound) this.host.off("textSpeechCanceled", this._onTtsCanceledBound);
|
|
26541
|
+
} catch {
|
|
26542
|
+
}
|
|
26543
|
+
this._onTtsStartBound = null;
|
|
26544
|
+
this._onTtsEndBound = null;
|
|
26545
|
+
this._onTtsCanceledBound = null;
|
|
26546
|
+
const wasLocalVc = this._localVcActive;
|
|
26547
|
+
this._localVcActive = false;
|
|
26548
|
+
this._wakeViaKwsLocalAsr = false;
|
|
26549
|
+
if (this._rtc) {
|
|
26550
|
+
try {
|
|
26551
|
+
if (wasLocalVc && this._rtc.stopAsr) {
|
|
26552
|
+
try {
|
|
26553
|
+
this._rtc.stopAsr();
|
|
26554
|
+
} catch {
|
|
26555
|
+
}
|
|
26556
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
26557
|
+
}
|
|
26558
|
+
(_b2 = (_a2 = this._rtc).stop) == null ? void 0 : _b2.call(_a2);
|
|
26559
|
+
(_d = (_c = this._rtc).destroy) == null ? void 0 : _d.call(_c);
|
|
26560
|
+
} catch (e) {
|
|
26561
|
+
console$6.warn("destroy error: " + ((e == null ? void 0 : e.message) || e));
|
|
26562
|
+
}
|
|
26563
|
+
}
|
|
26564
|
+
this._rtc = null;
|
|
26565
|
+
this._preloaded = false;
|
|
26566
|
+
this._preloadPromise = null;
|
|
26567
|
+
this._localAsrEndTime = 0;
|
|
26568
|
+
if (typeof window !== "undefined") window.localRTC = null;
|
|
26569
|
+
}
|
|
26570
|
+
}
|
|
25364
26571
|
SDKLogger.createModuleConsole("SpeechRTC");
|
|
25365
26572
|
const DEFAULT_WS_URL = "wss://openspeech.bytedance.com/api/v3/tts/bidirection";
|
|
25366
26573
|
const DEFAULT_PROXY_URL = "wss://speechrtc.keepwork.com/tts";
|
|
@@ -26913,145 +28120,6 @@ class SpeechRTCSession {
|
|
|
26913
28120
|
this._audioTime = 0;
|
|
26914
28121
|
}
|
|
26915
28122
|
}
|
|
26916
|
-
function detectFormat(url) {
|
|
26917
|
-
if (!url || typeof url !== "string") return null;
|
|
26918
|
-
const path = url.split(/[?#]/)[0].toLowerCase();
|
|
26919
|
-
if (path.endsWith(".json")) return "json";
|
|
26920
|
-
if (path.endsWith(".yml") || path.endsWith(".yaml")) return "yml";
|
|
26921
|
-
if (path.endsWith(".md")) return "md";
|
|
26922
|
-
return null;
|
|
26923
|
-
}
|
|
26924
|
-
function normalize(config) {
|
|
26925
|
-
if (!config || typeof config !== "object") return config;
|
|
26926
|
-
if (config.content && !config.system_prompt) {
|
|
26927
|
-
const body = String(config.content).trim();
|
|
26928
|
-
if (body) config.system_prompt = body;
|
|
26929
|
-
}
|
|
26930
|
-
delete config.content;
|
|
26931
|
-
if (config.workspace) {
|
|
26932
|
-
if (!config.tools) config.tools = {};
|
|
26933
|
-
if (!config.tools.fileOps) config.tools.fileOps = { enabled: false };
|
|
26934
|
-
if (!config.tools.fileOps.workspace) {
|
|
26935
|
-
config.tools.fileOps.workspace = config.workspace;
|
|
26936
|
-
}
|
|
26937
|
-
}
|
|
26938
|
-
if (config.mountFolder) {
|
|
26939
|
-
if (!config.tools) config.tools = {};
|
|
26940
|
-
if (!config.tools.fileOps) config.tools.fileOps = { enabled: false };
|
|
26941
|
-
if (!config.tools.fileOps.mountFolder) {
|
|
26942
|
-
config.tools.fileOps.mountFolder = config.mountFolder;
|
|
26943
|
-
}
|
|
26944
|
-
}
|
|
26945
|
-
if (config.history_length !== void 0 && config.historyLength === void 0) {
|
|
26946
|
-
config.historyLength = config.history_length;
|
|
26947
|
-
}
|
|
26948
|
-
delete config.history_length;
|
|
26949
|
-
return config;
|
|
26950
|
-
}
|
|
26951
|
-
function parseTable(tableText) {
|
|
26952
|
-
if (!tableText || typeof tableText !== "string") return {};
|
|
26953
|
-
const lines = tableText.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("|"));
|
|
26954
|
-
if (lines.length < 2) return {};
|
|
26955
|
-
const headerCells = lines[0].split("|").map((c) => c.trim()).filter(Boolean);
|
|
26956
|
-
const dataLines = lines.slice(2);
|
|
26957
|
-
const rows = dataLines.map((line) => {
|
|
26958
|
-
const cells = line.split("|").map((c) => c.trim()).filter(Boolean);
|
|
26959
|
-
const row = {};
|
|
26960
|
-
headerCells.forEach((h, i) => {
|
|
26961
|
-
row[h] = cells[i] !== void 0 ? cells[i] : "";
|
|
26962
|
-
});
|
|
26963
|
-
return row;
|
|
26964
|
-
});
|
|
26965
|
-
if (headerCells.length === 2) {
|
|
26966
|
-
const [keyCol, valCol] = headerCells;
|
|
26967
|
-
const isKV = keyCol.toLowerCase() === "key" && valCol.toLowerCase() === "value";
|
|
26968
|
-
if (isKV) {
|
|
26969
|
-
const obj = {};
|
|
26970
|
-
for (const row of rows) {
|
|
26971
|
-
const k = row[keyCol];
|
|
26972
|
-
if (k) obj[k] = _coerceValue(row[valCol]);
|
|
26973
|
-
}
|
|
26974
|
-
return obj;
|
|
26975
|
-
}
|
|
26976
|
-
}
|
|
26977
|
-
return rows;
|
|
26978
|
-
}
|
|
26979
|
-
function _coerceValue(v) {
|
|
26980
|
-
if (v === "true") return true;
|
|
26981
|
-
if (v === "false") return false;
|
|
26982
|
-
if (v === "null" || v === "") return null;
|
|
26983
|
-
const n = Number(v);
|
|
26984
|
-
if (!isNaN(n) && v.trim() !== "") return n;
|
|
26985
|
-
return v;
|
|
26986
|
-
}
|
|
26987
|
-
function parse(text, formatHint) {
|
|
26988
|
-
if (!text || typeof text !== "string") return {};
|
|
26989
|
-
const trimmed = text.trim();
|
|
26990
|
-
if (formatHint === "json" || trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
26991
|
-
return normalize(JSON.parse(trimmed));
|
|
26992
|
-
}
|
|
26993
|
-
if (trimmed.startsWith("---\n") || trimmed.startsWith("---\r\n")) {
|
|
26994
|
-
const YML = _getYMLParser();
|
|
26995
|
-
if (YML) return normalize(YML.yamlToObject(trimmed, true));
|
|
26996
|
-
}
|
|
26997
|
-
const firstLine = trimmed.split("\n").find((l) => l.trim());
|
|
26998
|
-
if (firstLine && firstLine.trim().startsWith("|")) {
|
|
26999
|
-
return normalize(parseTable(trimmed));
|
|
27000
|
-
}
|
|
27001
|
-
try {
|
|
27002
|
-
return normalize(JSON.parse(trimmed));
|
|
27003
|
-
} catch {
|
|
27004
|
-
const YML = _getYMLParser();
|
|
27005
|
-
if (YML) return normalize(YML.yamlToObject(trimmed, true));
|
|
27006
|
-
}
|
|
27007
|
-
return {};
|
|
27008
|
-
}
|
|
27009
|
-
async function fetchConfig(source) {
|
|
27010
|
-
if (source && typeof source === "object") {
|
|
27011
|
-
return normalize({ ...source });
|
|
27012
|
-
}
|
|
27013
|
-
if (typeof source !== "string" || !source.trim()) {
|
|
27014
|
-
throw new Error("AgentConfig.fetch: source must be a non-empty string or object");
|
|
27015
|
-
}
|
|
27016
|
-
const trimmed = source.trim();
|
|
27017
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
27018
|
-
return normalize(JSON.parse(trimmed));
|
|
27019
|
-
}
|
|
27020
|
-
const resp = await fetch(trimmed);
|
|
27021
|
-
if (!resp.ok) {
|
|
27022
|
-
throw new Error(`AgentConfig.fetch: fetch failed (${resp.status}) for ${trimmed}`);
|
|
27023
|
-
}
|
|
27024
|
-
let text = await resp.text();
|
|
27025
|
-
text = text.replace(
|
|
27026
|
-
/<script[^>]*\/___vscode_livepreview_injected_script[^>]*><\/script>\s*/gi,
|
|
27027
|
-
""
|
|
27028
|
-
);
|
|
27029
|
-
const format = detectFormat(trimmed);
|
|
27030
|
-
return parse(text, format);
|
|
27031
|
-
}
|
|
27032
|
-
function _getYMLParser() {
|
|
27033
|
-
if (typeof YMLParser !== "undefined") return YMLParser;
|
|
27034
|
-
if (typeof window !== "undefined" && window.YMLParser) {
|
|
27035
|
-
return window.YMLParser;
|
|
27036
|
-
}
|
|
27037
|
-
return null;
|
|
27038
|
-
}
|
|
27039
|
-
const AgentConfig = {
|
|
27040
|
-
detectFormat,
|
|
27041
|
-
normalize,
|
|
27042
|
-
parse,
|
|
27043
|
-
parseTable,
|
|
27044
|
-
fetch: fetchConfig
|
|
27045
|
-
};
|
|
27046
|
-
const AgentConfig$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
27047
|
-
__proto__: null,
|
|
27048
|
-
default: AgentConfig,
|
|
27049
|
-
detectFormat,
|
|
27050
|
-
fetchConfig,
|
|
27051
|
-
normalize,
|
|
27052
|
-
parse,
|
|
27053
|
-
parseTable
|
|
27054
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
27055
28123
|
function clearExternalContextDebounce(target) {
|
|
27056
28124
|
if (target._externalContextDebounceTimer) {
|
|
27057
28125
|
clearTimeout(target._externalContextDebounceTimer);
|
|
@@ -27347,11 +28415,14 @@ const _MinigameTools = class _MinigameTools {
|
|
|
27347
28415
|
const name = slotName ?? options["slot"] ?? this._activeSlot ?? "default";
|
|
27348
28416
|
const slot = this._getSlot(name);
|
|
27349
28417
|
if (!(slot == null ? void 0 : slot.container)) return false;
|
|
28418
|
+
this._cancelPendingClose(slot);
|
|
27350
28419
|
const frameOptions = { ...slot.defaultFrameOptions ?? {}, ...options["frameOptions"] ?? {}, ...options };
|
|
27351
28420
|
delete frameOptions["frameOptions"];
|
|
27352
28421
|
this._applyFrameOptions(slot, frameOptions);
|
|
27353
28422
|
this.setSlotForegroundElements(name, options["foregroundElements"], options["foregroundOptions"]);
|
|
28423
|
+
const wasHidden = slot.container.style.display === "none";
|
|
27354
28424
|
slot.container.style.display = "flex";
|
|
28425
|
+
if (wasHidden) this._animateSlotIn(slot);
|
|
27355
28426
|
this.setActiveSlot(name);
|
|
27356
28427
|
const session = this.getLaunchSession(name);
|
|
27357
28428
|
if (session) {
|
|
@@ -27367,6 +28438,7 @@ const _MinigameTools = class _MinigameTools {
|
|
|
27367
28438
|
const visible = options.visible !== false;
|
|
27368
28439
|
const slotName = this._resolveSlot(fnArgs["slot"]);
|
|
27369
28440
|
const slot = this._getOrCreateSlot(slotName);
|
|
28441
|
+
this._cancelPendingClose(slot);
|
|
27370
28442
|
const session = this.getLaunchSession(slotName);
|
|
27371
28443
|
const shouldShow = visible && !((session == null ? void 0 : session.preload) && session.revealed === false);
|
|
27372
28444
|
const pKey = fnArgs["persistKey"] ?? null;
|
|
@@ -27385,6 +28457,7 @@ const _MinigameTools = class _MinigameTools {
|
|
|
27385
28457
|
const url = store ? store.getAbsUrl(relativePath) : relativePath;
|
|
27386
28458
|
(_e = this._log) == null ? void 0 : _e.call(this, `[load_minigame] slot=${slotName}, ${relativePath} → ${url}`);
|
|
27387
28459
|
const c = slot.container;
|
|
28460
|
+
const wasHidden = c.style.display === "none";
|
|
27388
28461
|
c.style.left = "50%";
|
|
27389
28462
|
c.style.top = "50%";
|
|
27390
28463
|
c.style.right = "";
|
|
@@ -27394,6 +28467,7 @@ const _MinigameTools = class _MinigameTools {
|
|
|
27394
28467
|
slot.title.textContent = "🎮 " + relativePath.split("/").pop();
|
|
27395
28468
|
if (slot.defaultFrameOptions) this._applyFrameOptions(slot, shouldShow ? slot.defaultFrameOptions : this._withoutBackdrop(slot.defaultFrameOptions));
|
|
27396
28469
|
this._applyFrameOptions(slot, shouldShow ? fnArgs : this._withoutBackdrop(fnArgs));
|
|
28470
|
+
if (shouldShow && wasHidden) this._animateSlotIn(slot);
|
|
27397
28471
|
this.setActiveSlot(slotName);
|
|
27398
28472
|
const iframe = slot.iframe;
|
|
27399
28473
|
const loaded = await new Promise((resolve) => {
|
|
@@ -27441,11 +28515,19 @@ iframe已设置但未收到gameLoaded确认,URL: ${url}` : `[小游戏预加
|
|
|
27441
28515
|
if (!slot) return;
|
|
27442
28516
|
const reason = opts.reason ?? "user";
|
|
27443
28517
|
const wasVisible = ((_a2 = slot.container) == null ? void 0 : _a2.style.display) !== "none";
|
|
27444
|
-
if (slot.container) slot.container.style.display = "none";
|
|
27445
|
-
if (slot.iframe) slot.iframe.src = "";
|
|
27446
28518
|
slot.persistKey = null;
|
|
27447
28519
|
this._hideBackdrop(slot);
|
|
27448
28520
|
this._restoreForegroundElements(slot);
|
|
28521
|
+
const finalize = () => {
|
|
28522
|
+
if (slot.container) {
|
|
28523
|
+
slot.container.style.display = "none";
|
|
28524
|
+
slot.container.style.opacity = "1";
|
|
28525
|
+
slot.container.style.transition = "";
|
|
28526
|
+
}
|
|
28527
|
+
if (slot.iframe) slot.iframe.src = "";
|
|
28528
|
+
};
|
|
28529
|
+
if (wasVisible && reason !== "destroy" && this._slotTransitionEnabled(slot)) this._animateSlotOut(slot, finalize);
|
|
28530
|
+
else finalize();
|
|
27449
28531
|
if (slotName === this._activeSlot) {
|
|
27450
28532
|
let fallback = null;
|
|
27451
28533
|
for (const [name, s] of this._slots) {
|
|
@@ -27609,6 +28691,10 @@ iframe已设置但未收到gameLoaded确认,URL: ${url}` : `[小游戏预加
|
|
|
27609
28691
|
document.body.appendChild(el);
|
|
27610
28692
|
slot.backdropEl = el;
|
|
27611
28693
|
}
|
|
28694
|
+
if (slot.backdropHideTimer) {
|
|
28695
|
+
clearTimeout(slot.backdropHideTimer);
|
|
28696
|
+
slot.backdropHideTimer = null;
|
|
28697
|
+
}
|
|
27612
28698
|
const zIndex = parseInt(((_a2 = slot.container) == null ? void 0 : _a2.style.zIndex) || String(this.zIndex), 10) - 1;
|
|
27613
28699
|
slot.backdropEl.style.zIndex = String(zIndex);
|
|
27614
28700
|
slot.backdropEl.style.background = bg;
|
|
@@ -27617,10 +28703,79 @@ iframe已设置但未收到gameLoaded确认,URL: ${url}` : `[小游戏预加
|
|
|
27617
28703
|
slot.backdropEl.style.opacity = "1";
|
|
27618
28704
|
}
|
|
27619
28705
|
_hideBackdrop(slot) {
|
|
27620
|
-
|
|
27621
|
-
|
|
27622
|
-
|
|
28706
|
+
const el = slot.backdropEl;
|
|
28707
|
+
if (!el) return;
|
|
28708
|
+
if (slot.backdropHideTimer) {
|
|
28709
|
+
clearTimeout(slot.backdropHideTimer);
|
|
28710
|
+
slot.backdropHideTimer = null;
|
|
28711
|
+
}
|
|
28712
|
+
el.style.opacity = "0";
|
|
28713
|
+
slot.backdropHideTimer = setTimeout(() => {
|
|
28714
|
+
slot.backdropHideTimer = null;
|
|
28715
|
+
if (el.style.opacity === "0") el.style.display = "none";
|
|
28716
|
+
}, 220);
|
|
28717
|
+
}
|
|
28718
|
+
/** slot 是否启用显隐过渡动画(frameOptions.transition,默认启用)。 */
|
|
28719
|
+
_slotTransitionEnabled(slot) {
|
|
28720
|
+
var _a2;
|
|
28721
|
+
return ((_a2 = slot.defaultFrameOptions) == null ? void 0 : _a2.transition) !== false;
|
|
28722
|
+
}
|
|
28723
|
+
/** 取消尚未完成的关闭淡出收尾(重新打开 slot 时调用)。 */
|
|
28724
|
+
_cancelPendingClose(slot) {
|
|
28725
|
+
if (slot.closeTimer) {
|
|
28726
|
+
clearTimeout(slot.closeTimer);
|
|
28727
|
+
slot.closeTimer = null;
|
|
28728
|
+
}
|
|
28729
|
+
if (slot.container) {
|
|
28730
|
+
slot.container.style.transition = "";
|
|
28731
|
+
slot.container.style.opacity = "1";
|
|
28732
|
+
}
|
|
28733
|
+
}
|
|
28734
|
+
/**
|
|
28735
|
+
* 弹窗淡入:opacity 0→1 + 轻微 scale 放大。动画结束后移除 transition,
|
|
28736
|
+
* 避免影响后续拖拽(拖拽直接改 left/top/transform)。
|
|
28737
|
+
*/
|
|
28738
|
+
_animateSlotIn(slot) {
|
|
28739
|
+
const c = slot.container;
|
|
28740
|
+
if (!c) return;
|
|
28741
|
+
this._cancelPendingClose(slot);
|
|
28742
|
+
if (!this._slotTransitionEnabled(slot)) {
|
|
28743
|
+
c.style.opacity = "1";
|
|
28744
|
+
return;
|
|
28745
|
+
}
|
|
28746
|
+
const baseTransform = c.style.transform || "none";
|
|
28747
|
+
const enterTransform = baseTransform === "none" ? "scale(0.96)" : `${baseTransform} scale(0.96)`;
|
|
28748
|
+
c.style.transition = "none";
|
|
28749
|
+
c.style.opacity = "0";
|
|
28750
|
+
c.style.transform = enterTransform;
|
|
28751
|
+
void c.offsetWidth;
|
|
28752
|
+
c.style.transition = "opacity 0.28s ease, transform 0.28s ease";
|
|
28753
|
+
c.style.opacity = "1";
|
|
28754
|
+
c.style.transform = baseTransform;
|
|
28755
|
+
setTimeout(() => {
|
|
28756
|
+
if (c.style.opacity === "1") {
|
|
28757
|
+
c.style.transition = "";
|
|
28758
|
+
}
|
|
28759
|
+
}, 320);
|
|
28760
|
+
}
|
|
28761
|
+
/** 弹窗淡出;done 在动画结束后调用(负责 display:none 与清理)。 */
|
|
28762
|
+
_animateSlotOut(slot, done) {
|
|
28763
|
+
const c = slot.container;
|
|
28764
|
+
if (!c) {
|
|
28765
|
+
done();
|
|
28766
|
+
return;
|
|
27623
28767
|
}
|
|
28768
|
+
const baseTransform = c.style.transform || "none";
|
|
28769
|
+
const exitTransform = baseTransform === "none" ? "scale(0.96)" : `${baseTransform} scale(0.96)`;
|
|
28770
|
+
c.style.transition = "opacity 0.24s ease, transform 0.24s ease";
|
|
28771
|
+
void c.offsetWidth;
|
|
28772
|
+
c.style.opacity = "0";
|
|
28773
|
+
c.style.transform = exitTransform;
|
|
28774
|
+
slot.closeTimer = setTimeout(() => {
|
|
28775
|
+
slot.closeTimer = null;
|
|
28776
|
+
c.style.transform = baseTransform;
|
|
28777
|
+
done();
|
|
28778
|
+
}, 260);
|
|
27624
28779
|
}
|
|
27625
28780
|
_normalizeForegroundElements(elements) {
|
|
27626
28781
|
const source = Array.isArray(elements) ? elements : elements ? [elements] : [];
|
|
@@ -28641,13 +29796,16 @@ const _DigitalHuman = class _DigitalHuman {
|
|
|
28641
29796
|
* @param {HTMLElement} [options.container] - Container element for avatar rendering
|
|
28642
29797
|
* @param {Object} [options.config] - Initial configuration
|
|
28643
29798
|
*/
|
|
28644
|
-
constructor({ sdk, container, config, subtitle } = {}) {
|
|
29799
|
+
constructor({ sdk, container, config, subtitle, localRTC } = {}) {
|
|
28645
29800
|
var _a2, _b2;
|
|
28646
29801
|
if (!sdk) throw new Error("DigitalHuman requires a KeepworkSDK instance");
|
|
28647
29802
|
this.sdk = sdk;
|
|
28648
29803
|
this.container = container || null;
|
|
28649
29804
|
this.config = config || {};
|
|
28650
29805
|
this._subtitleOverlay = new DigitalHumanSubtitleOverlay(this, subtitle ?? this.config.subtitle);
|
|
29806
|
+
this._localRTCConfig = localRTC ?? this.config.localRTC ?? void 0;
|
|
29807
|
+
this._localRTCController = null;
|
|
29808
|
+
this._localRTCHooks = null;
|
|
28651
29809
|
EventEmitterMixin$1._initEvents.call(this);
|
|
28652
29810
|
this._avatarRoot = null;
|
|
28653
29811
|
this._videoIdle = null;
|
|
@@ -28916,6 +30074,93 @@ const _DigitalHuman = class _DigitalHuman {
|
|
|
28916
30074
|
showSubtitle(text, options = {}) {
|
|
28917
30075
|
this._subtitleOverlay.updateAssistant(text, { definite: true, paragraph: true, ...options });
|
|
28918
30076
|
}
|
|
30077
|
+
// ========================================================================
|
|
30078
|
+
// Local RTC (sherpa-onnx KWS + local ASR + cloud TTS) — host-level API
|
|
30079
|
+
// ========================================================================
|
|
30080
|
+
/**
|
|
30081
|
+
* 内部:确保 LocalRTCController 已构造(host 用本 DigitalHuman 实例的注入接口)。
|
|
30082
|
+
* @returns {LocalRTCController|null}
|
|
30083
|
+
*/
|
|
30084
|
+
_ensureLocalRTCController() {
|
|
30085
|
+
if (this._localRTCController) return this._localRTCController;
|
|
30086
|
+
if (!this._localRTCConfig) return null;
|
|
30087
|
+
const self = this;
|
|
30088
|
+
this._localRTCController = new LocalRTCController({
|
|
30089
|
+
host: {
|
|
30090
|
+
send: (text, opts) => self.send(text, opts),
|
|
30091
|
+
sendMessage: (text, opts) => self.sendMessage(text, opts),
|
|
30092
|
+
cancelSend: (reason) => self.cancelSend(reason),
|
|
30093
|
+
updateVoiceChat: (command, opts) => {
|
|
30094
|
+
var _a2;
|
|
30095
|
+
return (_a2 = self.updateVoiceChat) == null ? void 0 : _a2.call(self, command, opts);
|
|
30096
|
+
},
|
|
30097
|
+
startVoiceChat: (preset) => {
|
|
30098
|
+
var _a2;
|
|
30099
|
+
return (_a2 = self.startVoiceChat) == null ? void 0 : _a2.call(self, preset);
|
|
30100
|
+
},
|
|
30101
|
+
stopVoiceChat: () => {
|
|
30102
|
+
var _a2;
|
|
30103
|
+
return (_a2 = self.stopVoiceChat) == null ? void 0 : _a2.call(self);
|
|
30104
|
+
},
|
|
30105
|
+
on: (event, handler) => self.on(event, handler),
|
|
30106
|
+
off: (event, handler) => self.off(event, handler)
|
|
30107
|
+
},
|
|
30108
|
+
config: this._localRTCConfig,
|
|
30109
|
+
hooks: this._localRTCHooks || {}
|
|
30110
|
+
});
|
|
30111
|
+
return this._localRTCController;
|
|
30112
|
+
}
|
|
30113
|
+
/** 获取 LocalRTCController 实例(高级用法 / 调试)。 */
|
|
30114
|
+
getLocalRTCController() {
|
|
30115
|
+
return this._localRTCController;
|
|
30116
|
+
}
|
|
30117
|
+
/** 设置/更新本地 RTC 配置;若已有控制器则同步配置。 */
|
|
30118
|
+
setLocalRTCConfig(config) {
|
|
30119
|
+
this._localRTCConfig = config;
|
|
30120
|
+
if (this._localRTCController) this._localRTCController.config = config || {};
|
|
30121
|
+
}
|
|
30122
|
+
/** 读取当前本地 RTC 配置。 */
|
|
30123
|
+
getLocalRTCConfig() {
|
|
30124
|
+
return this._localRTCConfig;
|
|
30125
|
+
}
|
|
30126
|
+
/**
|
|
30127
|
+
* 注入业务钩子(onUserSpeech 字幕、onStatus、isLocalAsrEnabled、onToggleVoiceChat、onLoadProgress)。
|
|
30128
|
+
* 控制器已构造时同步合并,未构造时缓存待构造时使用。
|
|
30129
|
+
*/
|
|
30130
|
+
setLocalRTCHooks(hooks) {
|
|
30131
|
+
this._localRTCHooks = { ...this._localRTCHooks || {}, ...hooks || {} };
|
|
30132
|
+
if (this._localRTCController) this._localRTCController.hooks = this._localRTCHooks;
|
|
30133
|
+
}
|
|
30134
|
+
/** 便捷:注册本地 ASR 识别到用户说话的回调。 */
|
|
30135
|
+
onLocalUserSpeech(cb) {
|
|
30136
|
+
this.setLocalRTCHooks({ onUserSpeech: cb });
|
|
30137
|
+
}
|
|
30138
|
+
/** 本地 ASR 语音会话是否活跃。 */
|
|
30139
|
+
isLocalVoiceActive() {
|
|
30140
|
+
var _a2;
|
|
30141
|
+
return !!((_a2 = this._localRTCController) == null ? void 0 : _a2.isLocalVcActive());
|
|
30142
|
+
}
|
|
30143
|
+
/** 启动本地 ASR 语音会话(ASR → LLM → 云端 TTS)。 */
|
|
30144
|
+
async enableLocalVoice(opts) {
|
|
30145
|
+
const ctrl = this._ensureLocalRTCController();
|
|
30146
|
+
if (!ctrl) return false;
|
|
30147
|
+
return ctrl.enableLocalAsr(opts);
|
|
30148
|
+
}
|
|
30149
|
+
/** 结束本地 ASR 语音会话。 */
|
|
30150
|
+
async disableLocalVoice(opts) {
|
|
30151
|
+
if (!this._localRTCController) return;
|
|
30152
|
+
return this._localRTCController.disableLocalAsr(opts);
|
|
30153
|
+
}
|
|
30154
|
+
/** 重启 WASM KWS 回到待唤醒。 */
|
|
30155
|
+
async resumeLocalKws() {
|
|
30156
|
+
if (!this._localRTCController) return false;
|
|
30157
|
+
return this._localRTCController.resumeKws();
|
|
30158
|
+
}
|
|
30159
|
+
/** 云端启动前释放麦克风(停 WASM KWS)。 */
|
|
30160
|
+
async releaseLocalMicForCloud() {
|
|
30161
|
+
if (!this._localRTCController) return;
|
|
30162
|
+
return this._localRTCController.releaseMicForCloud();
|
|
30163
|
+
}
|
|
28919
30164
|
_getAudioEngine() {
|
|
28920
30165
|
var _a2;
|
|
28921
30166
|
return ((_a2 = this.sdk) == null ? void 0 : _a2.audioEngine) || AudioEngine.getShared();
|
|
@@ -32477,6 +33722,7 @@ You only need to play idle animation if you are looping in indefinite loop of an
|
|
|
32477
33722
|
* @returns {Promise<Object>} { session, config, bootResponse? }
|
|
32478
33723
|
*/
|
|
32479
33724
|
async initFromConfig(config = {}) {
|
|
33725
|
+
var _a2;
|
|
32480
33726
|
this.characterConfig = config;
|
|
32481
33727
|
if (Object.prototype.hasOwnProperty.call(config, "subtitle")) {
|
|
32482
33728
|
this.setSubtitleConfig(config.subtitle);
|
|
@@ -32507,6 +33753,19 @@ You only need to play idle animation if you are looping in indefinite loop of an
|
|
|
32507
33753
|
if (config.pageRouters) {
|
|
32508
33754
|
this._pageRouters = config.pageRouters;
|
|
32509
33755
|
}
|
|
33756
|
+
if (Object.prototype.hasOwnProperty.call(config, "localRTC")) {
|
|
33757
|
+
this._localRTCConfig = config.localRTC;
|
|
33758
|
+
}
|
|
33759
|
+
if (this._localRTCConfig && this._localRTCConfig.enabled !== false) {
|
|
33760
|
+
try {
|
|
33761
|
+
this._ensureLocalRTCController();
|
|
33762
|
+
void ((_a2 = this._localRTCController) == null ? void 0 : _a2.preload().catch((e) => {
|
|
33763
|
+
console$4.warn("[DigitalHuman] LocalRTC preload failed:", e);
|
|
33764
|
+
}));
|
|
33765
|
+
} catch (e) {
|
|
33766
|
+
console$4.warn("[DigitalHuman] LocalRTC init failed:", e);
|
|
33767
|
+
}
|
|
33768
|
+
}
|
|
32510
33769
|
return { session, config };
|
|
32511
33770
|
}
|
|
32512
33771
|
// ========================================================================
|
|
@@ -34769,6 +36028,13 @@ ${turn.Content}`;
|
|
|
34769
36028
|
this._clearVoiceIdleTimer();
|
|
34770
36029
|
this._clearVoiceLifecycleHandlers();
|
|
34771
36030
|
this._subtitleOverlay.destroy();
|
|
36031
|
+
if (this._localRTCController) {
|
|
36032
|
+
try {
|
|
36033
|
+
await this._localRTCController.destroy();
|
|
36034
|
+
} catch (e) {
|
|
36035
|
+
}
|
|
36036
|
+
this._localRTCController = null;
|
|
36037
|
+
}
|
|
34772
36038
|
if ((_a2 = this._vcSession) == null ? void 0 : _a2.isActive) {
|
|
34773
36039
|
try {
|
|
34774
36040
|
await this._vcSession.stop();
|
|
@@ -35086,7 +36352,7 @@ class DigitalHumanFrame {
|
|
|
35086
36352
|
* @param {string} [options.sdkSrc] - URL to keepworkSDK.iife.js
|
|
35087
36353
|
* @param {boolean} [options.useLocalSdk] - Set to true if sdkSrc is a local ES module instead of IIFE bundle
|
|
35088
36354
|
*/
|
|
35089
|
-
constructor({ sdk, container, sdkSrc, useLocalSdk, useExternalHtml, workspace, proxyCategories, subtitle } = {}) {
|
|
36355
|
+
constructor({ sdk, container, sdkSrc, useLocalSdk, useExternalHtml, workspace, proxyCategories, subtitle, localRTC } = {}) {
|
|
35090
36356
|
__publicField(this, "sdk");
|
|
35091
36357
|
__publicField(this, "container");
|
|
35092
36358
|
__publicField(this, "workspace");
|
|
@@ -35104,6 +36370,9 @@ class DigitalHumanFrame {
|
|
|
35104
36370
|
this.sdk = sdk;
|
|
35105
36371
|
this.container = container;
|
|
35106
36372
|
this.workspace = workspace;
|
|
36373
|
+
this.localRTCConfig = localRTC;
|
|
36374
|
+
this._localRTCController = null;
|
|
36375
|
+
this._localRTCHooks = null;
|
|
35107
36376
|
this._useLocalSdk = useLocalSdk !== void 0 ? !!useLocalSdk : !!sdk.constructor.sourceIsModule;
|
|
35108
36377
|
this._useExternalHtml = !!useExternalHtml;
|
|
35109
36378
|
this._proxyCategories = proxyCategories || null;
|
|
@@ -35891,9 +37160,15 @@ class DigitalHumanFrame {
|
|
|
35891
37160
|
}
|
|
35892
37161
|
}
|
|
35893
37162
|
async initFromConfig(config = {}) {
|
|
37163
|
+
var _a2;
|
|
35894
37164
|
if (this.subtitleConfig !== void 0 && !Object.prototype.hasOwnProperty.call(config, "subtitle")) {
|
|
35895
37165
|
config = { ...config, subtitle: this.subtitleConfig };
|
|
35896
37166
|
}
|
|
37167
|
+
if (Object.prototype.hasOwnProperty.call(config, "localRTC")) {
|
|
37168
|
+
if (this.localRTCConfig === void 0) this.localRTCConfig = config.localRTC;
|
|
37169
|
+
const { localRTC: _stripped, ...rest } = config;
|
|
37170
|
+
config = rest;
|
|
37171
|
+
}
|
|
35897
37172
|
await this._prepareConfigForIframe(config);
|
|
35898
37173
|
this.characterConfig = config;
|
|
35899
37174
|
const frameState = extractDigitalHumanFrameState(config);
|
|
@@ -35906,6 +37181,16 @@ class DigitalHumanFrame {
|
|
|
35906
37181
|
this.subtitleConfig = frameState.subtitleConfig;
|
|
35907
37182
|
if (frameState.avatarOnlyMode) this.avatarOnlyMode = true;
|
|
35908
37183
|
const res = await this._rpc(MSG.INIT_FROM_CONFIG, { config });
|
|
37184
|
+
if (this.localRTCConfig && this.localRTCConfig.enabled !== false) {
|
|
37185
|
+
try {
|
|
37186
|
+
this._ensureLocalRTCController();
|
|
37187
|
+
void ((_a2 = this._localRTCController) == null ? void 0 : _a2.preload().catch((e) => {
|
|
37188
|
+
console$3.warn("[DigitalHumanFrame] LocalRTC preload failed:", e);
|
|
37189
|
+
}));
|
|
37190
|
+
} catch (e) {
|
|
37191
|
+
console$3.warn("[DigitalHumanFrame] LocalRTC init failed:", e);
|
|
37192
|
+
}
|
|
37193
|
+
}
|
|
35909
37194
|
return {
|
|
35910
37195
|
session: this._proxySession,
|
|
35911
37196
|
config: res.config,
|
|
@@ -36106,6 +37391,80 @@ class DigitalHumanFrame {
|
|
|
36106
37391
|
const result = await this._rpc(MSG.GET_SUBTITLE_CONFIG);
|
|
36107
37392
|
return (result == null ? void 0 : result.config) || null;
|
|
36108
37393
|
}
|
|
37394
|
+
// ========================================================================
|
|
37395
|
+
// Local RTC (sherpa-onnx KWS + local ASR + cloud TTS) — host-level API
|
|
37396
|
+
// 控制器在父窗口,host 用本 DHF 实例(镜像 sendMessage/cancelSend/updateVoiceChat,
|
|
37397
|
+
// 并转发内层 textSpeech 事件)。
|
|
37398
|
+
// ========================================================================
|
|
37399
|
+
/** 内部:确保父窗口 LocalRTCController 已构造。 */
|
|
37400
|
+
_ensureLocalRTCController() {
|
|
37401
|
+
if (this._localRTCController) return this._localRTCController;
|
|
37402
|
+
if (!this.localRTCConfig) return null;
|
|
37403
|
+
const self = this;
|
|
37404
|
+
this._localRTCController = new LocalRTCController({
|
|
37405
|
+
host: {
|
|
37406
|
+
send: (text, opts) => self.send(text, opts),
|
|
37407
|
+
sendMessage: (text, opts) => self.sendMessage(text, opts),
|
|
37408
|
+
cancelSend: (reason) => self.cancelSend(reason),
|
|
37409
|
+
updateVoiceChat: (command, opts) => self.updateVoiceChat(command, opts || {}),
|
|
37410
|
+
startVoiceChat: (preset) => self.startVoiceChat(preset || {}),
|
|
37411
|
+
stopVoiceChat: () => self.stopVoiceChat(),
|
|
37412
|
+
on: (event, handler) => self.on(event, handler),
|
|
37413
|
+
off: (event, handler) => self.off(event, handler)
|
|
37414
|
+
},
|
|
37415
|
+
config: this.localRTCConfig,
|
|
37416
|
+
hooks: this._localRTCHooks || {}
|
|
37417
|
+
});
|
|
37418
|
+
return this._localRTCController;
|
|
37419
|
+
}
|
|
37420
|
+
/** 获取父窗口 LocalRTCController 实例(高级用法 / 调试)。 */
|
|
37421
|
+
getLocalRTCController() {
|
|
37422
|
+
return this._localRTCController;
|
|
37423
|
+
}
|
|
37424
|
+
/** 设置/更新本地 RTC 配置;若已有控制器则同步配置。 */
|
|
37425
|
+
setLocalRTCConfig(config) {
|
|
37426
|
+
this.localRTCConfig = config;
|
|
37427
|
+
if (this._localRTCController) this._localRTCController.config = config || {};
|
|
37428
|
+
}
|
|
37429
|
+
/** 读取当前本地 RTC 配置。 */
|
|
37430
|
+
getLocalRTCConfig() {
|
|
37431
|
+
return this.localRTCConfig;
|
|
37432
|
+
}
|
|
37433
|
+
/** 注入业务钩子(onUserSpeech 字幕、onStatus、isLocalAsrEnabled、onToggleVoiceChat、onLoadProgress)。 */
|
|
37434
|
+
setLocalRTCHooks(hooks) {
|
|
37435
|
+
this._localRTCHooks = { ...this._localRTCHooks || {}, ...hooks || {} };
|
|
37436
|
+
if (this._localRTCController) this._localRTCController.hooks = this._localRTCHooks;
|
|
37437
|
+
}
|
|
37438
|
+
/** 便捷:注册本地 ASR 识别到用户说话的回调。 */
|
|
37439
|
+
onLocalUserSpeech(cb) {
|
|
37440
|
+
this.setLocalRTCHooks({ onUserSpeech: cb });
|
|
37441
|
+
}
|
|
37442
|
+
/** 本地 ASR 语音会话是否活跃。 */
|
|
37443
|
+
isLocalVoiceActive() {
|
|
37444
|
+
var _a2;
|
|
37445
|
+
return !!((_a2 = this._localRTCController) == null ? void 0 : _a2.isLocalVcActive());
|
|
37446
|
+
}
|
|
37447
|
+
/** 启动本地 ASR 语音会话(ASR → LLM → 云端 TTS)。 */
|
|
37448
|
+
async enableLocalVoice(opts) {
|
|
37449
|
+
const ctrl = this._ensureLocalRTCController();
|
|
37450
|
+
if (!ctrl) return false;
|
|
37451
|
+
return ctrl.enableLocalAsr(opts);
|
|
37452
|
+
}
|
|
37453
|
+
/** 结束本地 ASR 语音会话。 */
|
|
37454
|
+
async disableLocalVoice(opts) {
|
|
37455
|
+
if (!this._localRTCController) return;
|
|
37456
|
+
return this._localRTCController.disableLocalAsr(opts);
|
|
37457
|
+
}
|
|
37458
|
+
/** 重启 WASM KWS 回到待唤醒。 */
|
|
37459
|
+
async resumeLocalKws() {
|
|
37460
|
+
if (!this._localRTCController) return false;
|
|
37461
|
+
return this._localRTCController.resumeKws();
|
|
37462
|
+
}
|
|
37463
|
+
/** 云端启动前释放麦克风(停 WASM KWS)。 */
|
|
37464
|
+
async releaseLocalMicForCloud() {
|
|
37465
|
+
if (!this._localRTCController) return;
|
|
37466
|
+
return this._localRTCController.releaseMicForCloud();
|
|
37467
|
+
}
|
|
36109
37468
|
async clearSubtitle(options = {}) {
|
|
36110
37469
|
return this._rpc(MSG.CLEAR_SUBTITLE, { options });
|
|
36111
37470
|
}
|
|
@@ -36363,6 +37722,13 @@ class DigitalHumanFrame {
|
|
|
36363
37722
|
this._authStateUnsubscribe();
|
|
36364
37723
|
this._authStateUnsubscribe = null;
|
|
36365
37724
|
}
|
|
37725
|
+
if (this._localRTCController) {
|
|
37726
|
+
try {
|
|
37727
|
+
await this._localRTCController.destroy();
|
|
37728
|
+
} catch (_) {
|
|
37729
|
+
}
|
|
37730
|
+
this._localRTCController = null;
|
|
37731
|
+
}
|
|
36366
37732
|
await this._tearDownIframe("DigitalHumanFrame destroyed");
|
|
36367
37733
|
window.removeEventListener("message", this._onMessage);
|
|
36368
37734
|
clearExternalContextDebounce(this);
|
|
@@ -38158,6 +39524,8 @@ if (typeof window !== "undefined") {
|
|
|
38158
39524
|
window.AIChat = AIChat;
|
|
38159
39525
|
window.AIChatRTC = AIChatRTC$1;
|
|
38160
39526
|
window.AIChatRTCLocal = AIChatRTCLocal;
|
|
39527
|
+
window.LocalRTC = LocalRTC;
|
|
39528
|
+
window.LocalRTCController = LocalRTCController;
|
|
38161
39529
|
window.SpeechRTC = SpeechRTC;
|
|
38162
39530
|
window.DigitalHuman = DigitalHuman;
|
|
38163
39531
|
window.DigitalHumanFrame = DigitalHumanFrame;
|
|
@@ -38186,6 +39554,8 @@ export {
|
|
|
38186
39554
|
DigitalHumanFrame,
|
|
38187
39555
|
KeepworkSDK,
|
|
38188
39556
|
LocalAPIKeySettings,
|
|
39557
|
+
LocalRTC,
|
|
39558
|
+
LocalRTCController,
|
|
38189
39559
|
LocalStorageUtil,
|
|
38190
39560
|
LoginWindow,
|
|
38191
39561
|
MinigameTools,
|