@prettier-ai/dsh-client-ui-chat 0.1.2-alpha.2 → 0.1.2-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +13 -2
- package/README.zh.md +13 -2
- package/lib/client.js +848 -355
- package/lib/types/client/chat/ChatNodeSeat.d.ts +3 -2
- package/lib/types/client/chat/ChatView.d.ts +1 -1
- package/lib/types/client/chat/MessageItem.d.ts +5 -5
- package/lib/types/client/chat/TurnNavigator.d.ts +11 -6
- package/lib/types/client/chat/turn-rail-items.d.ts +37 -0
- package/lib/types/client/chat/use-turn-data.d.ts +9 -0
- package/lib/types/client/contract/slots.d.ts +18 -5
- package/lib/types/client/contract/snapshot.d.ts +27 -0
- package/lib/types/client/contract/store.d.ts +1 -2
- package/lib/types/client/contract/turn-process.d.ts +5 -20
- package/lib/types/client/conversation-nodes/inbox.d.ts +18 -9
- package/lib/types/client/conversation-nodes/turn-process-presentation.d.ts +30 -0
- package/lib/types/client/conversation-nodes/turn-process.d.ts +5 -3
- package/lib/types/client/index.d.ts +2 -2
- package/lib/types/client/locale.d.ts +2 -0
- package/lib/types/client/stores.d.ts +2 -3
- package/package.json +28 -33
- package/lib/invariant.js +0 -16
- package/lib/types/client/chat/use-throttled-visual-update.d.ts +0 -8
- package/lib/types/invariant.d.ts +0 -13
package/lib/client.js
CHANGED
|
@@ -32,11 +32,25 @@ window.__ModuleLoader__.load({
|
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region lib/types/client/contract/snapshot.js
|
|
34
34
|
const EMPTY_LIST$1 = [];
|
|
35
|
+
const EMPTY_TIMELINE = {
|
|
36
|
+
turnOrder: EMPTY_LIST$1,
|
|
37
|
+
turns: /* @__PURE__ */ new Map()
|
|
38
|
+
};
|
|
39
|
+
const EMPTY_NODE_SOURCE = {
|
|
40
|
+
getSnapshot: () => void 0,
|
|
41
|
+
subscribe: () => () => {}
|
|
42
|
+
};
|
|
43
|
+
const EMPTY_NODE_PROCESS_SOURCE = {
|
|
44
|
+
getSnapshot: () => void 0,
|
|
45
|
+
subscribe: () => () => {}
|
|
46
|
+
};
|
|
35
47
|
/** Empty Chat target used before a view builder is registered. */
|
|
36
48
|
const EMPTY_CHAT_SNAPSHOT = {
|
|
37
49
|
order: EMPTY_LIST$1,
|
|
38
50
|
nodes: {
|
|
39
51
|
get: () => void 0,
|
|
52
|
+
source: () => EMPTY_NODE_SOURCE,
|
|
53
|
+
processSource: () => EMPTY_NODE_PROCESS_SOURCE,
|
|
40
54
|
values: () => EMPTY_LIST$1
|
|
41
55
|
},
|
|
42
56
|
locations: {
|
|
@@ -44,10 +58,7 @@ window.__ModuleLoader__.load({
|
|
|
44
58
|
getStep: () => EMPTY_LIST$1
|
|
45
59
|
},
|
|
46
60
|
navigation: { items: () => EMPTY_LIST$1 },
|
|
47
|
-
timeline:
|
|
48
|
-
turnOrder: EMPTY_LIST$1,
|
|
49
|
-
turns: /* @__PURE__ */ new Map()
|
|
50
|
-
},
|
|
61
|
+
timeline: EMPTY_TIMELINE,
|
|
51
62
|
legacy: {
|
|
52
63
|
nodes: EMPTY_LIST$1,
|
|
53
64
|
turnTimings: /* @__PURE__ */ new Map(),
|
|
@@ -206,7 +217,7 @@ window.__ModuleLoader__.load({
|
|
|
206
217
|
});
|
|
207
218
|
//#endregion
|
|
208
219
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ContextBody.module.css.mjs
|
|
209
|
-
const css$14 = ".abgUBa_text{color:var(--dsw-alias-label-secondary);font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_fields{border-top
|
|
220
|
+
const css$14 = ".abgUBa_text{color:var(--dsw-alias-label-secondary);font:inherit;white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_fields{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:2px;margin:8px 0 0;padding-top:8px;display:flex}.abgUBa_field{gap:8px;min-width:0;display:flex}.abgUBa_fieldKey{min-width:96px;color:var(--dsw-alias-label-caption);flex:none}.abgUBa_fieldValue{min-width:0;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;flex:auto;margin:0}.abgUBa_files{flex-wrap:wrap;gap:4px 12px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_file{align-items:baseline;gap:6px;min-width:0;display:flex}.abgUBa_filePath{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_fileAction{color:var(--dsw-alias-label-caption)}.abgUBa_catalogNotice{color:var(--dsw-alias-label-caption);margin:0 0 6px}.abgUBa_entries{flex-direction:column;gap:4px;margin:0;padding:0;list-style:none;display:flex}.abgUBa_entry{gap:8px;min-width:0;display:flex}.abgUBa_entryName{color:var(--dsw-alias-label-secondary);flex:none}.abgUBa_entryDescription{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.abgUBa_sections{flex-direction:column;gap:8px;margin:0;display:flex}.abgUBa_section{flex-direction:column;gap:2px;min-width:0;display:flex}.abgUBa_sectionName{color:var(--dsw-alias-label-caption)}.abgUBa_sectionText{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0}.abgUBa_relaySender{color:var(--dsw-alias-label-caption);overflow-wrap:anywhere;margin:0 0 6px}.abgUBa_recalls{flex-direction:column;gap:2px;margin:0 0 8px;padding:0;list-style:none;display:flex}.abgUBa_recall{gap:8px;min-width:0;display:flex}.abgUBa_recallLabel{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere}.abgUBa_recallCounts{color:var(--dsw-alias-label-caption);flex:none}";
|
|
210
221
|
const tagId$14 = "@prettier-ai/dsh-client-ui-chat/ContextBody.module.css";
|
|
211
222
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$14) + "]") === null) {
|
|
212
223
|
const tag = document.createElement("style");
|
|
@@ -947,7 +958,7 @@ window.__ModuleLoader__.load({
|
|
|
947
958
|
}
|
|
948
959
|
//#endregion
|
|
949
960
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/MessageIconActions.module.css.mjs
|
|
950
|
-
const css$12 = ".BmHDMW_actions{height:calc(28px + var(--dsh-content-font-delta,0px));align-items:center;gap:8px;display:flex}.BmHDMW_timeStart{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-right:12px}.BmHDMW_timeEnd{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap}@media (hover:hover){[data-actions-reveal=hover] .BmHDMW_actions{opacity:0;transition:opacity 80ms}[data-actions-reveal=hover]:hover .BmHDMW_actions,[data-actions-reveal=hover]:focus-within .BmHDMW_actions{opacity:1}}.BmHDMW_action{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.BmHDMW_action svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px))}.BmHDMW_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.BmHDMW_action[data-unavailable]{cursor:default;opacity:.4}.BmHDMW_action[data-unavailable]:hover{color:var(--dsw-alias-label-tertiary);background:0 0}.BmHDMW_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
|
|
961
|
+
const css$12 = ".BmHDMW_actions{height:calc(28px + var(--dsh-content-font-delta,0px));align-items:center;gap:8px;display:flex}.BmHDMW_timeStart{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap;padding-right:12px}.BmHDMW_timeEnd{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);white-space:nowrap}@media (hover:hover){[data-actions-reveal=hover] .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])) .BmHDMW_actions{opacity:0;transition:opacity 80ms}[data-actions-reveal=hover]:hover .BmHDMW_actions,[data-actions-reveal=hover]:focus-within .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])):hover .BmHDMW_actions,:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering]):has(~:is([data-chat-flow-kind=user],[data-chat-flow-kind=steering])):focus-within .BmHDMW_actions{opacity:1}}.BmHDMW_action{width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:6px;display:inline-flex}.BmHDMW_action svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px))}.BmHDMW_action:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.BmHDMW_action[data-unavailable]{cursor:default;opacity:.4}.BmHDMW_action[data-unavailable]:hover{color:var(--dsw-alias-label-tertiary);background:0 0}.BmHDMW_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
|
|
951
962
|
const tagId$12 = "@prettier-ai/dsh-client-ui-chat/MessageIconActions.module.css";
|
|
952
963
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$12) + "]") === null) {
|
|
953
964
|
const tag = document.createElement("style");
|
|
@@ -1169,7 +1180,7 @@ window.__ModuleLoader__.load({
|
|
|
1169
1180
|
});
|
|
1170
1181
|
}
|
|
1171
1182
|
/** Right-aligned bubble shared by user and steering rows. */
|
|
1172
|
-
function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], previewImages,
|
|
1183
|
+
function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], previewImages, t }) {
|
|
1173
1184
|
const { text, images: contentImages, rest } = contentParts(content);
|
|
1174
1185
|
const images = previewImages ?? contentImages;
|
|
1175
1186
|
const truncated = (total) => t("json.truncated", { total });
|
|
@@ -1178,7 +1189,6 @@ window.__ModuleLoader__.load({
|
|
|
1178
1189
|
className: MessageItem_module_css_default.userRow,
|
|
1179
1190
|
"data-pending-steering": pending || void 0,
|
|
1180
1191
|
"data-submission-echo": echo || void 0,
|
|
1181
|
-
"data-actions-reveal": reveal,
|
|
1182
1192
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
1183
1193
|
className: MessageItem_module_css_default.userStack,
|
|
1184
1194
|
children: [
|
|
@@ -1223,10 +1233,10 @@ window.__ModuleLoader__.load({
|
|
|
1223
1233
|
});
|
|
1224
1234
|
}
|
|
1225
1235
|
/**
|
|
1226
|
-
* Render one local submission echo with the
|
|
1227
|
-
*
|
|
1228
|
-
*
|
|
1229
|
-
*
|
|
1236
|
+
* Render one local transcript or steering submission echo with the same
|
|
1237
|
+
* visual language and surface marker as the Host occurrence that replaces
|
|
1238
|
+
* it: draft text plus object-URL previews, visible from the submit click
|
|
1239
|
+
* until the durable `user/message` or steering occurrence renders.
|
|
1230
1240
|
* @param props - the session snapshot's pending submission and render seats.
|
|
1231
1241
|
* @returns the echoed user bubble.
|
|
1232
1242
|
*/
|
|
@@ -1243,6 +1253,7 @@ window.__ModuleLoader__.load({
|
|
|
1243
1253
|
...image.height === void 0 ? {} : { height: image.height }
|
|
1244
1254
|
} })), [submission.images]),
|
|
1245
1255
|
renderMessageImages,
|
|
1256
|
+
pending: submission.placement === "steering",
|
|
1246
1257
|
echo: true,
|
|
1247
1258
|
t,
|
|
1248
1259
|
actions: (text) => (0, react_jsx_runtime.jsx)(MessageIconActions, {
|
|
@@ -1255,20 +1266,12 @@ window.__ModuleLoader__.load({
|
|
|
1255
1266
|
});
|
|
1256
1267
|
}
|
|
1257
1268
|
/** User and admitted-steering keyed Chat renderer. */
|
|
1258
|
-
const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages,
|
|
1269
|
+
const UserMessageNodeView = (0, react.memo)(function UserMessageNodeView({ node, renderMessageImages, t }) {
|
|
1259
1270
|
const data = node.data;
|
|
1260
|
-
const isLatestUserRow = useChat((snapshot) => {
|
|
1261
|
-
for (let index = snapshot.order.length - 1; index >= 0; index -= 1) {
|
|
1262
|
-
const candidate = snapshot.nodes.get(snapshot.order[index] ?? "");
|
|
1263
|
-
if (candidate?.kind === "user" || candidate?.kind === "steering") return candidate.key === node.key;
|
|
1264
|
-
}
|
|
1265
|
-
return true;
|
|
1266
|
-
});
|
|
1267
1271
|
return (0, react_jsx_runtime.jsx)(UserStyleBubble, {
|
|
1268
1272
|
content: data.content,
|
|
1269
1273
|
renderMessageImages,
|
|
1270
1274
|
...data.referenceLabels === void 0 ? {} : { referenceLabels: data.referenceLabels },
|
|
1271
|
-
reveal: isLatestUserRow ? "always" : "hover",
|
|
1272
1275
|
t,
|
|
1273
1276
|
actions: (text) => (0, react_jsx_runtime.jsx)(MessageIconActions, {
|
|
1274
1277
|
text,
|
|
@@ -1340,49 +1343,13 @@ window.__ModuleLoader__.load({
|
|
|
1340
1343
|
"turn-tail"
|
|
1341
1344
|
]);
|
|
1342
1345
|
/**
|
|
1343
|
-
*
|
|
1344
|
-
* @param
|
|
1345
|
-
* @
|
|
1346
|
-
|
|
1347
|
-
function turnProcessGeneration(spec) {
|
|
1348
|
-
return `${String(spec.turn)}|${spec.answerStep === null ? "" : String(spec.answerStep)}`;
|
|
1349
|
-
}
|
|
1350
|
-
/**
|
|
1351
|
-
* Encode one process specification as a primitive Location-data value.
|
|
1352
|
-
* @param spec - current Turn process specification.
|
|
1353
|
-
* @returns reference-stable scalar for equal specifications.
|
|
1346
|
+
* Compare immutable Turn-process specifications by their published fields.
|
|
1347
|
+
* @param left - previous specification.
|
|
1348
|
+
* @param right - next specification.
|
|
1349
|
+
* @returns whether both values describe the same process presentation.
|
|
1354
1350
|
*/
|
|
1355
|
-
function
|
|
1356
|
-
return
|
|
1357
|
-
spec.turn,
|
|
1358
|
-
spec.controlAnchorSeq,
|
|
1359
|
-
spec.processStartSeq,
|
|
1360
|
-
spec.answerAnchorSeq ?? "",
|
|
1361
|
-
spec.answerStep ?? "",
|
|
1362
|
-
spec.inlineReasoning ? 1 : 0,
|
|
1363
|
-
spec.messageCount,
|
|
1364
|
-
spec.toolCallCount,
|
|
1365
|
-
spec.subagentCount
|
|
1366
|
-
].join("|");
|
|
1367
|
-
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Decode a same-process signature produced by {@link encodeTurnProcess}.
|
|
1370
|
-
* @param signature - encoded Turn process value.
|
|
1371
|
-
* @returns decoded process specification.
|
|
1372
|
-
*/
|
|
1373
|
-
function decodeTurnProcess(signature) {
|
|
1374
|
-
const [turn, controlAnchorSeq, processStartSeq, answerAnchorSeq, answerStep, inlineReasoning, messageCount, toolCallCount, subagentCount] = signature.split("|");
|
|
1375
|
-
return {
|
|
1376
|
-
turn: Number(turn),
|
|
1377
|
-
controlAnchorSeq: Number(controlAnchorSeq),
|
|
1378
|
-
processStartSeq: Number(processStartSeq),
|
|
1379
|
-
answerAnchorSeq: answerAnchorSeq === "" ? null : Number(answerAnchorSeq),
|
|
1380
|
-
answerStep: answerStep === "" ? null : Number(answerStep),
|
|
1381
|
-
inlineReasoning: inlineReasoning === "1",
|
|
1382
|
-
messageCount: Number(messageCount),
|
|
1383
|
-
toolCallCount: Number(toolCallCount),
|
|
1384
|
-
subagentCount: Number(subagentCount)
|
|
1385
|
-
};
|
|
1351
|
+
function sameTurnProcessSpec(left, right) {
|
|
1352
|
+
return left.turn === right.turn && left.controlAnchorSeq === right.controlAnchorSeq && left.processStartSeq === right.processStartSeq && left.answerAnchorSeq === right.answerAnchorSeq && left.answerStep === right.answerStep && left.inlineReasoning === right.inlineReasoning && left.messageCount === right.messageCount && left.toolCallCount === right.toolCallCount && left.subagentCount === right.subagentCount;
|
|
1386
1353
|
}
|
|
1387
1354
|
/**
|
|
1388
1355
|
* Recognize the shipped subagent delegation name and its configured variants.
|
|
@@ -1397,7 +1364,7 @@ window.__ModuleLoader__.load({
|
|
|
1397
1364
|
//#region lib/types/client/stores.js
|
|
1398
1365
|
/** Per-Session Chat selection store shared by the transcript and details panel. */
|
|
1399
1366
|
/**
|
|
1400
|
-
* Resolve
|
|
1367
|
+
* Resolve the manually expanded answer for one Turn.
|
|
1401
1368
|
* @param state - Chat store snapshot.
|
|
1402
1369
|
* @param turn - owning Turn.
|
|
1403
1370
|
* @returns the Turn's stored entry, when present.
|
|
@@ -1419,7 +1386,7 @@ window.__ModuleLoader__.load({
|
|
|
1419
1386
|
select: (draft, target) => {
|
|
1420
1387
|
draft.selection = target;
|
|
1421
1388
|
},
|
|
1422
|
-
setTurnProcessOpen: (draft, turn,
|
|
1389
|
+
setTurnProcessOpen: (draft, turn, answerStep, open) => {
|
|
1423
1390
|
const index = draft.turnProcesses.findIndex((entry) => entry.turn === turn);
|
|
1424
1391
|
if (!open) {
|
|
1425
1392
|
if (index >= 0) draft.turnProcesses.splice(index, 1);
|
|
@@ -1427,7 +1394,7 @@ window.__ModuleLoader__.load({
|
|
|
1427
1394
|
}
|
|
1428
1395
|
const next = {
|
|
1429
1396
|
turn,
|
|
1430
|
-
|
|
1397
|
+
answerStep
|
|
1431
1398
|
};
|
|
1432
1399
|
if (index < 0) draft.turnProcesses.push(next);
|
|
1433
1400
|
else draft.turnProcesses[index] = next;
|
|
@@ -1467,7 +1434,7 @@ window.__ModuleLoader__.load({
|
|
|
1467
1434
|
}
|
|
1468
1435
|
//#endregion
|
|
1469
1436
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ChatView.module.css.mjs
|
|
1470
|
-
const css$11 = ".fnEpAq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.fnEpAq_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}[data-conversation-scroll] .fnEpAq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .fnEpAq_scroll{flex:none;min-height:auto;overflow:visible}.fnEpAq_column{max-width:var(--dsh-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}.fnEpAq_column>:not([hidden]):not(.fnEpAq_flowItem:empty)~:not([hidden]):not(.fnEpAq_flowItem:empty){margin-top:var(--dsh-chat-flow-gap,16px)}.fnEpAq_flowItem{min-width:0}.fnEpAq_flowItem[data-turn-process-answer]{--dsh-chat-flow-gap:8px}.fnEpAq_flowItem:empty{display:none}.fnEpAq_callRow{border-radius:6px}.fnEpAq_turnStatus{height:calc(26px + var(--dsh-content-font-delta,0px));font:var(--dsw-font-s-strong-14);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite fnEpAq_dsh-turn-status-shimmer;display:inline-flex}.fnEpAq_turnStatusClock{font:var(--dsw-font-xs-13);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes fnEpAq_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.fnEpAq_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.fnEpAq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_openError{color:var(--dsw-alias-state-error-primary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_older{justify-content:center;display:flex}.fnEpAq_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.fnEpAq_older button:disabled{cursor:default;opacity:.6}.fnEpAq_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .fnEpAq_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.fnEpAq_toBottom{
|
|
1437
|
+
const css$11 = ".fnEpAq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative}.fnEpAq_scroll{min-height:0;padding:16px calc(var(--dsh-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}[data-conversation-scroll] .fnEpAq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .fnEpAq_scroll{flex:none;min-height:auto;overflow:visible}.fnEpAq_column{max-width:var(--dsh-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}.fnEpAq_column>:not([hidden]):not(.fnEpAq_flowItem:empty)~:not([hidden]):not(.fnEpAq_flowItem:empty){margin-top:var(--dsh-chat-flow-gap,16px)}.fnEpAq_flowItem{min-width:0}.fnEpAq_flowItem[data-turn-process-answer]{--dsh-chat-flow-gap:8px}.fnEpAq_flowItem:empty{display:none}.fnEpAq_callRow{border-radius:6px}.fnEpAq_turnStatus{height:calc(26px + var(--dsh-content-font-delta,0px));font:var(--dsw-font-s-strong-14);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:nowrap;background:linear-gradient(90deg, var(--dsw-static-deepseek-500) 0%, var(--dsw-static-deepseek-500) 40%, var(--dsw-static-deepseek-200) 50%, var(--dsw-static-deepseek-500) 60%, var(--dsw-static-deepseek-500) 100%);color:#0000;-webkit-text-fill-color:transparent;background-position:100% 0;background-size:250% 100%;-webkit-background-clip:text;background-clip:text;flex:none;align-self:flex-start;align-items:center;animation:1.8s linear infinite fnEpAq_dsh-turn-status-shimmer;display:inline-flex}.fnEpAq_turnStatusClock{font:var(--dsw-font-xs-13);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption);-webkit-text-fill-color:var(--dsw-alias-label-caption);margin-left:8px;font-weight:400}@keyframes fnEpAq_dsh-turn-status-shimmer{to{background-position:0 0}}@media (prefers-reduced-motion:reduce){.fnEpAq_turnStatus{background-position:0 0;background-size:100% 100%;animation:none}}.fnEpAq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_openError{color:var(--dsw-alias-state-error-primary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.fnEpAq_older{justify-content:center;display:flex}.fnEpAq_older button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover-solid);cursor:pointer;border:none;border-radius:14px;padding:4px 12px;font-size:12px}.fnEpAq_older button:disabled{cursor:default;opacity:.6}.fnEpAq_toBottomSlot{z-index:8;height:0;padding-right:max(0px, calc((100% - var(--dsh-chat-content-width)) / 2));pointer-events:none;justify-content:flex-end;display:flex;position:sticky;bottom:16px}[data-conversation-scroll] .fnEpAq_toBottomSlot{bottom:calc(var(--dsh-composer-height,152px) + 16px)}.fnEpAq_toBottom{--dsw-elevation-stroke-color:var(--dsw-alias-border-l3);corner-shape:round;width:34px;height:34px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-button-floating-fill);box-shadow:var(--dsw-elevation-panel);cursor:pointer;pointer-events:auto;border:0;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.fnEpAq_toBottom:hover{background:var(--dsw-alias-button-floating-hover)}.fnEpAq_modalAction{min-width:72px}";
|
|
1471
1438
|
const tagId$11 = "@prettier-ai/dsh-client-ui-chat/ChatView.module.css";
|
|
1472
1439
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$11) + "]") === null) {
|
|
1473
1440
|
const tag = document.createElement("style");
|
|
@@ -1494,85 +1461,44 @@ window.__ModuleLoader__.load({
|
|
|
1494
1461
|
};
|
|
1495
1462
|
//#endregion
|
|
1496
1463
|
//#region lib/types/client/chat/ChatNodeSeat.js
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
for (const key of keys) {
|
|
1501
|
-
const node = nodes.get(key);
|
|
1502
|
-
if ((node?.kind === "user" || node?.kind === "steering") && node.anchorSeq < spec.controlAnchorSeq) anchor = Math.min(anchor ?? node.anchorSeq, node.anchorSeq);
|
|
1503
|
-
}
|
|
1504
|
-
return anchor;
|
|
1464
|
+
function turnDataOf(node) {
|
|
1465
|
+
const location = node?.location;
|
|
1466
|
+
return location?.kind === "turn" || location?.kind === "step" ? location.turn.data : void 0;
|
|
1505
1467
|
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
let compactAnswer = true;
|
|
1510
|
-
const openingHumanAnchor = turnProcessOpeningHumanAnchor(keys, nodes, spec);
|
|
1511
|
-
for (const key of keys) {
|
|
1512
|
-
const node = nodes.get(key);
|
|
1513
|
-
if (node === void 0 || node.kind === "turn-process") continue;
|
|
1514
|
-
if ((node.kind === "user" || node.kind === "steering") && (openingHumanAnchor === void 0 || node.anchorSeq > openingHumanAnchor) && (spec.answerAnchorSeq === null || node.anchorSeq < spec.answerAnchorSeq)) compactAnswer = false;
|
|
1515
|
-
if (TURN_PROCESS_INDEPENDENT_KINDS.has(node.kind) || node.anchorSeq < spec.processStartSeq || spec.answerAnchorSeq !== null && node.anchorSeq >= spec.answerAnchorSeq) continue;
|
|
1516
|
-
if (node.kind !== "assistant-step" || spec.answerStep === null || node.data.step !== spec.answerStep) hasExternalProcess = true;
|
|
1517
|
-
}
|
|
1518
|
-
return {
|
|
1519
|
-
hasExternalProcess,
|
|
1520
|
-
compactAnswer
|
|
1521
|
-
};
|
|
1468
|
+
function turnOf(node) {
|
|
1469
|
+
const location = node?.location;
|
|
1470
|
+
return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
|
|
1522
1471
|
}
|
|
1523
1472
|
/** Subscribe, apply Turn-process visibility, and dispatch one stable Context key. */
|
|
1524
|
-
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, renderMessageImages, fileMentions,
|
|
1525
|
-
const node =
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
const processSpec = (0, react.useMemo)(() => processSignature === void 0 ? void 0 : decodeTurnProcess(processSignature), [processSignature]);
|
|
1531
|
-
const nodeStore = useChat((snapshot) => snapshot.nodes);
|
|
1532
|
-
const processLayoutKeys = useChat((snapshot) => {
|
|
1533
|
-
if (!compactTranscript || historyIncomplete || processSpec === void 0) return EMPTY_PROCESS_KEYS;
|
|
1534
|
-
const current = snapshot.nodes.get(nodeKey);
|
|
1535
|
-
const location = current?.location;
|
|
1536
|
-
if (current === void 0 || location?.kind !== "turn" && location?.kind !== "step" || location.turn.status !== "closed" || location.turn.turn !== processSpec.turn) return EMPTY_PROCESS_KEYS;
|
|
1537
|
-
return current.kind === "turn-process" || current.kind === "assistant-step" && current.data.step === processSpec.answerStep ? snapshot.locations.getTurn(processSpec.turn) : EMPTY_PROCESS_KEYS;
|
|
1538
|
-
});
|
|
1539
|
-
const processLayout = (0, react.useMemo)(() => processSpec === void 0 || processLayoutKeys.length === 0 ? void 0 : turnProcessLayout(processLayoutKeys, nodeStore, processSpec), [
|
|
1540
|
-
nodeStore,
|
|
1541
|
-
processLayoutKeys,
|
|
1542
|
-
processSpec
|
|
1543
|
-
]);
|
|
1544
|
-
const processGeneration = (0, react.useMemo)(() => processSpec === void 0 ? void 0 : turnProcessGeneration(processSpec), [processSpec]);
|
|
1473
|
+
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
|
|
1474
|
+
const node = useChatNode(nodeKey);
|
|
1475
|
+
const routedNode = node;
|
|
1476
|
+
const turn = turnOf(routedNode);
|
|
1477
|
+
const processPresentation = useChatNodeProcess(nodeKey);
|
|
1478
|
+
const processSpec = processPresentation?.spec;
|
|
1545
1479
|
const storedEntry = useStore((state) => processSpec === void 0 ? void 0 : storedTurnProcessEntry(state, processSpec.turn));
|
|
1546
|
-
const processOpen = (storedEntry?.
|
|
1480
|
+
const processOpen = (processSpec !== void 0 && processSpec.answerStep !== null && storedEntry?.answerStep === processSpec.answerStep ? storedEntry : void 0) !== void 0;
|
|
1547
1481
|
const setOpen = (0, react.useCallback)((open) => {
|
|
1548
|
-
if (
|
|
1549
|
-
}, [
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
]);
|
|
1554
|
-
const routedNode = node;
|
|
1555
|
-
const sameTurn = routedNode !== void 0 && processSpec !== void 0 && (routedNode.location.kind === "turn" || routedNode.location.kind === "step") && routedNode.location.turn.turn === processSpec.turn;
|
|
1556
|
-
const turnClosed = sameTurn && routedNode.location.turn.status === "closed";
|
|
1557
|
-
const processWindowReady = processSpec !== void 0 && compactTranscript && processSpec.answerAnchorSeq !== null && turnClosed && !historyIncomplete;
|
|
1558
|
-
const processMember = sameTurn && processWindowReady && !TURN_PROCESS_INDEPENDENT_KINDS.has(routedNode.kind) && routedNode.anchorSeq >= processSpec.processStartSeq && routedNode.anchorSeq < processSpec.answerAnchorSeq;
|
|
1559
|
-
const processAnswer = sameTurn && processWindowReady && routedNode.kind === "assistant-step" && routedNode.data.step === processSpec.answerStep;
|
|
1482
|
+
if (processSpec !== void 0 && processSpec.answerStep !== null) actions.setTurnProcessOpen(processSpec.turn, processSpec.answerStep, open);
|
|
1483
|
+
}, [actions, processSpec]);
|
|
1484
|
+
const processWindowReady = processSpec !== void 0 && processPresentation !== void 0 && compactTranscript && processSpec.answerAnchorSeq !== null && processPresentation.turn === processSpec.turn && processPresentation.turnClosed && !historyIncomplete;
|
|
1485
|
+
const processMember = routedNode !== void 0 && processWindowReady && !TURN_PROCESS_INDEPENDENT_KINDS.has(routedNode.kind) && routedNode.anchorSeq >= processSpec.processStartSeq && routedNode.anchorSeq < processSpec.answerAnchorSeq;
|
|
1486
|
+
const processAnswer = routedNode !== void 0 && processWindowReady && routedNode.kind === "assistant-step" && routedNode.data.step === processSpec.answerStep;
|
|
1560
1487
|
const ownsDisclosure = routedNode?.kind === "turn-process" || processAnswer;
|
|
1561
|
-
const foldable = processWindowReady && (processMember || ownsDisclosure && (
|
|
1562
|
-
const turnProcess = (0, react.useMemo)(() =>
|
|
1488
|
+
const foldable = processWindowReady && (processMember || ownsDisclosure && (processPresentation.hasExternalProcess || processSpec.inlineReasoning));
|
|
1489
|
+
const turnProcess = (0, react.useMemo)(() => processSpec === void 0 ? void 0 : {
|
|
1563
1490
|
spec: processSpec,
|
|
1564
1491
|
foldable,
|
|
1565
1492
|
open: processOpen,
|
|
1566
1493
|
setOpen
|
|
1567
1494
|
}, [
|
|
1568
1495
|
foldable,
|
|
1569
|
-
processGeneration,
|
|
1570
1496
|
processOpen,
|
|
1571
1497
|
processSpec,
|
|
1572
1498
|
setOpen
|
|
1573
1499
|
]);
|
|
1574
1500
|
const controllerInactive = routedNode?.kind === "turn-process" && !foldable;
|
|
1575
|
-
const compactAnswer = processAnswer && foldable &&
|
|
1501
|
+
const compactAnswer = processAnswer && foldable && processPresentation.compactAnswer && !processOpen;
|
|
1576
1502
|
const processHidden = controllerInactive || foldable && processMember && !processOpen;
|
|
1577
1503
|
const wrapperRef = useSearchableHidden(processHidden, (0, react.useCallback)(() => {
|
|
1578
1504
|
if (processMember) setOpen(true);
|
|
@@ -1598,8 +1524,7 @@ window.__ModuleLoader__.load({
|
|
|
1598
1524
|
turnProcess
|
|
1599
1525
|
]);
|
|
1600
1526
|
if (routedNode === void 0 || owner === null) return null;
|
|
1601
|
-
const
|
|
1602
|
-
const turn = location.kind === "turn" || location.kind === "step" ? location.turn.turn : void 0;
|
|
1527
|
+
const turnData = turnDataOf(routedNode);
|
|
1603
1528
|
const routedOwner = {
|
|
1604
1529
|
...owner,
|
|
1605
1530
|
node: routedNode
|
|
@@ -1616,7 +1541,7 @@ window.__ModuleLoader__.load({
|
|
|
1616
1541
|
"data-turn-process-answer": compactAnswer || void 0,
|
|
1617
1542
|
children: renderSlot("conversation.chat.node", routedOwner, {
|
|
1618
1543
|
entryKey: routedNode.kind,
|
|
1619
|
-
hookContext:
|
|
1544
|
+
hookContext: turnData,
|
|
1620
1545
|
fallback: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.JsonBlock, {
|
|
1621
1546
|
label: t("message.unknownSurface", { type: routedNode.kind }),
|
|
1622
1547
|
payload: routedNode.data,
|
|
@@ -1627,7 +1552,7 @@ window.__ModuleLoader__.load({
|
|
|
1627
1552
|
});
|
|
1628
1553
|
//#endregion
|
|
1629
1554
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnNavigator.module.css.mjs
|
|
1630
|
-
const css$10 = ".alqd3G_slot{z-index:
|
|
1555
|
+
const css$10 = ".alqd3G_slot{z-index:7;pointer-events:none;height:0;position:sticky;top:0}.alqd3G_frame{--turn-rail-band:calc(var(--dsh-conversation-viewport-height,100dvh) - var(--dsh-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);right:calc(12px - (var(--dsh-composer-side-clearance) + 16px));width:28px;height:min(var(--turn-natural-height), max(0px, calc(var(--turn-rail-band) - 64px)), 420px);cursor:pointer;pointer-events:auto;transition:height .22s cubic-bezier(.2,.8,.2,1);position:absolute;transform:translateY(-50%)}.alqd3G_scroller{overscroll-behavior:contain;scrollbar-width:none;position:absolute;inset:0;overflow-y:auto}.alqd3G_scroller::-webkit-scrollbar{display:none}.alqd3G_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.alqd3G_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.alqd3G_fadeTop.alqd3G_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.alqd3G_marks{height:var(--turn-natural-height);position:relative}.alqd3G_markPosition{top:calc(var(--turn-natural-position) + var(--turn-rail-inset));height:10px;transition:top .22s cubic-bezier(.2,.8,.2,1);animation:.15s ease-out alqd3G_dsh-turn-mark-enter;position:absolute;left:0;right:0;transform:translateY(-50%)}.alqd3G_mark{cursor:pointer;pointer-events:none;background:0 0;border:0;border-radius:8px;width:20px;padding:0;position:absolute;inset:0 0 0 auto}.alqd3G_mark:before{background:var(--dsw-alias-border-l4);content:\"\";border-radius:2px;width:12px;height:2px;transition:width .14s,background-color .14s;position:absolute;top:50%;right:0;transform:translateY(-50%)}.alqd3G_markUnloaded:before{opacity:.6;width:8px}.alqd3G_markPreview:before{background:var(--dsw-alias-label-tertiary);width:18px}.alqd3G_markBusy:before{animation:1s ease-in-out infinite alqd3G_dsh-turn-mark-busy}.alqd3G_markActive:before{background:var(--dsw-alias-label-primary);width:20px}.alqd3G_mark:focus-visible:before{background:var(--dsw-alias-state-business-primary);width:20px}.alqd3G_mark:focus-visible{outline:1px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.alqd3G_preview{top:clamp(0px, calc(var(--turn-natural-position) + var(--turn-rail-inset) - var(--turn-scroll-top,0px) - var(--turn-preview-height) / 2), calc(100% - var(--turn-preview-height)));box-sizing:border-box;width:min(300px,100cqw - 120px);max-height:var(--turn-preview-height);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-panel);pointer-events:none;border:0;border-radius:10px;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out alqd3G_dsh-turn-preview-enter;position:absolute;right:calc(100% + 10px);overflow:hidden}.alqd3G_previewPrompt,.alqd3G_previewResponse{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.alqd3G_previewPrompt{font:var(--dsw-font-xs-strong-13);-webkit-line-clamp:1}.alqd3G_previewResponse{color:var(--dsw-alias-label-caption);font:var(--dsw-font-xxs-12);-webkit-line-clamp:3;margin-top:4px}@keyframes alqd3G_dsh-turn-mark-enter{0%{opacity:0}to{opacity:1}}@keyframes alqd3G_dsh-turn-preview-enter{0%{opacity:0;transform:translate(4px)}to{opacity:1;transform:translate(0)}}@keyframes alqd3G_dsh-turn-mark-busy{0%,to{opacity:1}50%{opacity:.35}}@container (width<=900px){.alqd3G_slot{display:none}}@media (prefers-reduced-motion:reduce){.alqd3G_frame,.alqd3G_scroller,.alqd3G_markPosition,.alqd3G_mark:before,.alqd3G_markBusy:before,.alqd3G_preview{scroll-behavior:auto;transition:none;animation:none}}";
|
|
1631
1556
|
const tagId$10 = "@prettier-ai/dsh-client-ui-chat/TurnNavigator.module.css";
|
|
1632
1557
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
|
|
1633
1558
|
const tag = document.createElement("style");
|
|
@@ -1637,96 +1562,173 @@ window.__ModuleLoader__.load({
|
|
|
1637
1562
|
document.head.appendChild(tag);
|
|
1638
1563
|
}
|
|
1639
1564
|
var TurnNavigator_module_css_default = {
|
|
1565
|
+
"dsh-turn-mark-busy": "alqd3G_dsh-turn-mark-busy",
|
|
1640
1566
|
"dsh-turn-mark-enter": "alqd3G_dsh-turn-mark-enter",
|
|
1641
1567
|
"dsh-turn-preview-enter": "alqd3G_dsh-turn-preview-enter",
|
|
1568
|
+
"fadeBottom": "alqd3G_fadeBottom",
|
|
1569
|
+
"fadeTop": "alqd3G_fadeTop",
|
|
1570
|
+
"frame": "alqd3G_frame",
|
|
1642
1571
|
"mark": "alqd3G_mark",
|
|
1643
1572
|
"markActive": "alqd3G_markActive",
|
|
1573
|
+
"markBusy": "alqd3G_markBusy",
|
|
1644
1574
|
"markPosition": "alqd3G_markPosition",
|
|
1645
1575
|
"markPreview": "alqd3G_markPreview",
|
|
1576
|
+
"markUnloaded": "alqd3G_markUnloaded",
|
|
1646
1577
|
"marks": "alqd3G_marks",
|
|
1647
1578
|
"preview": "alqd3G_preview",
|
|
1648
1579
|
"previewPrompt": "alqd3G_previewPrompt",
|
|
1649
1580
|
"previewResponse": "alqd3G_previewResponse",
|
|
1650
|
-
"
|
|
1581
|
+
"scroller": "alqd3G_scroller",
|
|
1651
1582
|
"slot": "alqd3G_slot"
|
|
1652
1583
|
};
|
|
1653
1584
|
//#endregion
|
|
1654
1585
|
//#region lib/types/client/chat/TurnNavigator.js
|
|
1655
|
-
/**
|
|
1586
|
+
/** Fixed pitch between neighbouring marks; overflow scrolls inside the frame. */
|
|
1656
1587
|
const TURN_SPACING_PX = 10;
|
|
1657
1588
|
/** Rail padding above the first mark and below the last one, per end. */
|
|
1658
1589
|
const RAIL_INSET_PX = 6;
|
|
1659
|
-
|
|
1660
|
-
|
|
1590
|
+
/** Fade band the mask reserves at a scrollable end. */
|
|
1591
|
+
const FADE_PX = 24;
|
|
1592
|
+
function itemPosition(index) {
|
|
1593
|
+
return { "--turn-natural-position": `${String(index * TURN_SPACING_PX)}px` };
|
|
1594
|
+
}
|
|
1595
|
+
function frameStyle(count, scrollTop) {
|
|
1661
1596
|
return {
|
|
1662
|
-
"--turn-natural-
|
|
1663
|
-
"--turn-
|
|
1597
|
+
"--turn-natural-height": `${String((count - 1) * TURN_SPACING_PX + 2 * RAIL_INSET_PX)}px`,
|
|
1598
|
+
"--turn-rail-inset": `${String(RAIL_INSET_PX)}px`,
|
|
1599
|
+
"--turn-scroll-top": `${String(scrollTop)}px`
|
|
1664
1600
|
};
|
|
1665
1601
|
}
|
|
1666
|
-
function
|
|
1602
|
+
function itemAtPointer(items, frame, scrollTop, clientY) {
|
|
1603
|
+
const offset = clientY - frame.getBoundingClientRect().top + scrollTop - RAIL_INSET_PX;
|
|
1604
|
+
return items[Math.max(0, Math.min(items.length - 1, Math.round(offset / TURN_SPACING_PX)))];
|
|
1605
|
+
}
|
|
1606
|
+
const RAIL_AT_REST = {
|
|
1607
|
+
top: 0,
|
|
1608
|
+
canScrollUp: false,
|
|
1609
|
+
canScrollDown: false
|
|
1610
|
+
};
|
|
1611
|
+
function railScrollState(scroller) {
|
|
1612
|
+
const top = scroller.scrollTop;
|
|
1667
1613
|
return {
|
|
1668
|
-
|
|
1669
|
-
|
|
1614
|
+
top,
|
|
1615
|
+
canScrollUp: top > 1,
|
|
1616
|
+
canScrollDown: top < scroller.scrollHeight - scroller.clientHeight - 1
|
|
1670
1617
|
};
|
|
1671
1618
|
}
|
|
1672
|
-
function
|
|
1673
|
-
|
|
1674
|
-
const usableHeight = Math.max(1, rect.height - 2 * RAIL_INSET_PX);
|
|
1675
|
-
const ratio = Math.max(0, Math.min(1, (clientY - rect.top - RAIL_INSET_PX) / usableHeight));
|
|
1676
|
-
return items[Math.round(ratio * (items.length - 1))];
|
|
1619
|
+
function sameRailScrollState(left, right) {
|
|
1620
|
+
return left.top === right.top && left.canScrollUp === right.canScrollUp && left.canScrollDown === right.canScrollDown;
|
|
1677
1621
|
}
|
|
1678
|
-
function TurnNavigatorRail({ items, activeTurn, onNavigate, t }) {
|
|
1622
|
+
function TurnNavigatorRail({ items, activeTurn, busyTurn, onNavigate, t }) {
|
|
1679
1623
|
const [previewTurn, setPreviewTurn] = (0, react.useState)(null);
|
|
1624
|
+
const [scrollState, setScrollState] = (0, react.useState)(RAIL_AT_REST);
|
|
1625
|
+
const scrollerRef = (0, react.useRef)(null);
|
|
1626
|
+
/** While the pointer works the rail, follow must not move it under the hand. */
|
|
1627
|
+
const pointerInsideRef = (0, react.useRef)(false);
|
|
1680
1628
|
const previewId = (0, react.useId)();
|
|
1629
|
+
const syncScrollState = () => {
|
|
1630
|
+
const scroller = scrollerRef.current;
|
|
1631
|
+
if (scroller === null) return;
|
|
1632
|
+
const next = railScrollState(scroller);
|
|
1633
|
+
setScrollState((current) => sameRailScrollState(current, next) ? current : next);
|
|
1634
|
+
};
|
|
1635
|
+
(0, react.useEffect)(() => {
|
|
1636
|
+
const scroller = scrollerRef.current;
|
|
1637
|
+
if (scroller === null || typeof ResizeObserver === "undefined") return;
|
|
1638
|
+
const observer = new ResizeObserver(syncScrollState);
|
|
1639
|
+
observer.observe(scroller);
|
|
1640
|
+
return () => {
|
|
1641
|
+
observer.disconnect();
|
|
1642
|
+
};
|
|
1643
|
+
}, []);
|
|
1644
|
+
(0, react.useEffect)(syncScrollState, [items.length]);
|
|
1645
|
+
(0, react.useEffect)(() => {
|
|
1646
|
+
const scroller = scrollerRef.current;
|
|
1647
|
+
const index = items.findIndex((item) => item.turn === activeTurn);
|
|
1648
|
+
if (scroller === null || index < 0 || pointerInsideRef.current) return;
|
|
1649
|
+
const markTop = index * TURN_SPACING_PX + RAIL_INSET_PX;
|
|
1650
|
+
const viewTop = scroller.scrollTop;
|
|
1651
|
+
const viewHeight = scroller.clientHeight;
|
|
1652
|
+
if (viewHeight <= 0 || markTop >= viewTop + FADE_PX && markTop <= viewTop + viewHeight - FADE_PX) return;
|
|
1653
|
+
const target = Math.max(0, markTop - viewHeight / 2);
|
|
1654
|
+
const reduced = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1655
|
+
if (typeof scroller.scrollTo === "function") scroller.scrollTo({
|
|
1656
|
+
top: target,
|
|
1657
|
+
behavior: reduced ? "auto" : "smooth"
|
|
1658
|
+
});
|
|
1659
|
+
else scroller.scrollTop = target;
|
|
1660
|
+
syncScrollState();
|
|
1661
|
+
}, [activeTurn, items]);
|
|
1681
1662
|
if (items.length < 2) return null;
|
|
1682
1663
|
const previewIndex = items.findIndex((item) => item.turn === previewTurn);
|
|
1683
1664
|
const preview = previewIndex < 0 ? void 0 : items[previewIndex];
|
|
1684
|
-
const previewPosition = previewIndex < 0 ? void 0 : itemPosition(previewIndex
|
|
1665
|
+
const previewPosition = previewIndex < 0 ? void 0 : itemPosition(previewIndex);
|
|
1685
1666
|
const previewAtPointer = (event) => {
|
|
1686
|
-
|
|
1667
|
+
const scrollTop = scrollerRef.current?.scrollTop ?? 0;
|
|
1668
|
+
setPreviewTurn(itemAtPointer(items, event.currentTarget, scrollTop, event.clientY)?.turn ?? null);
|
|
1687
1669
|
};
|
|
1688
1670
|
const navigateAtPointer = (event) => {
|
|
1689
|
-
const
|
|
1671
|
+
const scrollTop = scrollerRef.current?.scrollTop ?? 0;
|
|
1672
|
+
const item = itemAtPointer(items, event.currentTarget, scrollTop, event.clientY);
|
|
1690
1673
|
if (item !== void 0) onNavigate(item);
|
|
1691
1674
|
};
|
|
1675
|
+
const fadeClasses = [TurnNavigator_module_css_default.scroller];
|
|
1676
|
+
if (scrollState.canScrollUp) fadeClasses.push(TurnNavigator_module_css_default.fadeTop);
|
|
1677
|
+
if (scrollState.canScrollDown) fadeClasses.push(TurnNavigator_module_css_default.fadeBottom);
|
|
1692
1678
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
1693
1679
|
className: TurnNavigator_module_css_default.slot,
|
|
1694
1680
|
children: (0, react_jsx_runtime.jsxs)("nav", {
|
|
1695
|
-
className: TurnNavigator_module_css_default.
|
|
1696
|
-
style:
|
|
1681
|
+
className: TurnNavigator_module_css_default.frame,
|
|
1682
|
+
style: frameStyle(items.length, scrollState.top),
|
|
1697
1683
|
"aria-label": t("chat.turnNavigation.label"),
|
|
1698
1684
|
onClick: navigateAtPointer,
|
|
1699
1685
|
onPointerMove: previewAtPointer,
|
|
1686
|
+
onPointerEnter: () => {
|
|
1687
|
+
pointerInsideRef.current = true;
|
|
1688
|
+
},
|
|
1700
1689
|
onPointerLeave: () => {
|
|
1690
|
+
pointerInsideRef.current = false;
|
|
1701
1691
|
setPreviewTurn(null);
|
|
1702
1692
|
},
|
|
1703
1693
|
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1694
|
+
ref: scrollerRef,
|
|
1695
|
+
className: fadeClasses.join(" "),
|
|
1696
|
+
onScroll: () => {
|
|
1697
|
+
syncScrollState();
|
|
1698
|
+
},
|
|
1699
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
1700
|
+
className: TurnNavigator_module_css_default.marks,
|
|
1701
|
+
children: items.map((item, index) => {
|
|
1702
|
+
const active = item.turn === activeTurn;
|
|
1703
|
+
const showingPreview = item.turn === previewTurn;
|
|
1704
|
+
const classes = [TurnNavigator_module_css_default.mark];
|
|
1705
|
+
if (item.anchor.kind === "unloaded") classes.push(TurnNavigator_module_css_default.markUnloaded);
|
|
1706
|
+
if (active) classes.push(TurnNavigator_module_css_default.markActive);
|
|
1707
|
+
else if (showingPreview) classes.push(TurnNavigator_module_css_default.markPreview);
|
|
1708
|
+
if (item.turn === busyTurn) classes.push(TurnNavigator_module_css_default.markBusy);
|
|
1709
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
1710
|
+
className: TurnNavigator_module_css_default.markPosition,
|
|
1711
|
+
style: itemPosition(index),
|
|
1712
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
1713
|
+
type: "button",
|
|
1714
|
+
className: classes.join(" "),
|
|
1715
|
+
"aria-label": t(item.anchor.kind === "loaded" ? "chat.turnNavigation.jump" : "chat.turnNavigation.jumpLoad", { turn: item.turn }),
|
|
1716
|
+
"aria-current": active ? "true" : void 0,
|
|
1717
|
+
"aria-busy": item.turn === busyTurn ? "true" : void 0,
|
|
1718
|
+
"aria-describedby": showingPreview ? previewId : void 0,
|
|
1719
|
+
onClick: (event) => {
|
|
1720
|
+
event.stopPropagation();
|
|
1721
|
+
onNavigate(item);
|
|
1722
|
+
},
|
|
1723
|
+
onFocus: () => {
|
|
1724
|
+
setPreviewTurn(item.turn);
|
|
1725
|
+
},
|
|
1726
|
+
onBlur: () => {
|
|
1727
|
+
setPreviewTurn(null);
|
|
1728
|
+
}
|
|
1729
|
+
})
|
|
1730
|
+
}, item.turn);
|
|
1731
|
+
})
|
|
1730
1732
|
})
|
|
1731
1733
|
}), preview !== void 0 && previewPosition !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
1732
1734
|
id: previewId,
|
|
@@ -1745,9 +1747,12 @@ window.__ModuleLoader__.load({
|
|
|
1745
1747
|
});
|
|
1746
1748
|
}
|
|
1747
1749
|
/**
|
|
1748
|
-
*
|
|
1750
|
+
* Fixed-pitch rail of every known Turn — loaded marks scroll, unloaded marks
|
|
1751
|
+
* page history in first — with hover and focus previews. Overflow scrolls
|
|
1752
|
+
* inside the frame, gradient fades marking each scrollable end, and the
|
|
1753
|
+
* active mark keeps itself in view while the pointer is elsewhere.
|
|
1749
1754
|
*
|
|
1750
|
-
* Memoized because it renders two host elements per
|
|
1755
|
+
* Memoized because it renders two host elements per Turn while the
|
|
1751
1756
|
* enclosing view re-renders on every streaming delta: without the guard a long
|
|
1752
1757
|
* session rebuilds hundreds of marks per commit for a rail that only changes
|
|
1753
1758
|
* when a Turn is added, removed, or becomes active. Its props must therefore
|
|
@@ -1755,7 +1760,102 @@ window.__ModuleLoader__.load({
|
|
|
1755
1760
|
*/
|
|
1756
1761
|
const TurnNavigator = (0, react.memo)(TurnNavigatorRail);
|
|
1757
1762
|
//#endregion
|
|
1763
|
+
//#region ../../util/brand/src/index.ts
|
|
1764
|
+
/**
|
|
1765
|
+
* Apply a compile-time number brand without changing the value.
|
|
1766
|
+
* @param value - number admitted by the domain that owns the target brand.
|
|
1767
|
+
* @returns the same number with the requested compile-time brand.
|
|
1768
|
+
*/
|
|
1769
|
+
function brandNumber(value) {
|
|
1770
|
+
return value;
|
|
1771
|
+
}
|
|
1772
|
+
//#endregion
|
|
1773
|
+
//#region ../../core/session/src/types.ts
|
|
1774
|
+
/**
|
|
1775
|
+
* Admit a numeric value as an existing Session event position.
|
|
1776
|
+
* @param value - non-negative safe integer admitted by the owning log operation.
|
|
1777
|
+
* @returns the same number with the Session-sequence brand.
|
|
1778
|
+
*/
|
|
1779
|
+
function SessionSeq(value) {
|
|
1780
|
+
if (!Number.isSafeInteger(value) || value < 0 || Object.is(value, -0)) throw new TypeError(`SessionSeq must be a non-negative safe integer, got ${String(value)}`);
|
|
1781
|
+
return brandNumber(value);
|
|
1782
|
+
}
|
|
1783
|
+
//#endregion
|
|
1784
|
+
//#region lib/types/client/chat/turn-rail-items.js
|
|
1785
|
+
/**
|
|
1786
|
+
* View-layer union of the host turn outline and the loaded rail items. The
|
|
1787
|
+
* conversation snapshot never carries projection values, so this merge is the
|
|
1788
|
+
* one place the rail's two sources meet: the `turnOutline` projection names
|
|
1789
|
+
* every turn of the session, and the loaded window supplies anchors and
|
|
1790
|
+
* richer previews for the turns it holds.
|
|
1791
|
+
*/
|
|
1792
|
+
const EMPTY_ITEMS$1 = [];
|
|
1793
|
+
/**
|
|
1794
|
+
* Structurally narrow one wire outline entry (projection values cross the
|
|
1795
|
+
* wire). `turn` and `seq` are the load-bearing fields — a mark cannot exist
|
|
1796
|
+
* or jump without them — so their damage drops the entry; the previews are
|
|
1797
|
+
* decorative, so a malformed one degrades to `''` and the turn stays
|
|
1798
|
+
* navigable by number.
|
|
1799
|
+
*/
|
|
1800
|
+
function outlineEntry(value) {
|
|
1801
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
1802
|
+
const entry = value;
|
|
1803
|
+
if (typeof entry.turn !== "number" || !Number.isSafeInteger(entry.turn) || entry.turn < 0) return void 0;
|
|
1804
|
+
if (typeof entry.seq !== "number" || !Number.isSafeInteger(entry.seq) || entry.seq < 0 || Object.is(entry.seq, -0)) return void 0;
|
|
1805
|
+
return {
|
|
1806
|
+
turn: entry.turn,
|
|
1807
|
+
seq: SessionSeq(entry.seq),
|
|
1808
|
+
prompt: typeof entry.prompt === "string" ? entry.prompt : "",
|
|
1809
|
+
response: typeof entry.response === "string" ? entry.response : ""
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
/** Wire outline entries, or none when the projection is absent or malformed. */
|
|
1813
|
+
function outlineEntries(outline) {
|
|
1814
|
+
return Array.isArray(outline) ? outline : EMPTY_ITEMS$1;
|
|
1815
|
+
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Merge the host outline with the loaded rail items into the full ladder.
|
|
1818
|
+
* A turn present in both sides keeps the loaded anchor, taking an outline
|
|
1819
|
+
* preview only where the window's own is empty (a mid-Turn window head, or a
|
|
1820
|
+
* turn whose loaded nodes carry no text); turns on one side only pass
|
|
1821
|
+
* through. Result ascends by turn.
|
|
1822
|
+
* @param loaded - loaded-window rail items (timeline order).
|
|
1823
|
+
* @param outline - `turnOutline` projection value, treated as wire data.
|
|
1824
|
+
* @returns every known turn, ascending; a stable empty array when none.
|
|
1825
|
+
*/
|
|
1826
|
+
function mergeTurnRailItems(loaded, outline) {
|
|
1827
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
1828
|
+
for (const raw of outlineEntries(outline)) {
|
|
1829
|
+
const entry = outlineEntry(raw);
|
|
1830
|
+
if (entry === void 0) continue;
|
|
1831
|
+
byTurn.set(entry.turn, {
|
|
1832
|
+
turn: entry.turn,
|
|
1833
|
+
prompt: entry.prompt,
|
|
1834
|
+
response: entry.response,
|
|
1835
|
+
anchor: {
|
|
1836
|
+
kind: "unloaded",
|
|
1837
|
+
seq: entry.seq
|
|
1838
|
+
}
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
for (const item of loaded) {
|
|
1842
|
+
const preview = byTurn.get(item.turn);
|
|
1843
|
+
byTurn.set(item.turn, {
|
|
1844
|
+
turn: item.turn,
|
|
1845
|
+
prompt: item.prompt !== "" ? item.prompt : preview?.prompt ?? "",
|
|
1846
|
+
response: item.response !== "" ? item.response : preview?.response ?? "",
|
|
1847
|
+
anchor: {
|
|
1848
|
+
kind: "loaded",
|
|
1849
|
+
key: item.anchorKey
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
if (byTurn.size === 0) return EMPTY_ITEMS$1;
|
|
1854
|
+
return [...byTurn.values()].sort((left, right) => left.turn - right.turn);
|
|
1855
|
+
}
|
|
1856
|
+
//#endregion
|
|
1758
1857
|
//#region lib/types/client/chat/ChatView.js
|
|
1858
|
+
const SCROLL_SAMPLE_INTERVAL_MS = 500;
|
|
1759
1859
|
/** Active column host when present; otherwise the view-local scroller. */
|
|
1760
1860
|
function scrollerOf(from) {
|
|
1761
1861
|
return from.closest("[data-conversation-scroll]") ?? from;
|
|
@@ -1888,14 +1988,22 @@ window.__ModuleLoader__.load({
|
|
|
1888
1988
|
})]
|
|
1889
1989
|
});
|
|
1890
1990
|
}
|
|
1991
|
+
const ChatNodeList = (0, react.memo)(function ChatNodeList({ order, ...seatProps }) {
|
|
1992
|
+
return order.map((nodeKey) => (0, react_jsx_runtime.jsx)(ChatNodeSeat, {
|
|
1993
|
+
nodeKey,
|
|
1994
|
+
...seatProps
|
|
1995
|
+
}, nodeKey));
|
|
1996
|
+
});
|
|
1891
1997
|
/**
|
|
1892
1998
|
* The chat view slot entry: pure component over the composed props; each
|
|
1893
1999
|
* ordered business Node crosses the keyed renderer seat.
|
|
1894
2000
|
*/
|
|
1895
|
-
function ChatView({ useSession, useChat, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, t }) {
|
|
2001
|
+
function ChatView({ useSession, useChat, useChatNode, useChatNodeProcess, useSessions, useStore, actions, renderSlot, sessionId, openFile, loadOlder, loadThrough, loadImage, openView, chatScroll, forkAt, fileMentions, useTranscriptView, useProjection, t }) {
|
|
1896
2002
|
const order = useChat((s) => s.order);
|
|
1897
2003
|
const nodeStore = useChat((s) => s.nodes);
|
|
1898
2004
|
const turnNavigationItems = useChat((s) => s.navigation.items());
|
|
2005
|
+
const turnOutline = useProjection("turnOutline");
|
|
2006
|
+
const railItems = (0, react.useMemo)(() => mergeTurnRailItems(turnNavigationItems, turnOutline), [turnNavigationItems, turnOutline]);
|
|
1899
2007
|
const timeline = useChat((s) => s.timeline);
|
|
1900
2008
|
const inbox = useSession((s) => s.queue);
|
|
1901
2009
|
const cwd = useSessions((s) => s.byId[sessionId]?.cwd);
|
|
@@ -1938,7 +2046,7 @@ window.__ModuleLoader__.load({
|
|
|
1938
2046
|
const visibleSubmissions = (0, react.useMemo)(() => {
|
|
1939
2047
|
if (pendingSubmissions.length === 0) return pendingSubmissions;
|
|
1940
2048
|
const observed = observedRpcIds(order, nodeStore, inbox);
|
|
1941
|
-
return pendingSubmissions.filter((submission) => !observed.has(submission.requestId));
|
|
2049
|
+
return pendingSubmissions.filter((submission) => submission.placement !== "queued" && !observed.has(submission.requestId));
|
|
1942
2050
|
}, [
|
|
1943
2051
|
pendingSubmissions,
|
|
1944
2052
|
order,
|
|
@@ -1954,12 +2062,23 @@ window.__ModuleLoader__.load({
|
|
|
1954
2062
|
const columnRef = (0, react.useRef)(null);
|
|
1955
2063
|
const [atBottom, setAtBottom] = (0, react.useState)(() => chatScroll.read() === null);
|
|
1956
2064
|
const atBottomRef = (0, react.useRef)(atBottom);
|
|
2065
|
+
const scrollSamplePendingRef = (0, react.useRef)(false);
|
|
2066
|
+
const [, setScrollSampleTick] = (0, react.useState)(0);
|
|
1957
2067
|
const [activeTurn, setActiveTurn] = (0, react.useState)(() => turnNavigationItems.at(-1)?.turn ?? null);
|
|
1958
2068
|
/** Last position delivered or written on the main thread. */
|
|
1959
2069
|
const observedTopRef = (0, react.useRef)(0);
|
|
1960
2070
|
/** Paging anchor: semantic row/position at click, updated by reader scrolls
|
|
1961
2071
|
* while the request is pending and restored after the prepend lands. */
|
|
1962
2072
|
const anchorRef = (0, react.useRef)(null);
|
|
2073
|
+
/** Unloaded-turn jump in flight: target turn plus its load-through seq. */
|
|
2074
|
+
const pendingJumpRef = (0, react.useRef)(null);
|
|
2075
|
+
/** Whether the in-flight jump already landed mid-paging (settle then only corrects an untouched landing). */
|
|
2076
|
+
const jumpLandedRef = (0, react.useRef)(false);
|
|
2077
|
+
const [busyJumpTurn, setBusyJumpTurn] = (0, react.useState)(null);
|
|
2078
|
+
/** Bumped when a loadThrough completion settles, after its last page's commit. */
|
|
2079
|
+
const [jumpSettleTick, setJumpSettleTick] = (0, react.useState)(0);
|
|
2080
|
+
/** Window head at the last settle-time repage; an unmoved head falls back instead of repaging forever. */
|
|
2081
|
+
const jumpRepageHeadRef = (0, react.useRef)(null);
|
|
1963
2082
|
const firstSeqRef = (0, react.useRef)(null);
|
|
1964
2083
|
const openedRef = (0, react.useRef)(false);
|
|
1965
2084
|
const lastKeyRef = (0, react.useRef)(null);
|
|
@@ -1977,6 +2096,7 @@ window.__ModuleLoader__.load({
|
|
|
1977
2096
|
const lastSubmissionId = visibleSubmissions[visibleSubmissions.length - 1]?.requestId ?? null;
|
|
1978
2097
|
const followSig = `${openState}:${firstSeq}:${lastKey}:${order.length}:${running ? 1 : 0}:${lastSteeringId ?? ""}:${lastSubmissionId ?? ""}`;
|
|
1979
2098
|
const syncActiveTurn = (0, react.useCallback)(() => {
|
|
2099
|
+
if (scrollSamplePendingRef.current) return;
|
|
1980
2100
|
const local = listRef.current;
|
|
1981
2101
|
const first = turnNavigationItems[0];
|
|
1982
2102
|
if (local === null || first === void 0) {
|
|
@@ -1984,13 +2104,17 @@ window.__ModuleLoader__.load({
|
|
|
1984
2104
|
return;
|
|
1985
2105
|
}
|
|
1986
2106
|
const el = scrollerOf(local);
|
|
2107
|
+
if (el.scrollHeight - el.scrollTop - el.clientHeight <= 25) {
|
|
2108
|
+
const latest = turnNavigationItems.at(-1)?.turn ?? first.turn;
|
|
2109
|
+
setActiveTurn((current) => current === latest ? current : latest);
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
1987
2112
|
const reading = turnAtLine(local, el.getBoundingClientRect().top + Math.min(96, el.clientHeight * .2));
|
|
1988
2113
|
let next = first.turn;
|
|
1989
2114
|
if (reading !== null) for (const item of turnNavigationItems) {
|
|
1990
2115
|
if (item.turn > reading) break;
|
|
1991
2116
|
next = item.turn;
|
|
1992
2117
|
}
|
|
1993
|
-
if (el.scrollHeight - el.scrollTop - el.clientHeight <= 25) next = turnNavigationItems.at(-1)?.turn ?? next;
|
|
1994
2118
|
setActiveTurn((current) => current === next ? current : next);
|
|
1995
2119
|
}, [turnNavigationItems]);
|
|
1996
2120
|
const activeTurnRef = (0, react.useRef)(null);
|
|
@@ -2015,6 +2139,8 @@ window.__ModuleLoader__.load({
|
|
|
2015
2139
|
}, [scheduleActiveTurn]);
|
|
2016
2140
|
const toBottom = (el) => {
|
|
2017
2141
|
anchorRef.current = null;
|
|
2142
|
+
pendingJumpRef.current = null;
|
|
2143
|
+
setBusyJumpTurn((current) => current === null ? current : null);
|
|
2018
2144
|
el.scrollTop = el.scrollHeight;
|
|
2019
2145
|
observedTopRef.current = el.scrollTop;
|
|
2020
2146
|
atBottomRef.current = true;
|
|
@@ -2022,7 +2148,52 @@ window.__ModuleLoader__.load({
|
|
|
2022
2148
|
chatScroll.save(null);
|
|
2023
2149
|
setActiveTurn(turnNavigationItems.at(-1)?.turn ?? null);
|
|
2024
2150
|
};
|
|
2151
|
+
const landOnRowRef = (0, react.useRef)(() => {});
|
|
2152
|
+
landOnRowRef.current = (local, el, row, turn) => {
|
|
2153
|
+
el.scrollTop += flowTop(row, el) - 24;
|
|
2154
|
+
observedTopRef.current = el.scrollTop;
|
|
2155
|
+
const isAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= 25;
|
|
2156
|
+
atBottomRef.current = isAtBottom;
|
|
2157
|
+
setAtBottom(isAtBottom);
|
|
2158
|
+
setActiveTurn(turn);
|
|
2159
|
+
const position = isAtBottom ? null : scrollPosition(local, el);
|
|
2160
|
+
if (isAtBottom) chatScroll.save(null);
|
|
2161
|
+
else if (position !== null) chatScroll.save(position);
|
|
2162
|
+
};
|
|
2163
|
+
/**
|
|
2164
|
+
* Land the pending jump once its Turn has a rendered anchor row; false
|
|
2165
|
+
* while it must keep waiting. Mid-jump landings (`settle` false) keep the
|
|
2166
|
+
* jump armed with the target row as the paging anchor, so later chunks and
|
|
2167
|
+
* the load-earlier button's unmount re-land on the same row; the settling
|
|
2168
|
+
* call clears the jump.
|
|
2169
|
+
*/
|
|
2170
|
+
const realizePendingJump = (local, el, settle) => {
|
|
2171
|
+
const pending = pendingJumpRef.current;
|
|
2172
|
+
if (pending === null) return true;
|
|
2173
|
+
const item = railItems.find((candidate) => candidate.turn === pending.turn);
|
|
2174
|
+
if (item === void 0 || item.anchor.kind !== "loaded") return false;
|
|
2175
|
+
const row = anchorElement(local, item.anchor.key);
|
|
2176
|
+
if (row === null) return false;
|
|
2177
|
+
if (settle) {
|
|
2178
|
+
pendingJumpRef.current = null;
|
|
2179
|
+
setBusyJumpTurn(null);
|
|
2180
|
+
const held = anchorRef.current;
|
|
2181
|
+
const landedEarlier = jumpLandedRef.current;
|
|
2182
|
+
jumpLandedRef.current = false;
|
|
2183
|
+
anchorRef.current = null;
|
|
2184
|
+
if (!landedEarlier || held?.key === item.anchor.key) landOnRowRef.current(local, el, row, pending.turn);
|
|
2185
|
+
return true;
|
|
2186
|
+
}
|
|
2187
|
+
landOnRowRef.current(local, el, row, pending.turn);
|
|
2188
|
+
jumpLandedRef.current = true;
|
|
2189
|
+
anchorRef.current = {
|
|
2190
|
+
key: item.anchor.key,
|
|
2191
|
+
top: flowTop(row, el)
|
|
2192
|
+
};
|
|
2193
|
+
return true;
|
|
2194
|
+
};
|
|
2025
2195
|
(0, react.useLayoutEffect)(() => {
|
|
2196
|
+
if (scrollSamplePendingRef.current) return;
|
|
2026
2197
|
const local = listRef.current;
|
|
2027
2198
|
/* v8 ignore next -- ref-null guard: React attaches the ref before layout effects run. */
|
|
2028
2199
|
if (local === null) return;
|
|
@@ -2056,6 +2227,10 @@ window.__ModuleLoader__.load({
|
|
|
2056
2227
|
const row = anchorElement(local, anchor.key);
|
|
2057
2228
|
if (row !== null) el.scrollTop += flowTop(row, el) - anchor.top;
|
|
2058
2229
|
observedTopRef.current = el.scrollTop;
|
|
2230
|
+
if (!realizePendingJump(local, el, false) && row !== null) anchorRef.current = {
|
|
2231
|
+
key: anchor.key,
|
|
2232
|
+
top: flowTop(row, el)
|
|
2233
|
+
};
|
|
2059
2234
|
firstSeqRef.current = firstSeq;
|
|
2060
2235
|
/* v8 ignore next -- ?? arm: a prepend adds nodes, so the flow list here is never empty. */
|
|
2061
2236
|
lastKeyRef.current = lastKey;
|
|
@@ -2073,7 +2248,11 @@ window.__ModuleLoader__.load({
|
|
|
2073
2248
|
lastSteeringIdRef.current = lastSteeringId;
|
|
2074
2249
|
lastSubmissionIdRef.current = lastSubmissionId;
|
|
2075
2250
|
followSigRef.current = followSig;
|
|
2076
|
-
if (appendedUser || appendedSteering || appendedSubmission || tipMoved && atBottomRef.current)
|
|
2251
|
+
if (appendedUser || appendedSteering || appendedSubmission || tipMoved && atBottomRef.current) {
|
|
2252
|
+
toBottom(el);
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
if (pendingJumpRef.current !== null) realizePendingJump(local, el, false);
|
|
2077
2256
|
});
|
|
2078
2257
|
const onScrollRef = (0, react.useRef)(() => {});
|
|
2079
2258
|
onScrollRef.current = () => {
|
|
@@ -2106,16 +2285,31 @@ window.__ModuleLoader__.load({
|
|
|
2106
2285
|
/* v8 ignore next -- ref-null guard: effect runs after the list node commits. */
|
|
2107
2286
|
if (local === null) return;
|
|
2108
2287
|
const el = scrollerOf(local);
|
|
2109
|
-
|
|
2288
|
+
let sampleTimer;
|
|
2289
|
+
const sample = () => {
|
|
2290
|
+
if (!scrollSamplePendingRef.current) return;
|
|
2291
|
+
scrollSamplePendingRef.current = false;
|
|
2292
|
+
if (sampleTimer !== void 0) window.clearTimeout(sampleTimer);
|
|
2293
|
+
sampleTimer = void 0;
|
|
2110
2294
|
onScrollRef.current();
|
|
2295
|
+
setScrollSampleTick((tick) => tick + 1);
|
|
2296
|
+
};
|
|
2297
|
+
const onScroll = () => {
|
|
2298
|
+
scrollSamplePendingRef.current = true;
|
|
2299
|
+
sampleTimer ??= window.setTimeout(sample, SCROLL_SAMPLE_INTERVAL_MS);
|
|
2111
2300
|
};
|
|
2112
2301
|
el.addEventListener("scroll", onScroll, { passive: true });
|
|
2302
|
+
el.addEventListener("scrollend", sample, { passive: true });
|
|
2113
2303
|
return () => {
|
|
2114
2304
|
el.removeEventListener("scroll", onScroll);
|
|
2305
|
+
el.removeEventListener("scrollend", sample);
|
|
2306
|
+
if (sampleTimer !== void 0) window.clearTimeout(sampleTimer);
|
|
2307
|
+
scrollSamplePendingRef.current = false;
|
|
2115
2308
|
};
|
|
2116
2309
|
}, []);
|
|
2117
2310
|
const followRef = (0, react.useRef)(null);
|
|
2118
2311
|
followRef.current = () => {
|
|
2312
|
+
if (scrollSamplePendingRef.current) return;
|
|
2119
2313
|
const local = listRef.current;
|
|
2120
2314
|
if (local !== null && atBottomRef.current) {
|
|
2121
2315
|
const el = scrollerOf(local);
|
|
@@ -2142,6 +2336,39 @@ window.__ModuleLoader__.load({
|
|
|
2142
2336
|
(0, react.useEffect)(() => {
|
|
2143
2337
|
if (!loadingOlder) anchorRef.current = null;
|
|
2144
2338
|
}, [loadingOlder]);
|
|
2339
|
+
(0, react.useEffect)(() => {
|
|
2340
|
+
const pending = pendingJumpRef.current;
|
|
2341
|
+
const local = listRef.current;
|
|
2342
|
+
if (pending === null || local === null) return;
|
|
2343
|
+
const el = scrollerOf(local);
|
|
2344
|
+
if (realizePendingJump(local, el, true)) return;
|
|
2345
|
+
if ((firstSeq === null || firstSeq > pending.seq) && hasMore) {
|
|
2346
|
+
if (loadingOlder) return;
|
|
2347
|
+
if (jumpRepageHeadRef.current !== firstSeq) {
|
|
2348
|
+
jumpRepageHeadRef.current = firstSeq;
|
|
2349
|
+
const held = pagingAnchor(local, el);
|
|
2350
|
+
if (held !== null && held.dataset.chatAnchorKey !== void 0) anchorRef.current = {
|
|
2351
|
+
key: held.dataset.chatAnchorKey,
|
|
2352
|
+
top: flowTop(held, el)
|
|
2353
|
+
};
|
|
2354
|
+
loadThrough(pending.seq).finally(() => {
|
|
2355
|
+
setJumpSettleTick((tick) => tick + 1);
|
|
2356
|
+
});
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
for (const row of local.querySelectorAll("[data-chat-turn]:not([hidden])")) {
|
|
2361
|
+
const turn = Number(row.dataset.chatTurn);
|
|
2362
|
+
if (!Number.isSafeInteger(turn) || turn < pending.turn) continue;
|
|
2363
|
+
landOnRowRef.current(local, el, row, turn);
|
|
2364
|
+
break;
|
|
2365
|
+
}
|
|
2366
|
+
pendingJumpRef.current = null;
|
|
2367
|
+
setBusyJumpTurn(null);
|
|
2368
|
+
}, [jumpSettleTick]);
|
|
2369
|
+
(0, react.useEffect)(() => {
|
|
2370
|
+
if (!loadingOlder && pendingJumpRef.current !== null) setJumpSettleTick((tick) => tick + 1);
|
|
2371
|
+
}, [loadingOlder]);
|
|
2145
2372
|
const loadOlderAnchored = () => {
|
|
2146
2373
|
const local = listRef.current;
|
|
2147
2374
|
/* v8 ignore next -- ref-null guard: the paging button renders inside the list tree. */
|
|
@@ -2158,24 +2385,38 @@ window.__ModuleLoader__.load({
|
|
|
2158
2385
|
const navigateToTurn = (0, react.useCallback)((item) => {
|
|
2159
2386
|
const local = listRef.current;
|
|
2160
2387
|
if (local === null) return;
|
|
2161
|
-
const row = anchorElement(local, item.anchorKey);
|
|
2162
|
-
if (row === null) return;
|
|
2163
2388
|
const el = scrollerOf(local);
|
|
2164
|
-
|
|
2165
|
-
|
|
2389
|
+
if (item.anchor.kind === "unloaded") {
|
|
2390
|
+
atBottomRef.current = false;
|
|
2391
|
+
setAtBottom(false);
|
|
2392
|
+
const held = pagingAnchor(local, el);
|
|
2393
|
+
if (held !== null && held.dataset.chatAnchorKey !== void 0) anchorRef.current = {
|
|
2394
|
+
key: held.dataset.chatAnchorKey,
|
|
2395
|
+
top: flowTop(held, el)
|
|
2396
|
+
};
|
|
2397
|
+
pendingJumpRef.current = {
|
|
2398
|
+
turn: item.turn,
|
|
2399
|
+
seq: item.anchor.seq
|
|
2400
|
+
};
|
|
2401
|
+
jumpRepageHeadRef.current = null;
|
|
2402
|
+
jumpLandedRef.current = false;
|
|
2403
|
+
setBusyJumpTurn(item.turn);
|
|
2404
|
+
loadThrough(item.anchor.seq).finally(() => {
|
|
2405
|
+
setJumpSettleTick((tick) => tick + 1);
|
|
2406
|
+
});
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
const row = anchorElement(local, item.anchor.key);
|
|
2410
|
+
if (row === null) return;
|
|
2411
|
+
pendingJumpRef.current = null;
|
|
2412
|
+
setBusyJumpTurn((current) => current === null ? current : null);
|
|
2413
|
+
landOnRowRef.current(local, el, row, item.turn);
|
|
2166
2414
|
const landed = loadingOlder ? pagingAnchor(local, el) : null;
|
|
2167
2415
|
anchorRef.current = landed === null || landed.dataset.chatAnchorKey === void 0 ? null : {
|
|
2168
2416
|
key: landed.dataset.chatAnchorKey,
|
|
2169
2417
|
top: flowTop(landed, el)
|
|
2170
2418
|
};
|
|
2171
|
-
|
|
2172
|
-
atBottomRef.current = isAtBottom;
|
|
2173
|
-
setAtBottom(isAtBottom);
|
|
2174
|
-
setActiveTurn(item.turn);
|
|
2175
|
-
const position = isAtBottom ? null : scrollPosition(local, el);
|
|
2176
|
-
if (isAtBottom) chatScroll.save(null);
|
|
2177
|
-
else if (position !== null) chatScroll.save(position);
|
|
2178
|
-
}, [loadingOlder, chatScroll]);
|
|
2419
|
+
}, [loadingOlder, loadThrough]);
|
|
2179
2420
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2180
2421
|
className: ChatView_module_css_default.root,
|
|
2181
2422
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2183,8 +2424,9 @@ window.__ModuleLoader__.load({
|
|
|
2183
2424
|
className: ChatView_module_css_default.scroll,
|
|
2184
2425
|
children: [
|
|
2185
2426
|
(0, react_jsx_runtime.jsx)(TurnNavigator, {
|
|
2186
|
-
items:
|
|
2427
|
+
items: railItems,
|
|
2187
2428
|
activeTurn,
|
|
2429
|
+
busyTurn: busyJumpTurn,
|
|
2188
2430
|
onNavigate: navigateToTurn,
|
|
2189
2431
|
t
|
|
2190
2432
|
}),
|
|
@@ -2213,11 +2455,12 @@ window.__ModuleLoader__.load({
|
|
|
2213
2455
|
children: loadingOlder ? t("loading") : t("chat.loadOlder")
|
|
2214
2456
|
})
|
|
2215
2457
|
}),
|
|
2216
|
-
|
|
2217
|
-
|
|
2458
|
+
(0, react_jsx_runtime.jsx)(ChatNodeList, {
|
|
2459
|
+
order,
|
|
2460
|
+
useChatNode,
|
|
2461
|
+
useChatNodeProcess,
|
|
2218
2462
|
historyIncomplete: hasMore,
|
|
2219
2463
|
compactTranscript,
|
|
2220
|
-
useChat,
|
|
2221
2464
|
useStore,
|
|
2222
2465
|
actions,
|
|
2223
2466
|
selectedCallId,
|
|
@@ -2229,7 +2472,7 @@ window.__ModuleLoader__.load({
|
|
|
2229
2472
|
fileMentions,
|
|
2230
2473
|
renderSlot,
|
|
2231
2474
|
t
|
|
2232
|
-
}
|
|
2475
|
+
}),
|
|
2233
2476
|
running && (0, react_jsx_runtime.jsx)(TurnStatus, {
|
|
2234
2477
|
startTime: runningTurnStart,
|
|
2235
2478
|
t
|
|
@@ -2328,6 +2571,7 @@ window.__ModuleLoader__.load({
|
|
|
2328
2571
|
"chat.deepDiving": "深度求索中...",
|
|
2329
2572
|
"chat.turnNavigation.label": "轮次导航",
|
|
2330
2573
|
"chat.turnNavigation.jump": "跳转到第 {turn} 轮",
|
|
2574
|
+
"chat.turnNavigation.jumpLoad": "加载并跳转到第 {turn} 轮",
|
|
2331
2575
|
"chat.turnNavigation.turn": "第 {turn} 轮",
|
|
2332
2576
|
"settings.transcript.title": "对话显示",
|
|
2333
2577
|
"settings.transcript.description": "控制已完成轮次的过程内容",
|
|
@@ -2440,6 +2684,7 @@ window.__ModuleLoader__.load({
|
|
|
2440
2684
|
"chat.deepDiving": "Deep diving...",
|
|
2441
2685
|
"chat.turnNavigation.label": "Turn navigation",
|
|
2442
2686
|
"chat.turnNavigation.jump": "Jump to turn {turn}",
|
|
2687
|
+
"chat.turnNavigation.jumpLoad": "Load and jump to turn {turn}",
|
|
2443
2688
|
"chat.turnNavigation.turn": "Turn {turn}",
|
|
2444
2689
|
"settings.transcript.title": "Conversation display",
|
|
2445
2690
|
"settings.transcript.description": "Controls process content in completed turns",
|
|
@@ -2525,40 +2770,6 @@ window.__ModuleLoader__.load({
|
|
|
2525
2770
|
"clock.ymd": "{y}-{m}-{d}"
|
|
2526
2771
|
};
|
|
2527
2772
|
//#endregion
|
|
2528
|
-
//#region lib/types/client/chat/use-throttled-visual-update.js
|
|
2529
|
-
/** Frame-throttled scheduling for non-essential visual alignment. */
|
|
2530
|
-
const DEFAULT_INTERVAL_FRAMES = 3;
|
|
2531
|
-
/**
|
|
2532
|
-
* Return a stable scheduler that coalesces visual updates over a frame interval.
|
|
2533
|
-
* @param update - DOM alignment to run after the throttle interval.
|
|
2534
|
-
* @param intervalFrames - frames to wait before applying the latest alignment.
|
|
2535
|
-
* @returns a stable function that schedules the latest update.
|
|
2536
|
-
*/
|
|
2537
|
-
function useThrottledVisualUpdate(update, intervalFrames = DEFAULT_INTERVAL_FRAMES) {
|
|
2538
|
-
const updateRef = (0, react.useRef)(update);
|
|
2539
|
-
updateRef.current = update;
|
|
2540
|
-
const pendingFrameRef = (0, react.useRef)(null);
|
|
2541
|
-
(0, react.useLayoutEffect)(() => () => {
|
|
2542
|
-
if (pendingFrameRef.current === null) return;
|
|
2543
|
-
cancelAnimationFrame(pendingFrameRef.current);
|
|
2544
|
-
pendingFrameRef.current = null;
|
|
2545
|
-
}, []);
|
|
2546
|
-
return (0, react.useCallback)(() => {
|
|
2547
|
-
if (pendingFrameRef.current !== null) return;
|
|
2548
|
-
let remainingFrames = intervalFrames;
|
|
2549
|
-
const advance = () => {
|
|
2550
|
-
remainingFrames -= 1;
|
|
2551
|
-
if (remainingFrames > 0) {
|
|
2552
|
-
pendingFrameRef.current = requestAnimationFrame(advance);
|
|
2553
|
-
return;
|
|
2554
|
-
}
|
|
2555
|
-
pendingFrameRef.current = null;
|
|
2556
|
-
updateRef.current();
|
|
2557
|
-
};
|
|
2558
|
-
pendingFrameRef.current = requestAnimationFrame(advance);
|
|
2559
|
-
}, [intervalFrames]);
|
|
2560
|
-
}
|
|
2561
|
-
//#endregion
|
|
2562
2773
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/accessibility.module.css.mjs
|
|
2563
2774
|
const css$9 = ".nrZFeq_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}";
|
|
2564
2775
|
const tagId$9 = "@prettier-ai/dsh-client-ui-chat/accessibility.module.css";
|
|
@@ -2572,7 +2783,7 @@ window.__ModuleLoader__.load({
|
|
|
2572
2783
|
var accessibility_module_css_default = { "visuallyHidden": "nrZFeq_visuallyHidden" };
|
|
2573
2784
|
//#endregion
|
|
2574
2785
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/ReasoningRow.module.css.mjs
|
|
2575
|
-
const css$8 = ".xhC5dq_root{flex-direction:column;display:flex}.xhC5dq_row{position:relative;overflow:hidden}.xhC5dq_root[data-state=running] .xhC5dq_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite xhC5dq_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes xhC5dq_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.xhC5dq_leading{flex-shrink:0}.xhC5dq_chevron{color:var(--dsw-alias-label-secondary)}.xhC5dq_title{font-weight:400}.xhC5dq_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.xhC5dq_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));
|
|
2786
|
+
const css$8 = ".xhC5dq_root{flex-direction:column;display:flex}.xhC5dq_root:not([data-expanded]){contain:size layout;height:calc(24px + var(--dsh-content-font-delta,0px))}.xhC5dq_row{position:relative;overflow:hidden}.xhC5dq_root[data-state=running] .xhC5dq_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite xhC5dq_dsh-reasoning-row-sweep;position:absolute;left:0}@keyframes xhC5dq_dsh-reasoning-row-sweep{0%{left:-300px}90%,to{left:100%}}.xhC5dq_leading{flex-shrink:0}.xhC5dq_chevron{color:var(--dsw-alias-label-secondary)}.xhC5dq_title{font-weight:400}.xhC5dq_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.xhC5dq_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:nowrap;flex:auto;overflow:hidden}.xhC5dq_summaryText{text-overflow:ellipsis;display:block;overflow:hidden}.xhC5dq_summary[data-follow-end]{justify-content:flex-end;display:flex}.xhC5dq_summary[data-follow-end] .xhC5dq_summaryText{text-align:start;text-overflow:clip;flex:none;width:max-content;min-width:100%;overflow:visible}.xhC5dq_thinkBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));white-space:pre-wrap;word-break:break-word}@media (prefers-reduced-motion:reduce){.xhC5dq_root[data-state=running] .xhC5dq_row:after{animation:none}}";
|
|
2576
2787
|
const tagId$8 = "@prettier-ai/dsh-client-ui-chat/ReasoningRow.module.css";
|
|
2577
2788
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$8) + "]") === null) {
|
|
2578
2789
|
const tag = document.createElement("style");
|
|
@@ -2589,6 +2800,7 @@ window.__ModuleLoader__.load({
|
|
|
2589
2800
|
"row": "xhC5dq_row",
|
|
2590
2801
|
"separator": "xhC5dq_separator",
|
|
2591
2802
|
"summary": "xhC5dq_summary",
|
|
2803
|
+
"summaryText": "xhC5dq_summaryText",
|
|
2592
2804
|
"thinkBody": "xhC5dq_thinkBody",
|
|
2593
2805
|
"title": "xhC5dq_title"
|
|
2594
2806
|
};
|
|
@@ -2613,24 +2825,12 @@ window.__ModuleLoader__.load({
|
|
|
2613
2825
|
*/
|
|
2614
2826
|
function ReasoningRow({ text, running, t }) {
|
|
2615
2827
|
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
2616
|
-
const summaryRef = (0, react.useRef)(null);
|
|
2617
2828
|
const summary = running ? latestLine(text) : firstLine(text);
|
|
2618
|
-
const scheduleSummaryScroll = useThrottledVisualUpdate(() => {
|
|
2619
|
-
const element = summaryRef.current;
|
|
2620
|
-
if (element === null) return;
|
|
2621
|
-
element.scrollLeft = running ? element.scrollWidth - element.clientWidth : 0;
|
|
2622
|
-
});
|
|
2623
|
-
(0, react.useEffect)(() => {
|
|
2624
|
-
scheduleSummaryScroll();
|
|
2625
|
-
}, [
|
|
2626
|
-
running,
|
|
2627
|
-
scheduleSummaryScroll,
|
|
2628
|
-
summary
|
|
2629
|
-
]);
|
|
2630
2829
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2631
2830
|
className: ReasoningRow_module_css_default.root,
|
|
2632
2831
|
"data-variant": "think",
|
|
2633
2832
|
"data-state": running ? "running" : "ok",
|
|
2833
|
+
"data-expanded": expanded || void 0,
|
|
2634
2834
|
children: [running && (0, react_jsx_runtime.jsx)("span", {
|
|
2635
2835
|
className: accessibility_module_css_default.visuallyHidden,
|
|
2636
2836
|
children: t("row.running")
|
|
@@ -2651,10 +2851,12 @@ window.__ModuleLoader__.load({
|
|
|
2651
2851
|
className: ReasoningRow_module_css_default.separator,
|
|
2652
2852
|
"aria-hidden": true
|
|
2653
2853
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
2654
|
-
ref: summaryRef,
|
|
2655
2854
|
className: ReasoningRow_module_css_default.summary,
|
|
2656
2855
|
"data-follow-end": running || void 0,
|
|
2657
|
-
children:
|
|
2856
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
2857
|
+
className: ReasoningRow_module_css_default.summaryText,
|
|
2858
|
+
children: summary
|
|
2859
|
+
})
|
|
2658
2860
|
})] }),
|
|
2659
2861
|
children: (0, react_jsx_runtime.jsx)("div", {
|
|
2660
2862
|
className: ReasoningRow_module_css_default.thinkBody,
|
|
@@ -2793,7 +2995,7 @@ window.__ModuleLoader__.load({
|
|
|
2793
2995
|
});
|
|
2794
2996
|
//#endregion
|
|
2795
2997
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/GenericCommandCard.module.css.mjs
|
|
2796
|
-
const css$6 = "._0R17eG_root{flex-direction:column;display:flex}._0R17eG_row{position:relative;overflow:hidden}._0R17eG_root[data-state=running] ._0R17eG_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _0R17eG_dsh-command-row-sweep;position:absolute;left:0}@keyframes _0R17eG_dsh-command-row-sweep{0%{left:-300px}90%,to{left:100%}}._0R17eG_leading{flex-shrink:0}._0R17eG_chevron{color:var(--dsw-alias-label-secondary)}._0R17eG_title{font-weight:400}._0R17eG_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._0R17eG_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}._0R17eG_summary[data-error],._0R17eG_body[data-error]{color:var(--dsw-alias-state-error-primary)}._0R17eG_body{border
|
|
2998
|
+
const css$6 = "._0R17eG_root{flex-direction:column;display:flex}._0R17eG_row{position:relative;overflow:hidden}._0R17eG_root[data-state=running] ._0R17eG_row:after{content:\"\";inset-block:0;background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _0R17eG_dsh-command-row-sweep;position:absolute;left:0}@keyframes _0R17eG_dsh-command-row-sweep{0%{left:-300px}90%,to{left:100%}}._0R17eG_leading{flex-shrink:0}._0R17eG_chevron{color:var(--dsw-alias-label-secondary)}._0R17eG_title{font-weight:400}._0R17eG_separator{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._0R17eG_summary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}._0R17eG_summary[data-error],._0R17eG_body[data-error]{color:var(--dsw-alias-state-error-primary)}._0R17eG_body{border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);max-height:260px;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;border-radius:12px;margin:4px 0 4px 4px;padding:12px 16px;overflow:auto}@media (prefers-reduced-motion:reduce){._0R17eG_root[data-state=running] ._0R17eG_row:after{animation:none}}";
|
|
2797
2999
|
const tagId$6 = "@prettier-ai/dsh-client-ui-chat/GenericCommandCard.module.css";
|
|
2798
3000
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
|
|
2799
3001
|
const tag = document.createElement("style");
|
|
@@ -2969,7 +3171,7 @@ window.__ModuleLoader__.load({
|
|
|
2969
3171
|
});
|
|
2970
3172
|
//#endregion
|
|
2971
3173
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnProcessNodeView.module.css.mjs
|
|
2972
|
-
const css$5 = ".SfQmhG_root{box-sizing:border-box;border:none;border-bottom
|
|
3174
|
+
const css$5 = ".SfQmhG_root{box-sizing:border-box;border:none;border-bottom:.5px solid var(--dsw-alias-border-l2);width:100%;min-width:0;height:33px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;align-items:center;padding:0 0 8px;display:flex}.SfQmhG_root:not([data-open]){margin-bottom:8px}.SfQmhG_chevron{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;margin-left:6px;transition:transform .1s;transform:rotate(-90deg)}.SfQmhG_root[data-open] .SfQmhG_chevron{transform:rotate(0)}.SfQmhG_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:24px;overflow:hidden}@media (prefers-reduced-motion:reduce){.SfQmhG_chevron{transition:none}}";
|
|
2973
3175
|
const tagId$5 = "@prettier-ai/dsh-client-ui-chat/TurnProcessNodeView.module.css";
|
|
2974
3176
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
|
|
2975
3177
|
const tag = document.createElement("style");
|
|
@@ -3097,7 +3299,7 @@ window.__ModuleLoader__.load({
|
|
|
3097
3299
|
}
|
|
3098
3300
|
//#endregion
|
|
3099
3301
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/chat/TurnUsagePanel.module.css.mjs
|
|
3100
|
-
const css$4 = ".ZVOUHW_root{min-width:0;display:inline-flex}.ZVOUHW_root+.ZVOUHW_root{margin-left:-6px}.ZVOUHW_trigger{min-width:0;height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(24px + var(--dsh-content-font-delta,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;display:inline-flex}.ZVOUHW_label{text-overflow:ellipsis;min-width:0;overflow:hidden}.ZVOUHW_trigger svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px));flex:none}.ZVOUHW_trigger:hover,.ZVOUHW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}@media (width<=480px){.ZVOUHW_trigger{width:calc(28px + var(--dsh-content-font-delta,0px));justify-content:center;padding:6px}.ZVOUHW_trigger .ZVOUHW_label{display:none}.ZVOUHW_root+.ZVOUHW_root{margin-left:0}}.ZVOUHW_panel{z-index:1100;box-sizing:border-box;
|
|
3302
|
+
const css$4 = ".ZVOUHW_root{min-width:0;display:inline-flex}.ZVOUHW_root+.ZVOUHW_root{margin-left:-6px}.ZVOUHW_trigger{min-width:0;height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);font-variant-numeric:tabular-nums;line-height:calc(24px + var(--dsh-content-font-delta,0px));white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:28px;align-items:center;gap:4px;padding:6px 8px;display:inline-flex}.ZVOUHW_label{text-overflow:ellipsis;min-width:0;overflow:hidden}.ZVOUHW_trigger svg{width:calc(15px + var(--dsh-content-font-delta,0px));height:calc(15px + var(--dsh-content-font-delta,0px));flex:none}.ZVOUHW_trigger:hover,.ZVOUHW_trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}@media (width<=480px){.ZVOUHW_trigger{width:calc(28px + var(--dsh-content-font-delta,0px));justify-content:center;padding:6px}.ZVOUHW_trigger .ZVOUHW_label{display:none}.ZVOUHW_root+.ZVOUHW_root{margin-left:0}}.ZVOUHW_panel{z-index:1100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:max-content;min-width:min(300px,100vw - 24px);max-width:min(440px,100vw - 24px);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-secondary);cursor:default;border:0;border-radius:12px;padding:16px;font-size:12px;line-height:18px;position:fixed}.ZVOUHW_title{color:var(--dsw-alias-label-primary);justify-content:space-between;gap:16px;margin-bottom:8px;font-weight:500;display:flex}.ZVOUHW_titleRule{border-top:.5px solid var(--dsw-alias-border-l2);margin-bottom:10px}.ZVOUHW_titleValue{font-variant-numeric:tabular-nums}.ZVOUHW_titleLabel{align-items:center;gap:6px;min-width:0;display:inline-flex}.ZVOUHW_titleLabel svg{flex:none;width:14px;height:14px}.ZVOUHW_details{color:var(--dsw-alias-label-tertiary);grid-template-columns:minmax(76px,auto) minmax(0,1fr);gap:6px 16px;margin:0;display:grid}.ZVOUHW_details dt,.ZVOUHW_details dd{min-width:0;margin:0}.ZVOUHW_details dd{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;text-align:right}.ZVOUHW_details .ZVOUHW_route{overflow-wrap:anywhere}.ZVOUHW_reasoning{color:var(--dsw-alias-label-tertiary);white-space:nowrap}";
|
|
3101
3303
|
const tagId$4 = "@prettier-ai/dsh-client-ui-chat/TurnUsagePanel.module.css";
|
|
3102
3304
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
3103
3305
|
const tag = document.createElement("style");
|
|
@@ -3628,6 +3830,42 @@ window.__ModuleLoader__.load({
|
|
|
3628
3830
|
function billedInputTokens(usage) {
|
|
3629
3831
|
return usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
3630
3832
|
}
|
|
3833
|
+
/** Render and measure one non-empty statistics line. */
|
|
3834
|
+
const StatsLineContent = (0, react.memo)(function StatsLineContent({ groups, line }) {
|
|
3835
|
+
const rootRef = (0, react.useRef)(null);
|
|
3836
|
+
const [truncated, setTruncated] = (0, react.useState)(false);
|
|
3837
|
+
const measure = (0, react.useCallback)(() => {
|
|
3838
|
+
const el = rootRef.current;
|
|
3839
|
+
if (el === null) return;
|
|
3840
|
+
const next = el.scrollWidth > el.clientWidth;
|
|
3841
|
+
setTruncated((current) => current === next ? current : next);
|
|
3842
|
+
}, []);
|
|
3843
|
+
(0, react.useLayoutEffect)(() => {
|
|
3844
|
+
const el = rootRef.current;
|
|
3845
|
+
if (el === null || typeof ResizeObserver === "undefined") return;
|
|
3846
|
+
const observer = new ResizeObserver(measure);
|
|
3847
|
+
observer.observe(el);
|
|
3848
|
+
return () => {
|
|
3849
|
+
observer.disconnect();
|
|
3850
|
+
};
|
|
3851
|
+
}, [measure]);
|
|
3852
|
+
(0, react.useLayoutEffect)(measure, [line, measure]);
|
|
3853
|
+
return (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.Tooltip, {
|
|
3854
|
+
label: line,
|
|
3855
|
+
side: "top",
|
|
3856
|
+
delayMs: 500,
|
|
3857
|
+
disabled: !truncated,
|
|
3858
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
3859
|
+
ref: rootRef,
|
|
3860
|
+
className: StatsLine_module_css_default.root,
|
|
3861
|
+
children: groups.map((group, i) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [i > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
|
|
3862
|
+
className: StatsLine_module_css_default.sep,
|
|
3863
|
+
"aria-hidden": true,
|
|
3864
|
+
children: "|"
|
|
3865
|
+
}), " "] }), (0, react_jsx_runtime.jsx)("span", { children: group })] }, group))
|
|
3866
|
+
})
|
|
3867
|
+
});
|
|
3868
|
+
});
|
|
3631
3869
|
const StatsLine = (0, react.memo)(function StatsLine({ useChat, useProjection, t }) {
|
|
3632
3870
|
const settledNodes = useChat((s) => s.legacy.nodes);
|
|
3633
3871
|
const usage = useProjection("tokenUsage");
|
|
@@ -3657,37 +3895,10 @@ window.__ModuleLoader__.load({
|
|
|
3657
3895
|
}));
|
|
3658
3896
|
}
|
|
3659
3897
|
const line = groups.join(" | ");
|
|
3660
|
-
const rootRef = (0, react.useRef)(null);
|
|
3661
|
-
const [truncated, setTruncated] = (0, react.useState)(false);
|
|
3662
|
-
(0, react.useLayoutEffect)(() => {
|
|
3663
|
-
const el = rootRef.current;
|
|
3664
|
-
if (el === null) return;
|
|
3665
|
-
const measure = () => {
|
|
3666
|
-
setTruncated(el.scrollWidth > el.clientWidth);
|
|
3667
|
-
};
|
|
3668
|
-
measure();
|
|
3669
|
-
if (typeof ResizeObserver === "undefined") return;
|
|
3670
|
-
const observer = new ResizeObserver(measure);
|
|
3671
|
-
observer.observe(el);
|
|
3672
|
-
return () => {
|
|
3673
|
-
observer.disconnect();
|
|
3674
|
-
};
|
|
3675
|
-
}, [line]);
|
|
3676
3898
|
if (groups.length === 0) return null;
|
|
3677
|
-
return (0, react_jsx_runtime.jsx)(
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
delayMs: 500,
|
|
3681
|
-
disabled: !truncated,
|
|
3682
|
-
children: (0, react_jsx_runtime.jsx)("div", {
|
|
3683
|
-
ref: rootRef,
|
|
3684
|
-
className: StatsLine_module_css_default.root,
|
|
3685
|
-
children: groups.map((group, i) => (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [i > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
|
|
3686
|
-
className: StatsLine_module_css_default.sep,
|
|
3687
|
-
"aria-hidden": true,
|
|
3688
|
-
children: "|"
|
|
3689
|
-
}), " "] }), (0, react_jsx_runtime.jsx)("span", { children: group })] }, group))
|
|
3690
|
-
})
|
|
3899
|
+
return (0, react_jsx_runtime.jsx)(StatsLineContent, {
|
|
3900
|
+
groups,
|
|
3901
|
+
line
|
|
3691
3902
|
});
|
|
3692
3903
|
});
|
|
3693
3904
|
//#endregion
|
|
@@ -4245,6 +4456,10 @@ window.__ModuleLoader__.load({
|
|
|
4245
4456
|
}
|
|
4246
4457
|
};
|
|
4247
4458
|
}
|
|
4459
|
+
function publishedAssistantData(context) {
|
|
4460
|
+
const location = context.start?.location ?? context.matches.at(-1)?.location;
|
|
4461
|
+
return location?.kind === "step" ? location.step.data.get("assistant-step") : void 0;
|
|
4462
|
+
}
|
|
4248
4463
|
/** Per-step Assistant streaming/final/interruption Definition. */
|
|
4249
4464
|
const assistantDefinition = {
|
|
4250
4465
|
kind: "assistant-step",
|
|
@@ -4309,15 +4524,17 @@ window.__ModuleLoader__.load({
|
|
|
4309
4524
|
};
|
|
4310
4525
|
},
|
|
4311
4526
|
buildViewNode: (context) => {
|
|
4312
|
-
const
|
|
4313
|
-
if (
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4527
|
+
const state = context.state ?? fallbackState$5(context);
|
|
4528
|
+
if (state === void 0) return null;
|
|
4529
|
+
const data = publishedAssistantData(context);
|
|
4530
|
+
if (data === void 0) return null;
|
|
4531
|
+
const settled = data.finalNode;
|
|
4532
|
+
const visible = settled === void 0 ? state.visibleBlocks > 0 : hasVisibleContent(data.blocks);
|
|
4533
|
+
if (settled === void 0 && !visible) {
|
|
4317
4534
|
const current = context.current.get("chat");
|
|
4318
4535
|
if (!state.hidden || current === void 0 || current === null) return null;
|
|
4319
4536
|
}
|
|
4320
|
-
return chatNode(context, "assistant-step",
|
|
4537
|
+
return chatNode(context, "assistant-step", settled?.seq ?? state.firstVisibleSeq ?? context.matches[0]?.event.seq ?? 0, data, { visibility: settled?.interrupted === true || visible ? "visible" : "hidden" });
|
|
4321
4538
|
}
|
|
4322
4539
|
};
|
|
4323
4540
|
/**
|
|
@@ -4348,27 +4565,42 @@ window.__ModuleLoader__.load({
|
|
|
4348
4565
|
//#endregion
|
|
4349
4566
|
//#region lib/types/client/conversation-nodes/turn-navigation.js
|
|
4350
4567
|
/**
|
|
4351
|
-
* Preview
|
|
4352
|
-
*
|
|
4568
|
+
* Preview budgets, sized to the rail card's clamps (one prompt line, up to
|
|
4569
|
+
* three response lines) and mirrored by the turnOutline projection so a turn
|
|
4570
|
+
* shows the same words before and after its events load. Anything past a
|
|
4571
|
+
* budget is invisible; copying whole transcripts into navigation state would
|
|
4353
4572
|
* otherwise grow with the loaded window on every structural update.
|
|
4354
4573
|
*/
|
|
4355
|
-
const
|
|
4356
|
-
|
|
4357
|
-
|
|
4574
|
+
const PROMPT_PREVIEW_LIMIT = 50;
|
|
4575
|
+
const RESPONSE_PREVIEW_LIMIT = 120;
|
|
4576
|
+
/** Join rendered text, collapse whitespace, and cap at `limit` with a trailing ellipsis when clipped. */
|
|
4577
|
+
function preview(parts, limit) {
|
|
4358
4578
|
let text = "";
|
|
4579
|
+
let unread = false;
|
|
4359
4580
|
for (const part of parts) {
|
|
4360
|
-
|
|
4361
|
-
|
|
4581
|
+
if (text.length >= limit * 2) {
|
|
4582
|
+
unread = true;
|
|
4583
|
+
break;
|
|
4584
|
+
}
|
|
4585
|
+
const clipped = part.length > limit * 2;
|
|
4586
|
+
const chunk = clipped ? part.slice(0, limit * 2) : part;
|
|
4587
|
+
text += text === "" ? chunk : ` ${chunk}`;
|
|
4588
|
+
if (clipped) {
|
|
4589
|
+
unread = true;
|
|
4590
|
+
break;
|
|
4591
|
+
}
|
|
4362
4592
|
}
|
|
4363
|
-
|
|
4593
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
4594
|
+
if (normalized.length > limit - 1) return `${normalized.slice(0, limit - 1).trimEnd()}…`;
|
|
4595
|
+
return unread ? `${normalized}…` : normalized;
|
|
4364
4596
|
}
|
|
4365
4597
|
function promptText(node) {
|
|
4366
4598
|
if (node.kind !== "user") return "";
|
|
4367
|
-
return preview(node.data.content.flatMap((block) => block.type === "text" ? [block.text] : []));
|
|
4599
|
+
return preview(node.data.content.flatMap((block) => block.type === "text" ? [block.text] : []), PROMPT_PREVIEW_LIMIT);
|
|
4368
4600
|
}
|
|
4369
4601
|
function responseText(node) {
|
|
4370
4602
|
if (node.kind !== "assistant-step") return "";
|
|
4371
|
-
return preview(node.data.blocks.flatMap((block) => block.kind === "text" ? [block.text] : []));
|
|
4603
|
+
return preview(node.data.blocks.flatMap((block) => block.kind === "text" ? [block.text] : []), RESPONSE_PREVIEW_LIMIT);
|
|
4372
4604
|
}
|
|
4373
4605
|
/**
|
|
4374
4606
|
* Whether two items carry the same rail state, so the reader can keep its array.
|
|
@@ -4401,6 +4633,92 @@ window.__ModuleLoader__.load({
|
|
|
4401
4633
|
};
|
|
4402
4634
|
}
|
|
4403
4635
|
//#endregion
|
|
4636
|
+
//#region lib/types/client/conversation-nodes/turn-process-presentation.js
|
|
4637
|
+
function nodeTurn(node) {
|
|
4638
|
+
const location = node?.location;
|
|
4639
|
+
return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
|
|
4640
|
+
}
|
|
4641
|
+
function samePresentation(left, right) {
|
|
4642
|
+
return left === right || left !== void 0 && right !== void 0 && left.spec === right.spec && left.turn === right.turn && left.turnClosed === right.turnClosed && left.hasExternalProcess === right.hasExternalProcess && left.compactAnswer === right.compactAnswer;
|
|
4643
|
+
}
|
|
4644
|
+
function derivePresentation(turn, locations, nodes) {
|
|
4645
|
+
const keys = locations.getTurn(turn);
|
|
4646
|
+
const control = keys.map((key) => nodes.get(key)).find((node) => node?.kind === "turn-process");
|
|
4647
|
+
if (control === void 0) return void 0;
|
|
4648
|
+
const spec = control.data;
|
|
4649
|
+
const location = control.location;
|
|
4650
|
+
if (location.kind !== "turn" && location.kind !== "step") return void 0;
|
|
4651
|
+
let openingHumanAnchor;
|
|
4652
|
+
for (const key of keys) {
|
|
4653
|
+
const node = nodes.get(key);
|
|
4654
|
+
if ((node?.kind === "user" || node?.kind === "steering") && node.anchorSeq < spec.controlAnchorSeq) openingHumanAnchor = Math.min(openingHumanAnchor ?? node.anchorSeq, node.anchorSeq);
|
|
4655
|
+
}
|
|
4656
|
+
let hasExternalProcess = false;
|
|
4657
|
+
let compactAnswer = true;
|
|
4658
|
+
for (const key of keys) {
|
|
4659
|
+
const node = nodes.get(key);
|
|
4660
|
+
if (node === void 0 || node.kind === "turn-process") continue;
|
|
4661
|
+
if ((node.kind === "user" || node.kind === "steering") && (openingHumanAnchor === void 0 || node.anchorSeq > openingHumanAnchor) && (spec.answerAnchorSeq === null || node.anchorSeq < spec.answerAnchorSeq)) compactAnswer = false;
|
|
4662
|
+
if (TURN_PROCESS_INDEPENDENT_KINDS.has(node.kind) || node.anchorSeq < spec.processStartSeq || spec.answerAnchorSeq !== null && node.anchorSeq >= spec.answerAnchorSeq) continue;
|
|
4663
|
+
if (node.kind !== "assistant-step" || spec.answerStep === null || node.data.step !== spec.answerStep) hasExternalProcess = true;
|
|
4664
|
+
}
|
|
4665
|
+
return {
|
|
4666
|
+
turn,
|
|
4667
|
+
spec,
|
|
4668
|
+
turnClosed: location.turn.status === "closed",
|
|
4669
|
+
hasExternalProcess,
|
|
4670
|
+
compactAnswer
|
|
4671
|
+
};
|
|
4672
|
+
}
|
|
4673
|
+
/** Mutable projection of cross-Node process layout facts by Turn. */
|
|
4674
|
+
var ChatTurnProcessProjector = class {
|
|
4675
|
+
presentations = /* @__PURE__ */ new Map();
|
|
4676
|
+
/**
|
|
4677
|
+
* Read the retained process presentation for a Node's Turn.
|
|
4678
|
+
* @param node - Current Chat Node.
|
|
4679
|
+
* @returns The Turn's process presentation, when present.
|
|
4680
|
+
*/
|
|
4681
|
+
get(node) {
|
|
4682
|
+
const turn = nodeTurn(node);
|
|
4683
|
+
return turn === void 0 ? void 0 : this.presentations.get(turn);
|
|
4684
|
+
}
|
|
4685
|
+
/**
|
|
4686
|
+
* Replace every projected Turn.
|
|
4687
|
+
* @param order - visible Chat Node order.
|
|
4688
|
+
* @param locations - current Chat Location index.
|
|
4689
|
+
* @param nodes - current Chat Node store.
|
|
4690
|
+
* @returns Turns whose process presentation changed.
|
|
4691
|
+
*/
|
|
4692
|
+
replace(order, locations, nodes) {
|
|
4693
|
+
const turns = /* @__PURE__ */ new Set();
|
|
4694
|
+
for (const key of order) {
|
|
4695
|
+
const turn = nodeTurn(nodes.get(key));
|
|
4696
|
+
if (turn !== void 0) turns.add(turn);
|
|
4697
|
+
}
|
|
4698
|
+
const changed = /* @__PURE__ */ new Set();
|
|
4699
|
+
for (const turn of new Set([...this.presentations.keys(), ...turns])) if (this.set(turn, turns.has(turn) ? derivePresentation(turn, locations, nodes) : void 0)) changed.add(turn);
|
|
4700
|
+
return changed;
|
|
4701
|
+
}
|
|
4702
|
+
/**
|
|
4703
|
+
* Recompute selected Turns after incremental Node changes.
|
|
4704
|
+
* @param turns - affected Turn numbers.
|
|
4705
|
+
* @param locations - current Chat Location index.
|
|
4706
|
+
* @param nodes - current Chat Node store.
|
|
4707
|
+
* @returns Turns whose process presentation changed.
|
|
4708
|
+
*/
|
|
4709
|
+
update(turns, locations, nodes) {
|
|
4710
|
+
const changed = /* @__PURE__ */ new Set();
|
|
4711
|
+
for (const turn of turns) if (this.set(turn, derivePresentation(turn, locations, nodes))) changed.add(turn);
|
|
4712
|
+
return changed;
|
|
4713
|
+
}
|
|
4714
|
+
set(turn, next) {
|
|
4715
|
+
if (samePresentation(this.presentations.get(turn), next)) return false;
|
|
4716
|
+
if (next === void 0) this.presentations.delete(turn);
|
|
4717
|
+
else this.presentations.set(turn, next);
|
|
4718
|
+
return true;
|
|
4719
|
+
}
|
|
4720
|
+
};
|
|
4721
|
+
//#endregion
|
|
4404
4722
|
//#region lib/types/client/conversation-nodes/chat-snapshot-builder.js
|
|
4405
4723
|
const EMPTY_KEYS = [];
|
|
4406
4724
|
const EMPTY_TURNS = [];
|
|
@@ -4409,13 +4727,59 @@ window.__ModuleLoader__.load({
|
|
|
4409
4727
|
function sameReferences$1(left, right) {
|
|
4410
4728
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
4411
4729
|
}
|
|
4730
|
+
function cachedSource(sources, key, create) {
|
|
4731
|
+
let source = sources.get(key);
|
|
4732
|
+
if (source === void 0) {
|
|
4733
|
+
source = create();
|
|
4734
|
+
sources.set(key, source);
|
|
4735
|
+
}
|
|
4736
|
+
return source;
|
|
4737
|
+
}
|
|
4738
|
+
var MutableChatSource = class {
|
|
4739
|
+
read;
|
|
4740
|
+
label;
|
|
4741
|
+
listeners = /* @__PURE__ */ new Set();
|
|
4742
|
+
published;
|
|
4743
|
+
constructor(read, label) {
|
|
4744
|
+
this.read = read;
|
|
4745
|
+
this.label = label;
|
|
4746
|
+
this.published = read();
|
|
4747
|
+
}
|
|
4748
|
+
getSnapshot = () => this.read();
|
|
4749
|
+
subscribe = (listener) => {
|
|
4750
|
+
this.listeners.add(listener);
|
|
4751
|
+
return () => {
|
|
4752
|
+
this.listeners.delete(listener);
|
|
4753
|
+
};
|
|
4754
|
+
};
|
|
4755
|
+
publish() {
|
|
4756
|
+
const next = this.getSnapshot();
|
|
4757
|
+
if (this.published === next) return;
|
|
4758
|
+
this.published = next;
|
|
4759
|
+
(0, _prettier_ai_dsh_client_store.notifySubscribers)(this.listeners, this.label);
|
|
4760
|
+
}
|
|
4761
|
+
};
|
|
4412
4762
|
var MutableChatNodeStore = class {
|
|
4413
4763
|
byKey = /* @__PURE__ */ new Map();
|
|
4764
|
+
turnProcesses = new ChatTurnProcessProjector();
|
|
4765
|
+
sources = /* @__PURE__ */ new Map();
|
|
4766
|
+
processSources = /* @__PURE__ */ new Map();
|
|
4767
|
+
dirtyKeys = /* @__PURE__ */ new Set();
|
|
4768
|
+
dirtyProcessKeys = /* @__PURE__ */ new Set();
|
|
4414
4769
|
valuesCache = EMPTY_LIST;
|
|
4415
4770
|
valuesDirty = false;
|
|
4416
4771
|
get(key) {
|
|
4417
4772
|
return this.byKey.get(key);
|
|
4418
4773
|
}
|
|
4774
|
+
source(key) {
|
|
4775
|
+
return cachedSource(this.sources, key, () => new MutableChatSource(() => this.get(key), `[ui-chat] node source ${key}`));
|
|
4776
|
+
}
|
|
4777
|
+
processSource(key) {
|
|
4778
|
+
return cachedSource(this.processSources, key, () => new MutableChatSource(() => this.process(key), `[ui-chat] node process source ${key}`));
|
|
4779
|
+
}
|
|
4780
|
+
process(key) {
|
|
4781
|
+
return this.turnProcesses.get(this.get(key));
|
|
4782
|
+
}
|
|
4419
4783
|
values() {
|
|
4420
4784
|
if (this.valuesDirty) {
|
|
4421
4785
|
this.valuesCache = [...this.byKey.values()];
|
|
@@ -4424,8 +4788,20 @@ window.__ModuleLoader__.load({
|
|
|
4424
4788
|
return this.valuesCache;
|
|
4425
4789
|
}
|
|
4426
4790
|
replace(nodes) {
|
|
4791
|
+
const previous = new Map(this.byKey);
|
|
4427
4792
|
this.byKey.clear();
|
|
4428
|
-
for (const node of nodes)
|
|
4793
|
+
for (const node of nodes) {
|
|
4794
|
+
this.byKey.set(node.key, node);
|
|
4795
|
+
if (previous.get(node.key) !== node) {
|
|
4796
|
+
this.dirtyKeys.add(node.key);
|
|
4797
|
+
this.dirtyProcessKeys.add(node.key);
|
|
4798
|
+
}
|
|
4799
|
+
previous.delete(node.key);
|
|
4800
|
+
}
|
|
4801
|
+
for (const key of previous.keys()) {
|
|
4802
|
+
this.dirtyKeys.add(key);
|
|
4803
|
+
this.dirtyProcessKeys.add(key);
|
|
4804
|
+
}
|
|
4429
4805
|
this.valuesCache = [...this.byKey.values()];
|
|
4430
4806
|
this.valuesDirty = false;
|
|
4431
4807
|
}
|
|
@@ -4434,10 +4810,29 @@ window.__ModuleLoader__.load({
|
|
|
4434
4810
|
for (const node of nodes) {
|
|
4435
4811
|
if (this.byKey.get(node.key) === node) continue;
|
|
4436
4812
|
this.byKey.set(node.key, node);
|
|
4813
|
+
this.dirtyKeys.add(node.key);
|
|
4814
|
+
this.dirtyProcessKeys.add(node.key);
|
|
4437
4815
|
changed = true;
|
|
4438
4816
|
}
|
|
4439
4817
|
if (changed) this.valuesDirty = true;
|
|
4440
4818
|
}
|
|
4819
|
+
touchProcesses(turns, locations) {
|
|
4820
|
+
for (const turn of turns) for (const key of locations.getTurn(turn)) this.dirtyProcessKeys.add(key);
|
|
4821
|
+
}
|
|
4822
|
+
replaceProcesses(order, locations) {
|
|
4823
|
+
this.touchProcesses(this.turnProcesses.replace(order, locations, this), locations);
|
|
4824
|
+
}
|
|
4825
|
+
updateProcesses(turns, locations) {
|
|
4826
|
+
this.touchProcesses(this.turnProcesses.update(turns, locations, this), locations);
|
|
4827
|
+
}
|
|
4828
|
+
publish() {
|
|
4829
|
+
const dirty = [...this.dirtyKeys];
|
|
4830
|
+
const dirtyProcesses = [...this.dirtyProcessKeys];
|
|
4831
|
+
this.dirtyKeys.clear();
|
|
4832
|
+
this.dirtyProcessKeys.clear();
|
|
4833
|
+
for (const key of dirty) this.sources.get(key)?.publish();
|
|
4834
|
+
for (const key of dirtyProcesses) this.processSources.get(key)?.publish();
|
|
4835
|
+
}
|
|
4441
4836
|
};
|
|
4442
4837
|
var MutableChatLocationIndex = class {
|
|
4443
4838
|
turns = /* @__PURE__ */ new Map();
|
|
@@ -4553,6 +4948,15 @@ window.__ModuleLoader__.load({
|
|
|
4553
4948
|
if (location.kind === "turn") return { turn: location.turn.turn };
|
|
4554
4949
|
return {};
|
|
4555
4950
|
}
|
|
4951
|
+
function locationTurnStatus(location) {
|
|
4952
|
+
return location.kind === "turn" || location.kind === "step" ? location.turn.status : void 0;
|
|
4953
|
+
}
|
|
4954
|
+
function processPresentationInputChanged(previous, next, structural) {
|
|
4955
|
+
if (structural || previous === void 0) return true;
|
|
4956
|
+
if (locationTurnStatus(previous.location) !== locationTurnStatus(next.location)) return true;
|
|
4957
|
+
if (previous.kind === "turn-process" && next.kind === "turn-process") return previous.data !== next.data;
|
|
4958
|
+
return previous.kind === "assistant-step" && next.kind === "assistant-step" && previous.data.step !== next.data.step;
|
|
4959
|
+
}
|
|
4556
4960
|
function turnProcessPresentations(nodes) {
|
|
4557
4961
|
const presentations = /* @__PURE__ */ new Map();
|
|
4558
4962
|
for (const raw of nodes) {
|
|
@@ -4911,12 +5315,16 @@ window.__ModuleLoader__.load({
|
|
|
4911
5315
|
this.store.replace(nodes);
|
|
4912
5316
|
this.order = orderedVisibleChatNodes(nodes).map((node) => node.key);
|
|
4913
5317
|
this.locations.rebuild(this.order, this.store);
|
|
5318
|
+
this.store.replaceProcesses(this.order, this.locations);
|
|
4914
5319
|
this.navigation.rebuild(input.timeline, this.locations, this.store);
|
|
4915
5320
|
this.timeline = input.timeline;
|
|
4916
|
-
|
|
5321
|
+
const snapshot = this.snapshot(input.timeline, this.legacy.replace(nodes, input.timeline));
|
|
5322
|
+
this.store.publish();
|
|
5323
|
+
return snapshot;
|
|
4917
5324
|
}
|
|
4918
5325
|
apply(input) {
|
|
4919
5326
|
const upserts = this.referenceLabels.apply(input.upserts, this.store);
|
|
5327
|
+
const processTurns = /* @__PURE__ */ new Set();
|
|
4920
5328
|
let structural = false;
|
|
4921
5329
|
const contentOnly = [];
|
|
4922
5330
|
for (const node of upserts) {
|
|
@@ -4924,6 +5332,12 @@ window.__ModuleLoader__.load({
|
|
|
4924
5332
|
const nodeStructural = previous === void 0 || previous.kind !== node.kind || previous.anchorSeq !== node.anchorSeq || previous.visibility !== node.visibility || locationIdentity(previous.location) !== locationIdentity(node.location);
|
|
4925
5333
|
structural ||= nodeStructural;
|
|
4926
5334
|
if (!nodeStructural) contentOnly.push(node);
|
|
5335
|
+
if (processPresentationInputChanged(previous, node, nodeStructural)) {
|
|
5336
|
+
const previousTurn = previous === void 0 ? void 0 : locationCoordinates(previous.location).turn;
|
|
5337
|
+
const nextTurn = locationCoordinates(node.location).turn;
|
|
5338
|
+
if (previousTurn !== void 0) processTurns.add(previousTurn);
|
|
5339
|
+
if (nextTurn !== void 0) processTurns.add(nextTurn);
|
|
5340
|
+
}
|
|
4927
5341
|
}
|
|
4928
5342
|
this.store.upsert(upserts);
|
|
4929
5343
|
if (structural) {
|
|
@@ -4932,10 +5346,13 @@ window.__ModuleLoader__.load({
|
|
|
4932
5346
|
this.locations.rebuild(this.order, this.store);
|
|
4933
5347
|
}
|
|
4934
5348
|
this.locations.touch(contentOnly);
|
|
5349
|
+
this.store.updateProcesses(processTurns, this.locations);
|
|
4935
5350
|
if (structural || input.timeline !== this.timeline) this.navigation.rebuild(input.timeline, this.locations, this.store);
|
|
4936
5351
|
else this.navigation.touch(turnsOf(contentOnly), this.locations, this.store);
|
|
4937
5352
|
this.timeline = input.timeline;
|
|
4938
|
-
|
|
5353
|
+
const snapshot = this.snapshot(input.timeline, this.legacy.apply(upserts, input.timeline));
|
|
5354
|
+
this.store.publish();
|
|
5355
|
+
return snapshot;
|
|
4939
5356
|
}
|
|
4940
5357
|
snapshot(timeline, legacy = this.legacy.replace(EMPTY_LIST, timeline)) {
|
|
4941
5358
|
return {
|
|
@@ -5224,43 +5641,87 @@ window.__ModuleLoader__.load({
|
|
|
5224
5641
|
}
|
|
5225
5642
|
//#endregion
|
|
5226
5643
|
//#region lib/types/client/conversation-nodes/inbox.js
|
|
5644
|
+
const EMPTY_PENDING = {
|
|
5645
|
+
kind: "snapshot",
|
|
5646
|
+
ids: []
|
|
5647
|
+
};
|
|
5648
|
+
const EMPTY_CURRENT_CLAIMED = /* @__PURE__ */ new Set();
|
|
5649
|
+
function materializePending(state) {
|
|
5650
|
+
const splices = [];
|
|
5651
|
+
let current = state;
|
|
5652
|
+
while (current.kind === "splice") {
|
|
5653
|
+
splices.push(current);
|
|
5654
|
+
current = current.previous;
|
|
5655
|
+
}
|
|
5656
|
+
const pending = [...current.ids];
|
|
5657
|
+
for (const splice of splices.reverse()) pending.splice(splice.start, splice.removedCount, ...splice.inserted);
|
|
5658
|
+
return pending;
|
|
5659
|
+
}
|
|
5660
|
+
function withoutInserted(claimed, inserted) {
|
|
5661
|
+
let next;
|
|
5662
|
+
for (const id of inserted) {
|
|
5663
|
+
if (!claimed.has(id)) continue;
|
|
5664
|
+
next ??= new Set(claimed);
|
|
5665
|
+
next.delete(id);
|
|
5666
|
+
}
|
|
5667
|
+
return next ?? claimed;
|
|
5668
|
+
}
|
|
5669
|
+
/**
|
|
5670
|
+
* Apply one next-step splice under the AgentLoop's durable event ordering.
|
|
5671
|
+
* An entered claim logs its complete message batch before another claim; a
|
|
5672
|
+
* rejected claim logs no messages, so only the current claim can classify a
|
|
5673
|
+
* later `user/message`.
|
|
5674
|
+
*/
|
|
5227
5675
|
function applySplice(previous, splice) {
|
|
5228
|
-
const
|
|
5229
|
-
const
|
|
5230
|
-
const
|
|
5231
|
-
|
|
5232
|
-
|
|
5676
|
+
const priorPending = previous?.state.pending ?? EMPTY_PENDING;
|
|
5677
|
+
const inserted = splice.inserted.map((identity) => identity.id);
|
|
5678
|
+
const removedCount = splice.removedCount ?? 0;
|
|
5679
|
+
if (removedCount > 0 && splice.outcome !== "canceled") {
|
|
5680
|
+
const pending = materializePending(priorPending);
|
|
5681
|
+
const removed = pending.splice(splice.start, removedCount, ...inserted);
|
|
5682
|
+
return {
|
|
5683
|
+
pending: {
|
|
5684
|
+
kind: "snapshot",
|
|
5685
|
+
ids: pending
|
|
5686
|
+
},
|
|
5687
|
+
currentClaimed: new Set(removed)
|
|
5688
|
+
};
|
|
5689
|
+
}
|
|
5690
|
+
const currentClaimed = withoutInserted(previous?.state.currentClaimed ?? EMPTY_CURRENT_CLAIMED, inserted);
|
|
5233
5691
|
return {
|
|
5234
|
-
pending
|
|
5235
|
-
|
|
5692
|
+
pending: {
|
|
5693
|
+
kind: "splice",
|
|
5694
|
+
previous: priorPending,
|
|
5695
|
+
start: splice.start,
|
|
5696
|
+
removedCount,
|
|
5697
|
+
inserted
|
|
5698
|
+
},
|
|
5699
|
+
currentClaimed
|
|
5236
5700
|
};
|
|
5237
5701
|
}
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5702
|
+
const NEXT_STEP_INBOX_KIND = "inbox-next-step";
|
|
5703
|
+
/** Persistent next-step Inbox state used to classify the current claimed batch as steering. */
|
|
5704
|
+
const nextStepInboxDefinition = {
|
|
5705
|
+
kind: NEXT_STEP_INBOX_KIND,
|
|
5706
|
+
match: (event) => {
|
|
5707
|
+
if (event.type === "agent/inbox/spliced" && event.data.target === "next-step") return {
|
|
5243
5708
|
id: String(event.seq),
|
|
5244
5709
|
role: "start"
|
|
5245
|
-
}
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
const nextTurnInboxDefinition = inboxDefinition("next-turn");
|
|
5256
|
-
/** Cumulative next-step inbox splice Definition used to classify steering. */
|
|
5257
|
-
const nextStepInboxDefinition = inboxDefinition("next-step");
|
|
5710
|
+
};
|
|
5711
|
+
return null;
|
|
5712
|
+
},
|
|
5713
|
+
start: (_context, match, reader) => {
|
|
5714
|
+
if (match.event.type !== "agent/inbox/spliced") throw new Error("inbox-next-step start requires agent/inbox/spliced");
|
|
5715
|
+
return applySplice(reader.previous(NEXT_STEP_INBOX_KIND), match.event.data);
|
|
5716
|
+
},
|
|
5717
|
+
update: (context) => context.state,
|
|
5718
|
+
publication: () => "none"
|
|
5719
|
+
};
|
|
5258
5720
|
/**
|
|
5259
|
-
* Register the
|
|
5721
|
+
* Register the next-step Inbox state used by Chat message classification.
|
|
5260
5722
|
* @param ctx - owning UI Conversation context.
|
|
5261
5723
|
*/
|
|
5262
5724
|
function registerInboxConversationNodes(ctx) {
|
|
5263
|
-
ctx.uiConversation.events.register(nextTurnInboxDefinition);
|
|
5264
5725
|
ctx.uiConversation.events.register(nextStepInboxDefinition);
|
|
5265
5726
|
}
|
|
5266
5727
|
//#endregion
|
|
@@ -5290,7 +5751,7 @@ window.__ModuleLoader__.load({
|
|
|
5290
5751
|
provenance: contextProvenance(event.data.source),
|
|
5291
5752
|
form: contextForm(event.data.source)
|
|
5292
5753
|
};
|
|
5293
|
-
return reader.previous("inbox-next-step")?.state.
|
|
5754
|
+
return reader.previous("inbox-next-step")?.state.currentClaimed.has(String(event.data.id)) === true ? {
|
|
5294
5755
|
kind: "steering",
|
|
5295
5756
|
messageId: event.data.id,
|
|
5296
5757
|
seq: event.seq,
|
|
@@ -5933,6 +6394,7 @@ window.__ModuleLoader__.load({
|
|
|
5933
6394
|
turn,
|
|
5934
6395
|
assistantStartByStep: /* @__PURE__ */ new Map(),
|
|
5935
6396
|
messageCountByStep: /* @__PURE__ */ new Map(),
|
|
6397
|
+
messageCount: 0,
|
|
5936
6398
|
toolCallCount: 0,
|
|
5937
6399
|
subagentCount: 0
|
|
5938
6400
|
};
|
|
@@ -5948,11 +6410,11 @@ window.__ModuleLoader__.load({
|
|
|
5948
6410
|
return data.blocks.some((block) => block.kind === "tool-call") ? null : data;
|
|
5949
6411
|
}
|
|
5950
6412
|
function processSpec(state, turn) {
|
|
5951
|
-
const controlAnchorSeq =
|
|
5952
|
-
if (
|
|
6413
|
+
const controlAnchorSeq = state.controlAnchorSeq;
|
|
6414
|
+
if (controlAnchorSeq === void 0) return null;
|
|
5953
6415
|
const answer = latestAnswer(turn);
|
|
5954
6416
|
const counts = {
|
|
5955
|
-
messageCount: answer === null ?
|
|
6417
|
+
messageCount: answer === null ? state.messageCount : [...state.messageCountByStep].filter(([step]) => step < answer.step).reduce((total, [, count]) => total + count, 0),
|
|
5956
6418
|
toolCallCount: state.toolCallCount,
|
|
5957
6419
|
subagentCount: state.subagentCount
|
|
5958
6420
|
};
|
|
@@ -5985,7 +6447,8 @@ window.__ModuleLoader__.load({
|
|
|
5985
6447
|
messageCountByStep.set(event.data.step, (messageCountByStep.get(event.data.step) ?? 0) + 1);
|
|
5986
6448
|
current = {
|
|
5987
6449
|
...current,
|
|
5988
|
-
messageCountByStep
|
|
6450
|
+
messageCountByStep,
|
|
6451
|
+
messageCount: current.messageCount + 1
|
|
5989
6452
|
};
|
|
5990
6453
|
}
|
|
5991
6454
|
if (event.type === "tool/call") {
|
|
@@ -6000,14 +6463,16 @@ window.__ModuleLoader__.load({
|
|
|
6000
6463
|
if (evidence === void 0) return current;
|
|
6001
6464
|
if (evidence.kind === "other") return current.otherStartSeq === void 0 ? {
|
|
6002
6465
|
...current,
|
|
6003
|
-
otherStartSeq: evidence.seq
|
|
6466
|
+
otherStartSeq: evidence.seq,
|
|
6467
|
+
controlAnchorSeq: Math.min(current.controlAnchorSeq ?? Number.POSITIVE_INFINITY, evidence.seq)
|
|
6004
6468
|
} : current;
|
|
6005
6469
|
if (current.assistantStartByStep.has(evidence.step)) return current;
|
|
6006
6470
|
const assistantStartByStep = new Map(current.assistantStartByStep);
|
|
6007
6471
|
assistantStartByStep.set(evidence.step, evidence.seq);
|
|
6008
6472
|
return {
|
|
6009
6473
|
...current,
|
|
6010
|
-
assistantStartByStep
|
|
6474
|
+
assistantStartByStep,
|
|
6475
|
+
controlAnchorSeq: Math.min(current.controlAnchorSeq ?? Number.POSITIVE_INFINITY, evidence.seq)
|
|
6011
6476
|
};
|
|
6012
6477
|
}
|
|
6013
6478
|
/** Turn-scoped process range and answer-boundary Definition. */
|
|
@@ -6033,6 +6498,7 @@ window.__ModuleLoader__.load({
|
|
|
6033
6498
|
turn: match.event.data.turn,
|
|
6034
6499
|
assistantStartByStep: /* @__PURE__ */ new Map(),
|
|
6035
6500
|
messageCountByStep: /* @__PURE__ */ new Map(),
|
|
6501
|
+
messageCount: 0,
|
|
6036
6502
|
toolCallCount: 0,
|
|
6037
6503
|
subagentCount: 0
|
|
6038
6504
|
};
|
|
@@ -6046,25 +6512,32 @@ window.__ModuleLoader__.load({
|
|
|
6046
6512
|
}
|
|
6047
6513
|
return "immediate";
|
|
6048
6514
|
},
|
|
6049
|
-
buildLocationData: (context, scope) => {
|
|
6515
|
+
buildLocationData: (context, scope, previous) => {
|
|
6050
6516
|
if (scope !== "turn") return null;
|
|
6051
6517
|
const state = context.state ?? fallbackState(context);
|
|
6052
6518
|
if (state === void 0) return null;
|
|
6053
6519
|
const turn = turnLocation$1(context);
|
|
6054
6520
|
if (turn === void 0) return null;
|
|
6521
|
+
const current = context.current.get("chat");
|
|
6522
|
+
const latestStep = turn.steps.at(-1);
|
|
6523
|
+
if (previous?.kind === "turn" && previous.key === "turn-process" && current?.kind === "turn-process" && current.data.answerAnchorSeq === null && current.data.controlAnchorSeq === state.controlAnchorSeq && current.data.messageCount === state.messageCount && current.data.toolCallCount === state.toolCallCount && current.data.subagentCount === state.subagentCount && turn.status !== "closed" && latestStep?.status !== "closed") return previous;
|
|
6055
6524
|
const spec = processSpec(state, turn);
|
|
6056
|
-
|
|
6525
|
+
if (spec === null) return null;
|
|
6526
|
+
if (previous?.kind === "turn" && previous.turn === spec.turn && previous.key === "turn-process" && sameTurnProcessSpec(previous.value, spec)) return previous;
|
|
6527
|
+
return {
|
|
6057
6528
|
kind: "turn",
|
|
6058
6529
|
turn: turn.turn,
|
|
6059
6530
|
key: "turn-process",
|
|
6060
|
-
value:
|
|
6531
|
+
value: spec
|
|
6061
6532
|
};
|
|
6062
6533
|
},
|
|
6063
6534
|
buildViewNode: (context) => {
|
|
6064
6535
|
const turn = turnLocation$1(context);
|
|
6065
|
-
const
|
|
6066
|
-
if (turn === void 0 ||
|
|
6067
|
-
const
|
|
6536
|
+
const data = turn?.data.get("turn-process");
|
|
6537
|
+
if (turn === void 0 || data === void 0) return null;
|
|
6538
|
+
const current = context.current.get("chat");
|
|
6539
|
+
const state = context.state;
|
|
6540
|
+
if (current?.kind === "turn-process" && state !== void 0 && current.data.answerAnchorSeq === null && current.data.controlAnchorSeq === state.controlAnchorSeq && current.data.messageCount === state.messageCount && current.data.toolCallCount === state.toolCallCount && current.data.subagentCount === state.subagentCount && turn.status !== "closed" && turn.steps.at(-1)?.status !== "closed" && current.location === (context.start?.location ?? context.matches[0]?.location)) return current;
|
|
6068
6541
|
return chatNode(context, "turn-process", data.controlAnchorSeq + CHAT_SYNTHETIC_SEQ_OFFSETS.processControl, data);
|
|
6069
6542
|
}
|
|
6070
6543
|
};
|
|
@@ -6354,7 +6827,7 @@ window.__ModuleLoader__.load({
|
|
|
6354
6827
|
return data.finalNode !== void 0 && data.blocks.some((block) => block.kind === "text" && block.text.trim() !== "");
|
|
6355
6828
|
}
|
|
6356
6829
|
function tailData(context) {
|
|
6357
|
-
const end = context.state
|
|
6830
|
+
const end = context.state === void 0 ? context.matches.find((match) => match.event.type === "turn/end") : context.state.end;
|
|
6358
6831
|
if (end?.event.type !== "turn/end") return null;
|
|
6359
6832
|
const turn = turnLocation(context);
|
|
6360
6833
|
if (turn === void 0) return null;
|
|
@@ -6484,7 +6957,7 @@ window.__ModuleLoader__.load({
|
|
|
6484
6957
|
}
|
|
6485
6958
|
//#endregion
|
|
6486
6959
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/details/DetailsPanel.module.css.mjs
|
|
6487
|
-
const css$1 = "._9bk3za_root{border-left
|
|
6960
|
+
const css$1 = "._9bk3za_root{border-left:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex-direction:column;min-width:0;height:100%;display:flex}._9bk3za_header{border-bottom:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;padding:14px 12px 12px;display:flex}._9bk3za_title{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:500;line-height:20px;overflow:hidden}._9bk3za_close{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:999px;flex:none;place-items:center;display:grid}._9bk3za_close:hover{background:var(--dsw-alias-interactive-bg-hover)}._9bk3za_body{flex:1;min-height:0;padding:12px 16px;overflow-y:auto}._9bk3za_empty{color:var(--dsw-alias-label-tertiary);padding:8px 0;font-size:13px;line-height:20px}._9bk3za_section{margin-bottom:16px}._9bk3za_sectionLabel{color:var(--dsw-alias-label-secondary);margin-bottom:6px;font-size:12px;font-weight:500;line-height:18px}._9bk3za_code{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:12px;margin:0;padding:16px;font-size:13px;line-height:22px}._9bk3za_code[data-error]{color:var(--dsw-alias-state-error-primary)}";
|
|
6488
6961
|
const tagId$1 = "@prettier-ai/dsh-client-ui-chat/DetailsPanel.module.css";
|
|
6489
6962
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
6490
6963
|
const tag = document.createElement("style");
|
|
@@ -6612,7 +7085,7 @@ window.__ModuleLoader__.load({
|
|
|
6612
7085
|
}
|
|
6613
7086
|
//#endregion
|
|
6614
7087
|
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-chat/src/client/settings/TranscriptViewRow.module.css.mjs
|
|
6615
|
-
const css = ".EKfs7G_row{border-bottom
|
|
7088
|
+
const css = ".EKfs7G_row{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.EKfs7G_rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.EKfs7G_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.EKfs7G_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.EKfs7G_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.EKfs7G_selector:hover{background:var(--dsw-alias-interactive-bg-hover)}.EKfs7G_chevron{flex:none}";
|
|
6616
7089
|
const tagId = "@prettier-ai/dsh-client-ui-chat/TranscriptViewRow.module.css";
|
|
6617
7090
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
6618
7091
|
const tag = document.createElement("style");
|
|
@@ -7530,12 +8003,25 @@ window.__ModuleLoader__.load({
|
|
|
7530
8003
|
}
|
|
7531
8004
|
};
|
|
7532
8005
|
//#endregion
|
|
8006
|
+
//#region lib/types/client/chat/use-turn-data.js
|
|
8007
|
+
const EMPTY_SOURCE = {
|
|
8008
|
+
getSnapshot: () => void 0,
|
|
8009
|
+
subscribe: () => () => {}
|
|
8010
|
+
};
|
|
8011
|
+
/**
|
|
8012
|
+
* Subscribe to one value from a Turn's keyed Location-data store.
|
|
8013
|
+
* @param data - current Turn data store, or absence for a Node outside a Turn.
|
|
8014
|
+
* @param key - declaration-merged business key.
|
|
8015
|
+
* @returns the current value for that key.
|
|
8016
|
+
*/
|
|
8017
|
+
function useTurnDataValue(data, key) {
|
|
8018
|
+
const source = data?.source(key) ?? EMPTY_SOURCE;
|
|
8019
|
+
return (0, react.useSyncExternalStore)(source.subscribe, source.getSnapshot);
|
|
8020
|
+
}
|
|
8021
|
+
//#endregion
|
|
7533
8022
|
//#region lib/types/client/apply.js
|
|
7534
|
-
const CHAT_NODE_INJECT = { hooks: { turnData: (
|
|
7535
|
-
return
|
|
7536
|
-
const location = snapshot.nodes.get(nodeKey)?.location;
|
|
7537
|
-
return location?.kind === "turn" || location?.kind === "step" ? location.turn.data.get(key) : void 0;
|
|
7538
|
-
});
|
|
8023
|
+
const CHAT_NODE_INJECT = { hooks: { turnData: (_standard, data) => function useTurnData(key) {
|
|
8024
|
+
return useTurnDataValue(data, key);
|
|
7539
8025
|
} } };
|
|
7540
8026
|
/** Services required by the Chat target and its presentation registrations. */
|
|
7541
8027
|
const inject = [
|
|
@@ -7613,10 +8099,16 @@ window.__ModuleLoader__.load({
|
|
|
7613
8099
|
},
|
|
7614
8100
|
store: chatStore,
|
|
7615
8101
|
inject: (sessionId, actions) => {
|
|
7616
|
-
const
|
|
7617
|
-
if (
|
|
8102
|
+
const binding = ctx.sessions.binding(sessionId);
|
|
8103
|
+
if (binding === void 0) throw new Error(`ui-chat: unknown session "${sessionId}"`);
|
|
8104
|
+
const session = binding.session;
|
|
8105
|
+
const chat = chatSource(binding);
|
|
7618
8106
|
return {
|
|
7619
8107
|
hooks: { transcriptView: transcriptView.mode },
|
|
8108
|
+
keyedHooks: {
|
|
8109
|
+
chatNode: (key) => chat.getSnapshot().nodes.source(key),
|
|
8110
|
+
chatNodeProcess: (key) => chat.getSnapshot().nodes.processSource(key)
|
|
8111
|
+
},
|
|
7620
8112
|
openDetails: (target) => {
|
|
7621
8113
|
actions.select(target);
|
|
7622
8114
|
ctx.layout.openDetails();
|
|
@@ -7630,6 +8122,7 @@ window.__ModuleLoader__.load({
|
|
|
7630
8122
|
loadOlder: () => {
|
|
7631
8123
|
session.loadOlder();
|
|
7632
8124
|
},
|
|
8125
|
+
loadThrough: (seq) => session.loadThrough(seq),
|
|
7633
8126
|
loadImage: Object.assign((attachment) => ctx.uiConversation.imageUrl(sessionId, attachment), { peek: (attachment) => ctx.uiConversation.peekImageUrl(sessionId, attachment) }),
|
|
7634
8127
|
chatScroll: {
|
|
7635
8128
|
save: (position) => {
|