@yfwu2020/dsh-selection-explain 0.11.1 → 0.12.0
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/README.md +11 -4
- package/lib/chat-context.js +84 -0
- package/lib/chat-context.js.map +1 -0
- package/lib/client.js +427 -110
- package/lib/client.js.map +4 -4
- package/lib/config-values.js +2 -0
- package/lib/config-values.js.map +1 -1
- package/lib/host/analyze.js +127 -26
- package/lib/host/analyze.js.map +1 -1
- package/lib/host/chat-context.js +155 -0
- package/lib/host/chat-context.js.map +1 -0
- package/lib/host/chat-materials.js +64 -0
- package/lib/host/chat-materials.js.map +1 -0
- package/lib/host/config.js +2 -1
- package/lib/host/config.js.map +1 -1
- package/lib/host/history-attachments.js +17 -53
- package/lib/host/history-attachments.js.map +1 -1
- package/lib/host/history-store.js +75 -62
- package/lib/host/history-store.js.map +1 -1
- package/lib/host/http.js +2 -1
- package/lib/host/http.js.map +1 -1
- package/lib/host/promote.js +0 -1
- package/lib/host/promote.js.map +1 -1
- package/lib/host/settings-store.js +17 -18
- package/lib/host/settings-store.js.map +1 -1
- package/lib/settings.js +3 -1
- package/lib/settings.js.map +1 -1
- package/lib/types/chat-context.d.ts +53 -0
- package/lib/types/config-values.d.ts +6 -0
- package/lib/types/host/chat-context.d.ts +31 -0
- package/lib/types/host/chat-materials.d.ts +16 -0
- package/lib/types/host/config.d.ts +4 -2
- package/lib/types/host/history-attachments.d.ts +7 -40
- package/lib/types/host/history-store.d.ts +1 -0
- package/lib/types/host/types.d.ts +4 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -151,7 +151,6 @@ var VOICE_SILENCE_RMS = 0.012;
|
|
|
151
151
|
var CONTEXT_WINDOW = 1500;
|
|
152
152
|
var KEY_CONTEXT_CHARS = 300;
|
|
153
153
|
var MAX_QUOTES = 4;
|
|
154
|
-
var MAX_QUOTE_CHARS = 3e3;
|
|
155
154
|
var MAX_QUOTE_SELECTION = 2e4;
|
|
156
155
|
var QUOTE_ONLY_QUESTION = "\u5C31\u4E0A\u9762\u5F15\u7528\u7684\u6587\u5B57\uFF0C\u8BF4\u8BF4\u5B83\u5728\u8FD9\u91CC\u662F\u4EC0\u4E48\u610F\u601D\u3002";
|
|
157
156
|
var QUOTE_CONTEXT_API = "/selection-explain/api/quote-context";
|
|
@@ -1836,6 +1835,13 @@ function adaptPreviewHtml(code, previewId) {
|
|
|
1836
1835
|
}
|
|
1837
1836
|
var previewSeq = 0;
|
|
1838
1837
|
var previewFrames = {};
|
|
1838
|
+
function releasePreviewFrames(root) {
|
|
1839
|
+
if (!root) return;
|
|
1840
|
+
for (var key in previewFrames) {
|
|
1841
|
+
var frame = previewFrames[key].frame;
|
|
1842
|
+
if (frame === root || root.contains && root.contains(frame)) delete previewFrames[key];
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1839
1845
|
function registerPreviewFrame(frame) {
|
|
1840
1846
|
previewSeq += 1;
|
|
1841
1847
|
var id = "pv" + previewSeq;
|
|
@@ -1919,6 +1925,7 @@ function webPreviewBlock(code) {
|
|
|
1919
1925
|
return { root: wrap, pre, frame };
|
|
1920
1926
|
}
|
|
1921
1927
|
function renderRich(parent2, text, options) {
|
|
1928
|
+
releasePreviewFrames(parent2);
|
|
1922
1929
|
parent2.textContent = "";
|
|
1923
1930
|
var lines = String(text || "").replace(/\r/g, "").split("\n");
|
|
1924
1931
|
var current = null;
|
|
@@ -3259,7 +3266,7 @@ function createVoiceCardController(env) {
|
|
|
3259
3266
|
}
|
|
3260
3267
|
function unpinVCardBox() {
|
|
3261
3268
|
if (vcardState.unpinTimer) {
|
|
3262
|
-
|
|
3269
|
+
env.timerScope.clear(vcardState.unpinTimer);
|
|
3263
3270
|
vcardState.unpinTimer = null;
|
|
3264
3271
|
}
|
|
3265
3272
|
if (vcard && vcardState.unpinHandler) {
|
|
@@ -3273,7 +3280,7 @@ function createVoiceCardController(env) {
|
|
|
3273
3280
|
function scheduleVCardUnpin() {
|
|
3274
3281
|
if (!vcard) return;
|
|
3275
3282
|
if (vcardState.unpinTimer) {
|
|
3276
|
-
|
|
3283
|
+
env.timerScope.clear(vcardState.unpinTimer);
|
|
3277
3284
|
vcardState.unpinTimer = null;
|
|
3278
3285
|
}
|
|
3279
3286
|
if (vcardState.unpinHandler) {
|
|
@@ -3582,7 +3589,7 @@ function createVoiceCardController(env) {
|
|
|
3582
3589
|
line.setAttribute("data-off", "a");
|
|
3583
3590
|
var done = function() {
|
|
3584
3591
|
if (vcardState.crtTimer) {
|
|
3585
|
-
|
|
3592
|
+
env.timerScope.clear(vcardState.crtTimer);
|
|
3586
3593
|
vcardState.crtTimer = null;
|
|
3587
3594
|
}
|
|
3588
3595
|
if (vcard && vcardState.crtHandler) {
|
|
@@ -3601,7 +3608,7 @@ function createVoiceCardController(env) {
|
|
|
3601
3608
|
function finishCrtOff() {
|
|
3602
3609
|
vcardState.closing = false;
|
|
3603
3610
|
if (vcardState.crtTimer) {
|
|
3604
|
-
|
|
3611
|
+
env.timerScope.clear(vcardState.crtTimer);
|
|
3605
3612
|
vcardState.crtTimer = null;
|
|
3606
3613
|
}
|
|
3607
3614
|
if (vcard && vcardState.crtHandler) {
|
|
@@ -3755,14 +3762,13 @@ function createVoiceCardController(env) {
|
|
|
3755
3762
|
function startMicWatch() {
|
|
3756
3763
|
if (vcardState.timer) return;
|
|
3757
3764
|
if (!env.state.selection && !env.state.quoteSelection) return;
|
|
3758
|
-
vcardState.timer =
|
|
3759
|
-
env.timers.push(vcardState.timer);
|
|
3765
|
+
vcardState.timer = env.timerScope.interval(micTick, MIC_POLL_MS);
|
|
3760
3766
|
micTick();
|
|
3761
3767
|
}
|
|
3762
3768
|
function stopMicWatch() {
|
|
3763
3769
|
quoteVoiceHandled = false;
|
|
3764
3770
|
if (!vcardState.timer) return;
|
|
3765
|
-
|
|
3771
|
+
env.timerScope.clear(vcardState.timer);
|
|
3766
3772
|
vcardState.timer = null;
|
|
3767
3773
|
}
|
|
3768
3774
|
function micTick() {
|
|
@@ -3882,8 +3888,6 @@ function createQuotesController(env) {
|
|
|
3882
3888
|
function addQuote(text, label, extra) {
|
|
3883
3889
|
var clean = String(text || "").replace(/\u00a0/g, " ").trim();
|
|
3884
3890
|
if (!clean) return false;
|
|
3885
|
-
var truncated = clean.length > MAX_QUOTE_CHARS;
|
|
3886
|
-
if (truncated) clean = clean.slice(0, MAX_QUOTE_CHARS) + "\u2026";
|
|
3887
3891
|
for (var i = 0; i < env.state.quotes.length; i += 1) {
|
|
3888
3892
|
if (env.state.quotes[i].text === clean) {
|
|
3889
3893
|
env.setStatus("\u8FD9\u6BB5\u5DF2\u7ECF\u5728\u5F15\u7528\u91CC\u4E86");
|
|
@@ -3896,19 +3900,27 @@ function createQuotesController(env) {
|
|
|
3896
3900
|
}
|
|
3897
3901
|
quoteSeq += 1;
|
|
3898
3902
|
var context = extra && typeof extra.context === "string" ? extra.context.trim() : "";
|
|
3899
|
-
|
|
3903
|
+
var quote = {
|
|
3900
3904
|
id: quoteSeq,
|
|
3901
3905
|
label: label || "\u5F15\u7528",
|
|
3902
3906
|
text: clean,
|
|
3903
3907
|
context,
|
|
3904
|
-
session: !!(extra && extra.session === true)
|
|
3905
|
-
|
|
3908
|
+
session: !!(extra && extra.session === true),
|
|
3909
|
+
sessionId: extra && extra.sessionId || env.currentSessionId(),
|
|
3910
|
+
contextJob: null
|
|
3911
|
+
};
|
|
3912
|
+
env.state.quotes.push(quote);
|
|
3913
|
+
if (quote.session && quote.sessionId) {
|
|
3914
|
+
quote.contextJob = fetchQuoteContext(quote.sessionId, quote.text).then(function(context2) {
|
|
3915
|
+
if (context2) quote.context = context2;
|
|
3916
|
+
});
|
|
3917
|
+
}
|
|
3906
3918
|
renderQuotes();
|
|
3907
3919
|
env.refreshAskState();
|
|
3908
3920
|
env.askRow.style.display = "";
|
|
3909
3921
|
if (env.composerVisible()) env.focusAskBox();
|
|
3910
3922
|
env.setStatus(
|
|
3911
|
-
"\u5DF2\u52A0\u5165\u5F15\u7528\uFF08" + quoteLabelOf(env.state.quotes[env.state.quotes.length - 1]) + " \xB7 " + clean.length + " \u5B57" + (
|
|
3923
|
+
"\u5DF2\u52A0\u5165\u5F15\u7528\uFF08" + quoteLabelOf(env.state.quotes[env.state.quotes.length - 1]) + " \xB7 " + clean.length + " \u5B57" + (context ? " \xB7 \u5E26\u4E0A\u4E0B\u6587 " + context.length + " \u5B57" : "") + "\uFF09"
|
|
3912
3924
|
);
|
|
3913
3925
|
return true;
|
|
3914
3926
|
}
|
|
@@ -3973,6 +3985,22 @@ function createQuotesController(env) {
|
|
|
3973
3985
|
function quoteContextFor(selection) {
|
|
3974
3986
|
if (!selection) return { context: "", session: false };
|
|
3975
3987
|
if (selection.source === "panel") {
|
|
3988
|
+
var index = selection.turnIndex;
|
|
3989
|
+
var through = env.state.contextState && env.state.contextState.through || 0;
|
|
3990
|
+
var visibleBefore = env.state.turns.slice(0, index).filter(function(t) {
|
|
3991
|
+
return !t.hidden;
|
|
3992
|
+
}).length;
|
|
3993
|
+
if (index >= 0 && visibleBefore < through) {
|
|
3994
|
+
var pieces = env.state.turns.slice(Math.max(0, index - 1), index + 2).filter(function(t) {
|
|
3995
|
+
return !t.hidden;
|
|
3996
|
+
}).map(function(t) {
|
|
3997
|
+
var text = t.role === "assistant" ? env.foldForHistory(t.text || "") : sentTextOf(t);
|
|
3998
|
+
var at = text.indexOf(selection.text);
|
|
3999
|
+
var start = at >= 0 ? Math.max(0, at - 500) : 0;
|
|
4000
|
+
return (t.role === "user" ? "\u7528\u6237\uFF1A" : "\u52A9\u624B\uFF1A") + text.slice(start, start + Math.max(1500, selection.text.length + 500));
|
|
4001
|
+
});
|
|
4002
|
+
return { context: pieces.join("\n"), session: false };
|
|
4003
|
+
}
|
|
3976
4004
|
return { context: "", session: false };
|
|
3977
4005
|
}
|
|
3978
4006
|
if (selection.source === "iframe") {
|
|
@@ -3993,22 +4021,16 @@ function createQuotesController(env) {
|
|
|
3993
4021
|
for (var i = 0; i < quotes.length; i += 1) {
|
|
3994
4022
|
if (quotes[i].session === true) jobs.push(quotes[i]);
|
|
3995
4023
|
}
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
return fetchQuoteContext(sessionId, quote.text).then(function(context) {
|
|
4001
|
-
if (context) quote.context = context;
|
|
4002
|
-
return quote;
|
|
4003
|
-
});
|
|
4004
|
-
})
|
|
4005
|
-
).then(function() {
|
|
4024
|
+
if (jobs.length === 0) return Promise.resolve(quotes);
|
|
4025
|
+
return Promise.all(jobs.map(function(quote) {
|
|
4026
|
+
return quote.contextJob || Promise.resolve();
|
|
4027
|
+
})).then(function() {
|
|
4006
4028
|
return quotes;
|
|
4007
4029
|
});
|
|
4008
4030
|
}
|
|
4009
4031
|
function fetchQuoteContext(sessionId, text) {
|
|
4010
4032
|
var controller = typeof AbortController === "function" ? new AbortController() : null;
|
|
4011
|
-
var timer =
|
|
4033
|
+
var timer = env.timerScope.later(function() {
|
|
4012
4034
|
if (controller) {
|
|
4013
4035
|
try {
|
|
4014
4036
|
controller.abort();
|
|
@@ -4016,7 +4038,6 @@ function createQuotesController(env) {
|
|
|
4016
4038
|
}
|
|
4017
4039
|
}
|
|
4018
4040
|
}, QUOTE_CONTEXT_TIMEOUT);
|
|
4019
|
-
env.timers.push(timer);
|
|
4020
4041
|
return fetch(QUOTE_CONTEXT_API, {
|
|
4021
4042
|
method: "POST",
|
|
4022
4043
|
headers: { "content-type": "application/json" },
|
|
@@ -4025,11 +4046,11 @@ function createQuotesController(env) {
|
|
|
4025
4046
|
}).then(function(response) {
|
|
4026
4047
|
return response.ok ? response.json() : null;
|
|
4027
4048
|
}).then(function(data) {
|
|
4028
|
-
|
|
4049
|
+
env.timerScope.clear(timer);
|
|
4029
4050
|
if (data && data.ok === true && data.matched === true && typeof data.context === "string") return data.context;
|
|
4030
4051
|
return "";
|
|
4031
4052
|
}).catch(function() {
|
|
4032
|
-
|
|
4053
|
+
env.timerScope.clear(timer);
|
|
4033
4054
|
return "";
|
|
4034
4055
|
});
|
|
4035
4056
|
}
|
|
@@ -4071,6 +4092,7 @@ function createQuotesController(env) {
|
|
|
4071
4092
|
out.push({
|
|
4072
4093
|
role: turn.role,
|
|
4073
4094
|
text: sentTextOf(turn),
|
|
4095
|
+
...turn.contextExcluded === true ? { contextExcluded: true } : {},
|
|
4074
4096
|
...turn.attachments && turn.attachments.length > 0 ? { attachments: turn.attachments } : {}
|
|
4075
4097
|
});
|
|
4076
4098
|
}
|
|
@@ -4919,7 +4941,7 @@ function createPreviewController(env) {
|
|
|
4919
4941
|
// src/client/panel.js
|
|
4920
4942
|
function createPanelController(env) {
|
|
4921
4943
|
function panelOrCurrentSessionId() {
|
|
4922
|
-
return env.panelSessionId || currentSessionId();
|
|
4944
|
+
return env.state.contextState && typeof env.state.contextState.sessionId === "string" ? env.state.contextState.sessionId : env.panelSessionId || currentSessionId();
|
|
4923
4945
|
}
|
|
4924
4946
|
function currentSessionId() {
|
|
4925
4947
|
try {
|
|
@@ -5017,6 +5039,7 @@ function createPanelController(env) {
|
|
|
5017
5039
|
function openPanelWithInner(text, context, label, anchor, keyContext, options) {
|
|
5018
5040
|
env.state.skipInterpretation = !!(options && options.askFirst);
|
|
5019
5041
|
env.panelSessionId = currentSessionId();
|
|
5042
|
+
env.state.contextState = null;
|
|
5020
5043
|
env.state.payload = buildPayload(text, context, label);
|
|
5021
5044
|
env.state.kind = env.state.payload.kind;
|
|
5022
5045
|
env.hideButton();
|
|
@@ -5282,12 +5305,12 @@ function createPanelController(env) {
|
|
|
5282
5305
|
env.panel.style.transition = "transform " + PANEL_GROW_MS + "ms " + PANEL_GROW_EASE;
|
|
5283
5306
|
env.panel.style.transform = "none";
|
|
5284
5307
|
if (env.panelGrowTimer) {
|
|
5285
|
-
|
|
5308
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5286
5309
|
env.panelGrowTimer = null;
|
|
5287
5310
|
}
|
|
5288
5311
|
var settle = function() {
|
|
5289
5312
|
if (env.panelGrowTimer) {
|
|
5290
|
-
|
|
5313
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5291
5314
|
env.panelGrowTimer = null;
|
|
5292
5315
|
}
|
|
5293
5316
|
if (env.panelGrowHandler) {
|
|
@@ -5310,7 +5333,7 @@ function createPanelController(env) {
|
|
|
5310
5333
|
env.panelOpen = false;
|
|
5311
5334
|
env.panel.style.display = "none";
|
|
5312
5335
|
if (env.panelGrowTimer) {
|
|
5313
|
-
|
|
5336
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5314
5337
|
env.panelGrowTimer = null;
|
|
5315
5338
|
}
|
|
5316
5339
|
if (env.panelGrowHandler) {
|
|
@@ -5328,6 +5351,11 @@ function createPanelController(env) {
|
|
|
5328
5351
|
if (env.state.request) env.state.aborted = true;
|
|
5329
5352
|
if (env.state.request) env.state.request.abort();
|
|
5330
5353
|
env.state.request = null;
|
|
5354
|
+
if (env.state.askRequest) {
|
|
5355
|
+
env.state.stopped = true;
|
|
5356
|
+
env.state.askRequest.abort();
|
|
5357
|
+
}
|
|
5358
|
+
releaseRenderedContent();
|
|
5331
5359
|
env.paintPill();
|
|
5332
5360
|
env.syncRouteWatch();
|
|
5333
5361
|
}
|
|
@@ -5356,7 +5384,20 @@ function createPanelController(env) {
|
|
|
5356
5384
|
var what = env.state.toolBusy ? "\u6B63\u5728\u68C0\u7D22\u8D44\u6599\u2026" : env.state.phase === "loading" ? "\u6B63\u5728\u5206\u6790\u2026" : "\u751F\u6210\u4E2D\u2026";
|
|
5357
5385
|
return what + " " + seconds + "s";
|
|
5358
5386
|
}
|
|
5387
|
+
function releaseRenderedContent() {
|
|
5388
|
+
env.clearWaiting();
|
|
5389
|
+
env.clearRenderedTurns();
|
|
5390
|
+
for (var content of [env.translationSection.content, env.detailSection.content]) {
|
|
5391
|
+
releasePreviewFrames(content);
|
|
5392
|
+
content.textContent = "";
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5359
5395
|
function paint() {
|
|
5396
|
+
if (!env.panelOpen) {
|
|
5397
|
+
releaseRenderedContent();
|
|
5398
|
+
env.paintPill();
|
|
5399
|
+
return;
|
|
5400
|
+
}
|
|
5360
5401
|
var streaming = env.state.phase === "loading" || env.state.phase === "streaming";
|
|
5361
5402
|
var stage = env.state.stage;
|
|
5362
5403
|
var selected = env.state.payload && env.state.payload.text ? env.state.payload.text : env.state.selection ? env.state.selection.text : "";
|
|
@@ -5555,6 +5596,7 @@ function createPanelController(env) {
|
|
|
5555
5596
|
env.panel.style.top = Math.round(top) + "px";
|
|
5556
5597
|
}
|
|
5557
5598
|
return {
|
|
5599
|
+
releaseRenderedContent,
|
|
5558
5600
|
openForSelection,
|
|
5559
5601
|
currentSessionId,
|
|
5560
5602
|
loadPanelSize,
|
|
@@ -6143,9 +6185,69 @@ function createPillController(env) {
|
|
|
6143
6185
|
};
|
|
6144
6186
|
}
|
|
6145
6187
|
|
|
6188
|
+
// src/chat-context.ts
|
|
6189
|
+
var CHAT_REQUEST_BYTES = 512 * 1024;
|
|
6190
|
+
var EMPTY_DIGEST = "811c9dc5";
|
|
6191
|
+
function readContextState(raw) {
|
|
6192
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6193
|
+
const s = raw;
|
|
6194
|
+
if (s.version !== 1 || !Number.isSafeInteger(s.through) || s.through < 0 || !/^[a-f0-9]{8}$/.test(s.source) || !/^[a-f0-9]{8}$/.test(s.digest) || typeof s.summary !== "string" || s.summary.length > 12e3 || s.through > 0 && !s.summary.trim()) return null;
|
|
6195
|
+
if (s.background !== null && (!s.background || typeof s.background.transcript !== "string" || s.background.transcript.length > 2e5 || typeof s.background.marked !== "boolean")) return null;
|
|
6196
|
+
if (s.sessionId !== void 0 && (typeof s.sessionId !== "string" || s.sessionId.length > 500)) return null;
|
|
6197
|
+
return {
|
|
6198
|
+
version: 1,
|
|
6199
|
+
...typeof s.sessionId === "string" ? { sessionId: s.sessionId } : {},
|
|
6200
|
+
source: s.source,
|
|
6201
|
+
through: s.through,
|
|
6202
|
+
digest: s.digest,
|
|
6203
|
+
summary: s.summary,
|
|
6204
|
+
background: s.background ? { transcript: s.background.transcript, marked: s.background.marked } : null
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
function modelTurn(turn) {
|
|
6208
|
+
if (turn.contextExcluded) return {
|
|
6209
|
+
role: turn.role === "assistant" ? "assistant" : "user",
|
|
6210
|
+
text: turn.role === "assistant" ? "\uFF08\u8BE5\u8F6E\u672A\u751F\u6210\u56DE\u7B54\u3002\uFF09" : "\uFF08\u8BE5\u63D0\u95EE\u672A\u63D0\u4EA4\u7ED9\u6A21\u578B\uFF0C\u539F\u59CB\u5185\u5BB9\u4ECD\u4FDD\u5B58\u5728\u754C\u9762\u5386\u53F2\u4E2D\uFF1B\u9700\u8981\u65F6\u8BF7\u91CD\u65B0\u5F15\u7528\u5FC5\u8981\u90E8\u5206\u3002\uFF09"
|
|
6211
|
+
};
|
|
6212
|
+
return {
|
|
6213
|
+
role: turn.role === "assistant" ? "assistant" : "user",
|
|
6214
|
+
text: turn.sent || turn.text || "",
|
|
6215
|
+
...turn.attachments?.length ? { attachments: turn.attachments } : {}
|
|
6216
|
+
};
|
|
6217
|
+
}
|
|
6218
|
+
function historyDigest(turns, initial = EMPTY_DIGEST) {
|
|
6219
|
+
let hash = Number.parseInt(initial, 16) >>> 0;
|
|
6220
|
+
for (const raw of turns) {
|
|
6221
|
+
const t = modelTurn(raw);
|
|
6222
|
+
const text = JSON.stringify([t.role, t.text, (t.attachments || []).map((a) => [a.kind, a.ref.attachmentId])]) + "\n";
|
|
6223
|
+
for (let i = 0; i < text.length; i++) hash = Math.imul(hash ^ text.charCodeAt(i), 16777619) >>> 0;
|
|
6224
|
+
}
|
|
6225
|
+
return hash.toString(16).padStart(8, "0");
|
|
6226
|
+
}
|
|
6227
|
+
function contextSource(session, text, context, initial) {
|
|
6228
|
+
return historyDigest([{ role: "user", text: JSON.stringify([session, text, context, initial]) }]);
|
|
6229
|
+
}
|
|
6230
|
+
function prepareChatHistory(turns, rawState) {
|
|
6231
|
+
const visible = turns.filter((t) => !t.hidden);
|
|
6232
|
+
let state = readContextState(rawState);
|
|
6233
|
+
if (state && (state.through > visible.length || historyDigest(visible.slice(0, state.through)) !== state.digest)) state = null;
|
|
6234
|
+
const start = state?.through || 0;
|
|
6235
|
+
const materials = [];
|
|
6236
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6237
|
+
visible.forEach((turn, index) => {
|
|
6238
|
+
for (const item of turn.attachments || []) {
|
|
6239
|
+
const key = item.kind + ":" + item.ref.attachmentId;
|
|
6240
|
+
if (!seen.has(key)) {
|
|
6241
|
+
seen.add(key);
|
|
6242
|
+
materials.push({ kind: item.kind, ref: item.ref, turn: index });
|
|
6243
|
+
}
|
|
6244
|
+
}
|
|
6245
|
+
});
|
|
6246
|
+
return { history: visible.slice(start).map(modelTurn), historyStart: start, contextState: state, materials };
|
|
6247
|
+
}
|
|
6248
|
+
|
|
6146
6249
|
// src/client/history.js
|
|
6147
6250
|
function createHistoryController(env) {
|
|
6148
|
-
var FOLD_HISTORY_KEEP_LATEST = true;
|
|
6149
6251
|
var foldCount = 0;
|
|
6150
6252
|
var HTML_VOID_TAGS = {
|
|
6151
6253
|
area: 1,
|
|
@@ -6426,16 +6528,6 @@ function createHistoryController(env) {
|
|
|
6426
6528
|
src = src.replace(/```html[ \t]*\n([\s\S]*)$/, one);
|
|
6427
6529
|
return src;
|
|
6428
6530
|
}
|
|
6429
|
-
function historyTextOf(turn, keepRaw) {
|
|
6430
|
-
if (!turn) return "";
|
|
6431
|
-
if (turn.role === "user") return env.sentTextOf(turn);
|
|
6432
|
-
if (keepRaw) return turn.text;
|
|
6433
|
-
if (typeof turn.foldedCache === "string") return turn.foldedCache;
|
|
6434
|
-
if (turn.streaming === true) return turn.text;
|
|
6435
|
-
var folded = foldForHistory(turn.text);
|
|
6436
|
-
turn.foldedCache = folded;
|
|
6437
|
-
return folded;
|
|
6438
|
-
}
|
|
6439
6531
|
function currentSurfaceTheme() {
|
|
6440
6532
|
try {
|
|
6441
6533
|
var bodyEl = document.body;
|
|
@@ -6464,6 +6556,7 @@ function createHistoryController(env) {
|
|
|
6464
6556
|
function visibleRaw() {
|
|
6465
6557
|
return env.state.raw;
|
|
6466
6558
|
}
|
|
6559
|
+
var historySaveSequence = 0;
|
|
6467
6560
|
function saveHistory(options) {
|
|
6468
6561
|
var payload = env.state.payload;
|
|
6469
6562
|
if (!payload || !env.state.cacheKey) return;
|
|
@@ -6474,6 +6567,22 @@ function createHistoryController(env) {
|
|
|
6474
6567
|
if (turn.hidden === true) continue;
|
|
6475
6568
|
turns.push(exported[i]);
|
|
6476
6569
|
}
|
|
6570
|
+
var owner = env.state.turns;
|
|
6571
|
+
var ownerKey = env.state.cacheKey;
|
|
6572
|
+
var sequence = ++historySaveSequence;
|
|
6573
|
+
function noteSaved(error) {
|
|
6574
|
+
if (sequence !== historySaveSequence || env.state.turns !== owner || env.state.cacheKey !== ownerKey) return;
|
|
6575
|
+
var last = owner[owner.length - 1];
|
|
6576
|
+
if (!last || last.role !== "assistant") return;
|
|
6577
|
+
if (error) {
|
|
6578
|
+
last.notice = "\u5386\u53F2\u8BB0\u5F55\u4FDD\u5B58\u5931\u8D25\uFF0C\u5F53\u524D\u539F\u6587\u4ECD\u5728\u5C0F\u7A97\u4E2D\uFF1B\u5237\u65B0\u6216\u9000\u51FA\u524D\u8BF7\u5148\u590D\u5236\u91CD\u8981\u5185\u5BB9\u3002";
|
|
6579
|
+
last.noticeCode = "history-save-failed";
|
|
6580
|
+
} else if (last.noticeCode === "history-save-failed") {
|
|
6581
|
+
last.notice = "";
|
|
6582
|
+
last.noticeCode = "";
|
|
6583
|
+
} else return;
|
|
6584
|
+
renderTurns();
|
|
6585
|
+
}
|
|
6477
6586
|
try {
|
|
6478
6587
|
fetch(HISTORY, {
|
|
6479
6588
|
method: "POST",
|
|
@@ -6486,15 +6595,23 @@ function createHistoryController(env) {
|
|
|
6486
6595
|
parts: env.state.parts,
|
|
6487
6596
|
turns,
|
|
6488
6597
|
toolDigest: env.state.toolDigest,
|
|
6598
|
+
contextState: env.state.contextState || null,
|
|
6489
6599
|
pinned: !!(options && options.pinned),
|
|
6490
6600
|
// 这段对话有没有解读,必须跟着条目落盘:回放时靠它决定画不画「翻译」一节。
|
|
6491
6601
|
// 不落盘的话,语音卡那条"跳过翻译与详解、直接追问"的对话下次开出来,
|
|
6492
6602
|
// 会顶着一张空翻译卡片("这次没有返回内容")——用户实测。
|
|
6493
6603
|
skipped: env.state.skipInterpretation === true
|
|
6494
6604
|
})
|
|
6605
|
+
}).then(function(response) {
|
|
6606
|
+
if (!response.ok) throw new Error("HTTP " + response.status);
|
|
6607
|
+
return response.json();
|
|
6608
|
+
}).then(function(result) {
|
|
6609
|
+
noteSaved(!result || result.ok !== true);
|
|
6495
6610
|
}).catch(function() {
|
|
6611
|
+
noteSaved(true);
|
|
6496
6612
|
});
|
|
6497
6613
|
} catch (error) {
|
|
6614
|
+
noteSaved(true);
|
|
6498
6615
|
}
|
|
6499
6616
|
}
|
|
6500
6617
|
function applyHistoryEntry(entry, source) {
|
|
@@ -6510,6 +6627,8 @@ function createHistoryController(env) {
|
|
|
6510
6627
|
}
|
|
6511
6628
|
var noInterpretation = !String(parts.translation || "").trim() && !String(parts.detail || "").trim();
|
|
6512
6629
|
env.state.skipInterpretation = entry.skipped === true || entry.skipped === void 0 && noInterpretation && hasAskTurn;
|
|
6630
|
+
env.state.contextState = readContextState(entry.contextState);
|
|
6631
|
+
if (env.state.contextState && typeof env.state.contextState.sessionId === "string") env.panelSessionId = env.state.contextState.sessionId;
|
|
6513
6632
|
env.state.turns = Array.isArray(entry.turns) ? entry.turns.slice() : [];
|
|
6514
6633
|
env.clearQuotes();
|
|
6515
6634
|
env.state.toolDigest = typeof entry.toolDigest === "string" ? entry.toolDigest : "";
|
|
@@ -6541,8 +6660,7 @@ function createHistoryController(env) {
|
|
|
6541
6660
|
settled = true;
|
|
6542
6661
|
if (env.state.cacheKey === cacheKey && onMiss) onMiss();
|
|
6543
6662
|
}
|
|
6544
|
-
var timer =
|
|
6545
|
-
env.timers.push(timer);
|
|
6663
|
+
var timer = env.timerScope.later(miss, 1500);
|
|
6546
6664
|
try {
|
|
6547
6665
|
fetch(HISTORY + "?key=" + encodeURIComponent(cacheKey)).then(function(response) {
|
|
6548
6666
|
return response.json();
|
|
@@ -6554,7 +6672,7 @@ function createHistoryController(env) {
|
|
|
6554
6672
|
}
|
|
6555
6673
|
if (data && data.ok === true && data.entry) {
|
|
6556
6674
|
settled = true;
|
|
6557
|
-
|
|
6675
|
+
env.timerScope.clear(timer);
|
|
6558
6676
|
applyHistoryEntry(data.entry, "history");
|
|
6559
6677
|
return;
|
|
6560
6678
|
}
|
|
@@ -6709,7 +6827,7 @@ function createHistoryController(env) {
|
|
|
6709
6827
|
});
|
|
6710
6828
|
bar.appendChild(undo);
|
|
6711
6829
|
env.historyList.appendChild(bar);
|
|
6712
|
-
|
|
6830
|
+
env.timerScope.later(function() {
|
|
6713
6831
|
if (bar.parentNode) bar.parentNode.removeChild(bar);
|
|
6714
6832
|
}, 5e3);
|
|
6715
6833
|
}
|
|
@@ -6841,24 +6959,81 @@ function createHistoryController(env) {
|
|
|
6841
6959
|
if (Date.now() - stickAt < 150) return;
|
|
6842
6960
|
env.state.follow = nearBottom();
|
|
6843
6961
|
}
|
|
6962
|
+
var turnWindowSize = 40;
|
|
6963
|
+
var turnWindowKey = null;
|
|
6964
|
+
var renderedTurns = [];
|
|
6965
|
+
function clearRenderedTurns() {
|
|
6966
|
+
env.clearWaiting(env.chatLog);
|
|
6967
|
+
releasePreviewFrames(env.chatLog);
|
|
6968
|
+
env.chatLog.textContent = "";
|
|
6969
|
+
renderedTurns = [];
|
|
6970
|
+
turnWindowSize = 40;
|
|
6971
|
+
turnWindowKey = null;
|
|
6972
|
+
}
|
|
6844
6973
|
function renderTurns(options) {
|
|
6974
|
+
if (!env.panelOpen) {
|
|
6975
|
+
clearRenderedTurns();
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6845
6978
|
var force = !!(options && options.stick === true);
|
|
6846
|
-
var stick = force || nearBottom();
|
|
6979
|
+
var stick = !(options && options.preservePosition) && (force || nearBottom());
|
|
6847
6980
|
var visible = [];
|
|
6848
6981
|
for (var i = 0; i < env.state.turns.length; i++) {
|
|
6849
6982
|
if (env.state.turns[i].hidden !== true) visible.push(env.state.turns[i]);
|
|
6850
6983
|
}
|
|
6851
|
-
if (
|
|
6984
|
+
if (turnWindowKey !== env.state.cacheKey) {
|
|
6985
|
+
turnWindowKey = env.state.cacheKey;
|
|
6986
|
+
turnWindowSize = 40;
|
|
6987
|
+
}
|
|
6988
|
+
var earlier = Math.max(0, visible.length - turnWindowSize);
|
|
6989
|
+
visible = visible.slice(earlier);
|
|
6990
|
+
var sameWindow = renderedTurns.length === visible.length && visible.every(function(turn2, index) {
|
|
6991
|
+
return renderedTurns[index] === turn2;
|
|
6992
|
+
});
|
|
6993
|
+
var prependCount = visible.length - renderedTurns.length;
|
|
6994
|
+
var canPrepend = options && options.prepend && renderedTurns.length > 0 && prependCount > 0 && renderedTurns.every(function(turn2, index) {
|
|
6995
|
+
return visible[prependCount + index] === turn2;
|
|
6996
|
+
});
|
|
6997
|
+
if (canPrepend) {
|
|
6998
|
+
var moreButton = env.chatLog.children[0];
|
|
6999
|
+
var firstBubble = env.chatLog.children[1];
|
|
7000
|
+
if (earlier > 0) moreButton.textContent = "\u663E\u793A\u66F4\u65E9\u7684\u6D88\u606F\uFF08\u8FD8\u6709 " + earlier + " \u6761\uFF09";
|
|
7001
|
+
else env.chatLog.removeChild(moreButton);
|
|
7002
|
+
for (var p = 0; p < prependCount; p++) {
|
|
7003
|
+
var prepended = bubbleFor(visible[p]);
|
|
7004
|
+
prepended.__turn = visible[p];
|
|
7005
|
+
env.chatLog.insertBefore(prepended, firstBubble);
|
|
7006
|
+
}
|
|
7007
|
+
renderedTurns = visible.slice();
|
|
7008
|
+
} else if (!sameWindow || env.chatLog.children.length !== visible.length + (earlier > 0 ? 1 : 0)) {
|
|
6852
7009
|
env.clearWaiting(env.chatLog);
|
|
7010
|
+
releasePreviewFrames(env.chatLog);
|
|
6853
7011
|
env.chatLog.textContent = "";
|
|
7012
|
+
if (earlier > 0) {
|
|
7013
|
+
var more = el("button", "dsh-sel-expand", "\u663E\u793A\u66F4\u65E9\u7684\u6D88\u606F\uFF08\u8FD8\u6709 " + earlier + " \u6761\uFF09");
|
|
7014
|
+
more.type = "button";
|
|
7015
|
+
more.setAttribute("data-history-more", "1");
|
|
7016
|
+
listen(more, "click", function(event) {
|
|
7017
|
+
event.preventDefault();
|
|
7018
|
+
event.stopPropagation();
|
|
7019
|
+
var top = env.body.scrollTop;
|
|
7020
|
+
var height = env.body.scrollHeight;
|
|
7021
|
+
turnWindowSize += 40;
|
|
7022
|
+
renderTurns({ preservePosition: true, prepend: true });
|
|
7023
|
+
env.body.scrollTop = top + Math.max(0, env.body.scrollHeight - height);
|
|
7024
|
+
env.state.follow = false;
|
|
7025
|
+
});
|
|
7026
|
+
env.chatLog.appendChild(more);
|
|
7027
|
+
}
|
|
6854
7028
|
for (var j = 0; j < visible.length; j++) {
|
|
6855
7029
|
var bubble = bubbleFor(visible[j]);
|
|
6856
7030
|
bubble.__turn = visible[j];
|
|
6857
7031
|
env.chatLog.appendChild(bubble);
|
|
6858
7032
|
}
|
|
7033
|
+
renderedTurns = visible.slice();
|
|
6859
7034
|
var fresh = visible[visible.length - 1];
|
|
6860
7035
|
if (fresh && fresh.role === "assistant" && fresh.asking === true && !fresh.text) {
|
|
6861
|
-
env.showWaiting(env.chatLog.children[
|
|
7036
|
+
env.showWaiting(env.chatLog.children[env.chatLog.children.length - 1], "\u6B63\u5728\u56DE\u7B54\u2026", {
|
|
6862
7037
|
startedAt: fresh.startedAt,
|
|
6863
7038
|
effort: fresh.effort,
|
|
6864
7039
|
effortOf: function() {
|
|
@@ -6870,7 +7045,7 @@ function createHistoryController(env) {
|
|
|
6870
7045
|
});
|
|
6871
7046
|
}
|
|
6872
7047
|
} else if (visible.length > 0) {
|
|
6873
|
-
var node = env.chatLog.children[
|
|
7048
|
+
var node = env.chatLog.children[env.chatLog.children.length - 1];
|
|
6874
7049
|
var turn = visible[visible.length - 1];
|
|
6875
7050
|
var painted = false;
|
|
6876
7051
|
node.className = "dsh-sel-bubble " + (turn.role === "user" ? "dsh-sel-bubble-user" : "dsh-sel-bubble-bot") + (turn.error ? " dsh-sel-bubble-err" : "");
|
|
@@ -7053,6 +7228,7 @@ function createHistoryController(env) {
|
|
|
7053
7228
|
return seed.length > 1500 ? seed.slice(0, 1500) + "\u2026" : seed;
|
|
7054
7229
|
}
|
|
7055
7230
|
return {
|
|
7231
|
+
clearRenderedTurns,
|
|
7056
7232
|
hideHistoryList,
|
|
7057
7233
|
placeHistoryList,
|
|
7058
7234
|
toggleHistoryList,
|
|
@@ -7085,13 +7261,6 @@ function createHistoryController(env) {
|
|
|
7085
7261
|
loadHistoryEntry,
|
|
7086
7262
|
seedHistoryFromExplanation,
|
|
7087
7263
|
ensureChatFollow,
|
|
7088
|
-
get FOLD_HISTORY_KEEP_LATEST() {
|
|
7089
|
-
return FOLD_HISTORY_KEEP_LATEST;
|
|
7090
|
-
},
|
|
7091
|
-
set FOLD_HISTORY_KEEP_LATEST(value) {
|
|
7092
|
-
FOLD_HISTORY_KEEP_LATEST = value;
|
|
7093
|
-
},
|
|
7094
|
-
historyTextOf,
|
|
7095
7264
|
clearTransientNotice,
|
|
7096
7265
|
saveHistory,
|
|
7097
7266
|
applyToolEvent,
|
|
@@ -7212,7 +7381,8 @@ function createConversationController(env) {
|
|
|
7212
7381
|
if (env.state.turns.length === 0 && (env.state.raw.trim() || env.state.parts.translation || env.state.parts.detail)) {
|
|
7213
7382
|
env.state.turns.push({ role: "assistant", text: env.seedHistoryFromExplanation(), seed: true, hidden: true });
|
|
7214
7383
|
}
|
|
7215
|
-
|
|
7384
|
+
var questionTurn = { role: "user", text: asked || QUOTE_ONLY_QUESTION, quotes, sent, attachments: withAttachments };
|
|
7385
|
+
env.state.turns.push(questionTurn);
|
|
7216
7386
|
var answerTurn = {
|
|
7217
7387
|
role: "assistant",
|
|
7218
7388
|
text: "",
|
|
@@ -7234,23 +7404,22 @@ function createConversationController(env) {
|
|
|
7234
7404
|
if (env.state.sessionOpen !== void 0) {
|
|
7235
7405
|
}
|
|
7236
7406
|
var startedAt = Date.now();
|
|
7237
|
-
var timer =
|
|
7407
|
+
var timer = env.timerScope.interval(function() {
|
|
7238
7408
|
env.paintPill();
|
|
7239
7409
|
env.setStatus(
|
|
7240
7410
|
(env.state.toolBusy ? "\u6B63\u5728\u68C0\u7D22\u8D44\u6599\u2026 " : "\u8FFD\u95EE\u4E2D\u2026 ") + ((Date.now() - startedAt) / 1e3).toFixed(1) + "s"
|
|
7241
7411
|
);
|
|
7242
7412
|
updateWaitClocks();
|
|
7243
7413
|
}, 200);
|
|
7244
|
-
env.timers.push(timer);
|
|
7245
7414
|
var historyTurns = env.state.turns.slice(0, env.state.turns.length - 2);
|
|
7246
|
-
var
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7415
|
+
var initialExplanation = env.state.skipInterpretation ? "" : env.seedHistoryFromExplanation();
|
|
7416
|
+
var source = contextSource(env.panelOrCurrentSessionId(), payload.text.trim(), payload.context, initialExplanation);
|
|
7417
|
+
if (env.state.contextState && env.state.contextState.source !== source) env.state.contextState = null;
|
|
7418
|
+
var prepared = prepareChatHistory(historyTurns, env.state.contextState);
|
|
7419
|
+
env.state.contextState = prepared.contextState;
|
|
7420
|
+
var history = prepared.history;
|
|
7421
|
+
var requestTurns = env.state.turns;
|
|
7422
|
+
var requestKey = env.state.cacheKey;
|
|
7254
7423
|
env.state.stopped = false;
|
|
7255
7424
|
var askController = new AbortController();
|
|
7256
7425
|
env.state.askRequest = {
|
|
@@ -7262,7 +7431,7 @@ function createConversationController(env) {
|
|
|
7262
7431
|
}
|
|
7263
7432
|
};
|
|
7264
7433
|
function finish(error) {
|
|
7265
|
-
|
|
7434
|
+
env.timerScope.clear(timer);
|
|
7266
7435
|
env.state.asking = false;
|
|
7267
7436
|
env.state.toolBusy = false;
|
|
7268
7437
|
env.clearTransientNotice(answerTurn);
|
|
@@ -7286,24 +7455,36 @@ function createConversationController(env) {
|
|
|
7286
7455
|
);
|
|
7287
7456
|
env.askFocusAfterTurn();
|
|
7288
7457
|
}
|
|
7458
|
+
var requestBody = JSON.stringify({
|
|
7459
|
+
text: payload.text,
|
|
7460
|
+
context: payload.context,
|
|
7461
|
+
label: payload.label,
|
|
7462
|
+
sessionId: env.panelOrCurrentSessionId(),
|
|
7463
|
+
question: sent,
|
|
7464
|
+
history,
|
|
7465
|
+
key: requestKey,
|
|
7466
|
+
historyStart: prepared.historyStart,
|
|
7467
|
+
contextState: prepared.contextState,
|
|
7468
|
+
materials: prepared.materials,
|
|
7469
|
+
initialExplanation,
|
|
7470
|
+
// 附件只带**引用**(图片/文件都已经在 host 的附件服务里),body 不会因为一张截图胖几 MB
|
|
7471
|
+
...withAttachments.length > 0 ? { attachments: withAttachments } : {},
|
|
7472
|
+
// 网页输出要跟着当前深浅走:深色 Harness 里给一张白底页面会很刺眼
|
|
7473
|
+
...env.state.webAnswer ? { webAnswer: true, theme: env.currentSurfaceTheme() } : {},
|
|
7474
|
+
...env.state.modelChoice ? { provider: env.state.modelChoice.provider, model: env.state.modelChoice.model } : {},
|
|
7475
|
+
...env.state.effort ? { effort: env.state.effort } : {},
|
|
7476
|
+
...env.state.toolDigest ? { toolDigest: env.state.toolDigest } : {}
|
|
7477
|
+
});
|
|
7478
|
+
if (new TextEncoder().encode(requestBody).byteLength > CHAT_REQUEST_BYTES) {
|
|
7479
|
+
questionTurn.contextExcluded = true;
|
|
7480
|
+
answerTurn.contextExcluded = true;
|
|
7481
|
+
finish("\u672C\u8F6E\u6750\u6599\u8D85\u8FC7\u8BF7\u6C42\u5BB9\u91CF\uFF0C\u8BF7\u7F29\u5C0F\u63D0\u95EE\u6216\u5F15\u7528\u8303\u56F4\uFF1B\u539F\u6587\u4ECD\u4FDD\u7559\u5728\u5F53\u524D\u5386\u53F2\u4E2D");
|
|
7482
|
+
return;
|
|
7483
|
+
}
|
|
7289
7484
|
fetch(API, {
|
|
7290
7485
|
method: "POST",
|
|
7291
7486
|
headers: { "content-type": "application/json" },
|
|
7292
|
-
body:
|
|
7293
|
-
text: payload.text,
|
|
7294
|
-
context: payload.context,
|
|
7295
|
-
label: payload.label,
|
|
7296
|
-
sessionId: env.panelOrCurrentSessionId(),
|
|
7297
|
-
question: sent,
|
|
7298
|
-
history,
|
|
7299
|
-
// 附件只带**引用**(图片/文件都已经在 host 的附件服务里),body 不会因为一张截图胖几 MB
|
|
7300
|
-
...withAttachments.length > 0 ? { attachments: withAttachments } : {},
|
|
7301
|
-
// 网页输出要跟着当前深浅走:深色 Harness 里给一张白底页面会很刺眼
|
|
7302
|
-
...env.state.webAnswer ? { webAnswer: true, theme: env.currentSurfaceTheme() } : {},
|
|
7303
|
-
...env.state.modelChoice ? { provider: env.state.modelChoice.provider, model: env.state.modelChoice.model } : {},
|
|
7304
|
-
...env.state.effort ? { effort: env.state.effort } : {},
|
|
7305
|
-
...env.state.toolDigest ? { toolDigest: env.state.toolDigest } : {}
|
|
7306
|
-
}),
|
|
7487
|
+
body: requestBody,
|
|
7307
7488
|
signal: askController.signal
|
|
7308
7489
|
}).then(function(response) {
|
|
7309
7490
|
if (!response.ok) {
|
|
@@ -7329,7 +7510,18 @@ function createConversationController(env) {
|
|
|
7329
7510
|
} catch (error) {
|
|
7330
7511
|
continue;
|
|
7331
7512
|
}
|
|
7332
|
-
if (message.type === "
|
|
7513
|
+
if (message.type === "context-state") {
|
|
7514
|
+
if (!askController.signal.aborted && env.state.turns === requestTurns && env.state.cacheKey === requestKey) {
|
|
7515
|
+
env.state.contextState = readContextState(message.state);
|
|
7516
|
+
}
|
|
7517
|
+
} else if (message.type === "material-restored") {
|
|
7518
|
+
var material = message.attachment;
|
|
7519
|
+
if (!askController.signal.aborted && material && (material.kind === "image" || material.kind === "file") && material.ref && material.ref.attachmentId) {
|
|
7520
|
+
if (!questionTurn.attachments.some(function(a) {
|
|
7521
|
+
return a.kind === material.kind && a.ref.attachmentId === material.ref.attachmentId;
|
|
7522
|
+
})) questionTurn.attachments.push(material);
|
|
7523
|
+
}
|
|
7524
|
+
} else if (message.type === "delta") {
|
|
7333
7525
|
env.clearTransientNotice(answerTurn);
|
|
7334
7526
|
if (!answerTurn.text.trim()) answerTurn.asking = false;
|
|
7335
7527
|
answerTurn.text += message.text;
|
|
@@ -7368,6 +7560,10 @@ function createConversationController(env) {
|
|
|
7368
7560
|
}
|
|
7369
7561
|
scheduleTurnsRender();
|
|
7370
7562
|
} else if (message.type === "error") {
|
|
7563
|
+
if (message.code === "context-rejected") {
|
|
7564
|
+
questionTurn.contextExcluded = true;
|
|
7565
|
+
answerTurn.contextExcluded = true;
|
|
7566
|
+
}
|
|
7371
7567
|
finish(message.message || "\u6A21\u578B\u8FD4\u56DE\u9519\u8BEF");
|
|
7372
7568
|
}
|
|
7373
7569
|
}
|
|
@@ -7525,16 +7721,15 @@ function createConversationController(env) {
|
|
|
7525
7721
|
env.state.startedAt = Date.now();
|
|
7526
7722
|
env.state.elapsed = 0;
|
|
7527
7723
|
env.paint();
|
|
7528
|
-
var ticker =
|
|
7724
|
+
var ticker = env.timerScope.interval(function() {
|
|
7529
7725
|
env.paintPill();
|
|
7530
7726
|
if (env.state.phase === "loading" || env.state.phase === "streaming") {
|
|
7531
7727
|
env.setStatus(env.progressText());
|
|
7532
7728
|
updateWaitClocks();
|
|
7533
7729
|
}
|
|
7534
7730
|
}, 200);
|
|
7535
|
-
env.timers.push(ticker);
|
|
7536
7731
|
function stopTicker() {
|
|
7537
|
-
|
|
7732
|
+
env.timerScope.clear(ticker);
|
|
7538
7733
|
}
|
|
7539
7734
|
function fail(message) {
|
|
7540
7735
|
if (env.state.phase === "done") return;
|
|
@@ -9123,6 +9318,101 @@ function createVoiceController(env) {
|
|
|
9123
9318
|
};
|
|
9124
9319
|
}
|
|
9125
9320
|
|
|
9321
|
+
// src/client/memory.js
|
|
9322
|
+
function createResultCache(maxEntries = 20, maxBytes = 8 * 1024 * 1024) {
|
|
9323
|
+
const entries = /* @__PURE__ */ new Map();
|
|
9324
|
+
let textBytes = 0;
|
|
9325
|
+
let disposed = false;
|
|
9326
|
+
function remove(key) {
|
|
9327
|
+
const entry = entries.get(key);
|
|
9328
|
+
if (!entry) return;
|
|
9329
|
+
textBytes -= entry.bytes;
|
|
9330
|
+
entries.delete(key);
|
|
9331
|
+
}
|
|
9332
|
+
const cache = {
|
|
9333
|
+
get size() {
|
|
9334
|
+
return entries.size;
|
|
9335
|
+
},
|
|
9336
|
+
// Conservative UTF-16 size of serialized text, not a measurement of JS heap size.
|
|
9337
|
+
get textBytes() {
|
|
9338
|
+
return textBytes;
|
|
9339
|
+
},
|
|
9340
|
+
keys() {
|
|
9341
|
+
return entries.keys();
|
|
9342
|
+
},
|
|
9343
|
+
get(key) {
|
|
9344
|
+
const entry = entries.get(key);
|
|
9345
|
+
if (!entry) return void 0;
|
|
9346
|
+
entries.delete(key);
|
|
9347
|
+
entries.set(key, entry);
|
|
9348
|
+
return JSON.parse(entry.json);
|
|
9349
|
+
},
|
|
9350
|
+
set(key, value) {
|
|
9351
|
+
if (disposed) return cache;
|
|
9352
|
+
remove(key);
|
|
9353
|
+
let json;
|
|
9354
|
+
try {
|
|
9355
|
+
json = JSON.stringify(value);
|
|
9356
|
+
} catch {
|
|
9357
|
+
return cache;
|
|
9358
|
+
}
|
|
9359
|
+
if (typeof json !== "string") return cache;
|
|
9360
|
+
const bytes = (String(key).length + json.length) * 2;
|
|
9361
|
+
if (bytes > maxBytes || maxEntries <= 0) return cache;
|
|
9362
|
+
entries.set(key, { json, bytes });
|
|
9363
|
+
textBytes += bytes;
|
|
9364
|
+
while (entries.size > maxEntries || textBytes > maxBytes) remove(entries.keys().next().value);
|
|
9365
|
+
return cache;
|
|
9366
|
+
},
|
|
9367
|
+
clear() {
|
|
9368
|
+
entries.clear();
|
|
9369
|
+
textBytes = 0;
|
|
9370
|
+
},
|
|
9371
|
+
dispose() {
|
|
9372
|
+
disposed = true;
|
|
9373
|
+
cache.clear();
|
|
9374
|
+
}
|
|
9375
|
+
};
|
|
9376
|
+
return cache;
|
|
9377
|
+
}
|
|
9378
|
+
function createTimerScope() {
|
|
9379
|
+
const active = /* @__PURE__ */ new Set();
|
|
9380
|
+
let disposed = false;
|
|
9381
|
+
return {
|
|
9382
|
+
get size() {
|
|
9383
|
+
return active.size;
|
|
9384
|
+
},
|
|
9385
|
+
later(fn, ms) {
|
|
9386
|
+
if (disposed) return null;
|
|
9387
|
+
const id = setTimeout(() => {
|
|
9388
|
+
active.delete(id);
|
|
9389
|
+
if (!disposed) fn();
|
|
9390
|
+
}, ms);
|
|
9391
|
+
active.add(id);
|
|
9392
|
+
return id;
|
|
9393
|
+
},
|
|
9394
|
+
interval(fn, ms) {
|
|
9395
|
+
if (disposed) return null;
|
|
9396
|
+
const id = setInterval(fn, ms);
|
|
9397
|
+
active.add(id);
|
|
9398
|
+
return id;
|
|
9399
|
+
},
|
|
9400
|
+
clear(id) {
|
|
9401
|
+
clearTimeout(id);
|
|
9402
|
+
clearInterval(id);
|
|
9403
|
+
active.delete(id);
|
|
9404
|
+
},
|
|
9405
|
+
dispose() {
|
|
9406
|
+
disposed = true;
|
|
9407
|
+
active.forEach((id) => {
|
|
9408
|
+
clearTimeout(id);
|
|
9409
|
+
clearInterval(id);
|
|
9410
|
+
});
|
|
9411
|
+
active.clear();
|
|
9412
|
+
}
|
|
9413
|
+
};
|
|
9414
|
+
}
|
|
9415
|
+
|
|
9126
9416
|
// src/client/index.js
|
|
9127
9417
|
function apply(ctx) {
|
|
9128
9418
|
var state = {
|
|
@@ -9235,7 +9525,8 @@ function apply(ctx) {
|
|
|
9235
9525
|
/** 升格请求进行中。 */
|
|
9236
9526
|
promoting: false
|
|
9237
9527
|
};
|
|
9238
|
-
var cache =
|
|
9528
|
+
var cache = createResultCache();
|
|
9529
|
+
var timerScope = createTimerScope();
|
|
9239
9530
|
var styleEl = el("style");
|
|
9240
9531
|
styleEl.setAttribute("data-plugin", "@yfwu2020/dsh-selection-explain");
|
|
9241
9532
|
styleEl.textContent = CSS;
|
|
@@ -9670,8 +9961,8 @@ function apply(ctx) {
|
|
|
9670
9961
|
get frameTouchedAt() {
|
|
9671
9962
|
return previewController.frameTouchedAt;
|
|
9672
9963
|
},
|
|
9673
|
-
get
|
|
9674
|
-
return
|
|
9964
|
+
get timerScope() {
|
|
9965
|
+
return timerScope;
|
|
9675
9966
|
},
|
|
9676
9967
|
get voice() {
|
|
9677
9968
|
return voiceController.voice;
|
|
@@ -9696,6 +9987,9 @@ function apply(ctx) {
|
|
|
9696
9987
|
}
|
|
9697
9988
|
});
|
|
9698
9989
|
var quotesController = createQuotesController({
|
|
9990
|
+
get foldForHistory() {
|
|
9991
|
+
return historyController.foldForHistory;
|
|
9992
|
+
},
|
|
9699
9993
|
get state() {
|
|
9700
9994
|
return state;
|
|
9701
9995
|
},
|
|
@@ -9729,8 +10023,8 @@ function apply(ctx) {
|
|
|
9729
10023
|
get currentSessionId() {
|
|
9730
10024
|
return panelController.currentSessionId;
|
|
9731
10025
|
},
|
|
9732
|
-
get
|
|
9733
|
-
return
|
|
10026
|
+
get timerScope() {
|
|
10027
|
+
return timerScope;
|
|
9734
10028
|
}
|
|
9735
10029
|
});
|
|
9736
10030
|
var previewController = createPreviewController({
|
|
@@ -9751,6 +10045,9 @@ function apply(ctx) {
|
|
|
9751
10045
|
}
|
|
9752
10046
|
});
|
|
9753
10047
|
var panelController = createPanelController({
|
|
10048
|
+
get timerScope() {
|
|
10049
|
+
return timerScope;
|
|
10050
|
+
},
|
|
9754
10051
|
get panelSessionId() {
|
|
9755
10052
|
return panelSessionId;
|
|
9756
10053
|
},
|
|
@@ -9787,6 +10084,12 @@ function apply(ctx) {
|
|
|
9787
10084
|
get renderTurns() {
|
|
9788
10085
|
return historyController.renderTurns;
|
|
9789
10086
|
},
|
|
10087
|
+
get clearRenderedTurns() {
|
|
10088
|
+
return historyController.clearRenderedTurns;
|
|
10089
|
+
},
|
|
10090
|
+
get clearWaiting() {
|
|
10091
|
+
return conversationController.clearWaiting;
|
|
10092
|
+
},
|
|
9790
10093
|
get sendAsk() {
|
|
9791
10094
|
return conversationController.sendAsk;
|
|
9792
10095
|
},
|
|
@@ -10046,6 +10349,9 @@ function apply(ctx) {
|
|
|
10046
10349
|
}
|
|
10047
10350
|
});
|
|
10048
10351
|
var historyController = createHistoryController({
|
|
10352
|
+
set panelSessionId(value) {
|
|
10353
|
+
panelSessionId = value;
|
|
10354
|
+
},
|
|
10049
10355
|
get sentTextOf() {
|
|
10050
10356
|
return quotesController.sentTextOf;
|
|
10051
10357
|
},
|
|
@@ -10076,8 +10382,8 @@ function apply(ctx) {
|
|
|
10076
10382
|
get paint() {
|
|
10077
10383
|
return panelController.paint;
|
|
10078
10384
|
},
|
|
10079
|
-
get
|
|
10080
|
-
return
|
|
10385
|
+
get timerScope() {
|
|
10386
|
+
return timerScope;
|
|
10081
10387
|
},
|
|
10082
10388
|
get panelOpen() {
|
|
10083
10389
|
return panelOpen;
|
|
@@ -10207,14 +10513,8 @@ function apply(ctx) {
|
|
|
10207
10513
|
get paintPill() {
|
|
10208
10514
|
return pillController.paintPill;
|
|
10209
10515
|
},
|
|
10210
|
-
get
|
|
10211
|
-
return
|
|
10212
|
-
},
|
|
10213
|
-
get FOLD_HISTORY_KEEP_LATEST() {
|
|
10214
|
-
return historyController.FOLD_HISTORY_KEEP_LATEST;
|
|
10215
|
-
},
|
|
10216
|
-
get historyTextOf() {
|
|
10217
|
-
return historyController.historyTextOf;
|
|
10516
|
+
get timerScope() {
|
|
10517
|
+
return timerScope;
|
|
10218
10518
|
},
|
|
10219
10519
|
get clearTransientNotice() {
|
|
10220
10520
|
return historyController.clearTransientNotice;
|
|
@@ -10488,7 +10788,6 @@ function apply(ctx) {
|
|
|
10488
10788
|
var STREAM_RENDER_MS = 90;
|
|
10489
10789
|
var turnsRenderPending = false;
|
|
10490
10790
|
var lastTurnsRenderAt = 0;
|
|
10491
|
-
var timers = [];
|
|
10492
10791
|
var PILL_POLL_MIN = 2e3;
|
|
10493
10792
|
var PILL_POLL_MAX = 6e4;
|
|
10494
10793
|
var pillPollDelay = PILL_POLL_MIN;
|
|
@@ -10508,9 +10807,7 @@ function apply(ctx) {
|
|
|
10508
10807
|
var pillObserver = null;
|
|
10509
10808
|
var waitList = [];
|
|
10510
10809
|
function later(fn, ms) {
|
|
10511
|
-
|
|
10512
|
-
timers.push(id);
|
|
10513
|
-
return id;
|
|
10810
|
+
return timerScope.later(fn, ms);
|
|
10514
10811
|
}
|
|
10515
10812
|
var offBridgeMessage = listen(window, "message", function(event) {
|
|
10516
10813
|
var data = event && event.data;
|
|
@@ -11080,6 +11377,14 @@ function apply(ctx) {
|
|
|
11080
11377
|
turns: function() {
|
|
11081
11378
|
return state.turns.slice();
|
|
11082
11379
|
},
|
|
11380
|
+
memory: function() {
|
|
11381
|
+
return {
|
|
11382
|
+
cacheEntries: cache.size,
|
|
11383
|
+
cacheTextBytes: cache.textBytes,
|
|
11384
|
+
timers: timerScope.size,
|
|
11385
|
+
previewFrames: Object.keys(previewFrames).length
|
|
11386
|
+
};
|
|
11387
|
+
},
|
|
11083
11388
|
/** 自检用:当前待发送的引用(引用区里那几张卡片)。 */
|
|
11084
11389
|
quotes: function() {
|
|
11085
11390
|
return state.quotes.map(function(quote2) {
|
|
@@ -11424,6 +11729,7 @@ function apply(ctx) {
|
|
|
11424
11729
|
state.selection = null;
|
|
11425
11730
|
state.bridgeActive = false;
|
|
11426
11731
|
state.parts = { translation: "", detail: "" };
|
|
11732
|
+
state.contextState = null;
|
|
11427
11733
|
state.turns = [];
|
|
11428
11734
|
quotesController.clearQuotes();
|
|
11429
11735
|
state.raw = "";
|
|
@@ -11451,6 +11757,13 @@ function apply(ctx) {
|
|
|
11451
11757
|
console.log("[dsh-selection-explain] \u5212\u8BCD\u89E3\u8BFB\u5DF2\u5C31\u7EEA\uFF08\u9009\u4E2D\u6587\u5B57\u8BD5\u8BD5\uFF09");
|
|
11452
11758
|
}
|
|
11453
11759
|
return function() {
|
|
11760
|
+
panelOpen = false;
|
|
11761
|
+
timerScope.dispose();
|
|
11762
|
+
cache.dispose();
|
|
11763
|
+
voiceCardController.closeVCard(false);
|
|
11764
|
+
attachController.clear();
|
|
11765
|
+
panelController.releaseRenderedContent();
|
|
11766
|
+
if (state.askRequest) state.askRequest.abort();
|
|
11454
11767
|
offPopEnd();
|
|
11455
11768
|
offQuotePopEnd();
|
|
11456
11769
|
offMouseUp();
|
|
@@ -11538,13 +11851,17 @@ function apply(ctx) {
|
|
|
11538
11851
|
}
|
|
11539
11852
|
});
|
|
11540
11853
|
previewController.bridged.clear();
|
|
11854
|
+
previewController.frameTouchedAt.clear();
|
|
11541
11855
|
state.turns = [];
|
|
11542
11856
|
state.quotes = [];
|
|
11857
|
+
state.selection = null;
|
|
11858
|
+
state.quoteSelection = null;
|
|
11859
|
+
state.payload = null;
|
|
11860
|
+
state.parts = { translation: "", detail: "" };
|
|
11861
|
+
state.raw = "";
|
|
11543
11862
|
if (state.request) state.request.abort();
|
|
11544
|
-
for (var i = 0; i < timers.length; i++) clearTimeout(timers[i]);
|
|
11545
11863
|
if (pillIdleId) clearTimeout(pillIdleId);
|
|
11546
11864
|
if (pillController.pillStarTimer) clearTimeout(pillController.pillStarTimer);
|
|
11547
|
-
cache.clear();
|
|
11548
11865
|
if (layer.parentNode) layer.parentNode.removeChild(layer);
|
|
11549
11866
|
if (button.parentNode) button.parentNode.removeChild(button);
|
|
11550
11867
|
if (quoteButton.parentNode) quoteButton.parentNode.removeChild(quoteButton);
|