@yfwu2020/dsh-selection-explain 0.11.0 → 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 +463 -115
- 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 +77 -45
- 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/mic.js +51 -6
- package/lib/host/mic.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 +6 -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 {
|
|
@@ -5015,8 +5037,9 @@ function createPanelController(env) {
|
|
|
5015
5037
|
env.state.selection = null;
|
|
5016
5038
|
}
|
|
5017
5039
|
function openPanelWithInner(text, context, label, anchor, keyContext, options) {
|
|
5018
|
-
env.state.
|
|
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();
|
|
@@ -5050,6 +5073,7 @@ function createPanelController(env) {
|
|
|
5050
5073
|
}
|
|
5051
5074
|
env.renderTurns();
|
|
5052
5075
|
if (cached) {
|
|
5076
|
+
env.state.skipInterpretation = false;
|
|
5053
5077
|
env.state.turns = (cached.turns || []).slice();
|
|
5054
5078
|
env.state.phase = "done";
|
|
5055
5079
|
env.state.stage = "";
|
|
@@ -5281,12 +5305,12 @@ function createPanelController(env) {
|
|
|
5281
5305
|
env.panel.style.transition = "transform " + PANEL_GROW_MS + "ms " + PANEL_GROW_EASE;
|
|
5282
5306
|
env.panel.style.transform = "none";
|
|
5283
5307
|
if (env.panelGrowTimer) {
|
|
5284
|
-
|
|
5308
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5285
5309
|
env.panelGrowTimer = null;
|
|
5286
5310
|
}
|
|
5287
5311
|
var settle = function() {
|
|
5288
5312
|
if (env.panelGrowTimer) {
|
|
5289
|
-
|
|
5313
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5290
5314
|
env.panelGrowTimer = null;
|
|
5291
5315
|
}
|
|
5292
5316
|
if (env.panelGrowHandler) {
|
|
@@ -5309,7 +5333,7 @@ function createPanelController(env) {
|
|
|
5309
5333
|
env.panelOpen = false;
|
|
5310
5334
|
env.panel.style.display = "none";
|
|
5311
5335
|
if (env.panelGrowTimer) {
|
|
5312
|
-
|
|
5336
|
+
env.timerScope.clear(env.panelGrowTimer);
|
|
5313
5337
|
env.panelGrowTimer = null;
|
|
5314
5338
|
}
|
|
5315
5339
|
if (env.panelGrowHandler) {
|
|
@@ -5327,6 +5351,11 @@ function createPanelController(env) {
|
|
|
5327
5351
|
if (env.state.request) env.state.aborted = true;
|
|
5328
5352
|
if (env.state.request) env.state.request.abort();
|
|
5329
5353
|
env.state.request = null;
|
|
5354
|
+
if (env.state.askRequest) {
|
|
5355
|
+
env.state.stopped = true;
|
|
5356
|
+
env.state.askRequest.abort();
|
|
5357
|
+
}
|
|
5358
|
+
releaseRenderedContent();
|
|
5330
5359
|
env.paintPill();
|
|
5331
5360
|
env.syncRouteWatch();
|
|
5332
5361
|
}
|
|
@@ -5340,7 +5369,7 @@ function createPanelController(env) {
|
|
|
5340
5369
|
for (var i = 0; i < env.state.turns.length; i += 1) {
|
|
5341
5370
|
if (env.state.turns[i].role === "user") asked = true;
|
|
5342
5371
|
}
|
|
5343
|
-
env.expandButton.style.display = !hasDetail && translationReady && !asked && !env.state.
|
|
5372
|
+
env.expandButton.style.display = !hasDetail && translationReady && !asked && !env.state.skipInterpretation ? "" : "none";
|
|
5344
5373
|
env.expandButton.disabled = false;
|
|
5345
5374
|
return asked;
|
|
5346
5375
|
}
|
|
@@ -5355,14 +5384,35 @@ function createPanelController(env) {
|
|
|
5355
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";
|
|
5356
5385
|
return what + " " + seconds + "s";
|
|
5357
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
|
+
}
|
|
5358
5395
|
function paint() {
|
|
5396
|
+
if (!env.panelOpen) {
|
|
5397
|
+
releaseRenderedContent();
|
|
5398
|
+
env.paintPill();
|
|
5399
|
+
return;
|
|
5400
|
+
}
|
|
5359
5401
|
var streaming = env.state.phase === "loading" || env.state.phase === "streaming";
|
|
5360
5402
|
var stage = env.state.stage;
|
|
5361
5403
|
var selected = env.state.payload && env.state.payload.text ? env.state.payload.text : env.state.selection ? env.state.selection.text : "";
|
|
5362
5404
|
var sections = splitSections(env.visibleRaw());
|
|
5363
|
-
env.translationSection.root.style.display = env.state.voiceAsk ? "none" : "";
|
|
5364
5405
|
var live = stripEchoPrefix(stage === "detail" ? "" : sections.translation || sections.other, selected);
|
|
5365
5406
|
var liveDetail = (sections.detail || sections.other || "").trim();
|
|
5407
|
+
var askedSoFar = false;
|
|
5408
|
+
for (var qi = 0; qi < env.state.turns.length; qi += 1) {
|
|
5409
|
+
if (env.state.turns[qi].role === "user") {
|
|
5410
|
+
askedSoFar = true;
|
|
5411
|
+
break;
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
var emptyInterpretation = !env.state.parts.translation && !env.state.parts.detail && !live.trim();
|
|
5415
|
+
env.translationSection.root.style.display = env.state.skipInterpretation || emptyInterpretation && askedSoFar ? "none" : "";
|
|
5366
5416
|
if (env.state.parts.translation) {
|
|
5367
5417
|
renderRich(env.translationSection.content, stripEchoPrefix(env.state.parts.translation, selected), { callout: true, settled: true });
|
|
5368
5418
|
} else if (stage !== "detail" && live.trim()) {
|
|
@@ -5423,7 +5473,7 @@ function createPanelController(env) {
|
|
|
5423
5473
|
var surfaceTheme = env.currentSurfaceTheme();
|
|
5424
5474
|
env.layer.setAttribute("data-theme", surfaceTheme);
|
|
5425
5475
|
env.panel.setAttribute("data-theme", surfaceTheme);
|
|
5426
|
-
env.askRow.style.display = wide || translationReady || env.state.
|
|
5476
|
+
env.askRow.style.display = wide || translationReady || env.state.skipInterpretation || env.state.quotes.length > 0 ? "" : "none";
|
|
5427
5477
|
syncExpandCta();
|
|
5428
5478
|
env.closeButton.title = "\u5173\u95ED\uFF08Esc\uFF09";
|
|
5429
5479
|
if (env.state.phase !== "error" && env.state.phase !== "paused" && env.retryButton.parentNode) {
|
|
@@ -5546,6 +5596,7 @@ function createPanelController(env) {
|
|
|
5546
5596
|
env.panel.style.top = Math.round(top) + "px";
|
|
5547
5597
|
}
|
|
5548
5598
|
return {
|
|
5599
|
+
releaseRenderedContent,
|
|
5549
5600
|
openForSelection,
|
|
5550
5601
|
currentSessionId,
|
|
5551
5602
|
loadPanelSize,
|
|
@@ -6134,9 +6185,69 @@ function createPillController(env) {
|
|
|
6134
6185
|
};
|
|
6135
6186
|
}
|
|
6136
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
|
+
|
|
6137
6249
|
// src/client/history.js
|
|
6138
6250
|
function createHistoryController(env) {
|
|
6139
|
-
var FOLD_HISTORY_KEEP_LATEST = true;
|
|
6140
6251
|
var foldCount = 0;
|
|
6141
6252
|
var HTML_VOID_TAGS = {
|
|
6142
6253
|
area: 1,
|
|
@@ -6417,16 +6528,6 @@ function createHistoryController(env) {
|
|
|
6417
6528
|
src = src.replace(/```html[ \t]*\n([\s\S]*)$/, one);
|
|
6418
6529
|
return src;
|
|
6419
6530
|
}
|
|
6420
|
-
function historyTextOf(turn, keepRaw) {
|
|
6421
|
-
if (!turn) return "";
|
|
6422
|
-
if (turn.role === "user") return env.sentTextOf(turn);
|
|
6423
|
-
if (keepRaw) return turn.text;
|
|
6424
|
-
if (typeof turn.foldedCache === "string") return turn.foldedCache;
|
|
6425
|
-
if (turn.streaming === true) return turn.text;
|
|
6426
|
-
var folded = foldForHistory(turn.text);
|
|
6427
|
-
turn.foldedCache = folded;
|
|
6428
|
-
return folded;
|
|
6429
|
-
}
|
|
6430
6531
|
function currentSurfaceTheme() {
|
|
6431
6532
|
try {
|
|
6432
6533
|
var bodyEl = document.body;
|
|
@@ -6455,6 +6556,7 @@ function createHistoryController(env) {
|
|
|
6455
6556
|
function visibleRaw() {
|
|
6456
6557
|
return env.state.raw;
|
|
6457
6558
|
}
|
|
6559
|
+
var historySaveSequence = 0;
|
|
6458
6560
|
function saveHistory(options) {
|
|
6459
6561
|
var payload = env.state.payload;
|
|
6460
6562
|
if (!payload || !env.state.cacheKey) return;
|
|
@@ -6465,6 +6567,22 @@ function createHistoryController(env) {
|
|
|
6465
6567
|
if (turn.hidden === true) continue;
|
|
6466
6568
|
turns.push(exported[i]);
|
|
6467
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
|
+
}
|
|
6468
6586
|
try {
|
|
6469
6587
|
fetch(HISTORY, {
|
|
6470
6588
|
method: "POST",
|
|
@@ -6477,16 +6595,40 @@ function createHistoryController(env) {
|
|
|
6477
6595
|
parts: env.state.parts,
|
|
6478
6596
|
turns,
|
|
6479
6597
|
toolDigest: env.state.toolDigest,
|
|
6480
|
-
|
|
6598
|
+
contextState: env.state.contextState || null,
|
|
6599
|
+
pinned: !!(options && options.pinned),
|
|
6600
|
+
// 这段对话有没有解读,必须跟着条目落盘:回放时靠它决定画不画「翻译」一节。
|
|
6601
|
+
// 不落盘的话,语音卡那条"跳过翻译与详解、直接追问"的对话下次开出来,
|
|
6602
|
+
// 会顶着一张空翻译卡片("这次没有返回内容")——用户实测。
|
|
6603
|
+
skipped: env.state.skipInterpretation === true
|
|
6481
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);
|
|
6482
6610
|
}).catch(function() {
|
|
6611
|
+
noteSaved(true);
|
|
6483
6612
|
});
|
|
6484
6613
|
} catch (error) {
|
|
6614
|
+
noteSaved(true);
|
|
6485
6615
|
}
|
|
6486
6616
|
}
|
|
6487
6617
|
function applyHistoryEntry(entry, source) {
|
|
6488
6618
|
var parts = entry.parts || {};
|
|
6489
6619
|
env.state.parts = { translation: parts.translation || "", detail: parts.detail || "" };
|
|
6620
|
+
var replayTurns = Array.isArray(entry.turns) ? entry.turns : [];
|
|
6621
|
+
var hasAskTurn = false;
|
|
6622
|
+
for (var step = 0; step < replayTurns.length; step += 1) {
|
|
6623
|
+
if (replayTurns[step] && replayTurns[step].role === "user") {
|
|
6624
|
+
hasAskTurn = true;
|
|
6625
|
+
break;
|
|
6626
|
+
}
|
|
6627
|
+
}
|
|
6628
|
+
var noInterpretation = !String(parts.translation || "").trim() && !String(parts.detail || "").trim();
|
|
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;
|
|
6490
6632
|
env.state.turns = Array.isArray(entry.turns) ? entry.turns.slice() : [];
|
|
6491
6633
|
env.clearQuotes();
|
|
6492
6634
|
env.state.toolDigest = typeof entry.toolDigest === "string" ? entry.toolDigest : "";
|
|
@@ -6518,8 +6660,7 @@ function createHistoryController(env) {
|
|
|
6518
6660
|
settled = true;
|
|
6519
6661
|
if (env.state.cacheKey === cacheKey && onMiss) onMiss();
|
|
6520
6662
|
}
|
|
6521
|
-
var timer =
|
|
6522
|
-
env.timers.push(timer);
|
|
6663
|
+
var timer = env.timerScope.later(miss, 1500);
|
|
6523
6664
|
try {
|
|
6524
6665
|
fetch(HISTORY + "?key=" + encodeURIComponent(cacheKey)).then(function(response) {
|
|
6525
6666
|
return response.json();
|
|
@@ -6531,7 +6672,7 @@ function createHistoryController(env) {
|
|
|
6531
6672
|
}
|
|
6532
6673
|
if (data && data.ok === true && data.entry) {
|
|
6533
6674
|
settled = true;
|
|
6534
|
-
|
|
6675
|
+
env.timerScope.clear(timer);
|
|
6535
6676
|
applyHistoryEntry(data.entry, "history");
|
|
6536
6677
|
return;
|
|
6537
6678
|
}
|
|
@@ -6686,7 +6827,7 @@ function createHistoryController(env) {
|
|
|
6686
6827
|
});
|
|
6687
6828
|
bar.appendChild(undo);
|
|
6688
6829
|
env.historyList.appendChild(bar);
|
|
6689
|
-
|
|
6830
|
+
env.timerScope.later(function() {
|
|
6690
6831
|
if (bar.parentNode) bar.parentNode.removeChild(bar);
|
|
6691
6832
|
}, 5e3);
|
|
6692
6833
|
}
|
|
@@ -6818,24 +6959,81 @@ function createHistoryController(env) {
|
|
|
6818
6959
|
if (Date.now() - stickAt < 150) return;
|
|
6819
6960
|
env.state.follow = nearBottom();
|
|
6820
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
|
+
}
|
|
6821
6973
|
function renderTurns(options) {
|
|
6974
|
+
if (!env.panelOpen) {
|
|
6975
|
+
clearRenderedTurns();
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6822
6978
|
var force = !!(options && options.stick === true);
|
|
6823
|
-
var stick = force || nearBottom();
|
|
6979
|
+
var stick = !(options && options.preservePosition) && (force || nearBottom());
|
|
6824
6980
|
var visible = [];
|
|
6825
6981
|
for (var i = 0; i < env.state.turns.length; i++) {
|
|
6826
6982
|
if (env.state.turns[i].hidden !== true) visible.push(env.state.turns[i]);
|
|
6827
6983
|
}
|
|
6828
|
-
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)) {
|
|
6829
7009
|
env.clearWaiting(env.chatLog);
|
|
7010
|
+
releasePreviewFrames(env.chatLog);
|
|
6830
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
|
+
}
|
|
6831
7028
|
for (var j = 0; j < visible.length; j++) {
|
|
6832
7029
|
var bubble = bubbleFor(visible[j]);
|
|
6833
7030
|
bubble.__turn = visible[j];
|
|
6834
7031
|
env.chatLog.appendChild(bubble);
|
|
6835
7032
|
}
|
|
7033
|
+
renderedTurns = visible.slice();
|
|
6836
7034
|
var fresh = visible[visible.length - 1];
|
|
6837
7035
|
if (fresh && fresh.role === "assistant" && fresh.asking === true && !fresh.text) {
|
|
6838
|
-
env.showWaiting(env.chatLog.children[
|
|
7036
|
+
env.showWaiting(env.chatLog.children[env.chatLog.children.length - 1], "\u6B63\u5728\u56DE\u7B54\u2026", {
|
|
6839
7037
|
startedAt: fresh.startedAt,
|
|
6840
7038
|
effort: fresh.effort,
|
|
6841
7039
|
effortOf: function() {
|
|
@@ -6847,7 +7045,7 @@ function createHistoryController(env) {
|
|
|
6847
7045
|
});
|
|
6848
7046
|
}
|
|
6849
7047
|
} else if (visible.length > 0) {
|
|
6850
|
-
var node = env.chatLog.children[
|
|
7048
|
+
var node = env.chatLog.children[env.chatLog.children.length - 1];
|
|
6851
7049
|
var turn = visible[visible.length - 1];
|
|
6852
7050
|
var painted = false;
|
|
6853
7051
|
node.className = "dsh-sel-bubble " + (turn.role === "user" ? "dsh-sel-bubble-user" : "dsh-sel-bubble-bot") + (turn.error ? " dsh-sel-bubble-err" : "");
|
|
@@ -7030,6 +7228,7 @@ function createHistoryController(env) {
|
|
|
7030
7228
|
return seed.length > 1500 ? seed.slice(0, 1500) + "\u2026" : seed;
|
|
7031
7229
|
}
|
|
7032
7230
|
return {
|
|
7231
|
+
clearRenderedTurns,
|
|
7033
7232
|
hideHistoryList,
|
|
7034
7233
|
placeHistoryList,
|
|
7035
7234
|
toggleHistoryList,
|
|
@@ -7062,13 +7261,6 @@ function createHistoryController(env) {
|
|
|
7062
7261
|
loadHistoryEntry,
|
|
7063
7262
|
seedHistoryFromExplanation,
|
|
7064
7263
|
ensureChatFollow,
|
|
7065
|
-
get FOLD_HISTORY_KEEP_LATEST() {
|
|
7066
|
-
return FOLD_HISTORY_KEEP_LATEST;
|
|
7067
|
-
},
|
|
7068
|
-
set FOLD_HISTORY_KEEP_LATEST(value) {
|
|
7069
|
-
FOLD_HISTORY_KEEP_LATEST = value;
|
|
7070
|
-
},
|
|
7071
|
-
historyTextOf,
|
|
7072
7264
|
clearTransientNotice,
|
|
7073
7265
|
saveHistory,
|
|
7074
7266
|
applyToolEvent,
|
|
@@ -7189,7 +7381,8 @@ function createConversationController(env) {
|
|
|
7189
7381
|
if (env.state.turns.length === 0 && (env.state.raw.trim() || env.state.parts.translation || env.state.parts.detail)) {
|
|
7190
7382
|
env.state.turns.push({ role: "assistant", text: env.seedHistoryFromExplanation(), seed: true, hidden: true });
|
|
7191
7383
|
}
|
|
7192
|
-
|
|
7384
|
+
var questionTurn = { role: "user", text: asked || QUOTE_ONLY_QUESTION, quotes, sent, attachments: withAttachments };
|
|
7385
|
+
env.state.turns.push(questionTurn);
|
|
7193
7386
|
var answerTurn = {
|
|
7194
7387
|
role: "assistant",
|
|
7195
7388
|
text: "",
|
|
@@ -7211,23 +7404,22 @@ function createConversationController(env) {
|
|
|
7211
7404
|
if (env.state.sessionOpen !== void 0) {
|
|
7212
7405
|
}
|
|
7213
7406
|
var startedAt = Date.now();
|
|
7214
|
-
var timer =
|
|
7407
|
+
var timer = env.timerScope.interval(function() {
|
|
7215
7408
|
env.paintPill();
|
|
7216
7409
|
env.setStatus(
|
|
7217
7410
|
(env.state.toolBusy ? "\u6B63\u5728\u68C0\u7D22\u8D44\u6599\u2026 " : "\u8FFD\u95EE\u4E2D\u2026 ") + ((Date.now() - startedAt) / 1e3).toFixed(1) + "s"
|
|
7218
7411
|
);
|
|
7219
7412
|
updateWaitClocks();
|
|
7220
7413
|
}, 200);
|
|
7221
|
-
env.timers.push(timer);
|
|
7222
7414
|
var historyTurns = env.state.turns.slice(0, env.state.turns.length - 2);
|
|
7223
|
-
var
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
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;
|
|
7231
7423
|
env.state.stopped = false;
|
|
7232
7424
|
var askController = new AbortController();
|
|
7233
7425
|
env.state.askRequest = {
|
|
@@ -7239,7 +7431,7 @@ function createConversationController(env) {
|
|
|
7239
7431
|
}
|
|
7240
7432
|
};
|
|
7241
7433
|
function finish(error) {
|
|
7242
|
-
|
|
7434
|
+
env.timerScope.clear(timer);
|
|
7243
7435
|
env.state.asking = false;
|
|
7244
7436
|
env.state.toolBusy = false;
|
|
7245
7437
|
env.clearTransientNotice(answerTurn);
|
|
@@ -7263,24 +7455,36 @@ function createConversationController(env) {
|
|
|
7263
7455
|
);
|
|
7264
7456
|
env.askFocusAfterTurn();
|
|
7265
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
|
+
}
|
|
7266
7484
|
fetch(API, {
|
|
7267
7485
|
method: "POST",
|
|
7268
7486
|
headers: { "content-type": "application/json" },
|
|
7269
|
-
body:
|
|
7270
|
-
text: payload.text,
|
|
7271
|
-
context: payload.context,
|
|
7272
|
-
label: payload.label,
|
|
7273
|
-
sessionId: env.panelOrCurrentSessionId(),
|
|
7274
|
-
question: sent,
|
|
7275
|
-
history,
|
|
7276
|
-
// 附件只带**引用**(图片/文件都已经在 host 的附件服务里),body 不会因为一张截图胖几 MB
|
|
7277
|
-
...withAttachments.length > 0 ? { attachments: withAttachments } : {},
|
|
7278
|
-
// 网页输出要跟着当前深浅走:深色 Harness 里给一张白底页面会很刺眼
|
|
7279
|
-
...env.state.webAnswer ? { webAnswer: true, theme: env.currentSurfaceTheme() } : {},
|
|
7280
|
-
...env.state.modelChoice ? { provider: env.state.modelChoice.provider, model: env.state.modelChoice.model } : {},
|
|
7281
|
-
...env.state.effort ? { effort: env.state.effort } : {},
|
|
7282
|
-
...env.state.toolDigest ? { toolDigest: env.state.toolDigest } : {}
|
|
7283
|
-
}),
|
|
7487
|
+
body: requestBody,
|
|
7284
7488
|
signal: askController.signal
|
|
7285
7489
|
}).then(function(response) {
|
|
7286
7490
|
if (!response.ok) {
|
|
@@ -7306,7 +7510,18 @@ function createConversationController(env) {
|
|
|
7306
7510
|
} catch (error) {
|
|
7307
7511
|
continue;
|
|
7308
7512
|
}
|
|
7309
|
-
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") {
|
|
7310
7525
|
env.clearTransientNotice(answerTurn);
|
|
7311
7526
|
if (!answerTurn.text.trim()) answerTurn.asking = false;
|
|
7312
7527
|
answerTurn.text += message.text;
|
|
@@ -7345,6 +7560,10 @@ function createConversationController(env) {
|
|
|
7345
7560
|
}
|
|
7346
7561
|
scheduleTurnsRender();
|
|
7347
7562
|
} else if (message.type === "error") {
|
|
7563
|
+
if (message.code === "context-rejected") {
|
|
7564
|
+
questionTurn.contextExcluded = true;
|
|
7565
|
+
answerTurn.contextExcluded = true;
|
|
7566
|
+
}
|
|
7348
7567
|
finish(message.message || "\u6A21\u578B\u8FD4\u56DE\u9519\u8BEF");
|
|
7349
7568
|
}
|
|
7350
7569
|
}
|
|
@@ -7502,16 +7721,15 @@ function createConversationController(env) {
|
|
|
7502
7721
|
env.state.startedAt = Date.now();
|
|
7503
7722
|
env.state.elapsed = 0;
|
|
7504
7723
|
env.paint();
|
|
7505
|
-
var ticker =
|
|
7724
|
+
var ticker = env.timerScope.interval(function() {
|
|
7506
7725
|
env.paintPill();
|
|
7507
7726
|
if (env.state.phase === "loading" || env.state.phase === "streaming") {
|
|
7508
7727
|
env.setStatus(env.progressText());
|
|
7509
7728
|
updateWaitClocks();
|
|
7510
7729
|
}
|
|
7511
7730
|
}, 200);
|
|
7512
|
-
env.timers.push(ticker);
|
|
7513
7731
|
function stopTicker() {
|
|
7514
|
-
|
|
7732
|
+
env.timerScope.clear(ticker);
|
|
7515
7733
|
}
|
|
7516
7734
|
function fail(message) {
|
|
7517
7735
|
if (env.state.phase === "done") return;
|
|
@@ -9100,6 +9318,101 @@ function createVoiceController(env) {
|
|
|
9100
9318
|
};
|
|
9101
9319
|
}
|
|
9102
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
|
+
|
|
9103
9416
|
// src/client/index.js
|
|
9104
9417
|
function apply(ctx) {
|
|
9105
9418
|
var state = {
|
|
@@ -9148,6 +9461,14 @@ function apply(ctx) {
|
|
|
9148
9461
|
payload: null,
|
|
9149
9462
|
/** 已生成的两节内容(分阶段产出)。 */
|
|
9150
9463
|
parts: { translation: "", detail: "" },
|
|
9464
|
+
/**
|
|
9465
|
+
* 这段对话**没有解读**(语音卡那条"跳过翻译与详解、直接追问"的路):
|
|
9466
|
+
* 翻译节整节不画,追问输入框直接可见。
|
|
9467
|
+
*
|
|
9468
|
+
* 语义单位是"一段对话"而不是"一次开窗":落盘时写进历史条目的 skipped,
|
|
9469
|
+
* 回放/缓存命中时按它复原(否则同一个词再开一次,空翻译卡片又冒出来 —— 用户实测)。
|
|
9470
|
+
*/
|
|
9471
|
+
skipInterpretation: false,
|
|
9151
9472
|
/** 当前阶段:'translation' | 'detail' | 'chat'。 */
|
|
9152
9473
|
stage: "",
|
|
9153
9474
|
/** 追问轮次:[{ role: 'user' | 'assistant', text }],只活在面板/内存里(临时)。 */
|
|
@@ -9204,7 +9525,8 @@ function apply(ctx) {
|
|
|
9204
9525
|
/** 升格请求进行中。 */
|
|
9205
9526
|
promoting: false
|
|
9206
9527
|
};
|
|
9207
|
-
var cache =
|
|
9528
|
+
var cache = createResultCache();
|
|
9529
|
+
var timerScope = createTimerScope();
|
|
9208
9530
|
var styleEl = el("style");
|
|
9209
9531
|
styleEl.setAttribute("data-plugin", "@yfwu2020/dsh-selection-explain");
|
|
9210
9532
|
styleEl.textContent = CSS;
|
|
@@ -9639,8 +9961,8 @@ function apply(ctx) {
|
|
|
9639
9961
|
get frameTouchedAt() {
|
|
9640
9962
|
return previewController.frameTouchedAt;
|
|
9641
9963
|
},
|
|
9642
|
-
get
|
|
9643
|
-
return
|
|
9964
|
+
get timerScope() {
|
|
9965
|
+
return timerScope;
|
|
9644
9966
|
},
|
|
9645
9967
|
get voice() {
|
|
9646
9968
|
return voiceController.voice;
|
|
@@ -9665,6 +9987,9 @@ function apply(ctx) {
|
|
|
9665
9987
|
}
|
|
9666
9988
|
});
|
|
9667
9989
|
var quotesController = createQuotesController({
|
|
9990
|
+
get foldForHistory() {
|
|
9991
|
+
return historyController.foldForHistory;
|
|
9992
|
+
},
|
|
9668
9993
|
get state() {
|
|
9669
9994
|
return state;
|
|
9670
9995
|
},
|
|
@@ -9698,8 +10023,8 @@ function apply(ctx) {
|
|
|
9698
10023
|
get currentSessionId() {
|
|
9699
10024
|
return panelController.currentSessionId;
|
|
9700
10025
|
},
|
|
9701
|
-
get
|
|
9702
|
-
return
|
|
10026
|
+
get timerScope() {
|
|
10027
|
+
return timerScope;
|
|
9703
10028
|
}
|
|
9704
10029
|
});
|
|
9705
10030
|
var previewController = createPreviewController({
|
|
@@ -9720,6 +10045,9 @@ function apply(ctx) {
|
|
|
9720
10045
|
}
|
|
9721
10046
|
});
|
|
9722
10047
|
var panelController = createPanelController({
|
|
10048
|
+
get timerScope() {
|
|
10049
|
+
return timerScope;
|
|
10050
|
+
},
|
|
9723
10051
|
get panelSessionId() {
|
|
9724
10052
|
return panelSessionId;
|
|
9725
10053
|
},
|
|
@@ -9756,6 +10084,12 @@ function apply(ctx) {
|
|
|
9756
10084
|
get renderTurns() {
|
|
9757
10085
|
return historyController.renderTurns;
|
|
9758
10086
|
},
|
|
10087
|
+
get clearRenderedTurns() {
|
|
10088
|
+
return historyController.clearRenderedTurns;
|
|
10089
|
+
},
|
|
10090
|
+
get clearWaiting() {
|
|
10091
|
+
return conversationController.clearWaiting;
|
|
10092
|
+
},
|
|
9759
10093
|
get sendAsk() {
|
|
9760
10094
|
return conversationController.sendAsk;
|
|
9761
10095
|
},
|
|
@@ -10015,6 +10349,9 @@ function apply(ctx) {
|
|
|
10015
10349
|
}
|
|
10016
10350
|
});
|
|
10017
10351
|
var historyController = createHistoryController({
|
|
10352
|
+
set panelSessionId(value) {
|
|
10353
|
+
panelSessionId = value;
|
|
10354
|
+
},
|
|
10018
10355
|
get sentTextOf() {
|
|
10019
10356
|
return quotesController.sentTextOf;
|
|
10020
10357
|
},
|
|
@@ -10045,8 +10382,8 @@ function apply(ctx) {
|
|
|
10045
10382
|
get paint() {
|
|
10046
10383
|
return panelController.paint;
|
|
10047
10384
|
},
|
|
10048
|
-
get
|
|
10049
|
-
return
|
|
10385
|
+
get timerScope() {
|
|
10386
|
+
return timerScope;
|
|
10050
10387
|
},
|
|
10051
10388
|
get panelOpen() {
|
|
10052
10389
|
return panelOpen;
|
|
@@ -10176,14 +10513,8 @@ function apply(ctx) {
|
|
|
10176
10513
|
get paintPill() {
|
|
10177
10514
|
return pillController.paintPill;
|
|
10178
10515
|
},
|
|
10179
|
-
get
|
|
10180
|
-
return
|
|
10181
|
-
},
|
|
10182
|
-
get FOLD_HISTORY_KEEP_LATEST() {
|
|
10183
|
-
return historyController.FOLD_HISTORY_KEEP_LATEST;
|
|
10184
|
-
},
|
|
10185
|
-
get historyTextOf() {
|
|
10186
|
-
return historyController.historyTextOf;
|
|
10516
|
+
get timerScope() {
|
|
10517
|
+
return timerScope;
|
|
10187
10518
|
},
|
|
10188
10519
|
get clearTransientNotice() {
|
|
10189
10520
|
return historyController.clearTransientNotice;
|
|
@@ -10457,7 +10788,6 @@ function apply(ctx) {
|
|
|
10457
10788
|
var STREAM_RENDER_MS = 90;
|
|
10458
10789
|
var turnsRenderPending = false;
|
|
10459
10790
|
var lastTurnsRenderAt = 0;
|
|
10460
|
-
var timers = [];
|
|
10461
10791
|
var PILL_POLL_MIN = 2e3;
|
|
10462
10792
|
var PILL_POLL_MAX = 6e4;
|
|
10463
10793
|
var pillPollDelay = PILL_POLL_MIN;
|
|
@@ -10477,9 +10807,7 @@ function apply(ctx) {
|
|
|
10477
10807
|
var pillObserver = null;
|
|
10478
10808
|
var waitList = [];
|
|
10479
10809
|
function later(fn, ms) {
|
|
10480
|
-
|
|
10481
|
-
timers.push(id);
|
|
10482
|
-
return id;
|
|
10810
|
+
return timerScope.later(fn, ms);
|
|
10483
10811
|
}
|
|
10484
10812
|
var offBridgeMessage = listen(window, "message", function(event) {
|
|
10485
10813
|
var data = event && event.data;
|
|
@@ -11049,6 +11377,14 @@ function apply(ctx) {
|
|
|
11049
11377
|
turns: function() {
|
|
11050
11378
|
return state.turns.slice();
|
|
11051
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
|
+
},
|
|
11052
11388
|
/** 自检用:当前待发送的引用(引用区里那几张卡片)。 */
|
|
11053
11389
|
quotes: function() {
|
|
11054
11390
|
return state.quotes.map(function(quote2) {
|
|
@@ -11393,6 +11729,7 @@ function apply(ctx) {
|
|
|
11393
11729
|
state.selection = null;
|
|
11394
11730
|
state.bridgeActive = false;
|
|
11395
11731
|
state.parts = { translation: "", detail: "" };
|
|
11732
|
+
state.contextState = null;
|
|
11396
11733
|
state.turns = [];
|
|
11397
11734
|
quotesController.clearQuotes();
|
|
11398
11735
|
state.raw = "";
|
|
@@ -11420,6 +11757,13 @@ function apply(ctx) {
|
|
|
11420
11757
|
console.log("[dsh-selection-explain] \u5212\u8BCD\u89E3\u8BFB\u5DF2\u5C31\u7EEA\uFF08\u9009\u4E2D\u6587\u5B57\u8BD5\u8BD5\uFF09");
|
|
11421
11758
|
}
|
|
11422
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();
|
|
11423
11767
|
offPopEnd();
|
|
11424
11768
|
offQuotePopEnd();
|
|
11425
11769
|
offMouseUp();
|
|
@@ -11507,13 +11851,17 @@ function apply(ctx) {
|
|
|
11507
11851
|
}
|
|
11508
11852
|
});
|
|
11509
11853
|
previewController.bridged.clear();
|
|
11854
|
+
previewController.frameTouchedAt.clear();
|
|
11510
11855
|
state.turns = [];
|
|
11511
11856
|
state.quotes = [];
|
|
11857
|
+
state.selection = null;
|
|
11858
|
+
state.quoteSelection = null;
|
|
11859
|
+
state.payload = null;
|
|
11860
|
+
state.parts = { translation: "", detail: "" };
|
|
11861
|
+
state.raw = "";
|
|
11512
11862
|
if (state.request) state.request.abort();
|
|
11513
|
-
for (var i = 0; i < timers.length; i++) clearTimeout(timers[i]);
|
|
11514
11863
|
if (pillIdleId) clearTimeout(pillIdleId);
|
|
11515
11864
|
if (pillController.pillStarTimer) clearTimeout(pillController.pillStarTimer);
|
|
11516
|
-
cache.clear();
|
|
11517
11865
|
if (layer.parentNode) layer.parentNode.removeChild(layer);
|
|
11518
11866
|
if (button.parentNode) button.parentNode.removeChild(button);
|
|
11519
11867
|
if (quoteButton.parentNode) quoteButton.parentNode.removeChild(quoteButton);
|