dsh-better-display 0.3.8 → 0.3.9
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/CHANGELOG.md +11 -0
- package/DESIGN.md +43 -3
- package/README.en.md +9 -1
- package/README.md +9 -1
- package/docs/dependency-update-policy.md +9 -0
- package/docs/extension-points.md +172 -0
- package/docs/official-rendering-bridge.md +48 -19
- package/docs/openapi.yaml +147 -0
- package/docs/runbooks/blank-reader.md +39 -0
- package/lib/client.js +1417 -490
- package/lib/client.js.map +1 -1
- package/lib/dsh-better-display.js +378 -144
- package/lib/types/client/AssistantNode.d.ts +20 -0
- package/lib/types/client/AssistantNode.d.ts.map +1 -0
- package/lib/types/client/AssistantNode.js +46 -0
- package/lib/types/client/AssistantNode.js.map +1 -0
- package/lib/types/client/Blocks.d.ts.map +1 -1
- package/lib/types/client/Blocks.js +33 -10
- package/lib/types/client/Blocks.js.map +1 -1
- package/lib/types/client/ChoreographedFlow.d.ts.map +1 -1
- package/lib/types/client/ChoreographedFlow.js +2 -0
- package/lib/types/client/ChoreographedFlow.js.map +1 -1
- package/lib/types/client/ClosedProcessSummary.d.ts.map +1 -1
- package/lib/types/client/ClosedProcessSummary.js +3 -1
- package/lib/types/client/ClosedProcessSummary.js.map +1 -1
- package/lib/types/client/McpAppFrame.d.ts.map +1 -1
- package/lib/types/client/McpAppFrame.js +5 -11
- package/lib/types/client/McpAppFrame.js.map +1 -1
- package/lib/types/client/OfficialContent.d.ts +17 -3
- package/lib/types/client/OfficialContent.d.ts.map +1 -1
- package/lib/types/client/OfficialContent.js +33 -7
- package/lib/types/client/OfficialContent.js.map +1 -1
- package/lib/types/client/Reader.d.ts.map +1 -1
- package/lib/types/client/Reader.js +43 -71
- package/lib/types/client/Reader.js.map +1 -1
- package/lib/types/client/SettingsSection.d.ts.map +1 -1
- package/lib/types/client/SettingsSection.js +0 -5
- package/lib/types/client/SettingsSection.js.map +1 -1
- package/lib/types/client/StickyLane.d.ts +12 -0
- package/lib/types/client/StickyLane.d.ts.map +1 -1
- package/lib/types/client/StickyLane.js +78 -2
- package/lib/types/client/StickyLane.js.map +1 -1
- package/lib/types/client/ToolActivity.js.map +1 -1
- package/lib/types/client/index.d.ts +3 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js +6 -0
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/live-turn.d.ts +17 -5
- package/lib/types/client/live-turn.d.ts.map +1 -1
- package/lib/types/client/live-turn.js +106 -76
- package/lib/types/client/live-turn.js.map +1 -1
- package/lib/types/client/motion.d.ts +26 -2
- package/lib/types/client/motion.d.ts.map +1 -1
- package/lib/types/client/motion.js +136 -10
- package/lib/types/client/motion.js.map +1 -1
- package/lib/types/client/official-slots.d.ts +9 -0
- package/lib/types/client/official-slots.d.ts.map +1 -1
- package/lib/types/client/official-slots.js +22 -7
- package/lib/types/client/official-slots.js.map +1 -1
- package/lib/types/client/projection.d.ts +15 -2
- package/lib/types/client/projection.d.ts.map +1 -1
- package/lib/types/client/projection.js +16 -4
- package/lib/types/client/projection.js.map +1 -1
- package/lib/types/client/rewind-cut.d.ts +131 -0
- package/lib/types/client/rewind-cut.d.ts.map +1 -0
- package/lib/types/client/rewind-cut.js +321 -0
- package/lib/types/client/rewind-cut.js.map +1 -0
- package/lib/types/client/text-transform.d.ts +93 -0
- package/lib/types/client/text-transform.d.ts.map +1 -0
- package/lib/types/client/text-transform.js +183 -0
- package/lib/types/client/text-transform.js.map +1 -0
- package/lib/types/client/timeline.d.ts.map +1 -1
- package/lib/types/client/timeline.js.map +1 -1
- package/lib/types/client/tool-activity.d.ts +9 -2
- package/lib/types/client/tool-activity.d.ts.map +1 -1
- package/lib/types/client/tool-activity.js +42 -2
- package/lib/types/client/tool-activity.js.map +1 -1
- package/lib/types/client/turn-slots.d.ts +29 -0
- package/lib/types/client/turn-slots.d.ts.map +1 -0
- package/lib/types/client/turn-slots.js +62 -0
- package/lib/types/client/turn-slots.js.map +1 -0
- package/lib/types/client/types.d.ts +18 -0
- package/lib/types/client/types.d.ts.map +1 -1
- package/lib/types/dsh-better-display.d.ts +4 -1
- package/lib/types/dsh-better-display.d.ts.map +1 -1
- package/lib/types/dsh-better-display.js +56 -7
- package/lib/types/dsh-better-display.js.map +1 -1
- package/lib/types/flags.d.ts +7 -0
- package/lib/types/flags.d.ts.map +1 -0
- package/lib/types/flags.js +37 -0
- package/lib/types/flags.js.map +1 -0
- package/lib/types/log.d.ts +17 -0
- package/lib/types/log.d.ts.map +1 -0
- package/lib/types/log.js +122 -0
- package/lib/types/log.js.map +1 -0
- package/lib/types/metrics.d.ts +18 -0
- package/lib/types/metrics.d.ts.map +1 -0
- package/lib/types/metrics.js +35 -0
- package/lib/types/metrics.js.map +1 -0
- package/package.json +36 -5
- package/scripts/changelog.mjs +20 -0
- package/scripts/check-agents-md.mjs +67 -0
- package/scripts/check-bundle-size.mjs +38 -0
- package/scripts/check-dead-flags.mjs +55 -0
- package/scripts/check-todo-debt.mjs +69 -0
- package/scripts/security-audit-report.mjs +92 -0
- package/scripts/verify-commentary-visible.mjs +627 -0
- package/src/client/AssistantNode.tsx +72 -0
- package/src/client/Blocks.tsx +49 -10
- package/src/client/ChoreographedFlow.tsx +3 -1
- package/src/client/ClosedProcessSummary.tsx +3 -1
- package/src/client/McpAppFrame.tsx +5 -13
- package/src/client/OfficialContent.tsx +47 -9
- package/src/client/Reader.module.css +68 -18
- package/src/client/Reader.tsx +36 -76
- package/src/client/SettingsSection.tsx +1 -7
- package/src/client/StickyLane.tsx +81 -2
- package/src/client/ToolActivity.tsx +1 -1
- package/src/client/index.tsx +8 -1
- package/src/client/live-turn.ts +100 -69
- package/src/client/motion.tsx +135 -7
- package/src/client/official-slots.tsx +23 -7
- package/src/client/projection.ts +16 -4
- package/src/client/rewind-cut.ts +340 -0
- package/src/client/text-transform.ts +265 -0
- package/src/client/timeline.ts +0 -2
- package/src/client/tool-activity.ts +49 -2
- package/src/client/turn-slots.ts +80 -0
- package/src/client/types.ts +19 -0
- package/src/dsh-better-display.ts +58 -7
- package/src/flags.ts +40 -0
- package/src/log.ts +137 -0
- package/src/metrics.ts +50 -0
- package/tests/browser-commentary.tsx +191 -0
- package/tests/chat-flow-hook.test.ts +1 -1
- package/tests/cloud-gate.test.ts +1 -1
- package/tests/context-tool-update.test.ts +1 -1
- package/tests/conversation-scroll.test.ts +1 -1
- package/tests/deliverables.test.ts +1 -1
- package/tests/entry.test.ts +1 -1
- package/tests/fixtures/reader-lane-owners.tsx +46 -0
- package/tests/fixtures/reader-official-users.tsx +64 -0
- package/tests/fixtures/reader-theme-overlap.html +80 -0
- package/tests/fixtures/reader-user-bubble.tsx +222 -0
- package/tests/flags.test.ts +66 -0
- package/tests/fold-choreography.test.ts +32 -8
- package/tests/fold-intensity.test.ts +11 -6
- package/tests/footer-precedence.test.ts +1 -1
- package/tests/history-word-regression.test.ts +1 -1
- package/tests/live-turn.test.ts +125 -54
- package/tests/log.test.ts +99 -0
- package/tests/mcp-apps.test.ts +1 -1
- package/tests/message-chrome.test.ts +1 -1
- package/tests/metrics.test.ts +52 -0
- package/tests/official-slots.test.ts +41 -2
- package/tests/open-file.test.ts +1 -1
- package/tests/pending-submission.test.ts +12 -1
- package/tests/pinned-selection.test.ts +16 -0
- package/tests/platform-media.test.ts +1 -1
- package/tests/projection.test.ts +66 -3
- package/tests/reader-glass-css.test.ts +1 -1
- package/tests/reader-official-users.test.ts +11 -1
- package/tests/reader-sticky-surface.test.ts +377 -0
- package/tests/reader-theme-lanes.test.ts +54 -0
- package/tests/reader-theme-overlap.test.ts +151 -0
- package/tests/reader-user-bubble.test.ts +137 -0
- package/tests/reasoning-follow.test.ts +1 -1
- package/tests/retiring-content.test.ts +98 -6
- package/tests/reveal.test.ts +3 -3
- package/tests/rewind-cut.test.ts +1090 -0
- package/tests/settings-copy.test.ts +1 -1
- package/tests/skill-status.test.ts +1 -1
- package/tests/stock-install.test.ts +1 -1
- package/tests/stream-buffer.test.ts +1 -1
- package/tests/styles.test.ts +30 -3
- package/tests/terminal-input-preview.test.ts +1 -1
- package/tests/text-transform.test.ts +272 -0
- package/tests/timeline.test.ts +1 -1
- package/tests/tool-clock.test.ts +1 -1
- package/tests/tool-diff.test.ts +1 -1
- package/tests/waiting-clock.test.ts +1 -1
- package/tests/word-timeline.test.ts +1 -1
package/lib/client.js
CHANGED
|
@@ -109,12 +109,286 @@ window.__ModuleLoader__.load({
|
|
|
109
109
|
return sessionFileAddress(sessionId, normalized);
|
|
110
110
|
}
|
|
111
111
|
//#endregion
|
|
112
|
+
//#region src/client/rewind-cut.ts
|
|
113
|
+
function asRecord$1(value) {
|
|
114
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
115
|
+
}
|
|
116
|
+
function safeSeq(value) {
|
|
117
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
118
|
+
}
|
|
119
|
+
/** The command payload of a `command` chat node, when it is structurally readable. */
|
|
120
|
+
function commandOf(node) {
|
|
121
|
+
if (node.kind !== "command") return void 0;
|
|
122
|
+
return asRecord$1(node.data);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* The engine names an executed rewind command node can carry. The plugin
|
|
126
|
+
* registers its command as `rewind-plugin` (`ENGINE_COMMANDS = new
|
|
127
|
+
* Set(['rewind-plugin', 'rewind'])` in dsh-rewind-plugin's
|
|
128
|
+
* `src/client/hidden.ts`), and that is the name the client projection actually
|
|
129
|
+
* publishes — the session log's `command/run.name` is not what the Reader sees.
|
|
130
|
+
* `rewind` stays accepted because older logs and the bili-side proxy record the
|
|
131
|
+
* shorter spelling.
|
|
132
|
+
*/
|
|
133
|
+
const REWIND_COMMANDS = /* @__PURE__ */ new Set(["rewind-plugin", "rewind"]);
|
|
134
|
+
/** True when a command payload is the rewind engine command, in either spelling. */
|
|
135
|
+
function isRewindCommand(command) {
|
|
136
|
+
return typeof command.name === "string" && REWIND_COMMANDS.has(command.name);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The render POSITION a row is anchored at: the view node's `anchorSeq`, else
|
|
140
|
+
* its payload seq.
|
|
141
|
+
*
|
|
142
|
+
* This is deliberately NOT integer-only. The host anchors synthetic rows at
|
|
143
|
+
* fractional offsets off a real seq (`CHAT_SYNTHETIC_SEQ_OFFSETS` in the
|
|
144
|
+
* official ChatView: `turn-process` at `controlAnchorSeq - 0.1`, `turn-tail` at
|
|
145
|
+
* `seq + 0.1`, an interrupted assistant step at `seq - 0.9`). An integer-only
|
|
146
|
+
* read made those rows invisible to the cut, so the last `turn-process` of a
|
|
147
|
+
* withdrawn turn survived on its own. Log seqs (marker, target) stay integer:
|
|
148
|
+
* see `safeSeq`.
|
|
149
|
+
*/
|
|
150
|
+
function anchorSeqOf(node) {
|
|
151
|
+
const raw = node.anchorSeq ?? asRecord$1(node.data)?.seq;
|
|
152
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : void 0;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Extract the rewind target seq from a `/rewind` command's structured `args`
|
|
156
|
+
* (e.g. `@5 chat`, `preview @5 both`). Locale-independent: it never parses the
|
|
157
|
+
* host's human outcome copy.
|
|
158
|
+
*/
|
|
159
|
+
function rewindTargetOfArgs(args) {
|
|
160
|
+
if (typeof args !== "string") return void 0;
|
|
161
|
+
const match = args.match(/@(\d+)/);
|
|
162
|
+
return match === null ? void 0 : Number(match[1]);
|
|
163
|
+
}
|
|
164
|
+
/** True for the internal candidate-list probe (`/rewind __candidates`). */
|
|
165
|
+
function isCandidateCommand(command) {
|
|
166
|
+
return typeof command.args === "string" && command.args.includes("__candidates");
|
|
167
|
+
}
|
|
168
|
+
/** True for an impact preview (`/rewind preview @5 both`). */
|
|
169
|
+
function isPreviewCommand(command) {
|
|
170
|
+
return typeof command.args === "string" && command.args.includes("preview");
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Merge overlapping or touching shadow ranges.
|
|
174
|
+
*
|
|
175
|
+
* Spans are kept SEPARATE unless they genuinely overlap: collapsing every cut
|
|
176
|
+
* to `[min target, max marker]` would hide a still-on-surface gap of new traffic
|
|
177
|
+
* between an earlier marker and a later target.
|
|
178
|
+
*/
|
|
179
|
+
function coalesceCutSpans(spans) {
|
|
180
|
+
if (spans.length < 2) return [...spans];
|
|
181
|
+
const sorted = [...spans].sort((left, right) => left.start - right.start || left.end - right.end);
|
|
182
|
+
const merged = [];
|
|
183
|
+
for (const span of sorted) {
|
|
184
|
+
const last = merged.at(-1);
|
|
185
|
+
if (last !== void 0 && span.start <= last.end) {
|
|
186
|
+
if (span.end > last.end) last.end = span.end;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
merged.push({
|
|
190
|
+
start: span.start,
|
|
191
|
+
end: span.end
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return merged;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* True when a row anchored at `seq` falls inside one of the cut spans.
|
|
198
|
+
*
|
|
199
|
+
* A cut runs from the target seq through the marker's own log seq, inclusive
|
|
200
|
+
* (`target <= anchorSeq && anchorSeq <= marker`), the same comparison
|
|
201
|
+
* `dsh-rewind-plugin`'s `RewindVisibilityBuilder` uses. The upper bound stops
|
|
202
|
+
* at the marker. Extending it to the next integer hides the following turn's
|
|
203
|
+
* process row, which the host anchors at `startSeq - 0.1` and therefore in
|
|
204
|
+
* `[marker, marker + 1)`. Fractional anchors inside the closed range still
|
|
205
|
+
* match: `anchorSeqOf` keeps them. A process or tail row parked outside the
|
|
206
|
+
* range is handled by `summaryTurns`, not by widening the cut. Spans stay
|
|
207
|
+
* disjoint, so new traffic between two rewinds survives.
|
|
208
|
+
*/
|
|
209
|
+
function cutContains(cuts, seq) {
|
|
210
|
+
let low = 0;
|
|
211
|
+
let high = cuts.length - 1;
|
|
212
|
+
let found = -1;
|
|
213
|
+
while (low <= high) {
|
|
214
|
+
const middle = low + high >> 1;
|
|
215
|
+
const cut = cuts[middle];
|
|
216
|
+
if (cut === void 0) return false;
|
|
217
|
+
if (seq < cut.start) high = middle - 1;
|
|
218
|
+
else {
|
|
219
|
+
found = middle;
|
|
220
|
+
low = middle + 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const span = found < 0 ? void 0 : cuts[found];
|
|
224
|
+
return span !== void 0 && seq <= span.end;
|
|
225
|
+
}
|
|
226
|
+
/** The turn id a node belongs to (absent outside a turn). */
|
|
227
|
+
function turnIdOf(node) {
|
|
228
|
+
const turn = asRecord$1(asRecord$1(node.location)?.turn);
|
|
229
|
+
if (turn === void 0 || !Object.hasOwn(turn, "turn")) return void 0;
|
|
230
|
+
return turn.turn;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Node kinds that SUMMARIZE a turn instead of carrying its content, so the host
|
|
234
|
+
* anchors them at the turn's edges rather than at an event inside it.
|
|
235
|
+
*/
|
|
236
|
+
const TURN_SUMMARY_KINDS = /* @__PURE__ */ new Set(["turn-process", "turn-tail"]);
|
|
237
|
+
/**
|
|
238
|
+
* True for a rewind command row the transcript should not keep.
|
|
239
|
+
*
|
|
240
|
+
* Probes (`preview`, `__candidates`) exist only to feed the popover. An
|
|
241
|
+
* executed rewind — success plus a marker seq — is the command that performed
|
|
242
|
+
* the cut, and the plugin hides that row even when its anchor sits outside
|
|
243
|
+
* the numeric range. A failed or still-running command stays visible.
|
|
244
|
+
*/
|
|
245
|
+
function commandHidden(node) {
|
|
246
|
+
const command = commandOf(node);
|
|
247
|
+
if (command === void 0 || !isRewindCommand(command)) return false;
|
|
248
|
+
if (isPreviewCommand(command) || isCandidateCommand(command)) return true;
|
|
249
|
+
const outcome = asRecord$1(command.outcome);
|
|
250
|
+
return outcome?.kind === "success" && safeSeq(outcome.sourceEventSeq) !== void 0;
|
|
251
|
+
}
|
|
252
|
+
/** True when the row's own anchor falls in a cut, or the row is a rewind command to hide. */
|
|
253
|
+
function anchorWithdrawn(node, cuts) {
|
|
254
|
+
if (commandHidden(node)) return true;
|
|
255
|
+
const seq = anchorSeqOf(node);
|
|
256
|
+
return seq !== void 0 && cutContains(cuts, seq);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Turns whose process and tail rows must leave.
|
|
260
|
+
*
|
|
261
|
+
* The host opens a turn before its user message is logged and anchors
|
|
262
|
+
* `turn-process` at `controlAnchorSeq - 0.1`, below the first withdrawn
|
|
263
|
+
* event, and `turn-tail` at `turn.end.seq + 0.1`, which can sit past the
|
|
264
|
+
* marker. Containment therefore misses those two rows, and the transcript
|
|
265
|
+
* kept announcing `执行过程 / 本轮已停止,已生成的内容仍保留。`
|
|
266
|
+
*
|
|
267
|
+
* A summary leaves only when every content row of its turn is already
|
|
268
|
+
* withdrawn — the same rule as the plugin's `deriveTurnProcess`. One content
|
|
269
|
+
* row before the target (a mid-turn steering rewind) keeps the summary and
|
|
270
|
+
* that earlier message. A turn with no content rows is left alone.
|
|
271
|
+
*/
|
|
272
|
+
function summaryTurns(chat, cuts) {
|
|
273
|
+
const stays = /* @__PURE__ */ new Map();
|
|
274
|
+
for (const key of chat.order) {
|
|
275
|
+
const node = chat.nodes.get(key);
|
|
276
|
+
if (node === void 0 || TURN_SUMMARY_KINDS.has(node.kind ?? "")) continue;
|
|
277
|
+
const id = turnIdOf(node);
|
|
278
|
+
if (id === void 0) continue;
|
|
279
|
+
const visible = node.visibility !== "hidden" && !anchorWithdrawn(node, cuts);
|
|
280
|
+
stays.set(id, (stays.get(id) ?? false) || visible);
|
|
281
|
+
}
|
|
282
|
+
const withdrawn = /* @__PURE__ */ new Set();
|
|
283
|
+
for (const [id, visible] of stays) if (!visible) withdrawn.add(id);
|
|
284
|
+
return withdrawn;
|
|
285
|
+
}
|
|
286
|
+
/** True when this row is a summary of a turn whose content is fully withdrawn. */
|
|
287
|
+
function summaryWithdrawn(node, summaries) {
|
|
288
|
+
if (!TURN_SUMMARY_KINDS.has(node.kind ?? "")) return false;
|
|
289
|
+
const id = turnIdOf(node);
|
|
290
|
+
return id !== void 0 && summaries.has(id);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* The shadow ranges a session's executed rewinds produced, newest state last.
|
|
294
|
+
* An executed rewind cuts `[target, marker]` — the target itself is included,
|
|
295
|
+
* because a rewind restores the state *before* that message was sent (its text
|
|
296
|
+
* goes back to the composer).
|
|
297
|
+
*/
|
|
298
|
+
function rewindCutSpans(chat) {
|
|
299
|
+
if (chat === void 0) return [];
|
|
300
|
+
const spans = [];
|
|
301
|
+
for (const key of chat.order) {
|
|
302
|
+
const node = chat.nodes.get(key);
|
|
303
|
+
if (node === void 0) continue;
|
|
304
|
+
const command = commandOf(node);
|
|
305
|
+
if (command === void 0 || !isRewindCommand(command)) continue;
|
|
306
|
+
if (isPreviewCommand(command) || isCandidateCommand(command)) continue;
|
|
307
|
+
const outcome = asRecord$1(command.outcome);
|
|
308
|
+
if (outcome?.kind !== "success") continue;
|
|
309
|
+
const marker = safeSeq(outcome.sourceEventSeq);
|
|
310
|
+
if (marker === void 0) continue;
|
|
311
|
+
const target = rewindTargetOfArgs(command.args);
|
|
312
|
+
if (target === void 0 || target > marker) continue;
|
|
313
|
+
spans.push({
|
|
314
|
+
start: target,
|
|
315
|
+
end: marker
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return coalesceCutSpans(spans);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* The chat keys the Reader should render, in snapshot order: withdrawn rows and
|
|
322
|
+
* rows the host itself marked hidden are dropped, everything else keeps its
|
|
323
|
+
* position. Returns the snapshot's own `order` array when nothing is filtered,
|
|
324
|
+
* so React selectors see a stable reference.
|
|
325
|
+
*/
|
|
326
|
+
function visibleChatKeys(chat) {
|
|
327
|
+
const cuts = rewindCutSpans(chat);
|
|
328
|
+
const summaries = summaryTurns(chat, cuts);
|
|
329
|
+
const visible = [];
|
|
330
|
+
for (const key of chat.order) {
|
|
331
|
+
const node = chat.nodes.get(key);
|
|
332
|
+
if (node === void 0) continue;
|
|
333
|
+
if (node.visibility === "hidden") continue;
|
|
334
|
+
if (anchorWithdrawn(node, cuts) || summaryWithdrawn(node, summaries)) continue;
|
|
335
|
+
visible.push(key);
|
|
336
|
+
}
|
|
337
|
+
return visible.length === chat.order.length ? chat.order : visible;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A comparable signal for the visible row set, built for
|
|
341
|
+
* `useSyncExternalStore`-style subscription: the host re-runs a chat selector
|
|
342
|
+
* on every publish and compares the RESULT by `Object.is`, and a rewind
|
|
343
|
+
* publishes an in-place upsert of an existing command row. The snapshot's
|
|
344
|
+
* `order` array and node store are therefore both reference-stable across a
|
|
345
|
+
* rewind, so a selector on them never re-renders; a string does change exactly
|
|
346
|
+
* when the visible set does. Never return the array itself from a selector —
|
|
347
|
+
* a fresh array fails the `Object.is` check on every publish.
|
|
348
|
+
*/
|
|
349
|
+
function visibleChatSignature(chat) {
|
|
350
|
+
return visibleChatKeys(chat).join("\0");
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
112
353
|
//#region src/client/tool-activity.ts
|
|
113
|
-
/**
|
|
114
|
-
|
|
354
|
+
/**
|
|
355
|
+
* callId of a tool-call chat node. Drafts for a call whose node was cut must
|
|
356
|
+
* not be reintroduced after `group.keys` has already dropped that node.
|
|
357
|
+
*/
|
|
358
|
+
function toolCallId(node) {
|
|
359
|
+
const callId = node.data?.root?.callId;
|
|
360
|
+
return typeof callId === "string" && callId.length > 0 ? callId : void 0;
|
|
361
|
+
}
|
|
362
|
+
/** callIds whose tool-call node sits inside a rewind cut. */
|
|
363
|
+
function cutToolCallIds(order, get, spans) {
|
|
364
|
+
const ids = /* @__PURE__ */ new Set();
|
|
365
|
+
for (const key of order) {
|
|
366
|
+
const node = get(key);
|
|
367
|
+
if (node?.kind !== "tool-call") continue;
|
|
368
|
+
const seq = anchorSeqOf(node);
|
|
369
|
+
if (seq === void 0 || !cutContains(spans, seq)) continue;
|
|
370
|
+
const callId = toolCallId(node);
|
|
371
|
+
if (callId !== void 0) ids.add(callId);
|
|
372
|
+
}
|
|
373
|
+
return ids;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Public Step data includes tool-only model output before a chat node exists.
|
|
377
|
+
*
|
|
378
|
+
* `sourceOrder` is the unfiltered chat order. Drafts that belong to a cut step,
|
|
379
|
+
* or to a call whose tool-call node was cut, are not put back. A draft that
|
|
380
|
+
* still has no tool-call node, on a step outside the cut, stays — that is the
|
|
381
|
+
* in-flight call the host has not published a node for yet.
|
|
382
|
+
*/
|
|
383
|
+
function readerFlow(group, turn, get, sourceOrder) {
|
|
115
384
|
const flow = [];
|
|
116
385
|
const calls = /* @__PURE__ */ new Map();
|
|
117
386
|
const assistantOrder = /* @__PURE__ */ new Map();
|
|
387
|
+
const spans = sourceOrder === void 0 ? [] : rewindCutSpans({
|
|
388
|
+
order: sourceOrder,
|
|
389
|
+
nodes: { get }
|
|
390
|
+
});
|
|
391
|
+
const cutCalls = spans.length === 0 || sourceOrder === void 0 ? void 0 : cutToolCallIds(sourceOrder, get, spans);
|
|
118
392
|
for (const key of group.keys) {
|
|
119
393
|
const node = get(key);
|
|
120
394
|
if (!node || node.visibility === "hidden") continue;
|
|
@@ -141,10 +415,13 @@ window.__ModuleLoader__.load({
|
|
|
141
415
|
}
|
|
142
416
|
for (const step of turn?.steps ?? []) {
|
|
143
417
|
const data = step.data.get("assistant-step");
|
|
418
|
+
const stepSeq = step.start?.seq;
|
|
419
|
+
const stepCut = typeof stepSeq === "number" && spans.length > 0 && cutContains(spans, stepSeq);
|
|
144
420
|
let index = 0;
|
|
145
421
|
for (const draft of data?.blocks ?? []) {
|
|
146
422
|
if (draft.kind !== "tool-call" || !draft.callId) continue;
|
|
147
423
|
const previous = calls.get(draft.callId);
|
|
424
|
+
if (!previous && (stepCut || cutCalls?.has(draft.callId) === true)) continue;
|
|
148
425
|
calls.set(draft.callId, previous ? {
|
|
149
426
|
...previous,
|
|
150
427
|
draft
|
|
@@ -849,7 +1126,6 @@ ${trimmed}
|
|
|
849
1126
|
const iframeRef = (0, react.useRef)(null);
|
|
850
1127
|
const lastParamsRef = (0, react.useRef)({});
|
|
851
1128
|
const [height, setHeight] = (0, react.useState)(() => Math.max(60, Math.min(2400, initialHeight)));
|
|
852
|
-
const [ready, setReady] = (0, react.useState)(false);
|
|
853
1129
|
const [receipt, setReceipt] = (0, react.useState)(null);
|
|
854
1130
|
const [lastPrompt, setLastPrompt] = (0, react.useState)(null);
|
|
855
1131
|
const [reloadNonce, setReloadNonce] = (0, react.useState)(0);
|
|
@@ -872,7 +1148,7 @@ ${trimmed}
|
|
|
872
1148
|
}, [title, writeComposer]);
|
|
873
1149
|
const handleUserSubmit = (0, react.useCallback)((params) => {
|
|
874
1150
|
lastParamsRef.current = params;
|
|
875
|
-
let summary
|
|
1151
|
+
let summary;
|
|
876
1152
|
if (typeof params.choice === "string") {
|
|
877
1153
|
const desc = typeof params.desc === "string" ? ` (${params.desc})` : "";
|
|
878
1154
|
summary = `选择: ${params.choice}${desc}`;
|
|
@@ -904,13 +1180,9 @@ ${trimmed}
|
|
|
904
1180
|
}
|
|
905
1181
|
};
|
|
906
1182
|
iframe.contentWindow?.postMessage(response, "*");
|
|
907
|
-
setReady(true);
|
|
908
|
-
return;
|
|
909
|
-
}
|
|
910
|
-
if (data.method === "ui/ready" || data.method === "ui/notifications/initialized") {
|
|
911
|
-
setReady(true);
|
|
912
1183
|
return;
|
|
913
1184
|
}
|
|
1185
|
+
if (data.method === "ui/ready" || data.method === "ui/notifications/initialized") return;
|
|
914
1186
|
if (data.method === "ui/resize" && data.params?.height) {
|
|
915
1187
|
const h = Number(data.params.height);
|
|
916
1188
|
if (Number.isFinite(h) && h > 0) setHeight(Math.max(60, Math.min(2400, Math.round(h))));
|
|
@@ -978,11 +1250,9 @@ ${trimmed}
|
|
|
978
1250
|
styles: { variables: cssTokens }
|
|
979
1251
|
}
|
|
980
1252
|
}, "*");
|
|
981
|
-
setReady(true);
|
|
982
1253
|
}, []);
|
|
983
1254
|
const handleReload = (0, react.useCallback)(() => {
|
|
984
1255
|
setReloadNonce((n) => n + 1);
|
|
985
|
-
setReady(false);
|
|
986
1256
|
setReceipt(null);
|
|
987
1257
|
}, []);
|
|
988
1258
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -10426,7 +10696,7 @@ ${trimmed}
|
|
|
10426
10696
|
return count;
|
|
10427
10697
|
}
|
|
10428
10698
|
//#endregion
|
|
10429
|
-
//#region node_modules/escape-string-regexp/index.js
|
|
10699
|
+
//#region node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp/index.js
|
|
10430
10700
|
function escapeStringRegexp(string) {
|
|
10431
10701
|
if (typeof string !== "string") throw new TypeError("Expected a string");
|
|
10432
10702
|
return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
@@ -42466,7 +42736,7 @@ ${trimmed}
|
|
|
42466
42736
|
const readerPathImages = { resolve: (value) => typeof window === "undefined" ? void 0 : localPathMediaUrl(window.location.protocol, window.location.origin, value) };
|
|
42467
42737
|
//#endregion
|
|
42468
42738
|
//#region \0dshx-css-module:Reader.module.css.mjs
|
|
42469
|
-
const css$5 = ".gNoOdq_root{color:var(--dsw-alias-label-primary);padding:16px calc(var(--dsh-composer-side-clearance,16px) + 16px) 24px;overflow-anchor:auto;flex:none;min-width:0;font-family:inherit;font-size:16px;line-height:28px;container-type:inline-size}.gNoOdq_column{max-width:var(--dsh-chat-content-width,748px);flex-direction:column;gap:22px;width:100%;min-width:0;margin:0 auto;display:flex}.gNoOdq_toolbar{min-height:32px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);justify-content:flex-end;align-items:center;gap:6px;padding:0;font-size:12px;display:flex;position:sticky;top:0}.gNoOdq_turnProcessSticky{background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);align-items:center;min-height:32px;display:flex;position:sticky}.gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{min-height:32px}.gNoOdq_textButton,.gNoOdq_historyButton,.gNoOdq_iconButton,.gNoOdq_jump,.gNoOdq_disclosureButton,.gNoOdq_imageOpen,.gNoOdq_dialogClose{font:inherit;cursor:pointer}.gNoOdq_textButton{color:var(--dsw-alias-label-secondary);white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:2px 6px}.gNoOdq_textButton:hover,.gNoOdq_iconButton:hover,.gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root button:focus-visible,.gNoOdq_root summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px}.gNoOdq_turn,.gNoOdq_turnStickyRegion{flex-direction:column;gap:14px;min-width:0;display:flex}.gNoOdq_turnStickyLanes{top:max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px));z-index:6;flex-direction:column;min-width:0;display:flex;position:sticky}.gNoOdq_turn+.gNoOdq_turn{margin-top:12px}.gNoOdq_userCluster{flex-direction:column;align-self:flex-end;align-items:flex-end;gap:8px;min-width:0;max-width:min(525px,82%);margin-bottom:4px;display:flex}.gNoOdq_userImages{flex-direction:column;align-items:flex-end;min-width:0;max-width:100%;display:flex}.gNoOdq_userImages .gNoOdq_imageFigure{align-self:flex-end}.gNoOdq_user{background:var(--dsw-specific-bubble);max-width:100%;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;box-sizing:border-box;border-radius:22px;align-self:flex-end;padding:10px 16px;line-height:24px}.gNoOdq_user .gNoOdq_blocks{gap:10px}.gNoOdq_answer{overflow-wrap:anywhere;flex-direction:column;min-width:0;display:flex}.gNoOdq_readingText{min-width:0}.gNoOdq_reasonPlain{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;color:inherit}.gNoOdq_readingText button{min-width:24px;min-height:24px}.gNoOdq_streamWord{display:inline-block}.gNoOdq_streamInlineWord{display:inline}.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1;filter:none}.gNoOdq_streamAtom{min-width:0}@media (prefers-reduced-motion:reduce){.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1!important;filter:none!important}}.gNoOdq_retiringContent{min-width:0}.gNoOdq_retiringContent[data-reader-retiring=retiring]{overflow:hidden}.gNoOdq_mainFlow,.gNoOdq_blocks{flex-direction:column;gap:16px;min-width:0;display:flex}.gNoOdq_mainFlow:empty,.gNoOdq_blocks:empty{display:none}.gNoOdq_blocks>:first-child{margin-top:0}.gNoOdq_blocks>:last-child{margin-bottom:0}.gNoOdq_blocks .md-table-wide{max-width:100%}.gNoOdq_disclosure{min-width:0}.gNoOdq_disclosureButton{max-width:100%;min-height:32px;color:var(--dsw-alias-label-tertiary);text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:6px;margin-left:-6px;padding:4px 6px;font-size:14px;font-weight:400;line-height:24px;display:inline-flex}.gNoOdq_disclosure[data-reader-status-only]{align-items:center;min-height:32px;display:flex}.gNoOdq_statusText{min-width:0;max-width:100%;color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:400;line-height:24px;display:inline-flex}.gNoOdq_srOnly{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.gNoOdq_think{--think-swap:.15s;--think-gap:50ms;--think-distance:8px;--think-blur:2px;--think-shimmer:2s;--think-base:var(--dsw-alias-label-secondary);--think-highlight:var(--dsw-alias-label-primary);--think-ease:ease-in-out;text-align:left;max-width:100%;display:inline-block;position:relative}.gNoOdq_thinkSizer{visibility:hidden;white-space:nowrap;display:block}.gNoOdq_thinkText{color:var(--think-base);white-space:nowrap;text-overflow:ellipsis;filter:blur();opacity:1;transition:transform var(--think-swap) var(--think-ease), filter var(--think-swap) var(--think-ease), opacity var(--think-swap) var(--think-ease);display:block;position:absolute;top:0;left:0;right:0;overflow:hidden;transform:translateY(0)}.gNoOdq_think[data-reader-status-phase=running] .gNoOdq_thinkText[data-reader-status-copy=current]{transition-delay:var(--think-gap)}.gNoOdq_think:not([data-reader-status-phase=idle]) .gNoOdq_thinkText{will-change:transform, filter, opacity}@supports (background-clip:text){.gNoOdq_think[data-active=true] .gNoOdq_thinkText:before{content:attr(data-text);pointer-events:none;background-image:linear-gradient(90deg, transparent 0%, transparent 40%, var(--think-highlight) 50%, transparent 60%, transparent 100%);color:#0000;-webkit-text-fill-color:transparent;animation:gNoOdq_thinkShimmer var(--think-shimmer) linear infinite;background-repeat:no-repeat;background-size:400% 100%;background-clip:text;position:absolute;inset:0}}@keyframes gNoOdq_thinkShimmer{0%{background-position:100% 0}to{background-position:0 0}}.gNoOdq_thinkText.gNoOdq_isExit{transform:translateY(calc(var(--think-distance) * -1));filter:blur(var(--think-blur));opacity:0}.gNoOdq_thinkText.gNoOdq_isEnterStart{transform:translateY(var(--think-distance));filter:blur(var(--think-blur));opacity:0;transition:none}[data-motion=off] .gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}[data-motion=off] .gNoOdq_thinkText[data-reader-status-copy=outgoing],[data-motion=off] .gNoOdq_thinkText:before{display:none!important}@media (prefers-reduced-motion:reduce),(forced-colors:active){.gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.gNoOdq_thinkText[data-reader-status-copy=outgoing],.gNoOdq_thinkText:before{display:none!important}}.gNoOdq_processMeta{opacity:0;grid-template-rows:0fr;transition:grid-template-rows .26s cubic-bezier(.22,1,.36,1),opacity .16s ease-out;display:grid}.gNoOdq_processMeta[data-open=true]{opacity:1;grid-template-rows:1fr}.gNoOdq_processMetaInner{min-height:0;overflow:hidden}.gNoOdq_processMetaLine{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:8px;padding:8px 0 0 16px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processMetaLine .gNoOdq_meta{color:inherit}.gNoOdq_chevron{stroke:currentColor;fill:none;stroke-width:1.4px;stroke-linecap:round;stroke-linejoin:round;flex:none;transition:transform .26s cubic-bezier(.22,1,.36,1)}.gNoOdq_chevron[data-open=true]{transform:rotate(90deg)}.gNoOdq_disclosureBody{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_processContents{border-left:1px solid var(--dsw-alias-border-l2);padding:3px 0 2px var(--reader-gutter,16px);margin:0 0 0 var(--reader-rail,6px);color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;display:flow-root}.gNoOdq_processContents>:last-child{margin-bottom:0}.gNoOdq_processCommentary{color:var(--dsw-alias-label-secondary);margin:4px 0 8px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);font-size:14px;line-height:24px}.gNoOdq_processFrame{min-width:0}.gNoOdq_toolActivity{min-width:0;color:var(--dsw-alias-label-secondary)}.gNoOdq_nativeToolRow{min-width:0}.gNoOdq_rowSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.gNoOdq_nativeToolSummary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;font-size:14px;line-height:24px;overflow:hidden}.gNoOdq_nativeToolRow:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px;border-radius:4px}.gNoOdq_toolHeading{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:11px;grid-template-columns:20px minmax(0,1fr) auto;align-items:start;gap:10px;padding:10px 14px 4px;display:grid}.gNoOdq_toolHeading:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_toolHeading:focus-visible{outline-offset:-3px!important}.gNoOdq_toolGlyph{height:22px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:flex}.gNoOdq_toolHeadingCopy{flex-direction:column;gap:3px;min-width:0;display:flex}.gNoOdq_toolTitle{overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px}.gNoOdq_toolTarget{-webkit-line-clamp:2;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:19px;display:-webkit-box;overflow:hidden}.gNoOdq_toolHeadingState{min-height:22px;color:var(--dsw-alias-label-secondary);align-items:center;gap:7px;display:flex}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;gap:6px;margin-left:8px;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_diffAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_summaryRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.gNoOdq_summaryRow>.gNoOdq_diffStatRoot{flex:none;margin-left:auto}.gNoOdq_summaryRow>:first-child{min-width:0}.gNoOdq_diffStatRoot{flex:none;position:relative}.gNoOdq_diffStatButton{cursor:pointer;font:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background .12s,border-color .12s;display:inline-flex}.gNoOdq_diffStatButton:hover,.gNoOdq_diffStatButton:focus-visible,.gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}.gNoOdq_diffStatButton:focus-visible{outline:none}.gNoOdq_diffStatButton[aria-expanded=true] .gNoOdq_diffCaret{opacity:1}.gNoOdq_diffOverlayRow{box-sizing:border-box;flex:100%;width:100%;min-width:0;max-width:100%;margin-top:6px}.gNoOdq_diffOverlay{box-sizing:border-box;background:var(--dsw-alias-bg-module-platform,#7f7f7f14);border:1px solid var(--dsw-alias-border-l2,#80808038);border-radius:10px;flex-direction:column;width:100%;min-width:0;max-width:100%;padding:8px;display:flex;overflow:hidden}.gNoOdq_diffTabs{scrollbar-width:thin;flex-wrap:nowrap;gap:6px;max-width:100%;margin-bottom:4px;padding-bottom:6px;display:flex;overflow-x:auto}.gNoOdq_diffTab{text-overflow:ellipsis;white-space:nowrap;cursor:pointer;max-width:220px;font:inherit;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base,#fffc);border:1px solid var(--dsw-alias-border-l2,#80808033);border-radius:6px;flex:none;padding:3px 10px;font-size:11px;line-height:16px;transition:all .12s;overflow:hidden}.gNoOdq_diffTab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.gNoOdq_diffTab[data-active]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-state-business-primary,#1e90ff);background:var(--dsw-alias-bg-base);font-weight:500}.gNoOdq_diffScrollArea{overscroll-behavior:contain;-webkit-overflow-scrolling:touch;border:1px solid var(--dsw-alias-border-l2,#80808026);background:var(--dsw-alias-markdown-code-block,#0000000a);border-radius:8px;max-height:420px;overflow:auto}.gNoOdq_diffScrollArea [data-diff]{background:0 0!important;border-radius:0!important;margin:0!important}.gNoOdq_diffCaret{opacity:.6;flex:none;width:10px;font-size:10px}.gNoOdq_diffPath{text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;flex:auto;min-width:0;overflow:hidden}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;flex:none;gap:6px;font-size:11px;display:inline-flex}.gNoOdq_diffHunkBody{flex-direction:column;gap:4px;padding:2px 7px 7px 25px;display:flex}.gNoOdq_diffLines{font-size:11px;line-height:1.55;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre;border-radius:6px;margin:0;padding:6px 8px;overflow-x:auto}.gNoOdq_diffLines[data-side=removed]{background:#d1483c1f}.gNoOdq_diffLines[data-side=added]{background:#2f9e631f}.gNoOdq_diffLineRemoved,.gNoOdq_diffLineAdded{display:block}.gNoOdq_diffLineRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_diffLineAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffEmpty{color:var(--dsw-alias-label-secondary);margin:0;padding:2px 0;font-size:11px}.gNoOdq_nativeToolSummary[data-running]{background-image:linear-gradient(90deg, currentColor 0%, currentColor 35%, color-mix(in srgb, currentColor 35%, transparent) 50%, currentColor 65%, currentColor 100%);-webkit-text-fill-color:transparent;background-position:100% 0;background-repeat:no-repeat;background-size:300% 100%;background-clip:text;animation:1.6s linear infinite gNoOdq_readerStepShimmer}@keyframes gNoOdq_readerStepShimmer{to{background-position:0 0}}.gNoOdq_toolElapsed[data-slow]{opacity:1;color:var(--dsw-alias-state-warning-primary,#d8862c);font-weight:500}.gNoOdq_toolElapsed{opacity:.72;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}[data-motion=off] .gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}}.gNoOdq_toolState{white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}.gNoOdq_toolState[data-phase=preparing],.gNoOdq_toolState[data-phase=running]{color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{content:\"\";vertical-align:middle;background:currentColor;border-radius:50%;width:6px;height:6px;margin-right:6px;animation:1.4s ease-in-out infinite gNoOdq_readerRunningGlow;display:inline-block}@keyframes gNoOdq_readerRunningGlow{0%{box-shadow:0 0 0 0 color-mix(in srgb, currentColor 60%, transparent);opacity:1}70%{opacity:.7;box-shadow:0 0 0 7px #0000}to{opacity:1;box-shadow:0 0 #0000}}[data-motion=off] .gNoOdq_toolState[data-phase=preparing]:before,[data-motion=off] .gNoOdq_toolState[data-phase=running]:before{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{animation:none!important}}.gNoOdq_toolState[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.gNoOdq_toolState[data-phase=interrupted]{color:inherit;opacity:.7}.gNoOdq_toolLedger{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:10px 14px 0;font-size:11px;line-height:18px;display:flex}.gNoOdq_toolEngine{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gNoOdq_toolDetails{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;min-width:0;margin:6px 0 0 22px;overflow:hidden}.gNoOdq_toolTabs{align-items:center;gap:15px;padding:0 14px;display:flex}.gNoOdq_toolTabs>button{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;padding:10px 1px 8px;font-size:12px;line-height:20px}.gNoOdq_toolTabs>button[aria-selected=true]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolPanel{flex-direction:column;gap:12px;min-width:0;padding:12px 14px 14px;font-size:13px;line-height:22px;display:flex}.gNoOdq_toolPanel:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_toolDetailNote{color:var(--dsw-alias-label-secondary);margin:0 0 9px;font-size:12px;line-height:20px}.gNoOdq_toolRawLabel{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;font-weight:500}.gNoOdq_toolRaw{background:var(--dsw-alias-bg-module-platform);max-height:400px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_systemPrompt{background:var(--dsw-alias-bg-module-platform);max-height:320px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_commandInput{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.gNoOdq_toolReceipt .gNoOdq_blocks,.gNoOdq_toolDocument .gNoOdq_blocks{font-size:13px;line-height:22px}.gNoOdq_toolChildren{margin:0 14px 12px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:9px;display:flex}@container (width<=420px){.gNoOdq_toolHeading{grid-template-columns:16px minmax(0,1fr) auto;gap:7px;padding:11px 10px 6px}.gNoOdq_toolHeadingState{gap:4px}.gNoOdq_toolLedger{padding-left:33px;padding-right:10px}.gNoOdq_toolPanel{padding:10px}}@media (pointer:coarse){.gNoOdq_toolTabs>button{min-height:44px}}.gNoOdq_reasonCard{--reason-preview-height:224px;--reason-hold:.84s;--reason-step:.5s;--reason-lines:2;--reason-fade:28px;--reason-ease:cubic-bezier(.22, 1, .36, 1);border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);min-width:0;scroll-margin-block:16px calc(var(--dsh-composer-height,152px) + 16px);border-radius:12px;position:relative;overflow:hidden}.gNoOdq_reasonHeading{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;padding:10px 16px 0;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false]{background:0 0;border-color:#0000;border-radius:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonHeading{padding:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonText{padding:4px 0 0 22px}.gNoOdq_reasonLabel{font-weight:500}.gNoOdq_reasonViewport{max-height:var(--reason-preview-height);scroll-behavior:auto;overflow-anchor:none;overscroll-behavior-y:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l1) transparent;position:relative;overflow:auto}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{max-height:min(60vh, 560px, var(--reason-reading-height,560px))}.gNoOdq_reasonViewport[data-edges=both],.gNoOdq_reasonCard[data-following=true][data-overflow=true] .gNoOdq_reasonViewport{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonViewport[data-edges=top]{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%)}.gNoOdq_reasonViewport[data-edges=bottom]{-webkit-mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{mask-image:none}.gNoOdq_reasonViewport:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_reasonTrack{position:relative;transform:translateY(0)}.gNoOdq_reasonCard[data-following=true] .gNoOdq_reasonTrack{will-change:transform}.gNoOdq_reasonText{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;padding:8px 16px 16px;font-size:14px;line-height:24px}.gNoOdq_reasonText .gNoOdq_readingText>div{font-size:inherit;line-height:inherit;color:inherit}.gNoOdq_reasonFooter{color:var(--dsw-alias-label-secondary);justify-content:space-between;align-items:center;gap:8px;padding:2px 10px 8px;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonAction{min-height:28px;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:5px;padding:4px 6px;display:inline-flex}.gNoOdq_reasonAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_reasonAction:disabled{cursor:default;opacity:.65}.gNoOdq_reasonAction svg{fill:none;stroke:currentColor;stroke-width:1.3px;stroke-linecap:round;stroke-linejoin:round;flex:none}.gNoOdq_reasonCaption{padding-left:6px}@container (width<=480px){.gNoOdq_reasonCard{--reason-preview-height:192px}}@media (pointer:coarse){.gNoOdq_reasonAction{min-height:44px}}@media (prefers-reduced-motion:reduce){.gNoOdq_reasonTrack{will-change:auto!important;transition:none!important;transform:none!important}}@media (forced-colors:active){.gNoOdq_reasonViewport{mask-image:none!important}}.gNoOdq_processItem,.gNoOdq_tool{min-width:0;margin:0 0 18px}.gNoOdq_processLabel{color:var(--dsw-alias-label-tertiary);align-items:baseline;gap:12px;margin:0 0 6px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processFootnote{color:var(--dsw-alias-label-tertiary);margin:14px 0 0;font-size:12px;line-height:20px}.gNoOdq_detail{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:22px}.gNoOdq_detail>summary{cursor:pointer;padding:3px 0}.gNoOdq_detail[open]>summary{margin-bottom:8px}.gNoOdq_tool>.gNoOdq_tool{margin:10px 0 0 12px}.gNoOdq_meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px}.gNoOdq_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;margin-top:12px;padding:0 6px;font-size:11px;line-height:18px}.gNoOdq_compactionRow{box-sizing:border-box;flex-direction:column;align-items:center;width:100%;margin:16px 0;display:flex}.gNoOdq_compactionLine{width:100%;color:var(--dsw-alias-label-tertiary);-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;gap:12px;font-size:11px;line-height:18px;display:flex}.gNoOdq_compactionLine:before,.gNoOdq_compactionLine:after{content:\"\";background:var(--dsw-alias-border-l1);opacity:.7;flex:1;height:1px}.gNoOdq_compactionRow>.gNoOdq_compactionLine{animation:.52s cubic-bezier(.4,0,.2,1) both gNoOdq_compactionLineIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill{animation:.42s cubic-bezier(.34,1.4,.64,1) .12s both gNoOdq_compactionPillIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:.9s cubic-bezier(.4,0,.2,1) .2s both gNoOdq_compactionDial}@keyframes gNoOdq_compactionLineIn{0%{opacity:0;transform:scaleX(.6)}to{opacity:1;transform:scaleX(1)}}@keyframes gNoOdq_compactionPillIn{0%{opacity:0;transform:translateY(-6px)scale(.94)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes gNoOdq_compactionDial{0%{opacity:0;transform:rotate(-140deg)}to{opacity:.7;transform:rotate(0)}}[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_compactionRow>.gNoOdq_compactionLine,.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}}.gNoOdq_compactionPill{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);border-radius:12px;align-items:center;gap:6px;padding:2px 10px;font-family:inherit;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_compactionButton{cursor:pointer;transition:color .14s,border-color .14s,background-color .14s}.gNoOdq_compactionButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_compactionIcon{opacity:.7;flex:none;width:12px;height:12px}.gNoOdq_compactionToggle{opacity:.8;margin-left:2px;font-size:10px}.gNoOdq_compactionSummaryBox{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);width:100%;max-width:680px;color:var(--dsw-alias-label-secondary);box-sizing:border-box;border-radius:8px;margin-top:10px;padding:12px 16px;font-size:12px;line-height:20px}.gNoOdq_compactionSummaryHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px dashed var(--dsw-alias-border-l1);margin-bottom:8px;padding-bottom:4px;font-size:11px;font-weight:500}.gNoOdq_notice,.gNoOdq_error,.gNoOdq_attention{overflow-wrap:anywhere;border-radius:10px;padding:12px 14px;font-size:13px;line-height:20px}.gNoOdq_notice{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}.gNoOdq_error{color:var(--dsw-alias-label-primary);background:#ef44440f;border:1px solid #ef444438;align-items:flex-start;gap:10px;display:flex}.gNoOdq_errorIcon{color:#ef4444;flex:none;width:16px;height:16px;margin-top:2px}.gNoOdq_errorCopy{flex:1;min-width:0}.gNoOdq_errorTitle{color:#dc2626;align-items:center;gap:8px;margin-bottom:2px;font-weight:500;display:flex}.gNoOdq_errorMessage{color:var(--dsw-alias-label-secondary);word-break:break-word;margin:0;font-size:12px;line-height:18px}.gNoOdq_errorCode{color:#dc2626;background:#ef44441f;border-radius:4px;padding:1px 5px;font-family:inherit;font-size:11px}.gNoOdq_attention{border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);flex-direction:column;gap:3px;display:flex}.gNoOdq_attention span{color:var(--dsw-alias-label-secondary)}.gNoOdq_unknown{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:12px 14px;font-size:13px;line-height:22px}.gNoOdq_unknown p{margin:0 0 6px}.gNoOdq_historyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;align-self:center;padding:4px 12px;font-size:12px}.gNoOdq_historyButton:disabled{opacity:.55;cursor:default}.gNoOdq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;padding:40px 0}.gNoOdq_answerActions{align-items:center;gap:8px;min-height:28px;margin:13px 0 0 -6px;display:flex}.gNoOdq_userActions{align-items:center;gap:8px;min-height:28px;display:flex}.gNoOdq_messageClock{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:13px;line-height:24px}.gNoOdq_iconButton{color:var(--dsw-alias-label-tertiary);background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.gNoOdq_iconButton svg{fill:none;stroke:currentColor;stroke-width:1.2px;stroke-linecap:round;stroke-linejoin:round}.gNoOdq_imageFigure{box-sizing:border-box;align-self:flex-start;width:min(100%,360px);max-width:100%;margin:0}.gNoOdq_imageFrame{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;border-radius:12px;max-width:100%;min-height:96px;max-height:440px;position:relative;overflow:hidden}.gNoOdq_imageOpen{background:0 0;border:0;width:100%;height:100%;padding:0;display:flex;position:absolute;inset:0}.gNoOdq_imageOpen img{object-fit:contain;opacity:0;width:100%;height:100%;transition:opacity .2s cubic-bezier(.4,0,.2,1);display:block}.gNoOdq_imageOpen img[data-ready=true]{opacity:1}.gNoOdq_pendingImage{object-fit:contain;width:100%;max-width:100%;height:100%;display:block}.gNoOdq_imagePlaceholder{color:var(--dsw-alias-label-tertiary);pointer-events:none;flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:13px;display:flex;position:absolute;inset:0}.gNoOdq_imagePlaceholder button{pointer-events:auto}.gNoOdq_imageFigure figcaption{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin-top:6px;font-size:12px;line-height:20px}.gNoOdq_imageDialog{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:16px;max-width:90vw;max-height:90vh;padding:38px 20px 20px}.gNoOdq_imageDialog::backdrop{background:var(--dsw-alias-bg-mask-photo)}.gNoOdq_imageDialog img{object-fit:contain;max-width:82vw;max-height:75vh;display:block}.gNoOdq_dialogClose{color:inherit;background:0 0;border:0;border-radius:8px;width:32px;height:32px;font-size:24px;position:absolute;top:4px;right:8px}.gNoOdq_jumpDock{bottom:calc(var(--dsh-composer-height,152px) + 16px);z-index:8;pointer-events:none;justify-content:flex-end;height:0;display:flex;position:sticky}.gNoOdq_deliverablesRoot{grid-template-columns:max-content minmax(0,1fr);align-items:start;column-gap:10px;margin-top:14px;font-size:13px;line-height:22px;display:grid}.gNoOdq_deliverablesLabel{color:var(--dsw-alias-label-tertiary);grid-area:1/1;padding-top:2px;font-size:12px;font-weight:500}.gNoOdq_deliverablesLane{grid-area:1/2;min-width:0}.gNoOdq_deliverablesRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.gNoOdq_deliverableChip{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;font-size:12px;line-height:20px;transition:border-color .16s,background-color .16s,color .16s;display:inline-flex;overflow:hidden}.gNoOdq_deliverableChip:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-module-platform);box-shadow:0 1px 4px var(--dsw-alias-border-l1)}.gNoOdq_deliverableChip[data-status=opened]{color:#059669;background:#10b9811f;border-color:#10b981}.gNoOdq_chipMain{max-width:220px;color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:5px;padding:3px 6px 3px 8px;display:inline-flex}.gNoOdq_chipMain:hover{color:var(--dsw-alias-label-primary)}.gNoOdq_deliverableIcon,.gNoOdq_statusIcon{opacity:.8;flex:none;width:13px;height:13px}.gNoOdq_statusIcon{color:#10b981}.gNoOdq_deliverableName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.gNoOdq_chipActions{opacity:.65;border-left:1px solid #0000;align-items:center;gap:2px;padding-right:4px;transition:opacity .15s,border-left-color .15s;display:inline-flex}.gNoOdq_deliverableChip:hover .gNoOdq_chipActions{opacity:1;border-left-color:var(--dsw-alias-border-l2)}.gNoOdq_chipActionBtn{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;transition:color .12s,background-color .12s;display:inline-flex}.gNoOdq_chipActionBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_actionIcon{width:12px;height:12px}.gNoOdq_deliverablesMore{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.gNoOdq_deliverablesShowFolder{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:5px;align-items:center;gap:4px;padding:2px 7px;font-size:12px;transition:all .15s;display:inline-flex}.gNoOdq_deliverablesShowFolder:hover{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}.gNoOdq_deliverablesShowFolder[data-status=opened]{color:#10b981;background:#10b98114;border-color:#10b9814d}.gNoOdq_morphCluster{flex-direction:column;width:100%;min-width:0;display:flex}.gNoOdq_morphDrawer{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_liveFoldImpact{animation:.18s cubic-bezier(.2,0,0,1) both gNoOdq_liveFoldElastic}@keyframes gNoOdq_liveFoldElastic{0%{transform:scale(1)}50%{transform:scale(1.015)}to{transform:scale(1)}}.gNoOdq_liveFoldContainer{top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px)) + var(--reader-sticky-lane,40px) * 2);z-index:4;background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);transform-origin:0;will-change:transform, opacity;margin-bottom:6px;padding:4px 0;animation:.32s cubic-bezier(.16,1,.3,1) both gNoOdq_liveFoldPulse;position:sticky}@keyframes gNoOdq_liveFoldPulse{0%{opacity:.8;transform:translateY(-4px)scale(.98)}50%{opacity:1;transform:translateY(0)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}[data-motion=off] .gNoOdq_liveFoldContainer{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_liveFoldContainer{animation:none!important}}.gNoOdq_priorFoldDrawer{flex-direction:column;gap:14px;width:100%;min-width:0;display:flex}.gNoOdq_jump{width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill,var(--dsw-alias-bg-base));box-shadow:var(--dsw-elevation-panel,0 2px 8px var(--dsw-alias-border-l1));pointer-events:auto;border:0;border-radius:100px;flex:none;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.gNoOdq_jump:hover{background:var(--dsw-alias-button-floating-hover,var(--dsw-alias-interactive-bg-hover))}.gNoOdq_foldSummary{text-overflow:ellipsis;align-items:baseline;max-width:100%;display:inline-flex;overflow:hidden;white-space:nowrap!important}.gNoOdq_foldSummaryPart{flex:none;align-items:baseline;display:inline-flex;white-space:nowrap!important}.gNoOdq_numberRollRoot{vertical-align:baseline;line-height:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";text-align:center;flex-shrink:0;justify-content:center;min-width:1.45em;display:inline-flex;position:relative;overflow:hidden;white-space:nowrap!important}.gNoOdq_numberRollSizer{visibility:hidden;-webkit-user-select:none;user-select:none;pointer-events:none;line-height:inherit;white-space:nowrap}.gNoOdq_numberRollDigit{line-height:inherit;white-space:nowrap;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.gNoOdq_numberRollExit{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollOut}.gNoOdq_numberRollEnter{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollIn}@keyframes gNoOdq_numberRollOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}@keyframes gNoOdq_numberRollIn{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}[data-motion=off] .gNoOdq_chevron,[data-motion=off] .gNoOdq_imageOpen img,[data-motion=off] .gNoOdq_processMeta,[data-motion=off] .gNoOdq_numberRollDigit{transition:none!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_chevron,.gNoOdq_imageOpen img,.gNoOdq_processMeta,.gNoOdq_numberRollDigit{transition:none!important;animation:none!important}}.gNoOdq_turnStatus{white-space:nowrap;flex:none;align-self:flex-start;align-items:center;height:26px;margin:4px 0 12px;padding:0 4px;font-size:14px;line-height:22px;display:inline-flex}.gNoOdq_turnStatusLabel{background:linear-gradient(90deg, var(--dsw-static-deepseek-500,#4d6bfe) 0%, var(--dsw-static-deepseek-500,#4d6bfe) 40%, var(--dsw-static-deepseek-200,#a8c7fa) 50%, var(--dsw-static-deepseek-500,#4d6bfe) 60%, var(--dsw-static-deepseek-500,#4d6bfe) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;background-clip:text;font-weight:500;animation:1.8s linear infinite gNoOdq_dsh-turn-status-shimmer}.gNoOdq_waitClock{flex:none;align-items:center;margin-left:8px;display:inline-flex}.gNoOdq_waitSeconds{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86909c);font-size:13px;font-weight:400}.gNoOdq_waitOvertime{color:var(--dsw-alias-state-warning-primary,#d8862c);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,#d8862c) 16%, transparent);border-radius:5px;margin-left:8px;padding:0 6px;font-size:11px;line-height:16px}.gNoOdq_turnStatusClock{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86868b);-webkit-text-fill-color:var(--dsw-alias-label-caption,#86868b);margin-left:8px;font-size:13px;font-weight:400}@keyframes gNoOdq_dsh-turn-status-shimmer{to{background-position:0 0}}[data-motion=off] .gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}}@media (pointer:coarse){.gNoOdq_disclosureButton{min-height:44px}}@media (width<=600px){.gNoOdq_root{padding-inline:20px}.gNoOdq_column{gap:18px}.gNoOdq_toolbar{font-size:11px}.gNoOdq_user{max-width:90%}}.gNoOdq_choreographedFlow{overflow-anchor:none;flex-direction:column;min-width:0;display:flex}.gNoOdq_flowCell{min-width:0;display:flow-root;overflow:clip}.gNoOdq_flowCell[hidden]{display:none}.gNoOdq_flowCellInner{flex-direction:column;min-width:0;padding-bottom:16px;display:flex}.gNoOdq_flowCellInner:empty{padding-bottom:0}.gNoOdq_choreographedFlow[data-reader-transition=collapse] .gNoOdq_flowCell *{animation-play-state:paused!important}.gNoOdq_numberRollExit,.gNoOdq_numberRollEnter{animation-duration:.16s}.gNoOdq_foldSummary{align-items:baseline;display:inline-flex;white-space:nowrap!important;flex-wrap:nowrap!important}.gNoOdq_toolbar{box-sizing:border-box;z-index:7;-webkit-backdrop-filter:none;backdrop-filter:none;border-bottom:0;align-self:stretch;width:100%;max-width:100%;min-height:40px}.gNoOdq_turnProcessSticky{box-sizing:border-box;width:calc(100% - var(--reader-control-width,148px));top:max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px));z-index:6;-webkit-backdrop-filter:none;backdrop-filter:none;min-height:40px;box-shadow:0 -14px 0 var(--dsw-alias-bg-base), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-base);background-clip:padding-box;border-bottom:1px solid #0000;padding-right:0}.gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky,.gNoOdq_turnStickyLanes .gNoOdq_closedProcessSummary{z-index:auto;position:static;top:auto}.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px)) + var(--reader-sticky-lane,40px));z-index:5;box-sizing:border-box;background:var(--dsw-alias-bg-base);border-bottom:0;min-height:40px;padding-block:4px;position:sticky;overflow:visible}.gNoOdq_root .md-code-block{z-index:0}.gNoOdq_turnStickyRegion:has(>.gNoOdq_turnStickyLanes>.gNoOdq_closedProcessSummary),.gNoOdq_turnStickyRegion:has(.gNoOdq_flowCell[data-flow-summary]){--reader-code-summary-height:var(--reader-sticky-lane,40px)}.gNoOdq_root .md-code-block>:has(+[data-code-block-content]){top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,0px)) + var(--reader-status-height,0px) + var(--reader-code-summary-height,0px))}.gNoOdq_flowCell[data-flow-summary]{box-shadow:0 -16px 0 var(--dsw-alias-bg-base)}.gNoOdq_closedProcessSummary{box-shadow:0 -14px 0 var(--dsw-alias-bg-base)}.gNoOdq_foldControl{background:var(--dsw-alias-bg-module-platform);border-radius:8px;align-items:center;gap:0;padding:2px;display:inline-flex}.gNoOdq_foldStop{color:var(--dsw-alias-label-secondary);white-space:nowrap;font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:2px 8px;font-size:12px;line-height:18px}.gNoOdq_foldStop[data-on]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.gNoOdq_flowCell[data-flow-summary]>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_disclosureButton,.gNoOdq_closedProcessSummary .gNoOdq_disclosureButton{width:auto;max-width:100%}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_foldSummary,.gNoOdq_closedProcessSummary .gNoOdq_foldSummary{min-width:0}.gNoOdq_turnProcessSticky>.gNoOdq_disclosure{flex:auto;min-width:0}.gNoOdq_disclosureButton{width:max-content;max-width:calc(100% + 6px)}.gNoOdq_statusText{flex:0 auto}.gNoOdq_think{width:max-content;min-width:0}.gNoOdq_thinkSizer{white-space:normal;overflow-wrap:anywhere}.gNoOdq_thinkText{white-space:normal;overflow-wrap:anywhere;text-overflow:clip;overflow:visible}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky,.gNoOdq_root[data-reader-glass] .gNoOdq_liveFoldContainer{-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);box-shadow:none;background:0 0;border:0;border-radius:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky{-webkit-backdrop-filter:none;backdrop-filter:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar{pointer-events:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{pointer-events:auto;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1,#ffffffb3) 80%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-radius:999px;padding:2px 10px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{max-width:100%;margin-left:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root[data-reader-glass] .gNoOdq_flowCell[data-flow-summary],.gNoOdq_root[data-reader-glass] .gNoOdq_closedProcessSummary{box-shadow:none;z-index:auto;border-left:2px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808059) 80%, transparent);padding-block:2px;background:0 0;border-radius:0;min-height:32px;padding-left:10px;position:static}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes{z-index:auto;display:contents;position:static;top:auto}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyRegion{--reader-code-summary-height:0px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky{top:max(var(--reader-toolbar-height,40px), var(--reader-status-height,40px));z-index:6;position:sticky}.gNoOdq_root[data-reader-glass] .gNoOdq_user{background:color-mix(in srgb, var(--dsw-specific-bubble,#00000014) 25%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#8080804d) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_reasonCard{border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#80808059) 65%, transparent);background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolDetails,.gNoOdq_root[data-reader-glass] .gNoOdq_notice,.gNoOdq_root[data-reader-glass] .gNoOdq_unknown,.gNoOdq_root[data-reader-glass] .gNoOdq_toolRaw,.gNoOdq_root[data-reader-glass] .gNoOdq_systemPrompt,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionSummaryBox,.gNoOdq_root[data-reader-glass] .gNoOdq_attention,.gNoOdq_root[data-reader-glass] .gNoOdq_imageFrame,.gNoOdq_root[data-reader-glass] .gNoOdq_imageDialog{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffOverlay{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 20%, transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffScrollArea{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fffc) 25%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab[data-active]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 45%, transparent)}:is(.gNoOdq_root[data-reader-glass] .md-code-block,.gNoOdq_root[data-reader-glass] [data-diff]){border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#80808033) 30%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block,#0000000f) 25%, transparent)!important}.gNoOdq_root[data-reader-glass] .gNoOdq_foldControl{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 25%, transparent);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808033) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_foldStop[data-on]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 35%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton{background:0 0;border-color:#0000}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:focus-within,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}";
|
|
42739
|
+
const css$5 = ".gNoOdq_root{color:var(--dsw-alias-label-primary);padding:16px calc(var(--dsh-composer-side-clearance,16px) + 16px) 24px;overflow-anchor:auto;--reader-lane-block:max(40px, calc(40px + var(--dsh-content-font-delta,0px)));--reader-lane-plate:linear-gradient(var(--dsw-alias-bg-base), var(--dsw-alias-bg-base)), linear-gradient(var(--dsw-alias-bg-layer-1,transparent), var(--dsw-alias-bg-layer-1,transparent));flex:none;min-width:0;font-family:inherit;font-size:16px;line-height:28px;container-type:inline-size}.gNoOdq_column{max-width:var(--dsh-chat-content-width,748px);flex-direction:column;gap:22px;width:100%;min-width:0;margin:0 auto;display:flex}.gNoOdq_column:focus,.gNoOdq_column:focus-visible{outline:none}.gNoOdq_toolbar{min-height:32px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);justify-content:flex-end;align-items:center;gap:6px;padding:0;font-size:12px;display:flex;position:sticky;top:0}.gNoOdq_turnProcessSticky{background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);align-items:center;min-height:32px;display:flex;position:sticky}.gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{min-height:32px}.gNoOdq_textButton,.gNoOdq_historyButton,.gNoOdq_iconButton,.gNoOdq_jump,.gNoOdq_disclosureButton,.gNoOdq_imageOpen,.gNoOdq_dialogClose{font:inherit;cursor:pointer}.gNoOdq_textButton{color:var(--dsw-alias-label-secondary);white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:2px 6px}.gNoOdq_textButton:hover,.gNoOdq_iconButton:hover,.gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root button:focus-visible,.gNoOdq_root summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px}.gNoOdq_turn,.gNoOdq_turnStickyRegion{flex-direction:column;gap:14px;min-width:0;display:flex}.gNoOdq_turnStickyLanes{top:var(--reader-toolbar-height,var(--reader-lane-block,40px));z-index:6;flex-direction:column;min-width:0;display:flex;position:sticky}.gNoOdq_turn+.gNoOdq_turn,.gNoOdq_retiringContent+.gNoOdq_retiringContent>.gNoOdq_turn{margin-top:12px}.gNoOdq_userCluster{flex-direction:column;align-self:stretch;align-items:flex-end;gap:8px;width:100%;min-width:0;max-width:100%;margin-bottom:4px;display:flex}.gNoOdq_userCluster>[data-slot]>*{box-sizing:border-box;align-self:stretch;width:100%;min-width:0;max-width:100%}.gNoOdq_userImages{flex-direction:column;align-self:flex-end;align-items:flex-end;width:fit-content;min-width:0;max-width:100%;display:flex}.gNoOdq_userImages .gNoOdq_imageFigure{align-self:flex-end}.gNoOdq_user{width:fit-content;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);border-radius:var(--dsw-radius-xl,22px);background:var(--dsw-specific-bubble);color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;box-sizing:border-box;align-self:flex-end;margin-left:auto;padding:10px 16px;font-weight:400}.gNoOdq_user .gNoOdq_blocks{gap:10px}.gNoOdq_answer{overflow-wrap:anywhere;flex-direction:column;min-width:0;display:flex}.gNoOdq_readingText{min-width:0}.gNoOdq_reasonPlain{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;color:inherit}.gNoOdq_readingText button{min-width:24px;min-height:24px}.gNoOdq_streamWord{display:inline-block}.gNoOdq_streamInlineWord{display:inline}.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1;filter:none}.gNoOdq_streamAtom{min-width:0}@media (prefers-reduced-motion:reduce){.gNoOdq_streamWord,.gNoOdq_streamInlineWord,.gNoOdq_streamAtom{opacity:1!important;filter:none!important}}.gNoOdq_retiringContent{min-width:0}.gNoOdq_retiringContent[data-reader-retiring=retiring]{overflow:hidden}.gNoOdq_mainFlow,.gNoOdq_blocks{flex-direction:column;gap:16px;min-width:0;display:flex}.gNoOdq_mainFlow:empty,.gNoOdq_blocks:empty{display:none}.gNoOdq_blocks>:first-child{margin-top:0}.gNoOdq_blocks>:last-child{margin-bottom:0}.gNoOdq_blocks .md-table-wide{max-width:100%}.gNoOdq_disclosure{min-width:0}.gNoOdq_disclosureButton{max-width:100%;min-height:32px;color:var(--dsw-alias-label-tertiary);font-size:calc(14px + var(--dsh-content-font-delta,0px));line-height:calc(24px + var(--dsh-content-font-delta,0px));text-align:left;background:0 0;border:0;border-radius:7px;align-items:center;gap:6px;margin-left:-6px;padding:4px 6px;font-weight:400;display:inline-flex}.gNoOdq_disclosure[data-reader-status-only]{align-items:center;min-height:32px;display:flex}.gNoOdq_statusText{min-width:0;max-width:100%;font-size:calc(14px + var(--dsh-content-font-delta,0px));line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);font-weight:400;display:inline-flex}.gNoOdq_srOnly{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.gNoOdq_think{--think-swap:.15s;--think-gap:50ms;--think-distance:8px;--think-blur:2px;--think-shimmer:2s;--think-base:var(--dsw-alias-label-secondary);--think-highlight:var(--dsw-alias-label-primary);--think-ease:ease-in-out;text-align:left;max-width:100%;display:inline-block;position:relative}.gNoOdq_thinkSizer{visibility:hidden;white-space:nowrap;display:block}.gNoOdq_thinkText{color:var(--think-base);white-space:nowrap;text-overflow:ellipsis;filter:blur();opacity:1;transition:transform var(--think-swap) var(--think-ease), filter var(--think-swap) var(--think-ease), opacity var(--think-swap) var(--think-ease);display:block;position:absolute;top:0;left:0;right:0;overflow:hidden;transform:translateY(0)}.gNoOdq_think[data-reader-status-phase=running] .gNoOdq_thinkText[data-reader-status-copy=current]{transition-delay:var(--think-gap)}.gNoOdq_think:not([data-reader-status-phase=idle]) .gNoOdq_thinkText{will-change:transform, filter, opacity}@supports (background-clip:text){.gNoOdq_think[data-active=true] .gNoOdq_thinkText:before{content:attr(data-text);pointer-events:none;background-image:linear-gradient(90deg, transparent 0%, transparent 40%, var(--think-highlight) 50%, transparent 60%, transparent 100%);color:#0000;-webkit-text-fill-color:transparent;animation:gNoOdq_thinkShimmer var(--think-shimmer) linear infinite;background-repeat:no-repeat;background-size:400% 100%;background-clip:text;position:absolute;inset:0}}@keyframes gNoOdq_thinkShimmer{0%{background-position:100% 0}to{background-position:0 0}}.gNoOdq_thinkText.gNoOdq_isExit{transform:translateY(calc(var(--think-distance) * -1));filter:blur(var(--think-blur));opacity:0}.gNoOdq_thinkText.gNoOdq_isEnterStart{transform:translateY(var(--think-distance));filter:blur(var(--think-blur));opacity:0;transition:none}[data-motion=off] .gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}[data-motion=off] .gNoOdq_thinkText[data-reader-status-copy=outgoing],[data-motion=off] .gNoOdq_thinkText:before{display:none!important}@media (prefers-reduced-motion:reduce),(forced-colors:active){.gNoOdq_thinkText{filter:none!important;opacity:1!important;transition:none!important;transform:none!important}.gNoOdq_thinkText[data-reader-status-copy=outgoing],.gNoOdq_thinkText:before{display:none!important}}.gNoOdq_processMeta{opacity:0;grid-template-rows:0fr;transition:grid-template-rows .26s cubic-bezier(.22,1,.36,1),opacity .16s ease-out;display:grid}.gNoOdq_processMeta[data-open=true]{opacity:1;grid-template-rows:1fr}.gNoOdq_processMetaInner{min-height:0;overflow:hidden}.gNoOdq_processMetaLine{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:8px;padding:8px 0 0 16px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processMetaLine .gNoOdq_meta{color:inherit}.gNoOdq_chevron{stroke:currentColor;fill:none;stroke-width:1.4px;stroke-linecap:round;stroke-linejoin:round;flex:none;transition:transform .26s cubic-bezier(.22,1,.36,1)}.gNoOdq_chevron[data-open=true]{transform:rotate(90deg)}.gNoOdq_disclosureBody{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_processContents{border-left:1px solid var(--dsw-alias-border-l2);padding:3px 0 2px var(--reader-gutter,16px);margin:0 0 0 var(--reader-rail,6px);color:var(--dsw-alias-label-secondary);font-size:14px;line-height:24px;display:flow-root}.gNoOdq_processContents>:last-child{margin-bottom:0}.gNoOdq_processSeamRow{min-height:40px;margin-left:var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;align-items:center;display:flex}.gNoOdq_processSeamRow>.gNoOdq_disclosure{align-items:center;min-height:24px;display:flex}.gNoOdq_processSeamRow .gNoOdq_disclosureButton{min-height:24px;color:var(--dsw-alias-label-tertiary);padding-block:2px;font-size:12px;line-height:20px}.gNoOdq_flowCell:has(>.gNoOdq_flowCellInner>[data-reader-seam-after])>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_processFrame{min-width:0}.gNoOdq_toolActivity{min-width:0;color:var(--dsw-alias-label-secondary)}.gNoOdq_nativeToolRow{min-width:0}.gNoOdq_rowSeparator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.gNoOdq_nativeToolSummary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;font-size:14px;line-height:24px;overflow:hidden}.gNoOdq_nativeToolRow:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:3px;border-radius:4px}.gNoOdq_toolHeading{width:100%;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:11px;grid-template-columns:20px minmax(0,1fr) auto;align-items:start;gap:10px;padding:10px 14px 4px;display:grid}.gNoOdq_toolHeading:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_toolHeading:focus-visible{outline-offset:-3px!important}.gNoOdq_toolGlyph{height:22px;color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;display:flex}.gNoOdq_toolHeadingCopy{flex-direction:column;gap:3px;min-width:0;display:flex}.gNoOdq_toolTitle{overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px}.gNoOdq_toolTarget{-webkit-line-clamp:2;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary);-webkit-box-orient:vertical;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:19px;display:-webkit-box;overflow:hidden}.gNoOdq_toolHeadingState{min-height:22px;color:var(--dsw-alias-label-secondary);align-items:center;gap:7px;display:flex}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;gap:6px;margin-left:8px;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_diffAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_summaryRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;max-width:100%;display:flex}.gNoOdq_summaryRow>.gNoOdq_diffStatRoot{flex:none;margin-left:auto}.gNoOdq_summaryRow>:first-child{min-width:0}.gNoOdq_diffStatRoot{flex:none;position:relative}.gNoOdq_diffStatButton{cursor:pointer;font:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-secondary);background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:2px 8px;font-size:11px;line-height:16px;transition:background .12s,border-color .12s;display:inline-flex}.gNoOdq_diffStatButton:hover,.gNoOdq_diffStatButton:focus-visible,.gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}.gNoOdq_diffStatButton:focus-visible{outline:none}.gNoOdq_diffStatButton[aria-expanded=true] .gNoOdq_diffCaret{opacity:1}.gNoOdq_diffOverlayRow{box-sizing:border-box;flex:100%;width:100%;min-width:0;max-width:100%;margin-top:6px}.gNoOdq_diffOverlay{box-sizing:border-box;background:var(--dsw-alias-bg-module-platform,#7f7f7f14);border:1px solid var(--dsw-alias-border-l2,#80808038);border-radius:10px;flex-direction:column;width:100%;min-width:0;max-width:100%;padding:8px;display:flex;overflow:hidden}.gNoOdq_diffTabs{scrollbar-width:thin;flex-wrap:nowrap;gap:6px;max-width:100%;margin-bottom:4px;padding-bottom:6px;display:flex;overflow-x:auto}.gNoOdq_diffTab{text-overflow:ellipsis;white-space:nowrap;cursor:pointer;max-width:220px;font:inherit;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base,#fffc);border:1px solid var(--dsw-alias-border-l2,#80808033);border-radius:6px;flex:none;padding:3px 10px;font-size:11px;line-height:16px;transition:all .12s;overflow:hidden}.gNoOdq_diffTab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.gNoOdq_diffTab[data-active]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-state-business-primary,#1e90ff);background:var(--dsw-alias-bg-base);font-weight:500}.gNoOdq_diffScrollArea{overscroll-behavior:contain;-webkit-overflow-scrolling:touch;border:1px solid var(--dsw-alias-border-l2,#80808026);background:var(--dsw-alias-markdown-code-block,#0000000a);border-radius:8px;max-height:420px;overflow:auto}.gNoOdq_diffScrollArea [data-diff]{background:0 0!important;border-radius:0!important;margin:0!important}.gNoOdq_diffCaret{opacity:.6;flex:none;width:10px;font-size:10px}.gNoOdq_diffPath{text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;flex:auto;min-width:0;overflow:hidden}.gNoOdq_diffStat{font-variant-numeric:tabular-nums;flex:none;gap:6px;font-size:11px;display:inline-flex}.gNoOdq_diffHunkBody{flex-direction:column;gap:4px;padding:2px 7px 7px 25px;display:flex}.gNoOdq_diffLines{font-size:11px;line-height:1.55;font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);white-space:pre;border-radius:6px;margin:0;padding:6px 8px;overflow-x:auto}.gNoOdq_diffLines[data-side=removed]{background:#d1483c1f}.gNoOdq_diffLines[data-side=added]{background:#2f9e631f}.gNoOdq_diffLineRemoved,.gNoOdq_diffLineAdded{display:block}.gNoOdq_diffLineRemoved{color:var(--dsw-alias-state-error-primary,#d1483c)}.gNoOdq_diffLineAdded{color:var(--dsw-alias-state-success-primary,#2f9e63)}.gNoOdq_diffEmpty{color:var(--dsw-alias-label-secondary);margin:0;padding:2px 0;font-size:11px}.gNoOdq_nativeToolSummary[data-running]{background-image:linear-gradient(90deg, currentColor 0%, currentColor 35%, color-mix(in srgb, currentColor 35%, transparent) 50%, currentColor 65%, currentColor 100%);-webkit-text-fill-color:transparent;background-position:100% 0;background-repeat:no-repeat;background-size:300% 100%;background-clip:text;animation:1.6s linear infinite gNoOdq_readerStepShimmer}@keyframes gNoOdq_readerStepShimmer{to{background-position:0 0}}.gNoOdq_toolElapsed[data-slow]{opacity:1;color:var(--dsw-alias-state-warning-primary,#d8862c);font-weight:500}.gNoOdq_toolElapsed{opacity:.72;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}[data-motion=off] .gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_nativeToolSummary[data-running]{-webkit-text-fill-color:currentColor;background-image:none;animation:none!important}}.gNoOdq_toolState{white-space:nowrap;flex:none;margin-left:8px;font-size:11px;line-height:18px}.gNoOdq_toolState[data-phase=preparing],.gNoOdq_toolState[data-phase=running]{color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{content:\"\";vertical-align:middle;background:currentColor;border-radius:50%;width:6px;height:6px;margin-right:6px;animation:1.4s ease-in-out infinite gNoOdq_readerRunningGlow;display:inline-block}@keyframes gNoOdq_readerRunningGlow{0%{box-shadow:0 0 0 0 color-mix(in srgb, currentColor 60%, transparent);opacity:1}70%{opacity:.7;box-shadow:0 0 0 7px #0000}to{opacity:1;box-shadow:0 0 #0000}}[data-motion=off] .gNoOdq_toolState[data-phase=preparing]:before,[data-motion=off] .gNoOdq_toolState[data-phase=running]:before{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_toolState[data-phase=preparing]:before,.gNoOdq_toolState[data-phase=running]:before{animation:none!important}}.gNoOdq_toolState[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.gNoOdq_toolState[data-phase=interrupted]{color:inherit;opacity:.7}.gNoOdq_toolLedger{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex-wrap:wrap;align-items:baseline;gap:4px 12px;padding:10px 14px 0;font-size:11px;line-height:18px;display:flex}.gNoOdq_toolEngine{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.gNoOdq_toolDetails{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;min-width:0;margin:6px 0 0 22px;overflow:hidden}.gNoOdq_toolTabs{align-items:center;gap:15px;padding:0 14px;display:flex}.gNoOdq_toolTabs>button{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-bottom:2px solid #0000;padding:10px 1px 8px;font-size:12px;line-height:20px}.gNoOdq_toolTabs>button[aria-selected=true]{color:var(--dsw-alias-label-primary);border-bottom-color:var(--dsw-alias-state-business-primary)}.gNoOdq_toolPanel{flex-direction:column;gap:12px;min-width:0;padding:12px 14px 14px;font-size:13px;line-height:22px;display:flex}.gNoOdq_toolPanel:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_toolDetailNote{color:var(--dsw-alias-label-secondary);margin:0 0 9px;font-size:12px;line-height:20px}.gNoOdq_toolRawLabel{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;font-weight:500}.gNoOdq_toolRaw{background:var(--dsw-alias-bg-module-platform);max-height:400px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_systemPrompt{background:var(--dsw-alias-bg-module-platform);max-height:320px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:12px;font:12px/20px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:auto}.gNoOdq_commandInput{white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.gNoOdq_toolReceipt .gNoOdq_blocks,.gNoOdq_toolDocument .gNoOdq_blocks{font-size:13px;line-height:22px}.gNoOdq_toolChildren{margin:0 14px 12px var(--reader-rail,6px);padding-left:var(--reader-gutter,16px);border-left:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:9px;display:flex}@container (width<=420px){.gNoOdq_toolHeading{grid-template-columns:16px minmax(0,1fr) auto;gap:7px;padding:11px 10px 6px}.gNoOdq_toolHeadingState{gap:4px}.gNoOdq_toolLedger{padding-left:33px;padding-right:10px}.gNoOdq_toolPanel{padding:10px}}@media (pointer:coarse){.gNoOdq_toolTabs>button{min-height:44px}}.gNoOdq_reasonCard{--reason-preview-height:224px;--reason-hold:.84s;--reason-step:.5s;--reason-lines:2;--reason-fade:28px;--reason-ease:cubic-bezier(.22, 1, .36, 1);border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);min-width:0;scroll-margin-block:16px calc(var(--dsh-composer-height,152px) + 16px);border-radius:12px;position:relative;overflow:hidden}.gNoOdq_reasonHeading{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;padding:10px 16px 0;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false]{background:0 0;border-color:#0000;border-radius:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonHeading{padding:0}.gNoOdq_reasonCard[data-overflow=false][data-expanded=false] .gNoOdq_reasonText{padding:4px 0 0 22px}.gNoOdq_reasonLabel{font-weight:500}.gNoOdq_reasonViewport{max-height:var(--reason-preview-height);scroll-behavior:auto;overflow-anchor:none;overscroll-behavior-y:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l1) transparent;position:relative;overflow:auto}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{max-height:min(60vh, 560px, var(--reason-reading-height,560px))}.gNoOdq_reasonViewport[data-edges=both],.gNoOdq_reasonCard[data-following=true][data-overflow=true] .gNoOdq_reasonViewport{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonViewport[data-edges=top]{-webkit-mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%);mask-image:linear-gradient(transparent 0, black var(--reason-fade), black 100%)}.gNoOdq_reasonViewport[data-edges=bottom]{-webkit-mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%);mask-image:linear-gradient(black 0, black calc(100% - var(--reason-fade)), transparent 100%)}.gNoOdq_reasonCard[data-expanded=true] .gNoOdq_reasonViewport{mask-image:none}.gNoOdq_reasonViewport:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-3px}.gNoOdq_reasonTrack{position:relative;transform:translateY(0)}.gNoOdq_reasonCard[data-following=true] .gNoOdq_reasonTrack{will-change:transform}.gNoOdq_reasonText{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;padding:8px 16px 16px;font-size:14px;line-height:24px}.gNoOdq_reasonText .gNoOdq_readingText>div{font-size:inherit;line-height:inherit;color:inherit}.gNoOdq_reasonFooter{color:var(--dsw-alias-label-secondary);justify-content:space-between;align-items:center;gap:8px;padding:2px 10px 8px;font-size:12px;line-height:20px;display:flex}.gNoOdq_reasonAction{min-height:28px;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:5px;padding:4px 6px;display:inline-flex}.gNoOdq_reasonAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_reasonAction:disabled{cursor:default;opacity:.65}.gNoOdq_reasonAction svg{fill:none;stroke:currentColor;stroke-width:1.3px;stroke-linecap:round;stroke-linejoin:round;flex:none}.gNoOdq_reasonCaption{padding-left:6px}@container (width<=480px){.gNoOdq_reasonCard{--reason-preview-height:192px}}@media (pointer:coarse){.gNoOdq_reasonAction{min-height:44px}}@media (prefers-reduced-motion:reduce){.gNoOdq_reasonTrack{will-change:auto!important;transition:none!important;transform:none!important}}@media (forced-colors:active){.gNoOdq_reasonViewport{mask-image:none!important}}.gNoOdq_processItem,.gNoOdq_tool{min-width:0;margin:0 0 18px}.gNoOdq_processLabel{color:var(--dsw-alias-label-tertiary);align-items:baseline;gap:12px;margin:0 0 6px;font-size:12px;line-height:20px;display:flex}.gNoOdq_processFootnote{color:var(--dsw-alias-label-tertiary);margin:14px 0 0;font-size:12px;line-height:20px}.gNoOdq_detail{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:22px}.gNoOdq_detail>summary{cursor:pointer;padding:3px 0}.gNoOdq_detail[open]>summary{margin-bottom:8px}.gNoOdq_tool>.gNoOdq_tool{margin:10px 0 0 12px}.gNoOdq_meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px}.gNoOdq_stopped{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:6px;align-self:flex-start;margin-top:12px;padding:0 6px;font-size:11px;line-height:18px}.gNoOdq_compactionRow{box-sizing:border-box;flex-direction:column;align-items:center;width:100%;margin:16px 0;display:flex}.gNoOdq_compactionLine{width:100%;color:var(--dsw-alias-label-tertiary);-webkit-user-select:none;user-select:none;justify-content:center;align-items:center;gap:12px;font-size:11px;line-height:18px;display:flex}.gNoOdq_compactionLine:before,.gNoOdq_compactionLine:after{content:\"\";background:var(--dsw-alias-border-l1);opacity:.7;flex:1;height:1px}.gNoOdq_compactionRow>.gNoOdq_compactionLine{animation:.52s cubic-bezier(.4,0,.2,1) both gNoOdq_compactionLineIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill{animation:.42s cubic-bezier(.34,1.4,.64,1) .12s both gNoOdq_compactionPillIn}.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:.9s cubic-bezier(.4,0,.2,1) .2s both gNoOdq_compactionDial}@keyframes gNoOdq_compactionLineIn{0%{opacity:0;transform:scaleX(.6)}to{opacity:1;transform:scaleX(1)}}@keyframes gNoOdq_compactionPillIn{0%{opacity:0;transform:translateY(-6px)scale(.94)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes gNoOdq_compactionDial{0%{opacity:0;transform:rotate(-140deg)}to{opacity:.7;transform:rotate(0)}}[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,[data-motion=off] .gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_compactionRow>.gNoOdq_compactionLine,.gNoOdq_compactionRow>.gNoOdq_compactionLine>.gNoOdq_compactionPill,.gNoOdq_compactionRow>.gNoOdq_compactionLine .gNoOdq_compactionIcon{animation:none!important}}.gNoOdq_compactionPill{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);border-radius:12px;align-items:center;gap:6px;padding:2px 10px;font-family:inherit;font-size:11px;line-height:18px;display:inline-flex}.gNoOdq_compactionButton{cursor:pointer;transition:color .14s,border-color .14s,background-color .14s}.gNoOdq_compactionButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_compactionIcon{opacity:.7;flex:none;width:12px;height:12px}.gNoOdq_compactionToggle{opacity:.8;margin-left:2px;font-size:10px}.gNoOdq_compactionSummaryBox{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);width:100%;max-width:680px;color:var(--dsw-alias-label-secondary);box-sizing:border-box;border-radius:8px;margin-top:10px;padding:12px 16px;font-size:12px;line-height:20px}.gNoOdq_compactionSummaryHeader{color:var(--dsw-alias-label-tertiary);border-bottom:1px dashed var(--dsw-alias-border-l1);margin-bottom:8px;padding-bottom:4px;font-size:11px;font-weight:500}.gNoOdq_notice,.gNoOdq_error,.gNoOdq_attention{overflow-wrap:anywhere;border-radius:10px;padding:12px 14px;font-size:13px;line-height:20px}.gNoOdq_notice{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2)}.gNoOdq_error{color:var(--dsw-alias-label-primary);background:#ef44440f;border:1px solid #ef444438;align-items:flex-start;gap:10px;display:flex}.gNoOdq_errorIcon{color:#ef4444;flex:none;width:16px;height:16px;margin-top:2px}.gNoOdq_errorCopy{flex:1;min-width:0}.gNoOdq_errorTitle{color:#dc2626;align-items:center;gap:8px;margin-bottom:2px;font-weight:500;display:flex}.gNoOdq_errorMessage{color:var(--dsw-alias-label-secondary);word-break:break-word;margin:0;font-size:12px;line-height:18px}.gNoOdq_errorCode{color:#dc2626;background:#ef44441f;border-radius:4px;padding:1px 5px;font-family:inherit;font-size:11px}.gNoOdq_attention{border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);flex-direction:column;gap:3px;display:flex}.gNoOdq_attention span{color:var(--dsw-alias-label-secondary)}.gNoOdq_unknown{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;padding:12px 14px;font-size:13px;line-height:22px}.gNoOdq_unknown p{margin:0 0 6px}.gNoOdq_historyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;align-self:center;padding:4px 12px;font-size:12px}.gNoOdq_historyButton:disabled{opacity:.55;cursor:default}.gNoOdq_empty{color:var(--dsw-alias-label-tertiary);text-align:center;padding:40px 0}.gNoOdq_answerActions{align-items:center;gap:8px;min-height:28px;margin:13px 0 0 -6px;display:flex}.gNoOdq_userActions{align-items:center;gap:8px;min-height:28px;display:flex}.gNoOdq_messageClock{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:13px;line-height:24px}.gNoOdq_iconButton{color:var(--dsw-alias-label-tertiary);background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.gNoOdq_iconButton svg{fill:none;stroke:currentColor;stroke-width:1.2px;stroke-linecap:round;stroke-linejoin:round}.gNoOdq_imageFigure{box-sizing:border-box;align-self:flex-start;width:min(100%,360px);max-width:100%;margin:0}.gNoOdq_imageFrame{background:var(--dsw-alias-bg-module-platform);border:1px solid var(--dsw-alias-border-l2);box-sizing:border-box;border-radius:12px;max-width:100%;min-height:96px;max-height:440px;position:relative;overflow:hidden}.gNoOdq_imageOpen{background:0 0;border:0;width:100%;height:100%;padding:0;display:flex;position:absolute;inset:0}.gNoOdq_imageOpen img{object-fit:contain;opacity:0;width:100%;height:100%;transition:opacity .2s cubic-bezier(.4,0,.2,1);display:block}.gNoOdq_imageOpen img[data-ready=true]{opacity:1}.gNoOdq_pendingImage{object-fit:contain;width:100%;max-width:100%;height:100%;display:block}.gNoOdq_imagePlaceholder{color:var(--dsw-alias-label-tertiary);pointer-events:none;flex-direction:column;justify-content:center;align-items:center;gap:8px;font-size:13px;display:flex;position:absolute;inset:0}.gNoOdq_imagePlaceholder button{pointer-events:auto}.gNoOdq_imageFigure figcaption{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin-top:6px;font-size:12px;line-height:20px}.gNoOdq_imageDialog{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:16px;max-width:90vw;max-height:90vh;padding:38px 20px 20px}.gNoOdq_imageDialog::backdrop{background:var(--dsw-alias-bg-mask-photo)}.gNoOdq_imageDialog img{object-fit:contain;max-width:82vw;max-height:75vh;display:block}.gNoOdq_dialogClose{color:inherit;background:0 0;border:0;border-radius:8px;width:32px;height:32px;font-size:24px;position:absolute;top:4px;right:8px}.gNoOdq_jumpDock{bottom:calc(var(--dsh-composer-height,152px) + 16px);z-index:8;pointer-events:none;justify-content:flex-end;height:0;display:flex;position:sticky}.gNoOdq_deliverablesRoot{grid-template-columns:max-content minmax(0,1fr);align-items:start;column-gap:10px;margin-top:14px;font-size:13px;line-height:22px;display:grid}.gNoOdq_deliverablesLabel{color:var(--dsw-alias-label-tertiary);grid-area:1/1;padding-top:2px;font-size:12px;font-weight:500}.gNoOdq_deliverablesLane{grid-area:1/2;min-width:0}.gNoOdq_deliverablesRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.gNoOdq_deliverableChip{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;font-size:12px;line-height:20px;transition:border-color .16s,background-color .16s,color .16s;display:inline-flex;overflow:hidden}.gNoOdq_deliverableChip:hover{border-color:var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-module-platform);box-shadow:0 1px 4px var(--dsw-alias-border-l1)}.gNoOdq_deliverableChip[data-status=opened]{color:#059669;background:#10b9811f;border-color:#10b981}.gNoOdq_chipMain{max-width:220px;color:inherit;font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:5px;padding:3px 6px 3px 8px;display:inline-flex}.gNoOdq_chipMain:hover{color:var(--dsw-alias-label-primary)}.gNoOdq_deliverableIcon,.gNoOdq_statusIcon{opacity:.8;flex:none;width:13px;height:13px}.gNoOdq_statusIcon{color:#10b981}.gNoOdq_deliverableName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.gNoOdq_chipActions{opacity:.65;border-left:1px solid #0000;align-items:center;gap:2px;padding-right:4px;transition:opacity .15s,border-left-color .15s;display:inline-flex}.gNoOdq_deliverableChip:hover .gNoOdq_chipActions{opacity:1;border-left-color:var(--dsw-alias-border-l2)}.gNoOdq_chipActionBtn{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;padding:0;transition:color .12s,background-color .12s;display:inline-flex}.gNoOdq_chipActionBtn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_actionIcon{width:12px;height:12px}.gNoOdq_deliverablesMore{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.gNoOdq_deliverablesShowFolder{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:5px;align-items:center;gap:4px;padding:2px 7px;font-size:12px;transition:all .15s;display:inline-flex}.gNoOdq_deliverablesShowFolder:hover{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}.gNoOdq_deliverablesShowFolder[data-status=opened]{color:#10b981;background:#10b98114;border-color:#10b9814d}.gNoOdq_morphCluster{flex-direction:column;width:100%;min-width:0;display:flex}.gNoOdq_morphDrawer{transform-origin:top;will-change:height, opacity, transform;height:0;overflow:hidden}.gNoOdq_liveFoldImpact{animation:.18s cubic-bezier(.2,0,0,1) both gNoOdq_liveFoldElastic}@keyframes gNoOdq_liveFoldElastic{0%{transform:scale(1)}50%{transform:scale(1.015)}to{transform:scale(1)}}.gNoOdq_liveFoldContainer{top:calc(var(--reader-toolbar-height,var(--reader-lane-block,40px)) + var(--reader-status-height,var(--reader-lane-block,40px)) + var(--reader-summary-height,var(--reader-lane-block,40px)));z-index:4;background:var(--dsw-alias-bg-base);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);transform-origin:0;will-change:transform, opacity;margin-bottom:6px;padding:4px 0;animation:.32s cubic-bezier(.16,1,.3,1) both gNoOdq_liveFoldPulse;position:sticky}@keyframes gNoOdq_liveFoldPulse{0%{opacity:.8;transform:translateY(-4px)scale(.98)}50%{opacity:1;transform:translateY(0)scale(1.02)}to{opacity:1;transform:translateY(0)scale(1)}}[data-motion=off] .gNoOdq_liveFoldContainer{animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_liveFoldContainer{animation:none!important}}.gNoOdq_priorFoldDrawer{flex-direction:column;gap:14px;width:100%;min-width:0;display:flex}.gNoOdq_jump{width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill,var(--dsw-alias-bg-base));box-shadow:var(--dsw-elevation-panel,0 2px 8px var(--dsw-alias-border-l1));pointer-events:auto;border:0;border-radius:100px;flex:none;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.gNoOdq_jump:hover{background:var(--dsw-alias-button-floating-hover,var(--dsw-alias-interactive-bg-hover))}.gNoOdq_foldSummary{text-overflow:ellipsis;align-items:baseline;max-width:100%;display:inline-flex;overflow:hidden;white-space:nowrap!important}.gNoOdq_foldSummaryPart{flex:none;align-items:baseline;display:inline-flex;white-space:nowrap!important}.gNoOdq_numberRollRoot{vertical-align:baseline;line-height:inherit;font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";text-align:center;flex-shrink:0;justify-content:center;min-width:1.45em;display:inline-flex;position:relative;overflow:hidden;white-space:nowrap!important}.gNoOdq_numberRollSizer{visibility:hidden;-webkit-user-select:none;user-select:none;pointer-events:none;line-height:inherit;white-space:nowrap}.gNoOdq_numberRollDigit{line-height:inherit;white-space:nowrap;justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.gNoOdq_numberRollExit{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollOut}.gNoOdq_numberRollEnter{animation:.24s cubic-bezier(.16,1,.3,1) forwards gNoOdq_numberRollIn}@keyframes gNoOdq_numberRollOut{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}@keyframes gNoOdq_numberRollIn{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}[data-motion=off] .gNoOdq_chevron,[data-motion=off] .gNoOdq_imageOpen img,[data-motion=off] .gNoOdq_processMeta,[data-motion=off] .gNoOdq_numberRollDigit{transition:none!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_chevron,.gNoOdq_imageOpen img,.gNoOdq_processMeta,.gNoOdq_numberRollDigit{transition:none!important;animation:none!important}}.gNoOdq_turnStatus{white-space:nowrap;flex:none;align-self:flex-start;align-items:center;height:26px;margin:4px 0 12px;padding:0 4px;font-size:14px;line-height:22px;display:inline-flex}.gNoOdq_turnStatusLabel{background:linear-gradient(90deg, var(--dsw-static-deepseek-500,#4d6bfe) 0%, var(--dsw-static-deepseek-500,#4d6bfe) 40%, var(--dsw-static-deepseek-200,#a8c7fa) 50%, var(--dsw-static-deepseek-500,#4d6bfe) 60%, var(--dsw-static-deepseek-500,#4d6bfe) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;background-clip:text;font-weight:500;animation:1.8s linear infinite gNoOdq_dsh-turn-status-shimmer}.gNoOdq_waitClock{flex:none;align-items:center;margin-left:8px;display:inline-flex}.gNoOdq_waitSeconds{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86909c);font-size:13px;font-weight:400}.gNoOdq_waitOvertime{color:var(--dsw-alias-state-warning-primary,#d8862c);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary,#d8862c) 16%, transparent);border-radius:5px;margin-left:8px;padding:0 6px;font-size:11px;line-height:16px}.gNoOdq_turnStatusClock{font-variant-numeric:tabular-nums;font-feature-settings:\"tnum\";color:var(--dsw-alias-label-caption,#86868b);-webkit-text-fill-color:var(--dsw-alias-label-caption,#86868b);margin-left:8px;font-size:13px;font-weight:400}@keyframes gNoOdq_dsh-turn-status-shimmer{to{background-position:0 0}}[data-motion=off] .gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}@media (prefers-reduced-motion:reduce){.gNoOdq_turnStatusLabel{color:var(--dsw-static-deepseek-500,#4d6bfe)!important;-webkit-text-fill-color:var(--dsw-static-deepseek-500,#4d6bfe)!important;animation:none!important}}@media (pointer:coarse){.gNoOdq_disclosureButton{min-height:44px}}@media (width<=600px){.gNoOdq_root{padding-inline:20px}.gNoOdq_column{gap:18px}.gNoOdq_toolbar{font-size:11px}}.gNoOdq_choreographedFlow{overflow-anchor:none;flex-direction:column;min-width:0;display:flex}.gNoOdq_flowCell{min-width:0;display:flow-root;overflow:clip}.gNoOdq_flowCell[hidden]{display:none}.gNoOdq_flowCellInner{flex-direction:column;min-width:0;padding-bottom:16px;display:flex}.gNoOdq_flowCellInner:empty{padding-bottom:0}.gNoOdq_choreographedFlow[data-reader-transition=collapse] .gNoOdq_flowCell *{animation-play-state:paused!important}.gNoOdq_numberRollExit,.gNoOdq_numberRollEnter{animation-duration:.16s}.gNoOdq_foldSummary{align-items:baseline;display:inline-flex;white-space:nowrap!important;flex-wrap:nowrap!important}.gNoOdq_toolbar{box-sizing:border-box;width:100%;max-width:100%;min-height:var(--reader-lane-block,40px);z-index:7;-webkit-backdrop-filter:none;backdrop-filter:none;border-bottom:0;align-self:stretch}.gNoOdq_turnProcessSticky{box-sizing:border-box;width:calc(100% - var(--reader-control-width,148px));top:var(--reader-toolbar-height,var(--reader-lane-block,40px));min-height:var(--reader-lane-block,40px);z-index:6;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:0 -14px 0 var(--dsw-alias-bg-base), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-base), 0 -14px 0 var(--dsw-alias-bg-layer-1,transparent), var(--reader-control-width,148px) 0 0 var(--dsw-alias-bg-layer-1,transparent), 0 -14px 0 Canvas, var(--reader-control-width,148px) 0 0 Canvas;background-clip:padding-box;border-bottom:1px solid #0000;padding-right:0}.gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky,.gNoOdq_turnStickyLanes .gNoOdq_closedProcessSummary{z-index:auto;position:static;top:auto}.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{top:calc(var(--reader-toolbar-height,var(--reader-lane-block,40px)) + var(--reader-status-height,var(--reader-lane-block,40px)));z-index:5;box-sizing:border-box;min-height:var(--reader-lane-block,40px);background:var(--dsw-alias-bg-base);border-bottom:0;padding-block:4px;position:sticky;overflow:visible}.gNoOdq_root .md-code-block{z-index:0}.gNoOdq_turnStickyRegion:has(>.gNoOdq_turnStickyLanes>.gNoOdq_closedProcessSummary),.gNoOdq_turnStickyRegion:has(.gNoOdq_flowCell[data-flow-summary]){--reader-code-summary-height:var(--reader-summary-height,var(--reader-lane-block,40px))}.gNoOdq_root .md-code-block>:has(+[data-code-block-content]){top:calc(max(var(--reader-toolbar-height,40px), var(--reader-status-height,0px)) + var(--reader-status-height,0px) + var(--reader-code-summary-height,0px))}.gNoOdq_flowCell[data-flow-summary]{box-shadow:0 -16px 0 var(--dsw-alias-bg-base), 0 -16px 0 var(--dsw-alias-bg-layer-1,transparent), 0 -16px 0 Canvas}.gNoOdq_closedProcessSummary{box-shadow:0 -14px 0 var(--dsw-alias-bg-base), 0 -14px 0 var(--dsw-alias-bg-layer-1,transparent), 0 -14px 0 Canvas}.gNoOdq_foldControl{background:var(--dsw-alias-bg-module-platform);border-radius:8px;align-items:center;gap:0;padding:2px;display:inline-flex}.gNoOdq_foldStop{color:var(--dsw-alias-label-secondary);white-space:nowrap;font:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;padding:2px 8px;font-size:12px;line-height:18px}.gNoOdq_foldStop[data-on]{background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary)}.gNoOdq_flowCell[data-flow-summary]>.gNoOdq_flowCellInner{padding-bottom:0}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_disclosureButton,.gNoOdq_closedProcessSummary .gNoOdq_disclosureButton{width:auto;max-width:100%}.gNoOdq_flowCell[data-flow-summary] .gNoOdq_foldSummary,.gNoOdq_closedProcessSummary .gNoOdq_foldSummary{min-width:0}.gNoOdq_turnProcessSticky>.gNoOdq_disclosure{flex:auto;min-width:0}.gNoOdq_disclosureButton{width:max-content;max-width:calc(100% + 6px)}.gNoOdq_statusText{flex:0 auto}.gNoOdq_think{width:max-content;min-width:0}.gNoOdq_thinkSizer{white-space:normal;overflow-wrap:anywhere}.gNoOdq_thinkText{white-space:normal;overflow-wrap:anywhere;text-overflow:clip;overflow:visible}.gNoOdq_toolbar,.gNoOdq_turnStickyLanes,.gNoOdq_turnProcessSticky,.gNoOdq_liveFoldContainer,.gNoOdq_flowCell[data-flow-summary],.gNoOdq_closedProcessSummary{background-color:canvas;background-image:var(--reader-lane-plate);background-repeat:no-repeat}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky,.gNoOdq_root[data-reader-glass] .gNoOdq_liveFoldContainer{-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);box-shadow:none;background:0 0;border:0;border-radius:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky{-webkit-backdrop-filter:none;backdrop-filter:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar{pointer-events:none}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{pointer-events:auto;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1,#ffffffb3) 80%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-radius:999px;padding:2px 10px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton{max-width:100%;margin-left:0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolbar>.gNoOdq_textButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_turnProcessSticky .gNoOdq_disclosureButton:hover{background:var(--dsw-alias-interactive-bg-hover)}.gNoOdq_root[data-reader-glass] .gNoOdq_flowCell[data-flow-summary],.gNoOdq_root[data-reader-glass] .gNoOdq_closedProcessSummary{box-shadow:none;z-index:auto;border-left:2px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808059) 80%, transparent);padding-block:2px;background:0 0;border-radius:0;min-height:32px;padding-left:10px;position:static}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes{z-index:auto;display:contents;position:static;top:auto}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyRegion{--reader-code-summary-height:0px}.gNoOdq_root[data-reader-glass] .gNoOdq_turnStickyLanes .gNoOdq_turnProcessSticky{top:var(--reader-toolbar-height,var(--reader-lane-block,40px));z-index:6;position:sticky}.gNoOdq_root[data-reader-glass] .gNoOdq_user{background:color-mix(in srgb, var(--dsw-specific-bubble,#00000014) 25%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#8080804d) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_reasonCard{border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#80808059) 65%, transparent);background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_toolDetails,.gNoOdq_root[data-reader-glass] .gNoOdq_notice,.gNoOdq_root[data-reader-glass] .gNoOdq_unknown,.gNoOdq_root[data-reader-glass] .gNoOdq_toolRaw,.gNoOdq_root[data-reader-glass] .gNoOdq_systemPrompt,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionSummaryBox,.gNoOdq_root[data-reader-glass] .gNoOdq_attention,.gNoOdq_root[data-reader-glass] .gNoOdq_imageFrame,.gNoOdq_root[data-reader-glass] .gNoOdq_imageDialog{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffOverlay{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 20%, transparent);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffScrollArea{background:0 0}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fffc) 25%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_diffTab[data-active]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 45%, transparent)}:is(.gNoOdq_root[data-reader-glass] .md-code-block,.gNoOdq_root[data-reader-glass] [data-diff]){border:1px solid color-mix(in srgb, var(--dsw-alias-border-l1,#80808033) 30%, transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block,#0000000f) 25%, transparent)!important}.gNoOdq_root[data-reader-glass] .gNoOdq_foldControl{background:color-mix(in srgb, var(--dsw-alias-bg-module-platform,#7f7f7f1a) 25%, transparent);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#80808033) 30%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_foldStop[data-on]{background:color-mix(in srgb, var(--dsw-alias-bg-base,#fff) 35%, transparent)}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton{background:0 0;border-color:#0000}.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_compactionPill:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_deliverableChip:focus-within,.gNoOdq_root[data-reader-glass] .gNoOdq_toolState:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:hover,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton:focus-visible,.gNoOdq_root[data-reader-glass] .gNoOdq_diffStatButton[aria-expanded=true]{background:var(--dsw-alias-bg-module-platform,#7f7f7f1a);border-color:var(--dsw-alias-border-l2,#7f7f7f47)}";
|
|
42470
42740
|
const tagId$5 = "dsh-better-display/Reader.module.css";
|
|
42471
42741
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
|
|
42472
42742
|
const tag = document.createElement("style");
|
|
@@ -42577,7 +42847,6 @@ ${trimmed}
|
|
|
42577
42847
|
"numberRollSizer": "gNoOdq_numberRollSizer",
|
|
42578
42848
|
"pendingImage": "gNoOdq_pendingImage",
|
|
42579
42849
|
"priorFoldDrawer": "gNoOdq_priorFoldDrawer",
|
|
42580
|
-
"processCommentary": "gNoOdq_processCommentary",
|
|
42581
42850
|
"processContents": "gNoOdq_processContents",
|
|
42582
42851
|
"processFootnote": "gNoOdq_processFootnote",
|
|
42583
42852
|
"processFrame": "gNoOdq_processFrame",
|
|
@@ -42586,6 +42855,7 @@ ${trimmed}
|
|
|
42586
42855
|
"processMeta": "gNoOdq_processMeta",
|
|
42587
42856
|
"processMetaInner": "gNoOdq_processMetaInner",
|
|
42588
42857
|
"processMetaLine": "gNoOdq_processMetaLine",
|
|
42858
|
+
"processSeamRow": "gNoOdq_processSeamRow",
|
|
42589
42859
|
"readerRunningGlow": "gNoOdq_readerRunningGlow",
|
|
42590
42860
|
"readerStepShimmer": "gNoOdq_readerStepShimmer",
|
|
42591
42861
|
"readingText": "gNoOdq_readingText",
|
|
@@ -42810,6 +43080,216 @@ ${trimmed}
|
|
|
42810
43080
|
});
|
|
42811
43081
|
}
|
|
42812
43082
|
//#endregion
|
|
43083
|
+
//#region src/client/text-transform.ts
|
|
43084
|
+
/**
|
|
43085
|
+
* Cordis service name. Another client plugin lists this in `inject` and
|
|
43086
|
+
* registers a transformer. The reading view paints the result. The session
|
|
43087
|
+
* block, transcript, and fold inputs stay on the original text.
|
|
43088
|
+
*/
|
|
43089
|
+
const TEXT_TRANSFORM_SERVICE = "dsh-better-display.text-transform";
|
|
43090
|
+
const KINDS = /* @__PURE__ */ new Set(["reasoning", "body"]);
|
|
43091
|
+
function isKind(value) {
|
|
43092
|
+
return KINDS.has(value);
|
|
43093
|
+
}
|
|
43094
|
+
function reportTransformError(error) {
|
|
43095
|
+
console.warn("[dsh-better-display] text transform failed; showing original text", error);
|
|
43096
|
+
}
|
|
43097
|
+
function passthrough(request) {
|
|
43098
|
+
return {
|
|
43099
|
+
text: request.text,
|
|
43100
|
+
final: !request.streaming,
|
|
43101
|
+
transformRevision: 0,
|
|
43102
|
+
motionRevision: 0
|
|
43103
|
+
};
|
|
43104
|
+
}
|
|
43105
|
+
function normalize(value, request) {
|
|
43106
|
+
if (typeof value === "string") return {
|
|
43107
|
+
text: value,
|
|
43108
|
+
final: !request.streaming
|
|
43109
|
+
};
|
|
43110
|
+
if (!value || typeof value.text !== "string") return {
|
|
43111
|
+
text: request.text,
|
|
43112
|
+
final: !request.streaming
|
|
43113
|
+
};
|
|
43114
|
+
return {
|
|
43115
|
+
text: value.text,
|
|
43116
|
+
final: typeof value.final === "boolean" ? value.final : !request.streaming
|
|
43117
|
+
};
|
|
43118
|
+
}
|
|
43119
|
+
/**
|
|
43120
|
+
* Appends keep the motion revision. A replacement gets a new one so the
|
|
43121
|
+
* timeline treats the swapped string as already settled.
|
|
43122
|
+
*/
|
|
43123
|
+
function nextDisplayCursor(previous, display) {
|
|
43124
|
+
if (!previous) return {
|
|
43125
|
+
...display,
|
|
43126
|
+
transformRevision: 0,
|
|
43127
|
+
motionRevision: 0
|
|
43128
|
+
};
|
|
43129
|
+
if (previous.text === display.text && previous.final === display.final) return previous;
|
|
43130
|
+
const appended = display.text.startsWith(previous.text);
|
|
43131
|
+
return {
|
|
43132
|
+
text: display.text,
|
|
43133
|
+
final: display.final,
|
|
43134
|
+
transformRevision: previous.transformRevision + 1,
|
|
43135
|
+
motionRevision: appended ? previous.motionRevision : previous.motionRevision + 1
|
|
43136
|
+
};
|
|
43137
|
+
}
|
|
43138
|
+
/**
|
|
43139
|
+
* Streaming flag fed to the reveal. With no transformer this is the model's
|
|
43140
|
+
* flag. A transformer that reports `final: !streaming` produces the same flag.
|
|
43141
|
+
*/
|
|
43142
|
+
function displayStreaming(sourceStreaming, shown, active) {
|
|
43143
|
+
return active ? !shown.final : sourceStreaming;
|
|
43144
|
+
}
|
|
43145
|
+
var TextTransformRegistryImpl = class {
|
|
43146
|
+
stacks = /* @__PURE__ */ new Map();
|
|
43147
|
+
listeners = /* @__PURE__ */ new Map();
|
|
43148
|
+
cursors = /* @__PURE__ */ new Map();
|
|
43149
|
+
register(kind, transformer) {
|
|
43150
|
+
const requested = [...new Set(Array.isArray(kind) ? kind : [kind])];
|
|
43151
|
+
for (const item of requested) if (!isKind(item)) throw new Error(`Unknown display text kind: ${String(item)}`);
|
|
43152
|
+
const bound = [];
|
|
43153
|
+
for (const item of requested) {
|
|
43154
|
+
const entry = { transformer };
|
|
43155
|
+
try {
|
|
43156
|
+
entry.unsubscribe = transformer.subscribe?.(() => {
|
|
43157
|
+
this.emit(item);
|
|
43158
|
+
});
|
|
43159
|
+
} catch (error) {
|
|
43160
|
+
reportTransformError(error);
|
|
43161
|
+
}
|
|
43162
|
+
const stack = this.stacks.get(item) ?? [];
|
|
43163
|
+
stack.push(entry);
|
|
43164
|
+
this.stacks.set(item, stack);
|
|
43165
|
+
bound.push({
|
|
43166
|
+
kind: item,
|
|
43167
|
+
entry
|
|
43168
|
+
});
|
|
43169
|
+
this.emit(item);
|
|
43170
|
+
}
|
|
43171
|
+
return () => {
|
|
43172
|
+
for (const { kind: item, entry } of bound) {
|
|
43173
|
+
try {
|
|
43174
|
+
entry.unsubscribe?.();
|
|
43175
|
+
} catch (error) {
|
|
43176
|
+
reportTransformError(error);
|
|
43177
|
+
}
|
|
43178
|
+
const stack = this.stacks.get(item);
|
|
43179
|
+
if (!stack) continue;
|
|
43180
|
+
const next = stack.filter((candidate) => candidate !== entry);
|
|
43181
|
+
if (next.length > 0) this.stacks.set(item, next);
|
|
43182
|
+
else this.stacks.delete(item);
|
|
43183
|
+
this.emit(item);
|
|
43184
|
+
}
|
|
43185
|
+
};
|
|
43186
|
+
}
|
|
43187
|
+
has(kind) {
|
|
43188
|
+
return (this.stacks.get(kind)?.length ?? 0) > 0;
|
|
43189
|
+
}
|
|
43190
|
+
read(request) {
|
|
43191
|
+
const transformer = this.stacks.get(request.kind)?.at(-1)?.transformer;
|
|
43192
|
+
if (!transformer) return passthrough(request);
|
|
43193
|
+
let display;
|
|
43194
|
+
try {
|
|
43195
|
+
display = normalize(transformer.read(request), request);
|
|
43196
|
+
} catch (error) {
|
|
43197
|
+
reportTransformError(error);
|
|
43198
|
+
display = {
|
|
43199
|
+
text: request.text,
|
|
43200
|
+
final: !request.streaming
|
|
43201
|
+
};
|
|
43202
|
+
}
|
|
43203
|
+
const key = `${request.kind}\u0000${request.blockKey}`;
|
|
43204
|
+
const next = nextDisplayCursor(this.cursors.get(key), display);
|
|
43205
|
+
this.cursors.set(key, next);
|
|
43206
|
+
return next;
|
|
43207
|
+
}
|
|
43208
|
+
subscribe(kind, listener) {
|
|
43209
|
+
const set = this.listeners.get(kind) ?? /* @__PURE__ */ new Set();
|
|
43210
|
+
set.add(listener);
|
|
43211
|
+
this.listeners.set(kind, set);
|
|
43212
|
+
return () => {
|
|
43213
|
+
set.delete(listener);
|
|
43214
|
+
};
|
|
43215
|
+
}
|
|
43216
|
+
release(kind, blockKey) {
|
|
43217
|
+
this.cursors.delete(`${kind}\u0000${blockKey}`);
|
|
43218
|
+
}
|
|
43219
|
+
emit(kind) {
|
|
43220
|
+
const set = this.listeners.get(kind);
|
|
43221
|
+
if (!set) return;
|
|
43222
|
+
for (const listener of [...set]) listener();
|
|
43223
|
+
}
|
|
43224
|
+
};
|
|
43225
|
+
function createTextTransformRegistry() {
|
|
43226
|
+
return new TextTransformRegistryImpl();
|
|
43227
|
+
}
|
|
43228
|
+
let active;
|
|
43229
|
+
/** Points the reading view at the registry this client plugin provides. */
|
|
43230
|
+
function installTextTransformRegistry(registry) {
|
|
43231
|
+
const previous = active;
|
|
43232
|
+
active = registry;
|
|
43233
|
+
return () => {
|
|
43234
|
+
active = previous;
|
|
43235
|
+
};
|
|
43236
|
+
}
|
|
43237
|
+
function activeTextTransform() {
|
|
43238
|
+
return active;
|
|
43239
|
+
}
|
|
43240
|
+
/**
|
|
43241
|
+
* Subscribe while mounted. The reveal components call this only after
|
|
43242
|
+
* `has(kind)`, so an empty registry adds no hook and no listener.
|
|
43243
|
+
*/
|
|
43244
|
+
function useDisplayText(registry, request) {
|
|
43245
|
+
const [epoch, setEpoch] = (0, react.useState)(0);
|
|
43246
|
+
const { text, streaming, blockKey, kind, source } = request;
|
|
43247
|
+
(0, react.useEffect)(() => registry.subscribe(kind, () => {
|
|
43248
|
+
setEpoch((value) => value + 1);
|
|
43249
|
+
}), [registry, kind]);
|
|
43250
|
+
(0, react.useEffect)(() => () => {
|
|
43251
|
+
registry.release(kind, blockKey);
|
|
43252
|
+
}, [
|
|
43253
|
+
registry,
|
|
43254
|
+
kind,
|
|
43255
|
+
blockKey
|
|
43256
|
+
]);
|
|
43257
|
+
return (0, react.useMemo)(() => registry.read({
|
|
43258
|
+
text,
|
|
43259
|
+
streaming,
|
|
43260
|
+
blockKey,
|
|
43261
|
+
kind,
|
|
43262
|
+
source
|
|
43263
|
+
}), [
|
|
43264
|
+
registry,
|
|
43265
|
+
text,
|
|
43266
|
+
streaming,
|
|
43267
|
+
blockKey,
|
|
43268
|
+
kind,
|
|
43269
|
+
source,
|
|
43270
|
+
epoch
|
|
43271
|
+
]);
|
|
43272
|
+
}
|
|
43273
|
+
/** Chain-slot owner. Extra fields are optional so older callers still type-check. */
|
|
43274
|
+
function readerBlockOwner(block, streaming, source, presentation, holdFormatting) {
|
|
43275
|
+
return {
|
|
43276
|
+
block,
|
|
43277
|
+
streaming,
|
|
43278
|
+
source,
|
|
43279
|
+
presentation: {
|
|
43280
|
+
startedAt: presentation.startedAt,
|
|
43281
|
+
interrupted: presentation.interrupted,
|
|
43282
|
+
liveText: presentation.liveText
|
|
43283
|
+
},
|
|
43284
|
+
holdFormatting,
|
|
43285
|
+
liveText: presentation.liveText
|
|
43286
|
+
};
|
|
43287
|
+
}
|
|
43288
|
+
/** Copy actions read this. Display text never replaces it. */
|
|
43289
|
+
function originalAnswerText(blocks) {
|
|
43290
|
+
return blocks.flatMap((block) => block.kind === "text" && typeof block.text === "string" ? [block.text] : []).join("\n\n");
|
|
43291
|
+
}
|
|
43292
|
+
//#endregion
|
|
42813
43293
|
//#region \0dshx-css-module:TurnMetrics.module.css.mjs
|
|
42814
43294
|
const css$4 = "._QZbGG_container{color:var(--dsw-alias-label-tertiary);align-items:center;gap:2px;font-size:13px;line-height:24px;display:inline-flex;position:relative}._QZbGG_pillButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:12px;outline:none;align-items:center;gap:5px;padding:2px 8px;font-family:inherit;font-size:11px;transition:all .14s;display:inline-flex}._QZbGG_pillButton:hover,._QZbGG_pillButton[data-active=true]{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover)}._QZbGG_timeButton{height:28px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;font-family:inherit;font-size:13px;line-height:24px;display:inline-flex}._QZbGG_timeButton:hover,._QZbGG_timeButton[data-active=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}._QZbGG_pillIcon{opacity:.8;flex:none;width:12px;height:12px}._QZbGG_metricsPop{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);z-index:50;text-align:left;border-radius:10px;flex-direction:column;gap:8px;width:260px;padding:12px 14px;animation:.14s ease-out _QZbGG_popIn;display:flex;position:absolute;bottom:calc(100% + 8px);left:0;box-shadow:0 6px 20px #00000024}@keyframes _QZbGG_popIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}._QZbGG_popHeader{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding-bottom:6px;font-size:12px;font-weight:600;display:flex}._QZbGG_popSection{flex-direction:column;gap:4px;display:flex}._QZbGG_popSectionTitle{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:10px;font-weight:600}._QZbGG_popGrid{grid-template-columns:1fr auto;gap:3px 12px;font-size:11px;line-height:18px;display:grid}._QZbGG_popLabel{color:var(--dsw-alias-label-secondary)}._QZbGG_popValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;text-align:right;font-weight:500}._QZbGG_popBadge{background:var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:3px;margin-left:4px;padding:0 4px;font-size:10px}";
|
|
42815
43295
|
const tagId$4 = "dsh-better-display/TurnMetrics.module.css";
|
|
@@ -43174,7 +43654,7 @@ ${trimmed}
|
|
|
43174
43654
|
};
|
|
43175
43655
|
});
|
|
43176
43656
|
}
|
|
43177
|
-
function
|
|
43657
|
+
function MarkdownStream({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false, kind = "body", fileMentions, transformed = false }) {
|
|
43178
43658
|
const root = (0, react.useRef)(null);
|
|
43179
43659
|
const presentation = useStreamingText(text, streaming, {
|
|
43180
43660
|
startedAt,
|
|
@@ -43198,6 +43678,7 @@ ${trimmed}
|
|
|
43198
43678
|
"data-ud-motion": "reader-text-arrival",
|
|
43199
43679
|
"data-ud-motion-type": "reveal",
|
|
43200
43680
|
"data-ud-motion-no-flash": "true",
|
|
43681
|
+
"data-text-transform": transformed ? streaming ? "live" : "final" : void 0,
|
|
43201
43682
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MotionMarkdown, {
|
|
43202
43683
|
text: presentation.text,
|
|
43203
43684
|
streaming: effectiveMode,
|
|
@@ -43207,7 +43688,32 @@ ${trimmed}
|
|
|
43207
43688
|
})
|
|
43208
43689
|
});
|
|
43209
43690
|
}
|
|
43210
|
-
function
|
|
43691
|
+
function TransformedMarkdown({ registry, blockKey, source, text, streaming, ...props }) {
|
|
43692
|
+
const shown = useDisplayText(registry, {
|
|
43693
|
+
text,
|
|
43694
|
+
streaming,
|
|
43695
|
+
blockKey,
|
|
43696
|
+
kind: "body",
|
|
43697
|
+
source
|
|
43698
|
+
});
|
|
43699
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownStream, {
|
|
43700
|
+
...props,
|
|
43701
|
+
text: shown.text,
|
|
43702
|
+
streaming: displayStreaming(streaming, shown, true),
|
|
43703
|
+
transformed: true
|
|
43704
|
+
});
|
|
43705
|
+
}
|
|
43706
|
+
function ReadingMarkdown({ blockKey, source, ...props }) {
|
|
43707
|
+
const registry = activeTextTransform();
|
|
43708
|
+
if (registry?.has("body")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransformedMarkdown, {
|
|
43709
|
+
registry,
|
|
43710
|
+
blockKey,
|
|
43711
|
+
source,
|
|
43712
|
+
...props
|
|
43713
|
+
});
|
|
43714
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownStream, { ...props });
|
|
43715
|
+
}
|
|
43716
|
+
function ReasoningStream({ text, streaming, holdFormatting, startedAt, interrupted = false, liveText = false, transformed = false }) {
|
|
43211
43717
|
const presentation = useStreamingText(text, streaming, {
|
|
43212
43718
|
startedAt,
|
|
43213
43719
|
interrupted: interrupted || !liveText,
|
|
@@ -43224,6 +43730,7 @@ ${trimmed}
|
|
|
43224
43730
|
"data-ud-motion": "reader-text-arrival",
|
|
43225
43731
|
"data-ud-motion-type": "reveal",
|
|
43226
43732
|
"data-ud-motion-no-flash": "true",
|
|
43733
|
+
"data-text-transform": transformed ? streaming ? "live" : "final" : void 0,
|
|
43227
43734
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MotionPlainText, {
|
|
43228
43735
|
text: presentation.text,
|
|
43229
43736
|
enabled: liveText && presentation.reveal,
|
|
@@ -43231,7 +43738,32 @@ ${trimmed}
|
|
|
43231
43738
|
})
|
|
43232
43739
|
});
|
|
43233
43740
|
}
|
|
43234
|
-
function
|
|
43741
|
+
function TransformedReasoning({ registry, blockKey, source, text, streaming, ...props }) {
|
|
43742
|
+
const shown = useDisplayText(registry, {
|
|
43743
|
+
text,
|
|
43744
|
+
streaming,
|
|
43745
|
+
blockKey,
|
|
43746
|
+
kind: "reasoning",
|
|
43747
|
+
source
|
|
43748
|
+
});
|
|
43749
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningStream, {
|
|
43750
|
+
...props,
|
|
43751
|
+
text: shown.text,
|
|
43752
|
+
streaming: displayStreaming(streaming, shown, true),
|
|
43753
|
+
transformed: true
|
|
43754
|
+
});
|
|
43755
|
+
}
|
|
43756
|
+
function ReadingReasoning({ blockKey, source, ...props }) {
|
|
43757
|
+
const registry = activeTextTransform();
|
|
43758
|
+
if (registry?.has("reasoning")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TransformedReasoning, {
|
|
43759
|
+
registry,
|
|
43760
|
+
blockKey,
|
|
43761
|
+
source,
|
|
43762
|
+
...props
|
|
43763
|
+
});
|
|
43764
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningStream, { ...props });
|
|
43765
|
+
}
|
|
43766
|
+
function fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, presentation, blockKey, fileMentions) {
|
|
43235
43767
|
switch (block.kind) {
|
|
43236
43768
|
case "text": return source === "user" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
43237
43769
|
text: block.text,
|
|
@@ -43241,7 +43773,9 @@ ${trimmed}
|
|
|
43241
43773
|
streaming,
|
|
43242
43774
|
holdFormatting,
|
|
43243
43775
|
...presentation,
|
|
43244
|
-
fileMentions
|
|
43776
|
+
fileMentions,
|
|
43777
|
+
blockKey,
|
|
43778
|
+
source
|
|
43245
43779
|
});
|
|
43246
43780
|
case "image": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ImageBlock, {
|
|
43247
43781
|
attachment: block.attachment,
|
|
@@ -43251,7 +43785,9 @@ ${trimmed}
|
|
|
43251
43785
|
text: block.text,
|
|
43252
43786
|
streaming,
|
|
43253
43787
|
holdFormatting,
|
|
43254
|
-
...presentation
|
|
43788
|
+
...presentation,
|
|
43789
|
+
blockKey,
|
|
43790
|
+
source
|
|
43255
43791
|
});
|
|
43256
43792
|
case "tool-call": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
|
|
43257
43793
|
label: `工具参数 · ${block.name}`,
|
|
@@ -43280,20 +43816,21 @@ ${trimmed}
|
|
|
43280
43816
|
}
|
|
43281
43817
|
}
|
|
43282
43818
|
const Blocks = (0, react.memo)(function Blocks({ blocks, streaming = false, source = "assistant", holdFormatting = false, startedAt, interrupted, liveText, renderSlotChain, loadImage, fillComposer, fileMentions }) {
|
|
43819
|
+
const reactId = (0, react.useId)();
|
|
43283
43820
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerFillContext.Provider, {
|
|
43284
43821
|
value: fillComposer,
|
|
43285
43822
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
43286
43823
|
className: Reader_module_css_default.blocks,
|
|
43287
43824
|
"data-streaming": streaming || void 0,
|
|
43288
|
-
children: blocks.map((block, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlotChain("dsh-better-display.block", {
|
|
43289
|
-
|
|
43290
|
-
|
|
43291
|
-
|
|
43292
|
-
}, { fallback: fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, {
|
|
43825
|
+
children: blocks.map((block, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderSlotChain("dsh-better-display.block", readerBlockOwner(block, streaming, source, {
|
|
43826
|
+
startedAt,
|
|
43827
|
+
interrupted,
|
|
43828
|
+
liveText
|
|
43829
|
+
}, holdFormatting), { fallback: fallback(block, streaming, source, loadImage, fillComposer, holdFormatting, {
|
|
43293
43830
|
startedAt,
|
|
43294
43831
|
interrupted,
|
|
43295
43832
|
liveText
|
|
43296
|
-
}, fileMentions) }) }) }, block.kind === "image" ? `image:${block.attachment.attachmentId}:${index}` : `${index}:${block.kind}`))
|
|
43833
|
+
}, `${reactId}:${index}:${block.kind}`, fileMentions) }) }) }, block.kind === "image" ? `image:${block.attachment.attachmentId}:${index}` : `${index}:${block.kind}`))
|
|
43297
43834
|
})
|
|
43298
43835
|
});
|
|
43299
43836
|
});
|
|
@@ -43338,7 +43875,7 @@ ${trimmed}
|
|
|
43338
43875
|
}
|
|
43339
43876
|
function CopyAnswer({ blocks, onFork, metrics, extraActions }) {
|
|
43340
43877
|
const { receipt, copy } = useCopyReceipt();
|
|
43341
|
-
const text = blocks
|
|
43878
|
+
const text = originalAnswerText(blocks);
|
|
43342
43879
|
const endedAt = metrics?.endedAt;
|
|
43343
43880
|
const hasMetrics = metrics !== void 0 && (metrics.usage !== void 0 || metrics.runMs !== void 0 || endedAt !== void 0);
|
|
43344
43881
|
if (!text.trim() && !onFork && !hasMetrics) return null;
|
|
@@ -43830,11 +44367,21 @@ ${trimmed}
|
|
|
43830
44367
|
};
|
|
43831
44368
|
const officialSeat = (family, source = OFFICIAL_SLOTS[family]) => `dsh-better-display.official.${family}/${source}`;
|
|
43832
44369
|
const READER_OWNED_NODES = /* @__PURE__ */ new Set([
|
|
43833
|
-
"assistant-step",
|
|
43834
44370
|
"tool-call",
|
|
43835
44371
|
"turn-tail",
|
|
43836
44372
|
"turn-process"
|
|
43837
44373
|
]);
|
|
44374
|
+
/**
|
|
44375
|
+
* Mirror a chat-node registration into the Reader seat.
|
|
44376
|
+
* Assistant replacements are the entries that would actually replace the
|
|
44377
|
+
* official renderer on the host. The official priority itself stays out, so
|
|
44378
|
+
* Reader keeps its own answer markdown until a plugin opts in.
|
|
44379
|
+
*/
|
|
44380
|
+
function acceptMirroredChatNode(entry) {
|
|
44381
|
+
const key = entry.options.key ?? "";
|
|
44382
|
+
if (key === "assistant-step") return (entry.options.priority ?? 0) < 0;
|
|
44383
|
+
return !READER_OWNED_NODES.has(key);
|
|
44384
|
+
}
|
|
43838
44385
|
const EXPECTED = {
|
|
43839
44386
|
actions: {
|
|
43840
44387
|
kind: "list",
|
|
@@ -43984,7 +44531,7 @@ ${trimmed}
|
|
|
43984
44531
|
const target = officialSeat(family);
|
|
43985
44532
|
const declared = slots.spec(target);
|
|
43986
44533
|
if (spec.kind !== declared?.kind || spec.scope !== declared.scope) throw new Error(`Official slot contract changed: ${source}`);
|
|
43987
|
-
return mirrorOfficialSlot(slots, source, target, `dsh-better-display.official.${family}`, family === "nodes" ?
|
|
44534
|
+
return mirrorOfficialSlot(slots, source, target, `dsh-better-display.official.${family}`, family === "nodes" ? acceptMirroredChatNode : void 0);
|
|
43988
44535
|
}));
|
|
43989
44536
|
}
|
|
43990
44537
|
} catch (error) {
|
|
@@ -44049,11 +44596,8 @@ ${trimmed}
|
|
|
44049
44596
|
})
|
|
44050
44597
|
});
|
|
44051
44598
|
}
|
|
44052
|
-
function
|
|
44053
|
-
|
|
44054
|
-
const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
|
|
44055
|
-
if (!official) return fallback;
|
|
44056
|
-
const owner = {
|
|
44599
|
+
function chatNodeOwner(render, official) {
|
|
44600
|
+
return {
|
|
44057
44601
|
cwd: render.cwd,
|
|
44058
44602
|
openFile: render.openFile ?? (() => {}),
|
|
44059
44603
|
openSkill: () => {},
|
|
@@ -44066,13 +44610,18 @@ ${trimmed}
|
|
|
44066
44610
|
}),
|
|
44067
44611
|
fileMentions: official.officialFileMentions
|
|
44068
44612
|
};
|
|
44613
|
+
}
|
|
44614
|
+
function OfficialNode({ node, fallback, ...render }) {
|
|
44615
|
+
const official = render.official;
|
|
44616
|
+
const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
|
|
44617
|
+
if (!official) return fallback;
|
|
44069
44618
|
const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
|
|
44070
44619
|
const renderNode = official.renderSlot;
|
|
44071
44620
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
44072
44621
|
"data-reader-official-node": node.kind,
|
|
44073
44622
|
...node.kind === "user" || node.kind === "steering" ? chatSeatProps(node.kind, node.key) : {},
|
|
44074
44623
|
children: renderNode(OFFICIAL_SEATS.nodes, {
|
|
44075
|
-
...
|
|
44624
|
+
...chatNodeOwner(render, official),
|
|
44076
44625
|
node
|
|
44077
44626
|
}, {
|
|
44078
44627
|
entryKey: node.kind,
|
|
@@ -44084,6 +44633,46 @@ ${trimmed}
|
|
|
44084
44633
|
})
|
|
44085
44634
|
});
|
|
44086
44635
|
}
|
|
44636
|
+
/**
|
|
44637
|
+
* Body of one assistant segment. A mirrored assistant-step replacement draws
|
|
44638
|
+
* it; Reader markdown is the fallback when no replacement is registered.
|
|
44639
|
+
* The caller keeps reasoning blocks on the reading card.
|
|
44640
|
+
*/
|
|
44641
|
+
function OfficialAssistantBody({ node, blocks, streaming = false, holdFormatting = false, startedAt, interrupted = false, liveText = false, ...render }) {
|
|
44642
|
+
const official = render.official;
|
|
44643
|
+
const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
|
|
44644
|
+
const fallback = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
|
|
44645
|
+
...render,
|
|
44646
|
+
blocks,
|
|
44647
|
+
streaming,
|
|
44648
|
+
holdFormatting,
|
|
44649
|
+
startedAt,
|
|
44650
|
+
interrupted,
|
|
44651
|
+
liveText
|
|
44652
|
+
});
|
|
44653
|
+
if (!official) return fallback;
|
|
44654
|
+
const turn = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn : void 0;
|
|
44655
|
+
const view = blocks.length === node.data.blocks.length && blocks.every((block, index) => block === node.data.blocks[index]) ? node : {
|
|
44656
|
+
...node,
|
|
44657
|
+
data: {
|
|
44658
|
+
...node.data,
|
|
44659
|
+
blocks
|
|
44660
|
+
}
|
|
44661
|
+
};
|
|
44662
|
+
const renderNode = official.renderSlot;
|
|
44663
|
+
return renderNode(OFFICIAL_SEATS.nodes, {
|
|
44664
|
+
...chatNodeOwner(render, official),
|
|
44665
|
+
node: view,
|
|
44666
|
+
groupPart: "response"
|
|
44667
|
+
}, {
|
|
44668
|
+
entryKey: "assistant-step",
|
|
44669
|
+
hookContext: {
|
|
44670
|
+
turnData: turn?.data,
|
|
44671
|
+
disclosureReset
|
|
44672
|
+
},
|
|
44673
|
+
fallback
|
|
44674
|
+
});
|
|
44675
|
+
}
|
|
44087
44676
|
function OfficialTail({ official, owner, produced }) {
|
|
44088
44677
|
const tailOwner = owner && official ? {
|
|
44089
44678
|
...owner,
|
|
@@ -44097,6 +44686,69 @@ ${trimmed}
|
|
|
44097
44686
|
}) : null;
|
|
44098
44687
|
}
|
|
44099
44688
|
//#endregion
|
|
44689
|
+
//#region src/client/turn-slots.ts
|
|
44690
|
+
/**
|
|
44691
|
+
* Keep live turns in the incoming `groups` order, and keep a departing turn
|
|
44692
|
+
* next to the live neighbour that preceded it.
|
|
44693
|
+
*
|
|
44694
|
+
* A rewind removes turn keys from the visible order. Unmounting them in that
|
|
44695
|
+
* same commit snaps the transcript, so the lane retains the last group object
|
|
44696
|
+
* until the collapse finishes. A re-render, a stream tick, or a reconnect that
|
|
44697
|
+
* still contains the same keys only replaces the group object and leaves
|
|
44698
|
+
* `live` true — those updates must not start a collapse. A key that returns
|
|
44699
|
+
* is live again where `groups` places it. Loading older history therefore
|
|
44700
|
+
* stays in transcript order instead of appending the older turns after the
|
|
44701
|
+
* ones already on screen. A departing slot is inserted immediately after the
|
|
44702
|
+
* nearest preceding slot that is still live, or at the front when it had none,
|
|
44703
|
+
* so several departing neighbours keep their relative order.
|
|
44704
|
+
*
|
|
44705
|
+
* Returns `current` itself when nothing changed, so a React state update can
|
|
44706
|
+
* bail out on `Object.is`.
|
|
44707
|
+
*/
|
|
44708
|
+
function reconcileTurnSlots(current, groups) {
|
|
44709
|
+
const incoming = new Map(groups.map((group) => [group.key, group]));
|
|
44710
|
+
const next = groups.map((group) => ({
|
|
44711
|
+
group,
|
|
44712
|
+
live: true
|
|
44713
|
+
}));
|
|
44714
|
+
for (const slot of current) {
|
|
44715
|
+
if (incoming.has(slot.group.key)) continue;
|
|
44716
|
+
insertDeparting(next, {
|
|
44717
|
+
group: slot.group,
|
|
44718
|
+
live: false
|
|
44719
|
+
}, precedingLiveKey(current, incoming, slot.group.key));
|
|
44720
|
+
}
|
|
44721
|
+
return next.length === current.length && next.every((slot, index) => slot.live === current[index].live && slot.group === current[index].group) ? current : next;
|
|
44722
|
+
}
|
|
44723
|
+
/** Nearest preceding slot that is still in the incoming order, if any. */
|
|
44724
|
+
function precedingLiveKey(current, incoming, key) {
|
|
44725
|
+
const index = current.findIndex((slot) => slot.group.key === key);
|
|
44726
|
+
for (let cursor = index - 1; cursor >= 0; cursor--) {
|
|
44727
|
+
const candidate = current[cursor].group.key;
|
|
44728
|
+
if (incoming.has(candidate)) return candidate;
|
|
44729
|
+
}
|
|
44730
|
+
}
|
|
44731
|
+
/**
|
|
44732
|
+
* Place a departing slot after `anchorKey`, or at the front when the slot had
|
|
44733
|
+
* no preceding live neighbour. Slots that share an anchor keep `current` order
|
|
44734
|
+
* because each one is inserted at the end of the departing run after that anchor.
|
|
44735
|
+
*/
|
|
44736
|
+
function insertDeparting(next, slot, anchorKey) {
|
|
44737
|
+
if (anchorKey === void 0) {
|
|
44738
|
+
const firstLive = next.findIndex((item) => item.live);
|
|
44739
|
+
next.splice(firstLive < 0 ? next.length : firstLive, 0, slot);
|
|
44740
|
+
return;
|
|
44741
|
+
}
|
|
44742
|
+
const anchorIndex = next.findIndex((item) => item.group.key === anchorKey);
|
|
44743
|
+
if (anchorIndex < 0) {
|
|
44744
|
+
next.unshift(slot);
|
|
44745
|
+
return;
|
|
44746
|
+
}
|
|
44747
|
+
let insertAt = anchorIndex + 1;
|
|
44748
|
+
while (insertAt < next.length && next[insertAt]?.live === false) insertAt++;
|
|
44749
|
+
next.splice(insertAt, 0, slot);
|
|
44750
|
+
}
|
|
44751
|
+
//#endregion
|
|
44100
44752
|
//#region src/client/motion.tsx
|
|
44101
44753
|
const EASING = "cubic-bezier(.22,1,.36,1)";
|
|
44102
44754
|
function useMotionAllowed(enabled) {
|
|
@@ -44109,7 +44761,7 @@ ${trimmed}
|
|
|
44109
44761
|
}, []);
|
|
44110
44762
|
return enabled && !reduced;
|
|
44111
44763
|
}
|
|
44112
|
-
function usePinnedSelection(root, selector = "[data-reader-answer], [data-reader-process]") {
|
|
44764
|
+
function usePinnedSelection(root, selector = "[data-reader-answer], [data-reader-body], [data-reader-process]") {
|
|
44113
44765
|
const [keys, setKeys] = (0, react.useState)([]);
|
|
44114
44766
|
(0, react.useEffect)(() => {
|
|
44115
44767
|
const update = () => {
|
|
@@ -44355,12 +45007,14 @@ ${trimmed}
|
|
|
44355
45007
|
});
|
|
44356
45008
|
}
|
|
44357
45009
|
/** Retire only narration that was actually visible; historical rows stay folded. */
|
|
44358
|
-
function RetiringContent({ visible, children }) {
|
|
45010
|
+
function RetiringContent({ visible, children, onRetired }) {
|
|
44359
45011
|
const { enabled } = (0, react.useContext)(StreamMotionContext);
|
|
44360
45012
|
const root = (0, react.useRef)(null);
|
|
44361
45013
|
const animation = (0, react.useRef)(null);
|
|
44362
45014
|
const [present, setPresent] = (0, react.useState)(visible);
|
|
44363
45015
|
const [focusHeld, setFocusHeld] = (0, react.useState)(false);
|
|
45016
|
+
const retired = (0, react.useRef)(onRetired);
|
|
45017
|
+
retired.current = onRetired;
|
|
44364
45018
|
(0, react.useLayoutEffect)(() => {
|
|
44365
45019
|
const element = root.current;
|
|
44366
45020
|
if (visible) {
|
|
@@ -44370,16 +45024,38 @@ ${trimmed}
|
|
|
44370
45024
|
return;
|
|
44371
45025
|
}
|
|
44372
45026
|
if (!element) return;
|
|
44373
|
-
|
|
44374
|
-
|
|
45027
|
+
let retiredNow = false;
|
|
45028
|
+
const retireNow = () => {
|
|
45029
|
+
if (retiredNow) return;
|
|
45030
|
+
retiredNow = true;
|
|
45031
|
+
animation.current?.cancel();
|
|
45032
|
+
animation.current = null;
|
|
45033
|
+
focusSurvivesRetire(element);
|
|
45034
|
+
setPresent(false);
|
|
45035
|
+
retired.current?.();
|
|
45036
|
+
};
|
|
45037
|
+
if (!enabled || document.hidden) {
|
|
45038
|
+
retireNow();
|
|
44375
45039
|
return;
|
|
44376
45040
|
}
|
|
44377
|
-
|
|
45041
|
+
const canListen = typeof document.addEventListener === "function";
|
|
45042
|
+
const holdsFocus = element.contains(document.activeElement);
|
|
45043
|
+
if (holdsFocus || focusHeld) {
|
|
45044
|
+
if (holdsFocus) setFocusHeld(true);
|
|
45045
|
+
const onHiddenWhileHeld = () => {
|
|
45046
|
+
if (document.hidden) retireNow();
|
|
45047
|
+
};
|
|
45048
|
+
if (canListen) document.addEventListener("visibilitychange", onHiddenWhileHeld);
|
|
45049
|
+
return () => {
|
|
45050
|
+
if (canListen) document.removeEventListener("visibilitychange", onHiddenWhileHeld);
|
|
45051
|
+
};
|
|
45052
|
+
}
|
|
44378
45053
|
const from = element.getBoundingClientRect().height;
|
|
44379
45054
|
animation.current?.cancel();
|
|
44380
45055
|
animation.current = null;
|
|
44381
|
-
if (
|
|
45056
|
+
if (from < 1) {
|
|
44382
45057
|
setPresent(false);
|
|
45058
|
+
retired.current?.();
|
|
44383
45059
|
return;
|
|
44384
45060
|
}
|
|
44385
45061
|
const next = element.animate([{
|
|
@@ -44394,17 +45070,24 @@ ${trimmed}
|
|
|
44394
45070
|
fill: "both"
|
|
44395
45071
|
});
|
|
44396
45072
|
animation.current = next;
|
|
45073
|
+
let settled = false;
|
|
44397
45074
|
const settle = () => {
|
|
44398
|
-
if (animation.current
|
|
44399
|
-
|
|
44400
|
-
|
|
44401
|
-
|
|
44402
|
-
|
|
45075
|
+
if (settled || animation.current !== next) return;
|
|
45076
|
+
settled = true;
|
|
45077
|
+
animation.current = null;
|
|
45078
|
+
next.cancel();
|
|
45079
|
+
setPresent(false);
|
|
45080
|
+
retired.current?.();
|
|
44403
45081
|
};
|
|
44404
45082
|
next.onfinish = settle;
|
|
44405
45083
|
const deadline = window.setTimeout(settle, 460);
|
|
45084
|
+
const onHide = () => {
|
|
45085
|
+
if (document.hidden) settle();
|
|
45086
|
+
};
|
|
45087
|
+
if (canListen) document.addEventListener("visibilitychange", onHide);
|
|
44406
45088
|
return () => {
|
|
44407
45089
|
window.clearTimeout(deadline);
|
|
45090
|
+
if (canListen) document.removeEventListener("visibilitychange", onHide);
|
|
44408
45091
|
if (animation.current === next) animation.current = null;
|
|
44409
45092
|
next.cancel();
|
|
44410
45093
|
};
|
|
@@ -44426,6 +45109,80 @@ ${trimmed}
|
|
|
44426
45109
|
children
|
|
44427
45110
|
});
|
|
44428
45111
|
}
|
|
45112
|
+
/**
|
|
45113
|
+
* Keeps a departing turn mounted for the length of its own collapse.
|
|
45114
|
+
*
|
|
45115
|
+
* A rewind removes turns from the visible order, and unmounting them outright
|
|
45116
|
+
* snapped the transcript: every withdrawn row disappeared in one frame with
|
|
45117
|
+
* nothing to scroll. Instead each departing turn is retained, rendered with
|
|
45118
|
+
* `visible={false}` so it animates to zero height, and released only once the
|
|
45119
|
+
* collapse has settled — so the reader watches the rows fold away and the rows
|
|
45120
|
+
* below glide up into their place.
|
|
45121
|
+
*
|
|
45122
|
+
* Live slots follow the incoming group order, so older history stays above the
|
|
45123
|
+
* tail. A collapsing turn stays next to the live neighbour that preceded it;
|
|
45124
|
+
* appending it would jump it to the bottom for the length of the animation.
|
|
45125
|
+
* Retention is bounded by the animation itself: `onRetired`
|
|
45126
|
+
* drops the slot, so a departing turn lives for one collapse and no longer —
|
|
45127
|
+
* and a key that comes back later is re-added as a live slot.
|
|
45128
|
+
*/
|
|
45129
|
+
function RetiringTurns({ groups, render }) {
|
|
45130
|
+
const [slots, setSlots] = (0, react.useState)(() => groups.map((group) => ({
|
|
45131
|
+
group,
|
|
45132
|
+
live: true
|
|
45133
|
+
})));
|
|
45134
|
+
(0, react.useLayoutEffect)(() => {
|
|
45135
|
+
setSlots((current) => reconcileTurnSlots(current, groups));
|
|
45136
|
+
}, [groups]);
|
|
45137
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: slots.map((slot) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringContent, {
|
|
45138
|
+
visible: slot.live,
|
|
45139
|
+
onRetired: () => setSlots((current) => current.filter((candidate) => candidate.live || candidate.group.key !== slot.group.key)),
|
|
45140
|
+
children: render(slot.group)
|
|
45141
|
+
}, slot.group.key)) });
|
|
45142
|
+
}
|
|
45143
|
+
/** A turn that is still on screen, not one this commit is about to unmount. */
|
|
45144
|
+
function survivingTurn(node) {
|
|
45145
|
+
if (!(node instanceof HTMLElement) || node.dataset.readerRetiring === "retiring") return null;
|
|
45146
|
+
const turn = node.hasAttribute("data-reader-turn") ? node : node.querySelector("[data-reader-turn]");
|
|
45147
|
+
if (turn === null) return null;
|
|
45148
|
+
const retiring = turn.closest("[data-reader-retiring]");
|
|
45149
|
+
if (retiring instanceof HTMLElement && retiring.dataset.readerRetiring === "retiring") return null;
|
|
45150
|
+
return turn;
|
|
45151
|
+
}
|
|
45152
|
+
/**
|
|
45153
|
+
* Where focus goes when cut content is removed without an animation.
|
|
45154
|
+
* Prefer the nearest turn that is still live. Otherwise the reading column
|
|
45155
|
+
* (or the host scrollport) so focus does not fall through to the document.
|
|
45156
|
+
*/
|
|
45157
|
+
function retireFocusTarget(element) {
|
|
45158
|
+
const parent = element.parentElement;
|
|
45159
|
+
if (parent) {
|
|
45160
|
+
const siblings = [...parent.children];
|
|
45161
|
+
const index = siblings.indexOf(element);
|
|
45162
|
+
for (let cursor = index - 1; cursor >= 0; cursor--) {
|
|
45163
|
+
const turn = survivingTurn(siblings[cursor]);
|
|
45164
|
+
if (turn) return turn;
|
|
45165
|
+
}
|
|
45166
|
+
for (let cursor = index + 1; cursor < siblings.length; cursor++) {
|
|
45167
|
+
const turn = survivingTurn(siblings[cursor]);
|
|
45168
|
+
if (turn) return turn;
|
|
45169
|
+
}
|
|
45170
|
+
}
|
|
45171
|
+
const column = element.closest("[data-chat-flow]");
|
|
45172
|
+
if (column && !element.contains(column)) return column;
|
|
45173
|
+
const scroll = element.closest("[data-conversation-scroll]");
|
|
45174
|
+
if (scroll && !element.contains(scroll)) return scroll;
|
|
45175
|
+
return null;
|
|
45176
|
+
}
|
|
45177
|
+
/** Move focus out of `element` before it unmounts. A no-op when focus is elsewhere. */
|
|
45178
|
+
function focusSurvivesRetire(element) {
|
|
45179
|
+
const active = document.activeElement;
|
|
45180
|
+
if (active === null || !element.contains(active)) return;
|
|
45181
|
+
const target = retireFocusTarget(element);
|
|
45182
|
+
if (target === null || element.contains(target)) return;
|
|
45183
|
+
if (target.tabIndex < 0) target.tabIndex = -1;
|
|
45184
|
+
target.focus({ preventScroll: true });
|
|
45185
|
+
}
|
|
44429
45186
|
function useReadingScroll(root, motion) {
|
|
44430
45187
|
const port = (0, react.useRef)(null);
|
|
44431
45188
|
const following = (0, react.useRef)(true);
|
|
@@ -44641,6 +45398,345 @@ ${trimmed}
|
|
|
44641
45398
|
};
|
|
44642
45399
|
}
|
|
44643
45400
|
//#endregion
|
|
45401
|
+
//#region src/client/fold-choreography.ts
|
|
45402
|
+
/** Presentation clock, not model/network time. */
|
|
45403
|
+
const FOLD_TIMING = {
|
|
45404
|
+
collapse: 320,
|
|
45405
|
+
count: 160,
|
|
45406
|
+
settle: 80,
|
|
45407
|
+
reveal: 180,
|
|
45408
|
+
/**
|
|
45409
|
+
* Slack added to every phase deadline before the watchdog forces the next phase.
|
|
45410
|
+
*
|
|
45411
|
+
* The choreography advances on animation promises and rendered frames. Both are
|
|
45412
|
+
* best-effort: a cancelled animation *rejects* and a compositor that never
|
|
45413
|
+
* finishes one leaves its promise pending, while a backgrounded tab stops
|
|
45414
|
+
* delivering frames. Without a deadline the machine would sit in a non-idle
|
|
45415
|
+
* phase forever, and a non-idle phase freezes both the frame source and the text
|
|
45416
|
+
* reveal, so the turn would look stuck until a remount. This is the liveness
|
|
45417
|
+
* guarantee that does not depend on any of them.
|
|
45418
|
+
*/
|
|
45419
|
+
watchdogSlack: 240
|
|
45420
|
+
};
|
|
45421
|
+
/** A step always has the same parent and React key, even when its membership changes. */
|
|
45422
|
+
function flowRows(items) {
|
|
45423
|
+
return items.flatMap((item) => item.kind === "fold" ? [{
|
|
45424
|
+
kind: "summary",
|
|
45425
|
+
key: item.key,
|
|
45426
|
+
item
|
|
45427
|
+
}, ...item.steps.map((step) => ({
|
|
45428
|
+
kind: "step",
|
|
45429
|
+
key: step.key,
|
|
45430
|
+
step,
|
|
45431
|
+
foldKey: item.key
|
|
45432
|
+
}))] : [{
|
|
45433
|
+
kind: "step",
|
|
45434
|
+
key: item.key,
|
|
45435
|
+
step: item.step
|
|
45436
|
+
}]);
|
|
45437
|
+
}
|
|
45438
|
+
function retiringKeys(before, after, open) {
|
|
45439
|
+
const folded = new Set(flowRows(after).filter((row) => row.kind === "step" && row.foldKey && !open[row.foldKey]).map((row) => row.key));
|
|
45440
|
+
return flowRows(before).filter((row) => row.kind === "step" && !row.foldKey && folded.has(row.key)).map((row) => row.key);
|
|
45441
|
+
}
|
|
45442
|
+
/** Insert only new summary slots. Never admit incoming content during shrink. */
|
|
45443
|
+
function collapseRows(before, target) {
|
|
45444
|
+
const rows = flowRows(before);
|
|
45445
|
+
const headers = new Set(rows.filter((row) => row.kind === "summary").map((row) => row.key));
|
|
45446
|
+
for (const item of target) {
|
|
45447
|
+
if (item.kind !== "fold" || headers.has(item.key)) continue;
|
|
45448
|
+
const members = new Set(item.steps.map((step) => step.key));
|
|
45449
|
+
const at = rows.findIndex((row) => members.has(row.key));
|
|
45450
|
+
if (at >= 0) rows.splice(at, 0, {
|
|
45451
|
+
kind: "summary",
|
|
45452
|
+
key: item.key,
|
|
45453
|
+
item: {
|
|
45454
|
+
...item,
|
|
45455
|
+
summary: item.summary.replace(/\d+/g, "0")
|
|
45456
|
+
}
|
|
45457
|
+
});
|
|
45458
|
+
}
|
|
45459
|
+
return rows;
|
|
45460
|
+
}
|
|
45461
|
+
function containsNewUser(before, after) {
|
|
45462
|
+
const users = new Set(before.filter((item) => item.kind === "user").map((item) => item.key));
|
|
45463
|
+
return after.some((item) => item.kind === "user" && !users.has(item.key));
|
|
45464
|
+
}
|
|
45465
|
+
//#endregion
|
|
45466
|
+
//#region src/client/LiveFold.tsx
|
|
45467
|
+
/** Values are presentation commits, never live network counters. */
|
|
45468
|
+
function SubtleNumberRoll({ value, motion }) {
|
|
45469
|
+
const [outgoing, setOutgoing] = (0, react.useState)(null);
|
|
45470
|
+
const previous = (0, react.useRef)(value);
|
|
45471
|
+
(0, react.useLayoutEffect)(() => {
|
|
45472
|
+
if (value === previous.current) return;
|
|
45473
|
+
const old = previous.current;
|
|
45474
|
+
previous.current = value;
|
|
45475
|
+
if (!motion) {
|
|
45476
|
+
setOutgoing(null);
|
|
45477
|
+
return;
|
|
45478
|
+
}
|
|
45479
|
+
setOutgoing(old);
|
|
45480
|
+
const timer = window.setTimeout(() => setOutgoing(null), FOLD_TIMING.count);
|
|
45481
|
+
return () => window.clearTimeout(timer);
|
|
45482
|
+
}, [value, motion]);
|
|
45483
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
45484
|
+
className: Reader_module_css_default.numberRollRoot,
|
|
45485
|
+
"aria-hidden": "true",
|
|
45486
|
+
children: [
|
|
45487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45488
|
+
className: Reader_module_css_default.numberRollSizer,
|
|
45489
|
+
children: value
|
|
45490
|
+
}),
|
|
45491
|
+
outgoing !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45492
|
+
className: `${Reader_module_css_default.numberRollDigit} ${Reader_module_css_default.numberRollExit}`,
|
|
45493
|
+
children: outgoing
|
|
45494
|
+
}, `out-${outgoing}`),
|
|
45495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45496
|
+
className: `${Reader_module_css_default.numberRollDigit} ${outgoing !== null ? Reader_module_css_default.numberRollEnter : ""}`,
|
|
45497
|
+
children: value
|
|
45498
|
+
}, `cur-${value}`)
|
|
45499
|
+
]
|
|
45500
|
+
});
|
|
45501
|
+
}
|
|
45502
|
+
function FoldSummaryText({ summary, motion }) {
|
|
45503
|
+
const parts = (0, react.useMemo)(() => {
|
|
45504
|
+
const regex = /([^\d]+)(\d+)/g;
|
|
45505
|
+
const result = [];
|
|
45506
|
+
let end = 0;
|
|
45507
|
+
for (const match of summary.matchAll(regex)) {
|
|
45508
|
+
result.push({
|
|
45509
|
+
text: match[1],
|
|
45510
|
+
number: Number(match[2])
|
|
45511
|
+
});
|
|
45512
|
+
end = match.index + match[0].length;
|
|
45513
|
+
}
|
|
45514
|
+
if (end < summary.length) result.push({ text: summary.slice(end) });
|
|
45515
|
+
return result;
|
|
45516
|
+
}, [summary]);
|
|
45517
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45518
|
+
className: Reader_module_css_default.foldSummary,
|
|
45519
|
+
"data-reader-fold-summary": summary,
|
|
45520
|
+
"aria-label": summary,
|
|
45521
|
+
children: parts.map((part) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
45522
|
+
className: Reader_module_css_default.foldSummaryPart,
|
|
45523
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part.text }), part.number !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubtleNumberRoll, {
|
|
45524
|
+
value: part.number,
|
|
45525
|
+
motion
|
|
45526
|
+
})]
|
|
45527
|
+
}, part.text))
|
|
45528
|
+
});
|
|
45529
|
+
}
|
|
45530
|
+
//#endregion
|
|
45531
|
+
//#region src/client/projection.ts
|
|
45532
|
+
function groupNodes(order, get) {
|
|
45533
|
+
const groups = [];
|
|
45534
|
+
const seenTurns = /* @__PURE__ */ new Set();
|
|
45535
|
+
for (const key of order) {
|
|
45536
|
+
const node = get(key);
|
|
45537
|
+
if (!node || node.visibility === "hidden") continue;
|
|
45538
|
+
const turn = node.location.kind === "step" || node.location.kind === "turn" ? node.location.turn.turn : null;
|
|
45539
|
+
const previous = groups.at(-1);
|
|
45540
|
+
if (turn !== null && previous?.turn === turn) previous.keys.push(key);
|
|
45541
|
+
else {
|
|
45542
|
+
groups.push({
|
|
45543
|
+
key: turn === null ? `node:${key}` : seenTurns.has(turn) ? `turn:${turn}:${key}` : `turn:${turn}`,
|
|
45544
|
+
turn,
|
|
45545
|
+
keys: [key]
|
|
45546
|
+
});
|
|
45547
|
+
if (turn !== null) seenTurns.add(turn);
|
|
45548
|
+
}
|
|
45549
|
+
}
|
|
45550
|
+
return groups;
|
|
45551
|
+
}
|
|
45552
|
+
function boundaryOf(turn) {
|
|
45553
|
+
return {
|
|
45554
|
+
status: turn?.status ?? "unknown",
|
|
45555
|
+
reason: turn?.end?.data.reason.kind ?? null,
|
|
45556
|
+
latestStep: turn?.steps.at(-1)?.step ?? -1,
|
|
45557
|
+
closingStep: turn?.data.get("turn-tail")?.closing?.step ?? null
|
|
45558
|
+
};
|
|
45559
|
+
}
|
|
45560
|
+
/**
|
|
45561
|
+
* A settled body step before the closing step of a successful turn.
|
|
45562
|
+
*
|
|
45563
|
+
* This is presentation classification only. Narration is never process content
|
|
45564
|
+
* and never folds. The flag only marks body text that is no longer the turn's
|
|
45565
|
+
* final answer, so copy and fork stay on that final answer.
|
|
45566
|
+
*/
|
|
45567
|
+
function isEarlierNarration(data, boundary) {
|
|
45568
|
+
if (data.status !== "settled" || boundary.status !== "closed" || boundary.reason !== "completed") return false;
|
|
45569
|
+
if (data.blocks.some((block) => block.kind === "image" || block.kind === "other")) return false;
|
|
45570
|
+
return boundary.closingStep !== null && data.step < boundary.closingStep;
|
|
45571
|
+
}
|
|
45572
|
+
function processExpanded(choice, boundary) {
|
|
45573
|
+
return choice ?? !(boundary.status === "closed" && boundary.reason === "completed");
|
|
45574
|
+
}
|
|
45575
|
+
/** Reading while running must not pin the process open after completion. */
|
|
45576
|
+
function processChoiceKey(groupKey, boundary) {
|
|
45577
|
+
return `${groupKey}:${boundary.status}:${boundary.reason ?? "pending"}`;
|
|
45578
|
+
}
|
|
45579
|
+
/**
|
|
45580
|
+
* A body-only assistant step is not a thinking/process disclosure.
|
|
45581
|
+
*
|
|
45582
|
+
* Narration (text/image/other blocks) is always visible, so it never counts as
|
|
45583
|
+
* foldable process content; only literal reasoning does. Tool calls arrive as
|
|
45584
|
+
* their own flow entries and are checked separately by the reader.
|
|
45585
|
+
*/
|
|
45586
|
+
function hasProcessContent(node, _boundary) {
|
|
45587
|
+
if (!node || node.visibility === "hidden") return false;
|
|
45588
|
+
if (node.kind === "assistant-step") return node.data.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "");
|
|
45589
|
+
return node.kind === "context" || node.kind === "model-retry" || node.kind === "system-prompt" || node.kind === "turn-process" || node.kind === "command" || node.kind === "manual-compaction" || node.kind === "compaction";
|
|
45590
|
+
}
|
|
45591
|
+
function hasVisibleBody(blocks) {
|
|
45592
|
+
return blocks.some((block) => block.kind === "image" || block.kind === "other" || block.kind === "text" && block.text.trim() !== "");
|
|
45593
|
+
}
|
|
45594
|
+
/** Keep native block order. In particular, never lift a later Think above text. */
|
|
45595
|
+
function assistantSegments(blocks) {
|
|
45596
|
+
const segments = [];
|
|
45597
|
+
let previous;
|
|
45598
|
+
blocks.forEach((block, index) => {
|
|
45599
|
+
if (block.kind === "tool-call") {
|
|
45600
|
+
previous = void 0;
|
|
45601
|
+
return;
|
|
45602
|
+
}
|
|
45603
|
+
const kind = block.kind === "reasoning" ? "reasoning" : "body";
|
|
45604
|
+
if (previous?.kind === kind) previous.blocks.push(block);
|
|
45605
|
+
else {
|
|
45606
|
+
previous = {
|
|
45607
|
+
kind,
|
|
45608
|
+
start: index,
|
|
45609
|
+
blocks: [block]
|
|
45610
|
+
};
|
|
45611
|
+
segments.push(previous);
|
|
45612
|
+
}
|
|
45613
|
+
});
|
|
45614
|
+
return segments;
|
|
45615
|
+
}
|
|
45616
|
+
function terminalLabel(reason) {
|
|
45617
|
+
switch (reason) {
|
|
45618
|
+
case "completed": return null;
|
|
45619
|
+
case "aborted":
|
|
45620
|
+
case "interrupted": return "本轮已停止,已生成的内容仍保留。";
|
|
45621
|
+
case "blocked": return "本轮需要处理阻塞事项;请查看原对话与下方操作区。";
|
|
45622
|
+
case "max-tokens": return "输出达到本轮长度限制,内容可能尚未完整。";
|
|
45623
|
+
case "error": return "本轮未完成;错误信息保留在下方。";
|
|
45624
|
+
case null: return null;
|
|
45625
|
+
default: return `本轮结束状态:${reason}。请在原对话中核对完整记录。`;
|
|
45626
|
+
}
|
|
45627
|
+
}
|
|
45628
|
+
/**
|
|
45629
|
+
* Extract the first usable fork anchor seq from candidate message nodes.
|
|
45630
|
+
* Only the durable closing message seq cuts the intended turn prefix: an
|
|
45631
|
+
* absent anchor must surface as undefined (never as 0 or NaN), because the
|
|
45632
|
+
* host treats a missing atSeq as a whole-session fork.
|
|
45633
|
+
*/
|
|
45634
|
+
function forkAnchorSeq(candidates) {
|
|
45635
|
+
for (const candidate of candidates) {
|
|
45636
|
+
const seq = candidate?.seq;
|
|
45637
|
+
if (typeof seq === "number" && Number.isFinite(seq)) return seq;
|
|
45638
|
+
}
|
|
45639
|
+
}
|
|
45640
|
+
//#endregion
|
|
45641
|
+
//#region src/client/AssistantNode.tsx
|
|
45642
|
+
function isNode$1(node, kind) {
|
|
45643
|
+
return node.kind === kind;
|
|
45644
|
+
}
|
|
45645
|
+
const AssistantNode = (0, react.memo)(function AssistantNode({ useChat, nodeKey, boundary, processOpen = false, pinned = false, folded = false, partStart, seamSummary, seamAfter = false, motion, onRead, returnFocusTo, ...render }) {
|
|
45646
|
+
const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
|
|
45647
|
+
if (!node || node.visibility === "hidden" || !isNode$1(node, "assistant-step")) return null;
|
|
45648
|
+
const data = node.data;
|
|
45649
|
+
const parts = assistantSegments(data.blocks);
|
|
45650
|
+
const earlier = isEarlierNarration(data, boundary);
|
|
45651
|
+
const hasToolCalls = data.blocks.some((block) => block.kind === "tool-call");
|
|
45652
|
+
const isProcessStep = earlier || folded || hasToolCalls || boundary.latestStep > 0 && data.step < boundary.latestStep;
|
|
45653
|
+
const body = data.blocks.filter((block) => block.kind !== "reasoning" && block.kind !== "tool-call");
|
|
45654
|
+
const visible = partStart === void 0 ? parts : parts.filter((part) => part.start === partStart);
|
|
45655
|
+
const bodyProps = {
|
|
45656
|
+
streaming: data.status === "running",
|
|
45657
|
+
holdFormatting: pinned,
|
|
45658
|
+
startedAt: data.time,
|
|
45659
|
+
interrupted: data.status === "interrupted",
|
|
45660
|
+
liveText: true
|
|
45661
|
+
};
|
|
45662
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: visible.map((part) => {
|
|
45663
|
+
const last = parts.findIndex((item) => item.start === part.start) === parts.length - 1;
|
|
45664
|
+
if (part.kind === "reasoning") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
|
|
45665
|
+
open: processOpen,
|
|
45666
|
+
motion,
|
|
45667
|
+
onRead,
|
|
45668
|
+
returnFocusTo,
|
|
45669
|
+
nodeKey,
|
|
45670
|
+
framed: true,
|
|
45671
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningCard, {
|
|
45672
|
+
step: data.step,
|
|
45673
|
+
active: processOpen && boundary.status === "open" && data.step === boundary.latestStep,
|
|
45674
|
+
motion,
|
|
45675
|
+
selected: pinned,
|
|
45676
|
+
onRead,
|
|
45677
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
|
|
45678
|
+
...render,
|
|
45679
|
+
blocks: part.blocks,
|
|
45680
|
+
streaming: data.status === "running" && last && data.blocks.at(-1)?.kind === "reasoning",
|
|
45681
|
+
holdFormatting: pinned,
|
|
45682
|
+
startedAt: data.time,
|
|
45683
|
+
interrupted: data.status === "interrupted",
|
|
45684
|
+
liveText: true
|
|
45685
|
+
})
|
|
45686
|
+
})
|
|
45687
|
+
}, part.start);
|
|
45688
|
+
if (!hasVisibleBody(part.blocks)) return null;
|
|
45689
|
+
const isFinalAnswer = !isProcessStep;
|
|
45690
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [seamSummary && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
45691
|
+
className: Reader_module_css_default.processSeamRow,
|
|
45692
|
+
"data-reader-process-seam": true,
|
|
45693
|
+
"data-reader-process-seam-summary": seamSummary,
|
|
45694
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Disclosure, {
|
|
45695
|
+
open: false,
|
|
45696
|
+
onChange: () => onRead(),
|
|
45697
|
+
ariaLabel: "被折叠的过程",
|
|
45698
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldSummaryText, {
|
|
45699
|
+
summary: seamSummary,
|
|
45700
|
+
motion: false
|
|
45701
|
+
})
|
|
45702
|
+
})
|
|
45703
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
45704
|
+
className: Reader_module_css_default.answer,
|
|
45705
|
+
"data-reader-body": true,
|
|
45706
|
+
"data-reader-anchor": true,
|
|
45707
|
+
"data-reader-key": nodeKey,
|
|
45708
|
+
"data-reader-source-start": part.start,
|
|
45709
|
+
"data-reader-seam-after": seamAfter || void 0,
|
|
45710
|
+
"data-answer-status": data.status,
|
|
45711
|
+
"data-answer-phase": isFinalAnswer ? "body" : "process",
|
|
45712
|
+
children: [
|
|
45713
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialAssistantBody, {
|
|
45714
|
+
...render,
|
|
45715
|
+
node,
|
|
45716
|
+
blocks: part.blocks,
|
|
45717
|
+
...bodyProps
|
|
45718
|
+
}),
|
|
45719
|
+
isFinalAnswer && last && data.status === "interrupted" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45720
|
+
className: Reader_module_css_default.stopped,
|
|
45721
|
+
children: "已停止"
|
|
45722
|
+
}),
|
|
45723
|
+
isFinalAnswer && last && data.status !== "running" && boundary.status === "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyAnswer, {
|
|
45724
|
+
blocks: body,
|
|
45725
|
+
onFork: (() => {
|
|
45726
|
+
const anchor = forkAnchorSeq([data.finalNode, { seq: render.forkSeq }]);
|
|
45727
|
+
return render.forkAt && anchor !== void 0 ? () => render.forkAt(anchor) : void 0;
|
|
45728
|
+
})(),
|
|
45729
|
+
metrics: render.metrics,
|
|
45730
|
+
extraActions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialActions, {
|
|
45731
|
+
official: render.official,
|
|
45732
|
+
messageId: data.finalNode?.messageId
|
|
45733
|
+
})
|
|
45734
|
+
})
|
|
45735
|
+
]
|
|
45736
|
+
})] }, part.start);
|
|
45737
|
+
}) });
|
|
45738
|
+
});
|
|
45739
|
+
//#endregion
|
|
44644
45740
|
//#region src/client/native/tool-call-model.ts
|
|
44645
45741
|
/**
|
|
44646
45742
|
* Pure row-model derivation for tool summary rows: variant classification,
|
|
@@ -45434,106 +46530,6 @@ ${trimmed}
|
|
|
45434
46530
|
}, child.callId))] });
|
|
45435
46531
|
}
|
|
45436
46532
|
//#endregion
|
|
45437
|
-
//#region src/client/projection.ts
|
|
45438
|
-
function groupNodes(order, get) {
|
|
45439
|
-
const groups = [];
|
|
45440
|
-
const seenTurns = /* @__PURE__ */ new Set();
|
|
45441
|
-
for (const key of order) {
|
|
45442
|
-
const node = get(key);
|
|
45443
|
-
if (!node || node.visibility === "hidden") continue;
|
|
45444
|
-
const turn = node.location.kind === "step" || node.location.kind === "turn" ? node.location.turn.turn : null;
|
|
45445
|
-
const previous = groups.at(-1);
|
|
45446
|
-
if (turn !== null && previous?.turn === turn) previous.keys.push(key);
|
|
45447
|
-
else {
|
|
45448
|
-
groups.push({
|
|
45449
|
-
key: turn === null ? `node:${key}` : seenTurns.has(turn) ? `turn:${turn}:${key}` : `turn:${turn}`,
|
|
45450
|
-
turn,
|
|
45451
|
-
keys: [key]
|
|
45452
|
-
});
|
|
45453
|
-
if (turn !== null) seenTurns.add(turn);
|
|
45454
|
-
}
|
|
45455
|
-
}
|
|
45456
|
-
return groups;
|
|
45457
|
-
}
|
|
45458
|
-
function boundaryOf(turn) {
|
|
45459
|
-
return {
|
|
45460
|
-
status: turn?.status ?? "unknown",
|
|
45461
|
-
reason: turn?.end?.data.reason.kind ?? null,
|
|
45462
|
-
latestStep: turn?.steps.at(-1)?.step ?? -1,
|
|
45463
|
-
closingStep: turn?.data.get("turn-tail")?.closing?.step ?? null
|
|
45464
|
-
};
|
|
45465
|
-
}
|
|
45466
|
-
function isEarlierNarration(data, boundary) {
|
|
45467
|
-
if (data.status !== "settled" || boundary.status !== "closed" || boundary.reason !== "completed") return false;
|
|
45468
|
-
if (data.blocks.some((block) => block.kind === "image" || block.kind === "other")) return false;
|
|
45469
|
-
return boundary.closingStep !== null && data.step < boundary.closingStep;
|
|
45470
|
-
}
|
|
45471
|
-
function processExpanded(choice, boundary) {
|
|
45472
|
-
return choice ?? !(boundary.status === "closed" && boundary.reason === "completed");
|
|
45473
|
-
}
|
|
45474
|
-
/** Reading while running must not pin the process open after completion. */
|
|
45475
|
-
function processChoiceKey(groupKey, boundary) {
|
|
45476
|
-
return `${groupKey}:${boundary.status}:${boundary.reason ?? "pending"}`;
|
|
45477
|
-
}
|
|
45478
|
-
/** A body-only assistant step is not a thinking/process disclosure. */
|
|
45479
|
-
function hasProcessContent(node, boundary) {
|
|
45480
|
-
if (!node || node.visibility === "hidden") return false;
|
|
45481
|
-
if (node.kind === "assistant-step") {
|
|
45482
|
-
const data = node.data;
|
|
45483
|
-
return data.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "") || isEarlierNarration(data, boundary) && hasVisibleBody(data.blocks);
|
|
45484
|
-
}
|
|
45485
|
-
return node.kind === "context" || node.kind === "model-retry" || node.kind === "system-prompt" || node.kind === "turn-process" || node.kind === "command" || node.kind === "manual-compaction" || node.kind === "compaction";
|
|
45486
|
-
}
|
|
45487
|
-
function hasVisibleBody(blocks) {
|
|
45488
|
-
return blocks.some((block) => block.kind === "image" || block.kind === "other" || block.kind === "text" && block.text.trim() !== "");
|
|
45489
|
-
}
|
|
45490
|
-
/** Keep native block order. In particular, never lift a later Think above text. */
|
|
45491
|
-
function assistantSegments(blocks) {
|
|
45492
|
-
const segments = [];
|
|
45493
|
-
let previous;
|
|
45494
|
-
blocks.forEach((block, index) => {
|
|
45495
|
-
if (block.kind === "tool-call") {
|
|
45496
|
-
previous = void 0;
|
|
45497
|
-
return;
|
|
45498
|
-
}
|
|
45499
|
-
const kind = block.kind === "reasoning" ? "reasoning" : "body";
|
|
45500
|
-
if (previous?.kind === kind) previous.blocks.push(block);
|
|
45501
|
-
else {
|
|
45502
|
-
previous = {
|
|
45503
|
-
kind,
|
|
45504
|
-
start: index,
|
|
45505
|
-
blocks: [block]
|
|
45506
|
-
};
|
|
45507
|
-
segments.push(previous);
|
|
45508
|
-
}
|
|
45509
|
-
});
|
|
45510
|
-
return segments;
|
|
45511
|
-
}
|
|
45512
|
-
function terminalLabel(reason) {
|
|
45513
|
-
switch (reason) {
|
|
45514
|
-
case "completed": return null;
|
|
45515
|
-
case "aborted":
|
|
45516
|
-
case "interrupted": return "本轮已停止,已生成的内容仍保留。";
|
|
45517
|
-
case "blocked": return "本轮需要处理阻塞事项;请查看原对话与下方操作区。";
|
|
45518
|
-
case "max-tokens": return "输出达到本轮长度限制,内容可能尚未完整。";
|
|
45519
|
-
case "error": return "本轮未完成;错误信息保留在下方。";
|
|
45520
|
-
case null: return null;
|
|
45521
|
-
default: return `本轮结束状态:${reason}。请在原对话中核对完整记录。`;
|
|
45522
|
-
}
|
|
45523
|
-
}
|
|
45524
|
-
/**
|
|
45525
|
-
* Extract the first usable fork anchor seq from candidate message nodes.
|
|
45526
|
-
* Only the durable closing message seq cuts the intended turn prefix: an
|
|
45527
|
-
* absent anchor must surface as undefined (never as 0 or NaN), because the
|
|
45528
|
-
* host treats a missing atSeq as a whole-session fork.
|
|
45529
|
-
*/
|
|
45530
|
-
function forkAnchorSeq(candidates) {
|
|
45531
|
-
for (const candidate of candidates) {
|
|
45532
|
-
const seq = candidate?.seq;
|
|
45533
|
-
if (typeof seq === "number" && Number.isFinite(seq)) return seq;
|
|
45534
|
-
}
|
|
45535
|
-
}
|
|
45536
|
-
//#endregion
|
|
45537
46533
|
//#region src/client/open-file.ts
|
|
45538
46534
|
function deliverableOpenModeOf(value) {
|
|
45539
46535
|
return value === "sidebar" ? "sidebar" : "external";
|
|
@@ -46764,27 +47760,6 @@ ${trimmed}
|
|
|
46764
47760
|
if (extra) parts.push(`记录×${extra}`);
|
|
46765
47761
|
return parts.join(" · ") || "此前步骤";
|
|
46766
47762
|
}
|
|
46767
|
-
/** One chain: fold only when a new reasoning step has prior body/tool/reasoning. */
|
|
46768
|
-
function splitChain(chain) {
|
|
46769
|
-
const lastReasoning = chain.findLastIndex((step) => step.kind === "reasoning");
|
|
46770
|
-
if (lastReasoning < 0) return {
|
|
46771
|
-
fold: null,
|
|
46772
|
-
open: chain
|
|
46773
|
-
};
|
|
46774
|
-
const prior = chain.slice(0, lastReasoning);
|
|
46775
|
-
if (!prior.length) return {
|
|
46776
|
-
fold: null,
|
|
46777
|
-
open: chain
|
|
46778
|
-
};
|
|
46779
|
-
if (!prior.some((step) => step.kind === "reasoning" || step.kind === "body" || step.kind === "tool")) return {
|
|
46780
|
-
fold: null,
|
|
46781
|
-
open: chain
|
|
46782
|
-
};
|
|
46783
|
-
return {
|
|
46784
|
-
fold: prior,
|
|
46785
|
-
open: chain.slice(lastReasoning)
|
|
46786
|
-
};
|
|
46787
|
-
}
|
|
46788
47763
|
function skipReasoning(part) {
|
|
46789
47764
|
return part.kind === "reasoning" && !part.blocks.some((block) => block.kind === "reasoning" && block.text.trim() !== "");
|
|
46790
47765
|
}
|
|
@@ -46864,46 +47839,117 @@ ${trimmed}
|
|
|
46864
47839
|
}
|
|
46865
47840
|
return steps;
|
|
46866
47841
|
}
|
|
47842
|
+
/** Only a run that contains real thinking/tool work is worth folding. */
|
|
47843
|
+
function foldableRun(run) {
|
|
47844
|
+
return run.some((step) => step.kind === "reasoning" || step.kind === "tool");
|
|
47845
|
+
}
|
|
47846
|
+
/**
|
|
47847
|
+
* One live chain: narration stays visible, while every earlier reasoning/tool
|
|
47848
|
+
* run collapses into its own box at its original position.
|
|
47849
|
+
*/
|
|
46867
47850
|
function presentLiveTurn(steps, boundary, autoFold = true) {
|
|
46868
47851
|
const live = autoFold && liveFoldEnabled(boundary);
|
|
46869
47852
|
const items = [];
|
|
46870
|
-
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
46874
|
-
|
|
46875
|
-
|
|
46876
|
-
|
|
46877
|
-
|
|
46878
|
-
});
|
|
46879
|
-
chain = [];
|
|
46880
|
-
return;
|
|
46881
|
-
}
|
|
46882
|
-
const { fold, open } = splitChain(chain);
|
|
46883
|
-
if (fold?.length) items.push({
|
|
47853
|
+
const open = (step) => items.push({
|
|
47854
|
+
kind: "open",
|
|
47855
|
+
key: step.key,
|
|
47856
|
+
step
|
|
47857
|
+
});
|
|
47858
|
+
const fold = (run) => {
|
|
47859
|
+
if (!run.length) return;
|
|
47860
|
+
if (live && foldableRun(run)) items.push({
|
|
46884
47861
|
kind: "fold",
|
|
46885
|
-
key: `live-fold:${
|
|
46886
|
-
steps:
|
|
46887
|
-
summary: foldSummary(
|
|
46888
|
-
});
|
|
46889
|
-
for (const step of open) items.push({
|
|
46890
|
-
kind: "open",
|
|
46891
|
-
key: step.key,
|
|
46892
|
-
step
|
|
47862
|
+
key: `live-fold:${run[0].key}`,
|
|
47863
|
+
steps: run,
|
|
47864
|
+
summary: foldSummary(run)
|
|
46893
47865
|
});
|
|
46894
|
-
|
|
47866
|
+
else for (const step of run) open(step);
|
|
46895
47867
|
};
|
|
47868
|
+
let run = [];
|
|
47869
|
+
const flush = () => {
|
|
47870
|
+
fold(run);
|
|
47871
|
+
run = [];
|
|
47872
|
+
};
|
|
47873
|
+
const segments = [];
|
|
47874
|
+
let segment = [];
|
|
46896
47875
|
for (const step of steps) if (step.kind === "user") {
|
|
47876
|
+
segments.push(segment);
|
|
47877
|
+
segments.push([step]);
|
|
47878
|
+
segment = [];
|
|
47879
|
+
} else segment.push(step);
|
|
47880
|
+
segments.push(segment);
|
|
47881
|
+
for (const part of segments) {
|
|
47882
|
+
if (!part.length) continue;
|
|
47883
|
+
const first = part[0];
|
|
47884
|
+
if (part.length === 1 && first.kind === "user") {
|
|
47885
|
+
items.push({
|
|
47886
|
+
kind: "user",
|
|
47887
|
+
key: first.key,
|
|
47888
|
+
step: first
|
|
47889
|
+
});
|
|
47890
|
+
continue;
|
|
47891
|
+
}
|
|
47892
|
+
if (!live) {
|
|
47893
|
+
for (const step of part) open(step);
|
|
47894
|
+
continue;
|
|
47895
|
+
}
|
|
47896
|
+
const lastReasoning = part.findLastIndex((step) => step.kind === "reasoning");
|
|
47897
|
+
if (lastReasoning <= 0) {
|
|
47898
|
+
for (const step of part) open(step);
|
|
47899
|
+
continue;
|
|
47900
|
+
}
|
|
47901
|
+
for (let index = 0; index < part.length; index++) {
|
|
47902
|
+
const step = part[index];
|
|
47903
|
+
if (index < lastReasoning) {
|
|
47904
|
+
if (step.kind === "body") {
|
|
47905
|
+
flush();
|
|
47906
|
+
open(step);
|
|
47907
|
+
} else run.push(step);
|
|
47908
|
+
} else {
|
|
47909
|
+
if (index === lastReasoning) flush();
|
|
47910
|
+
open(step);
|
|
47911
|
+
}
|
|
47912
|
+
}
|
|
46897
47913
|
flush();
|
|
46898
|
-
|
|
46899
|
-
kind: "user",
|
|
46900
|
-
key: step.key,
|
|
46901
|
-
step
|
|
46902
|
-
});
|
|
46903
|
-
} else chain.push(step);
|
|
46904
|
-
flush();
|
|
47914
|
+
}
|
|
46905
47915
|
return items;
|
|
46906
47916
|
}
|
|
47917
|
+
/**
|
|
47918
|
+
* Summaries for collapsed process that sits between two narration blocks.
|
|
47919
|
+
*
|
|
47920
|
+
* A live-fold cell already shows that summary while the turn is open. Drawing
|
|
47921
|
+
* the seam as well repeats the same counts, so a run whose every step is
|
|
47922
|
+
* already inside a fold cell contributes neither a seam nor `after`. `after`
|
|
47923
|
+
* is what marks the previous body with `data-reader-seam-after` and drops its
|
|
47924
|
+
* bottom padding; skipping the seam must leave that spacing alone.
|
|
47925
|
+
*/
|
|
47926
|
+
function planProcessSeams(steps, liveItems, expanded) {
|
|
47927
|
+
const before = /* @__PURE__ */ new Map();
|
|
47928
|
+
const after = /* @__PURE__ */ new Set();
|
|
47929
|
+
if (expanded) return {
|
|
47930
|
+
before,
|
|
47931
|
+
after
|
|
47932
|
+
};
|
|
47933
|
+
const liveFolded = new Set(liveItems.flatMap((item) => item.kind === "fold" ? item.steps.map((step) => step.key) : []));
|
|
47934
|
+
let previousBody;
|
|
47935
|
+
let process = [];
|
|
47936
|
+
for (const step of steps) if (step.kind === "body") {
|
|
47937
|
+
const folded = process.filter((item) => item.kind !== "user");
|
|
47938
|
+
if (!(folded.length > 0 && folded.every((item) => liveFolded.has(item.key))) && previousBody && folded.some((item) => item.kind === "reasoning" || item.kind === "tool" || item.kind === "other")) {
|
|
47939
|
+
before.set(step.key, foldSummary(folded));
|
|
47940
|
+
after.add(previousBody.key);
|
|
47941
|
+
}
|
|
47942
|
+
previousBody = step;
|
|
47943
|
+
process = [];
|
|
47944
|
+
} else if (step.kind === "user") {
|
|
47945
|
+
previousBody = void 0;
|
|
47946
|
+
process = [];
|
|
47947
|
+
} else process.push(step);
|
|
47948
|
+
return {
|
|
47949
|
+
before,
|
|
47950
|
+
after
|
|
47951
|
+
};
|
|
47952
|
+
}
|
|
46907
47953
|
//#endregion
|
|
46908
47954
|
//#region src/client/fold-intensity.ts
|
|
46909
47955
|
function frostedGlassOf(state) {
|
|
@@ -46917,136 +47963,6 @@ ${trimmed}
|
|
|
46917
47963
|
return intensity === 2;
|
|
46918
47964
|
}
|
|
46919
47965
|
//#endregion
|
|
46920
|
-
//#region src/client/fold-choreography.ts
|
|
46921
|
-
/** Presentation clock, not model/network time. */
|
|
46922
|
-
const FOLD_TIMING = {
|
|
46923
|
-
collapse: 320,
|
|
46924
|
-
count: 160,
|
|
46925
|
-
settle: 80,
|
|
46926
|
-
reveal: 180,
|
|
46927
|
-
/**
|
|
46928
|
-
* Slack added to every phase deadline before the watchdog forces the next phase.
|
|
46929
|
-
*
|
|
46930
|
-
* The choreography advances on animation promises and rendered frames. Both are
|
|
46931
|
-
* best-effort: a cancelled animation *rejects* and a compositor that never
|
|
46932
|
-
* finishes one leaves its promise pending, while a backgrounded tab stops
|
|
46933
|
-
* delivering frames. Without a deadline the machine would sit in a non-idle
|
|
46934
|
-
* phase forever, and a non-idle phase freezes both the frame source and the text
|
|
46935
|
-
* reveal, so the turn would look stuck until a remount. This is the liveness
|
|
46936
|
-
* guarantee that does not depend on any of them.
|
|
46937
|
-
*/
|
|
46938
|
-
watchdogSlack: 240
|
|
46939
|
-
};
|
|
46940
|
-
/** A step always has the same parent and React key, even when its membership changes. */
|
|
46941
|
-
function flowRows(items) {
|
|
46942
|
-
return items.flatMap((item) => item.kind === "fold" ? [{
|
|
46943
|
-
kind: "summary",
|
|
46944
|
-
key: item.key,
|
|
46945
|
-
item
|
|
46946
|
-
}, ...item.steps.map((step) => ({
|
|
46947
|
-
kind: "step",
|
|
46948
|
-
key: step.key,
|
|
46949
|
-
step,
|
|
46950
|
-
foldKey: item.key
|
|
46951
|
-
}))] : [{
|
|
46952
|
-
kind: "step",
|
|
46953
|
-
key: item.key,
|
|
46954
|
-
step: item.step
|
|
46955
|
-
}]);
|
|
46956
|
-
}
|
|
46957
|
-
function retiringKeys(before, after, open) {
|
|
46958
|
-
const folded = new Set(flowRows(after).filter((row) => row.kind === "step" && row.foldKey && !open[row.foldKey]).map((row) => row.key));
|
|
46959
|
-
return flowRows(before).filter((row) => row.kind === "step" && !row.foldKey && folded.has(row.key)).map((row) => row.key);
|
|
46960
|
-
}
|
|
46961
|
-
/** Insert only new summary slots. Never admit incoming content during shrink. */
|
|
46962
|
-
function collapseRows(before, target) {
|
|
46963
|
-
const rows = flowRows(before);
|
|
46964
|
-
const headers = new Set(rows.filter((row) => row.kind === "summary").map((row) => row.key));
|
|
46965
|
-
for (const item of target) {
|
|
46966
|
-
if (item.kind !== "fold" || headers.has(item.key)) continue;
|
|
46967
|
-
const members = new Set(item.steps.map((step) => step.key));
|
|
46968
|
-
const at = rows.findIndex((row) => members.has(row.key));
|
|
46969
|
-
if (at >= 0) rows.splice(at, 0, {
|
|
46970
|
-
kind: "summary",
|
|
46971
|
-
key: item.key,
|
|
46972
|
-
item: {
|
|
46973
|
-
...item,
|
|
46974
|
-
summary: item.summary.replace(/\d+/g, "0")
|
|
46975
|
-
}
|
|
46976
|
-
});
|
|
46977
|
-
}
|
|
46978
|
-
return rows;
|
|
46979
|
-
}
|
|
46980
|
-
function containsNewUser(before, after) {
|
|
46981
|
-
const users = new Set(before.filter((item) => item.kind === "user").map((item) => item.key));
|
|
46982
|
-
return after.some((item) => item.kind === "user" && !users.has(item.key));
|
|
46983
|
-
}
|
|
46984
|
-
//#endregion
|
|
46985
|
-
//#region src/client/LiveFold.tsx
|
|
46986
|
-
/** Values are presentation commits, never live network counters. */
|
|
46987
|
-
function SubtleNumberRoll({ value, motion }) {
|
|
46988
|
-
const [outgoing, setOutgoing] = (0, react.useState)(null);
|
|
46989
|
-
const previous = (0, react.useRef)(value);
|
|
46990
|
-
(0, react.useLayoutEffect)(() => {
|
|
46991
|
-
if (value === previous.current) return;
|
|
46992
|
-
const old = previous.current;
|
|
46993
|
-
previous.current = value;
|
|
46994
|
-
if (!motion) {
|
|
46995
|
-
setOutgoing(null);
|
|
46996
|
-
return;
|
|
46997
|
-
}
|
|
46998
|
-
setOutgoing(old);
|
|
46999
|
-
const timer = window.setTimeout(() => setOutgoing(null), FOLD_TIMING.count);
|
|
47000
|
-
return () => window.clearTimeout(timer);
|
|
47001
|
-
}, [value, motion]);
|
|
47002
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
47003
|
-
className: Reader_module_css_default.numberRollRoot,
|
|
47004
|
-
"aria-hidden": "true",
|
|
47005
|
-
children: [
|
|
47006
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47007
|
-
className: Reader_module_css_default.numberRollSizer,
|
|
47008
|
-
children: value
|
|
47009
|
-
}),
|
|
47010
|
-
outgoing !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47011
|
-
className: `${Reader_module_css_default.numberRollDigit} ${Reader_module_css_default.numberRollExit}`,
|
|
47012
|
-
children: outgoing
|
|
47013
|
-
}, `out-${outgoing}`),
|
|
47014
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47015
|
-
className: `${Reader_module_css_default.numberRollDigit} ${outgoing !== null ? Reader_module_css_default.numberRollEnter : ""}`,
|
|
47016
|
-
children: value
|
|
47017
|
-
}, `cur-${value}`)
|
|
47018
|
-
]
|
|
47019
|
-
});
|
|
47020
|
-
}
|
|
47021
|
-
function FoldSummaryText({ summary, motion }) {
|
|
47022
|
-
const parts = (0, react.useMemo)(() => {
|
|
47023
|
-
const regex = /([^\d]+)(\d+)/g;
|
|
47024
|
-
const result = [];
|
|
47025
|
-
let end = 0;
|
|
47026
|
-
for (const match of summary.matchAll(regex)) {
|
|
47027
|
-
result.push({
|
|
47028
|
-
text: match[1],
|
|
47029
|
-
number: Number(match[2])
|
|
47030
|
-
});
|
|
47031
|
-
end = match.index + match[0].length;
|
|
47032
|
-
}
|
|
47033
|
-
if (end < summary.length) result.push({ text: summary.slice(end) });
|
|
47034
|
-
return result;
|
|
47035
|
-
}, [summary]);
|
|
47036
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47037
|
-
className: Reader_module_css_default.foldSummary,
|
|
47038
|
-
"data-reader-fold-summary": summary,
|
|
47039
|
-
"aria-label": summary,
|
|
47040
|
-
children: parts.map((part) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
47041
|
-
className: Reader_module_css_default.foldSummaryPart,
|
|
47042
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: part.text }), part.number !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SubtleNumberRoll, {
|
|
47043
|
-
value: part.number,
|
|
47044
|
-
motion
|
|
47045
|
-
})]
|
|
47046
|
-
}, part.text))
|
|
47047
|
-
});
|
|
47048
|
-
}
|
|
47049
|
-
//#endregion
|
|
47050
47966
|
//#region src/client/DiffPanel.tsx
|
|
47051
47967
|
/**
|
|
47052
47968
|
* Reveals and withdraws its child by animating real height, in the plugin's own
|
|
@@ -47215,6 +48131,123 @@ ${trimmed}
|
|
|
47215
48131
|
})] });
|
|
47216
48132
|
}
|
|
47217
48133
|
//#endregion
|
|
48134
|
+
//#region src/client/StickyLane.tsx
|
|
48135
|
+
const MIN_LANE_PX = 40;
|
|
48136
|
+
const LaneOwnerContext = (0, react.createContext)(null);
|
|
48137
|
+
const ownersByRoot = /* @__PURE__ */ new WeakMap();
|
|
48138
|
+
/** One map per Reader, so two roots that both contain turn 1 do not share a writer. */
|
|
48139
|
+
function ReaderLaneScope({ children }) {
|
|
48140
|
+
const owners = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
48141
|
+
(0, react.useLayoutEffect)(() => {
|
|
48142
|
+
const map = owners.current;
|
|
48143
|
+
return () => {
|
|
48144
|
+
map.clear();
|
|
48145
|
+
};
|
|
48146
|
+
}, []);
|
|
48147
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LaneOwnerContext.Provider, {
|
|
48148
|
+
value: owners.current,
|
|
48149
|
+
children
|
|
48150
|
+
});
|
|
48151
|
+
}
|
|
48152
|
+
function laneScope(el) {
|
|
48153
|
+
return el.closest("[data-reader-turn]") ?? el.closest("[data-dsh-better-display]");
|
|
48154
|
+
}
|
|
48155
|
+
function ownersFor(el, scoped) {
|
|
48156
|
+
if (scoped) return scoped;
|
|
48157
|
+
const root = el.closest("[data-dsh-better-display]") ?? el;
|
|
48158
|
+
let owners = ownersByRoot.get(root);
|
|
48159
|
+
if (!owners) {
|
|
48160
|
+
owners = /* @__PURE__ */ new Map();
|
|
48161
|
+
ownersByRoot.set(root, owners);
|
|
48162
|
+
}
|
|
48163
|
+
return owners;
|
|
48164
|
+
}
|
|
48165
|
+
function publishedLanePx(el) {
|
|
48166
|
+
return Math.max(MIN_LANE_PX, Math.ceil(el.getBoundingClientRect().height));
|
|
48167
|
+
}
|
|
48168
|
+
/** One writer per turn inside a single Reader. A retiring summary cannot clear the lane that replaced it. */
|
|
48169
|
+
function publishLaneHeight(el, property, scoped = null) {
|
|
48170
|
+
const scope = laneScope(el);
|
|
48171
|
+
if (!scope) return () => {};
|
|
48172
|
+
const owners = ownersFor(el, scoped);
|
|
48173
|
+
const root = el.closest("[data-dsh-better-display]");
|
|
48174
|
+
const key = `${property}\0${scope.getAttribute("data-reader-turn") ?? "root"}`;
|
|
48175
|
+
const update = () => {
|
|
48176
|
+
if (owners.get(key) !== el) return;
|
|
48177
|
+
scope.style.setProperty(property, `${publishedLanePx(el)}px`);
|
|
48178
|
+
};
|
|
48179
|
+
owners.set(key, el);
|
|
48180
|
+
update();
|
|
48181
|
+
const observer = new ResizeObserver(update);
|
|
48182
|
+
observer.observe(el);
|
|
48183
|
+
return () => {
|
|
48184
|
+
observer.disconnect();
|
|
48185
|
+
if (owners.get(key) !== el) return;
|
|
48186
|
+
owners.delete(key);
|
|
48187
|
+
scope.style.removeProperty(property);
|
|
48188
|
+
if (!scoped && root && owners.size === 0) ownersByRoot.delete(root);
|
|
48189
|
+
};
|
|
48190
|
+
}
|
|
48191
|
+
function usePublishedHeight(property) {
|
|
48192
|
+
const owners = (0, react.useContext)(LaneOwnerContext);
|
|
48193
|
+
const ref = (0, react.useRef)(null);
|
|
48194
|
+
(0, react.useLayoutEffect)(() => {
|
|
48195
|
+
const el = ref.current;
|
|
48196
|
+
if (!el) return;
|
|
48197
|
+
return publishLaneHeight(el, property, owners);
|
|
48198
|
+
}, [owners, property]);
|
|
48199
|
+
return ref;
|
|
48200
|
+
}
|
|
48201
|
+
function useSummaryLane(ref, active) {
|
|
48202
|
+
const owners = (0, react.useContext)(LaneOwnerContext);
|
|
48203
|
+
(0, react.useLayoutEffect)(() => {
|
|
48204
|
+
const el = ref.current;
|
|
48205
|
+
if (!active || !el) return;
|
|
48206
|
+
return publishLaneHeight(el, "--reader-summary-height", owners);
|
|
48207
|
+
}, [
|
|
48208
|
+
active,
|
|
48209
|
+
owners,
|
|
48210
|
+
ref
|
|
48211
|
+
]);
|
|
48212
|
+
}
|
|
48213
|
+
/** Publish real lane geometry; wrapped labels must not collide with statistics. */
|
|
48214
|
+
function StickyLane({ kind, className, children }) {
|
|
48215
|
+
const ref = (0, react.useRef)(null);
|
|
48216
|
+
(0, react.useLayoutEffect)(() => {
|
|
48217
|
+
const el = ref.current;
|
|
48218
|
+
const scope = el?.closest(kind === "toolbar" ? "[data-dsh-better-display]" : "[data-reader-turn]");
|
|
48219
|
+
if (!el || !scope) return;
|
|
48220
|
+
const property = kind === "toolbar" ? "--reader-toolbar-height" : "--reader-status-height";
|
|
48221
|
+
const update = () => {
|
|
48222
|
+
scope.style.setProperty(property, `${Math.max(MIN_LANE_PX, el.getBoundingClientRect().height)}px`);
|
|
48223
|
+
if (kind !== "toolbar") return;
|
|
48224
|
+
const controls = el.querySelectorAll("button");
|
|
48225
|
+
let width = 80;
|
|
48226
|
+
if (controls.length > 0) {
|
|
48227
|
+
const first = controls[0].getBoundingClientRect();
|
|
48228
|
+
width = controls[controls.length - 1].getBoundingClientRect().right - first.left;
|
|
48229
|
+
}
|
|
48230
|
+
scope.style.setProperty("--reader-control-width", `${width + 28}px`);
|
|
48231
|
+
};
|
|
48232
|
+
update();
|
|
48233
|
+
const observer = new ResizeObserver(update);
|
|
48234
|
+
observer.observe(el);
|
|
48235
|
+
if (kind === "toolbar") for (const control of el.querySelectorAll("button")) observer.observe(control);
|
|
48236
|
+
return () => {
|
|
48237
|
+
observer.disconnect();
|
|
48238
|
+
scope.style.removeProperty(property);
|
|
48239
|
+
if (kind === "toolbar") scope.style.removeProperty("--reader-control-width");
|
|
48240
|
+
};
|
|
48241
|
+
}, [kind]);
|
|
48242
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
48243
|
+
ref,
|
|
48244
|
+
className,
|
|
48245
|
+
"data-reader-lane": kind,
|
|
48246
|
+
"data-ud-check": kind === "toolbar" ? "reader-toolbar" : void 0,
|
|
48247
|
+
children
|
|
48248
|
+
});
|
|
48249
|
+
}
|
|
48250
|
+
//#endregion
|
|
47218
48251
|
//#region src/client/ChoreographedFlow.tsx
|
|
47219
48252
|
const FlowSnapshot = (0, react.createContext)(null);
|
|
47220
48253
|
/** Public projection only. Descendants cannot leak live data through a frozen frame. */
|
|
@@ -47257,6 +48290,7 @@ ${trimmed}
|
|
|
47257
48290
|
/** Manual disclosure shares the measured-size path; children survive until finish. */
|
|
47258
48291
|
function FlowCell({ hidden, instant, motion, rowKey, children, summary = false }) {
|
|
47259
48292
|
const ref = (0, react.useRef)(null);
|
|
48293
|
+
useSummaryLane(ref, summary);
|
|
47260
48294
|
const [present, setPresent] = (0, react.useState)(!hidden);
|
|
47261
48295
|
const previous = (0, react.useRef)(hidden);
|
|
47262
48296
|
if (!hidden && !present) setPresent(true);
|
|
@@ -47514,9 +48548,11 @@ ${trimmed}
|
|
|
47514
48548
|
/** Keep process counts discoverable after the live-fold presentation retires. */
|
|
47515
48549
|
function ClosedProcessSummary({ steps, open, onChange, controls }) {
|
|
47516
48550
|
const button = (0, react.useRef)(null);
|
|
48551
|
+
const lane = usePublishedHeight("--reader-summary-height");
|
|
47517
48552
|
if (!steps.length) return null;
|
|
47518
48553
|
const summary = foldSummary(steps);
|
|
47519
48554
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
48555
|
+
ref: lane,
|
|
47520
48556
|
className: Reader_module_css_default.closedProcessSummary,
|
|
47521
48557
|
"data-reader-closed-summary": summary,
|
|
47522
48558
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -47539,45 +48575,6 @@ ${trimmed}
|
|
|
47539
48575
|
});
|
|
47540
48576
|
}
|
|
47541
48577
|
//#endregion
|
|
47542
|
-
//#region src/client/StickyLane.tsx
|
|
47543
|
-
/** Publish real lane geometry; wrapped labels must not collide with statistics. */
|
|
47544
|
-
function StickyLane({ kind, className, children }) {
|
|
47545
|
-
const ref = (0, react.useRef)(null);
|
|
47546
|
-
(0, react.useLayoutEffect)(() => {
|
|
47547
|
-
const el = ref.current;
|
|
47548
|
-
const scope = el?.closest(kind === "toolbar" ? "[data-dsh-better-display]" : "[data-reader-turn]");
|
|
47549
|
-
if (!el || !scope) return;
|
|
47550
|
-
const property = kind === "toolbar" ? "--reader-toolbar-height" : "--reader-status-height";
|
|
47551
|
-
const update = () => {
|
|
47552
|
-
scope.style.setProperty(property, `${el.getBoundingClientRect().height}px`);
|
|
47553
|
-
if (kind !== "toolbar") return;
|
|
47554
|
-
const controls = el.querySelectorAll("button");
|
|
47555
|
-
let width = 80;
|
|
47556
|
-
if (controls.length > 0) {
|
|
47557
|
-
const first = controls[0].getBoundingClientRect();
|
|
47558
|
-
width = controls[controls.length - 1].getBoundingClientRect().right - first.left;
|
|
47559
|
-
}
|
|
47560
|
-
scope.style.setProperty("--reader-control-width", `${width + 28}px`);
|
|
47561
|
-
};
|
|
47562
|
-
update();
|
|
47563
|
-
const observer = new ResizeObserver(update);
|
|
47564
|
-
observer.observe(el);
|
|
47565
|
-
if (kind === "toolbar") for (const control of el.querySelectorAll("button")) observer.observe(control);
|
|
47566
|
-
return () => {
|
|
47567
|
-
observer.disconnect();
|
|
47568
|
-
scope.style.removeProperty(property);
|
|
47569
|
-
if (kind === "toolbar") scope.style.removeProperty("--reader-control-width");
|
|
47570
|
-
};
|
|
47571
|
-
}, [kind]);
|
|
47572
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
47573
|
-
ref,
|
|
47574
|
-
className,
|
|
47575
|
-
"data-reader-lane": kind,
|
|
47576
|
-
"data-ud-check": kind === "toolbar" ? "reader-toolbar" : void 0,
|
|
47577
|
-
children
|
|
47578
|
-
});
|
|
47579
|
-
}
|
|
47580
|
-
//#endregion
|
|
47581
48578
|
//#region src/client/Reader.tsx
|
|
47582
48579
|
function isNode(node, kind) {
|
|
47583
48580
|
return node.kind === kind;
|
|
@@ -47597,6 +48594,9 @@ ${trimmed}
|
|
|
47597
48594
|
return typeof block === "object" && block !== null && block.type === "text" && typeof block.text === "string";
|
|
47598
48595
|
}).map((block) => block.text).join("");
|
|
47599
48596
|
}
|
|
48597
|
+
function inboxAttachmentCount(item) {
|
|
48598
|
+
return (item.content ?? []).filter((block) => typeof block === "object" && block !== null && block.type !== "text").length;
|
|
48599
|
+
}
|
|
47600
48600
|
function cleanErrorMessage(raw) {
|
|
47601
48601
|
if (!raw) return "模型服务暂时无响应或连接中断,请稍后重试。";
|
|
47602
48602
|
let str = raw.trim();
|
|
@@ -47749,101 +48749,7 @@ ${trimmed}
|
|
|
47749
48749
|
children: content
|
|
47750
48750
|
});
|
|
47751
48751
|
});
|
|
47752
|
-
const
|
|
47753
|
-
const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
|
|
47754
|
-
if (!node || node.visibility === "hidden" || !isNode(node, "assistant-step")) return null;
|
|
47755
|
-
const data = node.data;
|
|
47756
|
-
const parts = assistantSegments(data.blocks);
|
|
47757
|
-
const earlier = isEarlierNarration(data, boundary);
|
|
47758
|
-
const hasToolCalls = data.blocks.some((block) => block.kind === "tool-call");
|
|
47759
|
-
const isProcessStep = earlier || folded || hasToolCalls || boundary.latestStep > 0 && data.step < boundary.latestStep;
|
|
47760
|
-
const body = data.blocks.filter((block) => block.kind !== "reasoning" && block.kind !== "tool-call");
|
|
47761
|
-
const visible = partStart === void 0 ? parts : parts.filter((part) => part.start === partStart);
|
|
47762
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: visible.map((part) => {
|
|
47763
|
-
const last = parts.findIndex((item) => item.start === part.start) === parts.length - 1;
|
|
47764
|
-
return part.kind === "reasoning" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
|
|
47765
|
-
open: processOpen,
|
|
47766
|
-
motion,
|
|
47767
|
-
onRead,
|
|
47768
|
-
returnFocusTo,
|
|
47769
|
-
nodeKey,
|
|
47770
|
-
framed: true,
|
|
47771
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningCard, {
|
|
47772
|
-
step: data.step,
|
|
47773
|
-
active: processOpen && boundary.status === "open" && data.step === boundary.latestStep,
|
|
47774
|
-
motion,
|
|
47775
|
-
selected: pinned,
|
|
47776
|
-
onRead,
|
|
47777
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
|
|
47778
|
-
...render,
|
|
47779
|
-
blocks: part.blocks,
|
|
47780
|
-
streaming: data.status === "running" && last && data.blocks.at(-1)?.kind === "reasoning",
|
|
47781
|
-
holdFormatting: pinned,
|
|
47782
|
-
startedAt: data.time,
|
|
47783
|
-
interrupted: data.status === "interrupted",
|
|
47784
|
-
liveText: true
|
|
47785
|
-
})
|
|
47786
|
-
})
|
|
47787
|
-
}, part.start) : isProcessStep ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProcessFragment, {
|
|
47788
|
-
open: processOpen,
|
|
47789
|
-
motion,
|
|
47790
|
-
onRead,
|
|
47791
|
-
returnFocusTo,
|
|
47792
|
-
nodeKey,
|
|
47793
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("article", {
|
|
47794
|
-
className: Reader_module_css_default.processCommentary,
|
|
47795
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
|
|
47796
|
-
...render,
|
|
47797
|
-
blocks: part.blocks,
|
|
47798
|
-
streaming: data.status === "running",
|
|
47799
|
-
holdFormatting: pinned,
|
|
47800
|
-
startedAt: data.time,
|
|
47801
|
-
interrupted: data.status === "interrupted",
|
|
47802
|
-
liveText: true
|
|
47803
|
-
})
|
|
47804
|
-
})
|
|
47805
|
-
}, part.start) : hasVisibleBody(part.blocks) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringContent, {
|
|
47806
|
-
visible: pinned || processOpen || !earlier && !folded,
|
|
47807
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
47808
|
-
className: Reader_module_css_default.answer,
|
|
47809
|
-
"data-reader-answer": true,
|
|
47810
|
-
"data-reader-anchor": true,
|
|
47811
|
-
"data-reader-key": nodeKey,
|
|
47812
|
-
"data-reader-source-start": part.start,
|
|
47813
|
-
"data-answer-status": data.status,
|
|
47814
|
-
"data-answer-phase": earlier || folded ? "process" : "body",
|
|
47815
|
-
children: [
|
|
47816
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Blocks, {
|
|
47817
|
-
...render,
|
|
47818
|
-
blocks: part.blocks,
|
|
47819
|
-
streaming: data.status === "running",
|
|
47820
|
-
holdFormatting: pinned,
|
|
47821
|
-
startedAt: data.time,
|
|
47822
|
-
interrupted: data.status === "interrupted",
|
|
47823
|
-
liveText: true
|
|
47824
|
-
}),
|
|
47825
|
-
last && data.status === "interrupted" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47826
|
-
className: Reader_module_css_default.stopped,
|
|
47827
|
-
children: "已停止"
|
|
47828
|
-
}),
|
|
47829
|
-
last && !earlier && !folded && data.status !== "running" && boundary.status === "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyAnswer, {
|
|
47830
|
-
blocks: body,
|
|
47831
|
-
onFork: (() => {
|
|
47832
|
-
const anchor = forkAnchorSeq([data.finalNode, { seq: render.forkSeq }]);
|
|
47833
|
-
return render.forkAt && anchor !== void 0 ? () => render.forkAt(anchor) : void 0;
|
|
47834
|
-
})(),
|
|
47835
|
-
metrics: render.metrics,
|
|
47836
|
-
extraActions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OfficialActions, {
|
|
47837
|
-
official: render.official,
|
|
47838
|
-
messageId: data.finalNode?.messageId
|
|
47839
|
-
})
|
|
47840
|
-
})
|
|
47841
|
-
]
|
|
47842
|
-
})
|
|
47843
|
-
}, part.start);
|
|
47844
|
-
}) });
|
|
47845
|
-
});
|
|
47846
|
-
const MainNode = (0, react.memo)(function MainNode({ useChat, nodeKey, boundary, pinned, processOpen = false, ...render }) {
|
|
48752
|
+
const MainNode = (0, react.memo)(function MainNode({ useChat, nodeKey, boundary, pinned, processOpen: _processOpen = false, ...render }) {
|
|
47847
48753
|
const node = useChat((snapshot) => snapshot.nodes.get(nodeKey));
|
|
47848
48754
|
const [disclosureReset] = (0, react.useState)(() => (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(0));
|
|
47849
48755
|
if (!node || node.visibility === "hidden") return null;
|
|
@@ -48059,7 +48965,7 @@ ${trimmed}
|
|
|
48059
48965
|
}
|
|
48060
48966
|
return 0;
|
|
48061
48967
|
}
|
|
48062
|
-
function GroupStatus({ group,
|
|
48968
|
+
function GroupStatus({ group, useChat, pending, motion }) {
|
|
48063
48969
|
const text = useChat((snapshot) => {
|
|
48064
48970
|
const turn = group.turn === null ? void 0 : snapshot.timeline.turns.get(group.turn);
|
|
48065
48971
|
if (turn?.status === "closed") {
|
|
@@ -48310,11 +49216,12 @@ ${trimmed}
|
|
|
48310
49216
|
const flow = (0, react.useMemo)(() => readerFlow({
|
|
48311
49217
|
...group,
|
|
48312
49218
|
keys: mainKeys
|
|
48313
|
-
}, turn, (key) => nodes.get(key)), [
|
|
49219
|
+
}, turn, (key) => nodes.get(key), snapshot.order), [
|
|
48314
49220
|
nodes,
|
|
48315
49221
|
group,
|
|
48316
49222
|
mainKeys,
|
|
48317
|
-
turn
|
|
49223
|
+
turn,
|
|
49224
|
+
snapshot.order
|
|
48318
49225
|
]);
|
|
48319
49226
|
const steps = (0, react.useMemo)(() => segmentLiveTurn(flow, (key) => nodes.get(key)), [flow, nodes]);
|
|
48320
49227
|
const liveItems = (0, react.useMemo)(() => presentLiveTurn(steps, boundary, autoFold), [
|
|
@@ -48330,6 +49237,11 @@ ${trimmed}
|
|
|
48330
49237
|
const showClosedSummary = boundary.status === "closed" && hasProcess && autoFold;
|
|
48331
49238
|
const holdingSelection = selectedProcessKeys.some((key) => flow.some((item) => item.key === key) || liveItems.some((item) => item.kind === "fold" ? item.key === key || item.steps.some((step) => step.key === key || "nodeKey" in step && step.nodeKey === key) : item.key === key || "nodeKey" in item.step && item.step.nodeKey === key));
|
|
48332
49239
|
const expanded = !autoFold || holdingSelection || processExpanded(expansionChoice, boundary);
|
|
49240
|
+
const seamPlan = (0, react.useMemo)(() => planProcessSeams(steps, liveItems, expanded), [
|
|
49241
|
+
steps,
|
|
49242
|
+
liveItems,
|
|
49243
|
+
expanded
|
|
49244
|
+
]);
|
|
48333
49245
|
const [foldOpenByKey, setFoldOpenByKey] = (0, react.useState)({});
|
|
48334
49246
|
(0, react.useLayoutEffect)(() => {
|
|
48335
49247
|
if (autoFold) setFoldOpenByKey((current) => Object.keys(current).length ? {} : current);
|
|
@@ -48448,7 +49360,9 @@ ${trimmed}
|
|
|
48448
49360
|
folded,
|
|
48449
49361
|
motion,
|
|
48450
49362
|
onRead: pinProcess,
|
|
48451
|
-
returnFocusTo: processButton
|
|
49363
|
+
returnFocusTo: processButton,
|
|
49364
|
+
seamSummary: step.kind === "body" ? seamPlan.before.get(step.key) : void 0,
|
|
49365
|
+
seamAfter: step.kind === "body" && seamPlan.after.has(step.key)
|
|
48452
49366
|
}) });
|
|
48453
49367
|
if (step.kind === "tool") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ProcessFragment, {
|
|
48454
49368
|
open: processOpen,
|
|
@@ -48516,7 +49430,6 @@ ${trimmed}
|
|
|
48516
49430
|
buttonRef: processButton,
|
|
48517
49431
|
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupStatus, {
|
|
48518
49432
|
group,
|
|
48519
|
-
sessionId: props.sessionId,
|
|
48520
49433
|
useChat: props.useChat,
|
|
48521
49434
|
pending: interaction,
|
|
48522
49435
|
motion
|
|
@@ -48526,12 +49439,7 @@ ${trimmed}
|
|
|
48526
49439
|
open: expanded,
|
|
48527
49440
|
onChange: setExpanded,
|
|
48528
49441
|
controls: flowId,
|
|
48529
|
-
steps: steps.filter((step) =>
|
|
48530
|
-
if (step.kind === "user") return false;
|
|
48531
|
-
if (step.kind !== "body") return true;
|
|
48532
|
-
const node = nodes.get(step.nodeKey);
|
|
48533
|
-
return !!node && isNode(node, "assistant-step") && (isEarlierNarration(node.data, boundary) || node.data.blocks.some((block) => block.kind === "tool-call") || boundary.latestStep > 0 && node.data.step < boundary.latestStep);
|
|
48534
|
-
})
|
|
49442
|
+
steps: steps.filter((step) => step.kind !== "user" && step.kind !== "body")
|
|
48535
49443
|
})]
|
|
48536
49444
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChoreographedFlow, {
|
|
48537
49445
|
id: flowId,
|
|
@@ -48556,7 +49464,6 @@ ${trimmed}
|
|
|
48556
49464
|
"data-reader-status-only": true,
|
|
48557
49465
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupStatus, {
|
|
48558
49466
|
group,
|
|
48559
|
-
sessionId: props.sessionId,
|
|
48560
49467
|
useChat: props.useChat,
|
|
48561
49468
|
pending: interaction,
|
|
48562
49469
|
motion
|
|
@@ -48589,6 +49496,15 @@ ${trimmed}
|
|
|
48589
49496
|
const activatedAt = (0, react.useRef)(Date.now());
|
|
48590
49497
|
const order = props.useChat((snapshot) => snapshot.order);
|
|
48591
49498
|
const nodes = props.useChat((snapshot) => snapshot.nodes);
|
|
49499
|
+
const rewindSignature = props.useChat((snapshot) => visibleChatSignature(snapshot));
|
|
49500
|
+
const renderKeys = (0, react.useMemo)(() => visibleChatKeys({
|
|
49501
|
+
order,
|
|
49502
|
+
nodes
|
|
49503
|
+
}), [
|
|
49504
|
+
order,
|
|
49505
|
+
nodes,
|
|
49506
|
+
rewindSignature
|
|
49507
|
+
]);
|
|
48592
49508
|
const timeline = props.useChat((snapshot) => snapshot.timeline);
|
|
48593
49509
|
const running = props.useSession((snapshot) => snapshot.running);
|
|
48594
49510
|
const pending = props.useSessionStatus((snapshot) => snapshot.get(props.sessionId)?.pendingInteraction);
|
|
@@ -48624,7 +49540,7 @@ ${trimmed}
|
|
|
48624
49540
|
pendingList,
|
|
48625
49541
|
visibleSubmissions
|
|
48626
49542
|
]);
|
|
48627
|
-
const waitAnchor = waitingAnchor(
|
|
49543
|
+
const waitAnchor = waitingAnchor(renderKeys, (key) => nodes.get(key), pendingList);
|
|
48628
49544
|
const motion = useMotionAllowed(props.useStore((state) => state.motion));
|
|
48629
49545
|
const prefsSnap = (0, react.useSyncExternalStore)(props.openPrefs?.subscribe ?? ((fn) => {
|
|
48630
49546
|
return () => {};
|
|
@@ -48642,14 +49558,14 @@ ${trimmed}
|
|
|
48642
49558
|
enabled: motion,
|
|
48643
49559
|
activatedAt: activatedAt.current
|
|
48644
49560
|
}), [motion]);
|
|
48645
|
-
const groups = (0, react.useMemo)(() => groupNodes(
|
|
48646
|
-
|
|
49561
|
+
const groups = (0, react.useMemo)(() => groupNodes(renderKeys, (key) => nodes.get(key)), [
|
|
49562
|
+
renderKeys,
|
|
48647
49563
|
nodes,
|
|
48648
49564
|
timeline
|
|
48649
49565
|
]);
|
|
48650
49566
|
const isAwaitingModel = (0, react.useMemo)(() => {
|
|
48651
49567
|
if (!running && pendingList.length > 0) return true;
|
|
48652
|
-
const lastKey =
|
|
49568
|
+
const lastKey = renderKeys.at(-1);
|
|
48653
49569
|
const lastNode = lastKey ? nodes.get(lastKey) : void 0;
|
|
48654
49570
|
if (!lastKey || !lastNode) return false;
|
|
48655
49571
|
if (lastNode.kind === "assistant-step") {
|
|
@@ -48662,7 +49578,7 @@ ${trimmed}
|
|
|
48662
49578
|
}, [
|
|
48663
49579
|
running,
|
|
48664
49580
|
pendingList,
|
|
48665
|
-
|
|
49581
|
+
renderKeys,
|
|
48666
49582
|
nodes,
|
|
48667
49583
|
groups,
|
|
48668
49584
|
timeline
|
|
@@ -48752,7 +49668,7 @@ ${trimmed}
|
|
|
48752
49668
|
scroll.release,
|
|
48753
49669
|
timelineItems
|
|
48754
49670
|
]);
|
|
48755
|
-
const lastKey =
|
|
49671
|
+
const lastKey = renderKeys.at(-1);
|
|
48756
49672
|
const lastNode = lastKey ? nodes.get(lastKey) : void 0;
|
|
48757
49673
|
const lastSubmissionId = pendingList.length ? pendingList[pendingList.length - 1].requestId : null;
|
|
48758
49674
|
const lastOrderKeyRef = (0, react.useRef)(lastKey);
|
|
@@ -48771,7 +49687,7 @@ ${trimmed}
|
|
|
48771
49687
|
]);
|
|
48772
49688
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StreamMotionContext.Provider, {
|
|
48773
49689
|
value: streamMotion,
|
|
48774
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
49690
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReaderLaneScope, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48775
49691
|
ref: root,
|
|
48776
49692
|
className: Reader_module_css_default.root,
|
|
48777
49693
|
"data-reader-build": "0.3.4",
|
|
@@ -48789,6 +49705,7 @@ ${trimmed}
|
|
|
48789
49705
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48790
49706
|
className: Reader_module_css_default.column,
|
|
48791
49707
|
"data-chat-flow": "",
|
|
49708
|
+
tabIndex: -1,
|
|
48792
49709
|
children: [
|
|
48793
49710
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StickyLane, {
|
|
48794
49711
|
kind: "toolbar",
|
|
@@ -48833,20 +49750,23 @@ ${trimmed}
|
|
|
48833
49750
|
role: "status",
|
|
48834
49751
|
children: "正在读取会话…"
|
|
48835
49752
|
}),
|
|
48836
|
-
|
|
48837
|
-
|
|
48838
|
-
group,
|
|
48839
|
-
|
|
48840
|
-
|
|
48841
|
-
|
|
48842
|
-
|
|
48843
|
-
|
|
48844
|
-
|
|
49753
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RetiringTurns, {
|
|
49754
|
+
groups,
|
|
49755
|
+
render: (group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TurnGroup, {
|
|
49756
|
+
...props,
|
|
49757
|
+
group,
|
|
49758
|
+
motion,
|
|
49759
|
+
autoFold,
|
|
49760
|
+
pinnedKeys,
|
|
49761
|
+
selectedProcessKeys,
|
|
49762
|
+
isAwaitingModel: isAwaitingModel && group.key === groups.at(-1)?.key
|
|
49763
|
+
})
|
|
49764
|
+
}),
|
|
48845
49765
|
pendingInputs.map((item, index) => {
|
|
48846
49766
|
const submission = "requestId" in item ? item : void 0;
|
|
48847
49767
|
const text = submission?.text ?? inboxText(item);
|
|
48848
49768
|
const images = submission ? pendingSubmissionImages(submission) : [];
|
|
48849
|
-
const attachmentCount = images.length;
|
|
49769
|
+
const attachmentCount = submission ? images.length : inboxAttachmentCount(item);
|
|
48850
49770
|
const requestId = submission?.requestId ?? `inbox-${index}`;
|
|
48851
49771
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
48852
49772
|
className: Reader_module_css_default.userCluster,
|
|
@@ -48919,7 +49839,7 @@ ${trimmed}
|
|
|
48919
49839
|
})
|
|
48920
49840
|
]
|
|
48921
49841
|
})]
|
|
48922
|
-
})
|
|
49842
|
+
}) })
|
|
48923
49843
|
});
|
|
48924
49844
|
}
|
|
48925
49845
|
//#endregion
|
|
@@ -49421,6 +50341,10 @@ ${trimmed}
|
|
|
49421
50341
|
];
|
|
49422
50342
|
ensureStyles();
|
|
49423
50343
|
function apply(ctx) {
|
|
50344
|
+
const textTransform = createTextTransformRegistry();
|
|
50345
|
+
const restoreTextTransform = installTextTransformRegistry(textTransform);
|
|
50346
|
+
ctx.provide(TEXT_TRANSFORM_SERVICE, textTransform);
|
|
50347
|
+
ctx.effect(() => restoreTextTransform);
|
|
49424
50348
|
const store = createReaderStore();
|
|
49425
50349
|
const prefs = store.create();
|
|
49426
50350
|
installBetterDisplaySettings(ctx, prefs);
|
|
@@ -49575,9 +50499,12 @@ ${trimmed}
|
|
|
49575
50499
|
}
|
|
49576
50500
|
//#endregion
|
|
49577
50501
|
exports.McpAppFrame = McpAppFrame;
|
|
50502
|
+
exports.TEXT_TRANSFORM_SERVICE = TEXT_TRANSFORM_SERVICE;
|
|
49578
50503
|
exports.apply = apply;
|
|
50504
|
+
exports.createTextTransformRegistry = createTextTransformRegistry;
|
|
49579
50505
|
exports.inject = inject;
|
|
49580
50506
|
exports.name = name;
|
|
50507
|
+
exports.originalAnswerText = originalAnswerText;
|
|
49581
50508
|
return module.exports;
|
|
49582
50509
|
}
|
|
49583
50510
|
});
|