@qilin-agent/client-ui-chat 3.1.4 → 3.1.6
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 +11 -11
- package/README.md +10 -6
- package/README.zh.md +10 -6
- package/lib/client.js +784 -220
- package/lib/index.js +21 -7
- package/lib/types/chat-settings.d.ts +11 -0
- package/lib/types/client/chat/ChatNodeSeat.d.ts +3 -1
- package/lib/types/client/chat/flow-motion.d.ts +50 -6
- package/lib/types/client/chat/use-chat-reading.d.ts +11 -1
- package/lib/types/client/chat/use-chat-viewport.d.ts +65 -33
- package/lib/types/client/locale.d.ts +14 -0
- package/lib/types/client/presentation-policy.d.ts +7 -10
- package/lib/types/client/settings/TranscriptViewRow.d.ts +3 -3
- package/lib/types/client/transcript-view.d.ts +3 -3
- package/lib/types/index.d.ts +30 -4
- package/package.json +40 -40
package/lib/client.js
CHANGED
|
@@ -906,7 +906,7 @@ window.__ModuleLoader__.load({
|
|
|
906
906
|
const location = node?.location;
|
|
907
907
|
if (location?.kind !== "turn" && location?.kind !== "step") return false;
|
|
908
908
|
const reason = location.turn.end?.data.reason.kind;
|
|
909
|
-
return location.turn.status === "open" || reason === "aborted" || reason === "error";
|
|
909
|
+
return location.turn.status === "open" || reason === "aborted" || reason === "interrupted" || reason === "error";
|
|
910
910
|
}
|
|
911
911
|
//#endregion
|
|
912
912
|
//#region lib/types/client/stores.js
|
|
@@ -997,9 +997,10 @@ window.__ModuleLoader__.load({
|
|
|
997
997
|
//#endregion
|
|
998
998
|
//#region lib/types/client/chat/flow-motion.js
|
|
999
999
|
/**
|
|
1000
|
-
*
|
|
1001
|
-
* the
|
|
1002
|
-
* Motion is opt-in under `[data-chat-motion]`, respects reduced motion,
|
|
1000
|
+
* Fold transitions owned by one Chat viewport. Every batch containing a closing row moves its boxes and
|
|
1001
|
+
* the scrollport on one frame clock; a batch that only reveals rows, or a viewport without a reading
|
|
1002
|
+
* policy, uses CSS transitions. Motion is opt-in under `[data-chat-motion]`, respects reduced motion,
|
|
1003
|
+
* and clears temporary styles.
|
|
1003
1004
|
*/
|
|
1004
1005
|
const FADE_OUT_MS = 70;
|
|
1005
1006
|
/** The box starts closing while the fade finishes; by then the row is nearly transparent. */
|
|
@@ -1025,18 +1026,159 @@ window.__ModuleLoader__.load({
|
|
|
1025
1026
|
return element.hasAttribute("hidden") || element.dataset.chatMotion === "collapse";
|
|
1026
1027
|
}
|
|
1027
1028
|
/**
|
|
1029
|
+
* Opacity of a revealing box at batch progress, continuing from the share its own transition reached.
|
|
1030
|
+
* @param box - revealing box.
|
|
1031
|
+
* @param progress - shared eased progress from zero to one.
|
|
1032
|
+
* @returns opacity from zero to one.
|
|
1033
|
+
*/
|
|
1034
|
+
function revealedShare(box, progress) {
|
|
1035
|
+
const start = box.height === 0 ? 0 : box.fromHeight / box.height;
|
|
1036
|
+
return start + (1 - start) * progress;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1028
1039
|
* Create animation coordination without cross-viewport broadcasts.
|
|
1029
|
-
* @param
|
|
1040
|
+
* @param driver - the viewport's driver for the next batch; null while detached.
|
|
1030
1041
|
* @param foldingChanged - disable or restore this viewport's native scroll anchoring.
|
|
1031
1042
|
* @returns stable callbacks and cleanup for this viewport's animations.
|
|
1032
1043
|
*/
|
|
1033
|
-
function createFlowMotion(
|
|
1044
|
+
function createFlowMotion(driver, foldingChanged) {
|
|
1034
1045
|
const running = /* @__PURE__ */ new Map();
|
|
1035
1046
|
let folding = 0;
|
|
1036
1047
|
const foldIdleListeners = /* @__PURE__ */ new Set();
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
let
|
|
1048
|
+
let batchScheduled = false;
|
|
1049
|
+
const boxes = /* @__PURE__ */ new Map();
|
|
1050
|
+
let frameRequest = null;
|
|
1051
|
+
let batch = false;
|
|
1052
|
+
let cancelled = false;
|
|
1053
|
+
let clearEpoch = 0;
|
|
1054
|
+
let batchCleanup = null;
|
|
1055
|
+
let cancelEmptyBatch = null;
|
|
1056
|
+
/** The batch is committing hidden rows and its final geometry; idle listeners wait until both land. */
|
|
1057
|
+
let settling = false;
|
|
1058
|
+
let anchoringDisabled = false;
|
|
1059
|
+
function cancelInput() {
|
|
1060
|
+
if (batch) cancelled = true;
|
|
1061
|
+
}
|
|
1062
|
+
function resumeInput() {
|
|
1063
|
+
if (batch) cancelled = false;
|
|
1064
|
+
}
|
|
1065
|
+
/** Rows inside a closing ancestor change with it and never join a batch on their own. */
|
|
1066
|
+
function batchMember(box) {
|
|
1067
|
+
return box.element.parentElement?.closest("[data-chat-motion=\"collapse\"]") === null;
|
|
1068
|
+
}
|
|
1069
|
+
function runBatch(current) {
|
|
1070
|
+
for (const box of [...boxes.values()]) {
|
|
1071
|
+
if (!batchMember(box)) continue;
|
|
1072
|
+
const height = box.element.offsetHeight;
|
|
1073
|
+
const marginTop = Number.parseFloat(getComputedStyle(box.element).marginTop) || 0;
|
|
1074
|
+
if (!box.closing) {
|
|
1075
|
+
box.fromHeight = Math.min(height, box.height);
|
|
1076
|
+
box.fromMarginTop = Math.min(marginTop, box.marginTop);
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
box.height = height;
|
|
1080
|
+
box.marginTop = marginTop;
|
|
1081
|
+
if (height === 0 && marginTop === 0) box.finish();
|
|
1082
|
+
}
|
|
1083
|
+
const owned = [...boxes.values()];
|
|
1084
|
+
const members = owned.filter(batchMember).sort((left, right) => left.element.compareDocumentPosition(right.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
1085
|
+
if (!members.some((box) => box.closing)) return;
|
|
1086
|
+
batch = true;
|
|
1087
|
+
cancelled = false;
|
|
1088
|
+
const travelling = current.begin(members.map((box) => box.closing ? box : {
|
|
1089
|
+
element: box.element,
|
|
1090
|
+
height: box.height - box.fromHeight,
|
|
1091
|
+
marginTop: box.marginTop - box.fromMarginTop,
|
|
1092
|
+
closing: false
|
|
1093
|
+
}));
|
|
1094
|
+
batchCleanup = () => {
|
|
1095
|
+
current.finish(true);
|
|
1096
|
+
};
|
|
1097
|
+
for (const box of owned) box.take();
|
|
1098
|
+
for (const box of members) {
|
|
1099
|
+
box.element.style.transition = "none";
|
|
1100
|
+
box.element.style.height = `${box.closing ? box.height : box.fromHeight}px`;
|
|
1101
|
+
box.element.style.marginTop = `${box.closing ? box.marginTop : box.fromMarginTop}px`;
|
|
1102
|
+
box.element.style.opacity = box.closing ? "1" : String(revealedShare(box, 0));
|
|
1103
|
+
}
|
|
1104
|
+
const memberSet = new Set(members);
|
|
1105
|
+
const settledTravel = /* @__PURE__ */ new Set();
|
|
1106
|
+
const freezeTravelling = () => {
|
|
1107
|
+
for (const element of travelling) {
|
|
1108
|
+
if (settledTravel.has(element)) continue;
|
|
1109
|
+
settledTravel.add(element);
|
|
1110
|
+
element.style.translate = "";
|
|
1111
|
+
for (const box of owned) {
|
|
1112
|
+
if (memberSet.has(box) || !element.contains(box.element)) continue;
|
|
1113
|
+
box.element.style.transition = "none";
|
|
1114
|
+
box.element.style.height = `${box.height}px`;
|
|
1115
|
+
box.element.style.marginTop = `${box.marginTop}px`;
|
|
1116
|
+
box.element.style.opacity = "1";
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
freezeTravelling();
|
|
1121
|
+
const reduced = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1122
|
+
let started;
|
|
1123
|
+
let displacement = 0;
|
|
1124
|
+
const settle = (finishCancelled) => {
|
|
1125
|
+
batch = false;
|
|
1126
|
+
batchCleanup = null;
|
|
1127
|
+
cancelEmptyBatch = null;
|
|
1128
|
+
settling = true;
|
|
1129
|
+
try {
|
|
1130
|
+
for (const box of owned) if (boxes.get(box.element) === box) box.finish();
|
|
1131
|
+
current.finish(finishCancelled);
|
|
1132
|
+
} finally {
|
|
1133
|
+
settling = false;
|
|
1134
|
+
}
|
|
1135
|
+
if (folding === 0) notifyIdle();
|
|
1136
|
+
if ([...boxes.values()].some((box) => box.held)) flushBatch();
|
|
1137
|
+
};
|
|
1138
|
+
cancelEmptyBatch = () => {
|
|
1139
|
+
if (members.some((box) => box.closing && boxes.get(box.element) === box)) return;
|
|
1140
|
+
if (frameRequest !== null) cancelAnimationFrame(frameRequest);
|
|
1141
|
+
frameRequest = null;
|
|
1142
|
+
settle(true);
|
|
1143
|
+
};
|
|
1144
|
+
const tick = (now) => {
|
|
1145
|
+
frameRequest = null;
|
|
1146
|
+
started ??= now;
|
|
1147
|
+
const elapsed = reduced ? 160 : now - started;
|
|
1148
|
+
const linear = Math.min(1, Math.max(0, (elapsed - CLOSE_DELAY_MS) / CLOSE_MS));
|
|
1149
|
+
const progress = linear * linear * (3 - 2 * linear);
|
|
1150
|
+
current.prepare(progress, cancelled);
|
|
1151
|
+
freezeTravelling();
|
|
1152
|
+
for (const box of members) {
|
|
1153
|
+
if (boxes.get(box.element) !== box) continue;
|
|
1154
|
+
if (box.closing) {
|
|
1155
|
+
box.element.style.height = `${box.height * (1 - progress)}px`;
|
|
1156
|
+
box.element.style.marginTop = `${box.marginTop * (1 - progress)}px`;
|
|
1157
|
+
box.element.style.opacity = travelling.has(box.element) ? "1" : String(Math.max(0, 1 - elapsed / FADE_OUT_MS));
|
|
1158
|
+
} else {
|
|
1159
|
+
box.element.style.height = `${box.fromHeight + (box.height - box.fromHeight) * progress}px`;
|
|
1160
|
+
box.element.style.marginTop = `${box.fromMarginTop + (box.marginTop - box.fromMarginTop) * progress}px`;
|
|
1161
|
+
box.element.style.opacity = String(revealedShare(box, progress));
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
displacement = current.frame(progress, cancelled);
|
|
1165
|
+
let removedBefore = 0;
|
|
1166
|
+
for (const box of members) {
|
|
1167
|
+
if (boxes.get(box.element) !== box) continue;
|
|
1168
|
+
if (box.closing) {
|
|
1169
|
+
if (!travelling.has(box.element)) box.element.style.translate = `0 ${displacement + removedBefore}px`;
|
|
1170
|
+
removedBefore += (box.height + box.marginTop) * progress;
|
|
1171
|
+
} else removedBefore -= (box.height - box.fromHeight + box.marginTop - box.fromMarginTop) * progress;
|
|
1172
|
+
}
|
|
1173
|
+
if (linear < 1) {
|
|
1174
|
+
frameRequest = requestAnimationFrame(tick);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
settle(cancelled);
|
|
1178
|
+
};
|
|
1179
|
+
if (reduced) tick(0);
|
|
1180
|
+
else frameRequest = requestAnimationFrame(tick);
|
|
1181
|
+
}
|
|
1040
1182
|
function foldActive() {
|
|
1041
1183
|
return folding > 0;
|
|
1042
1184
|
}
|
|
@@ -1047,30 +1189,41 @@ window.__ModuleLoader__.load({
|
|
|
1047
1189
|
foldIdleListeners.delete(listener);
|
|
1048
1190
|
};
|
|
1049
1191
|
}
|
|
1050
|
-
function
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1192
|
+
function flushBatch() {
|
|
1193
|
+
batchScheduled = false;
|
|
1194
|
+
if (batch) return;
|
|
1195
|
+
const current = [...boxes.values()].some((box) => box.closing) ? driver() : null;
|
|
1196
|
+
if (current !== null) {
|
|
1197
|
+
runBatch(current);
|
|
1198
|
+
return;
|
|
1057
1199
|
}
|
|
1058
|
-
|
|
1059
|
-
if (
|
|
1200
|
+
const reduced = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1201
|
+
for (const box of [...boxes.values()]) if (reduced || box.held && box.closing) box.finish();
|
|
1202
|
+
else if (box.held) box.release();
|
|
1060
1203
|
}
|
|
1061
|
-
function
|
|
1062
|
-
if (
|
|
1063
|
-
|
|
1064
|
-
|
|
1204
|
+
function scheduleBatch() {
|
|
1205
|
+
if (batchScheduled) return;
|
|
1206
|
+
batchScheduled = true;
|
|
1207
|
+
const epoch = clearEpoch;
|
|
1208
|
+
queueMicrotask(() => {
|
|
1209
|
+
if (epoch === clearEpoch) flushBatch();
|
|
1210
|
+
});
|
|
1065
1211
|
}
|
|
1066
1212
|
function foldStarted() {
|
|
1067
1213
|
folding += 1;
|
|
1068
|
-
if (folding
|
|
1214
|
+
if (folding !== 1 || anchoringDisabled) return;
|
|
1215
|
+
anchoringDisabled = true;
|
|
1216
|
+
foldingChanged(true);
|
|
1069
1217
|
}
|
|
1070
1218
|
function foldEnded() {
|
|
1071
1219
|
folding = Math.max(0, folding - 1);
|
|
1072
|
-
if (folding
|
|
1073
|
-
|
|
1220
|
+
if (folding === 0 && !settling) notifyIdle();
|
|
1221
|
+
}
|
|
1222
|
+
function notifyIdle() {
|
|
1223
|
+
if (anchoringDisabled) {
|
|
1224
|
+
anchoringDisabled = false;
|
|
1225
|
+
foldingChanged(false);
|
|
1226
|
+
}
|
|
1074
1227
|
const listeners = [...foldIdleListeners];
|
|
1075
1228
|
foldIdleListeners.clear();
|
|
1076
1229
|
for (const listener of listeners) listener();
|
|
@@ -1079,17 +1232,19 @@ window.__ModuleLoader__.load({
|
|
|
1079
1232
|
element.removeEventListener("transitionend", onEnd);
|
|
1080
1233
|
clearTimeout(timer);
|
|
1081
1234
|
running.delete(element);
|
|
1235
|
+
boxes.delete(element);
|
|
1082
1236
|
const { style } = element;
|
|
1083
1237
|
style.height = "";
|
|
1084
1238
|
style.marginTop = "";
|
|
1085
1239
|
style.opacity = "";
|
|
1086
1240
|
style.overflow = "";
|
|
1087
1241
|
style.transition = "";
|
|
1242
|
+
style.translate = "";
|
|
1088
1243
|
delete element.dataset.chatMotion;
|
|
1089
1244
|
}
|
|
1090
1245
|
function cancelMotion(element) {
|
|
1091
|
-
pendingReserve.delete(element);
|
|
1092
1246
|
running.get(element)?.();
|
|
1247
|
+
cancelEmptyBatch?.();
|
|
1093
1248
|
}
|
|
1094
1249
|
function collapse(element, done) {
|
|
1095
1250
|
cancelMotion(element);
|
|
@@ -1100,19 +1255,21 @@ window.__ModuleLoader__.load({
|
|
|
1100
1255
|
return;
|
|
1101
1256
|
}
|
|
1102
1257
|
const { style } = element;
|
|
1258
|
+
const held = batch;
|
|
1103
1259
|
element.dataset.chatMotion = "collapse";
|
|
1104
1260
|
foldStarted();
|
|
1105
|
-
|
|
1106
|
-
scheduleReserve();
|
|
1261
|
+
scheduleBatch();
|
|
1107
1262
|
style.transition = "none";
|
|
1108
1263
|
style.overflow = "hidden";
|
|
1109
1264
|
style.height = `${height}px`;
|
|
1110
1265
|
style.marginTop = `${marginTop}px`;
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1266
|
+
if (!held) {
|
|
1267
|
+
element.offsetHeight;
|
|
1268
|
+
style.transition = `opacity ${FADE_OUT_MS}ms ${EASING}, height ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms, margin-top ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms`;
|
|
1269
|
+
style.opacity = "0";
|
|
1270
|
+
style.height = "0px";
|
|
1271
|
+
style.marginTop = "0px";
|
|
1272
|
+
}
|
|
1116
1273
|
const finish = () => {
|
|
1117
1274
|
if (running.get(element) !== cancel) return;
|
|
1118
1275
|
clearMotion(element, onEnd, timer);
|
|
@@ -1122,21 +1279,35 @@ window.__ModuleLoader__.load({
|
|
|
1122
1279
|
const onEnd = (event) => {
|
|
1123
1280
|
if (event.target === element && event.propertyName === "height") finish();
|
|
1124
1281
|
};
|
|
1125
|
-
const timer = setTimeout(finish, 240);
|
|
1282
|
+
const timer = held ? void 0 : setTimeout(finish, 240);
|
|
1126
1283
|
const cancel = () => {
|
|
1127
1284
|
clearMotion(element, onEnd, timer);
|
|
1128
1285
|
foldEnded();
|
|
1129
1286
|
};
|
|
1130
|
-
element.addEventListener("transitionend", onEnd);
|
|
1287
|
+
if (!held) element.addEventListener("transitionend", onEnd);
|
|
1131
1288
|
running.set(element, cancel);
|
|
1289
|
+
boxes.set(element, {
|
|
1290
|
+
element,
|
|
1291
|
+
height,
|
|
1292
|
+
marginTop,
|
|
1293
|
+
fromHeight: height,
|
|
1294
|
+
fromMarginTop: marginTop,
|
|
1295
|
+
closing: true,
|
|
1296
|
+
held,
|
|
1297
|
+
finish,
|
|
1298
|
+
release: () => {},
|
|
1299
|
+
take: () => {
|
|
1300
|
+
element.removeEventListener("transitionend", onEnd);
|
|
1301
|
+
clearTimeout(timer);
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1132
1304
|
}
|
|
1133
1305
|
function reveal(element) {
|
|
1134
1306
|
cancelMotion(element);
|
|
1135
1307
|
const height = element.offsetHeight;
|
|
1136
1308
|
if (height === 0) return;
|
|
1137
1309
|
const marginTop = Number.parseFloat(getComputedStyle(element).marginTop) || 0;
|
|
1138
|
-
|
|
1139
|
-
scheduleReserve();
|
|
1310
|
+
scheduleBatch();
|
|
1140
1311
|
const { style } = element;
|
|
1141
1312
|
element.dataset.chatMotion = "reveal";
|
|
1142
1313
|
style.transition = "none";
|
|
@@ -1144,11 +1315,6 @@ window.__ModuleLoader__.load({
|
|
|
1144
1315
|
style.opacity = "0";
|
|
1145
1316
|
style.height = "0px";
|
|
1146
1317
|
style.marginTop = "0px";
|
|
1147
|
-
element.offsetHeight;
|
|
1148
|
-
style.transition = `height ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms, margin-top ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms, opacity ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms`;
|
|
1149
|
-
style.height = `${height}px`;
|
|
1150
|
-
style.marginTop = `${marginTop}px`;
|
|
1151
|
-
style.opacity = "1";
|
|
1152
1318
|
const finish = () => {
|
|
1153
1319
|
if (running.get(element) !== finish) return;
|
|
1154
1320
|
clearMotion(element, onEnd, timer);
|
|
@@ -1156,14 +1322,50 @@ window.__ModuleLoader__.load({
|
|
|
1156
1322
|
const onEnd = (event) => {
|
|
1157
1323
|
if (event.target === element && event.propertyName === "height") finish();
|
|
1158
1324
|
};
|
|
1159
|
-
|
|
1160
|
-
|
|
1325
|
+
let timer;
|
|
1326
|
+
const startTransition = () => {
|
|
1327
|
+
element.offsetHeight;
|
|
1328
|
+
style.transition = `height ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms, margin-top ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms, opacity ${CLOSE_MS}ms ${EASING} ${CLOSE_DELAY_MS}ms`;
|
|
1329
|
+
style.height = `${height}px`;
|
|
1330
|
+
style.marginTop = `${marginTop}px`;
|
|
1331
|
+
style.opacity = "1";
|
|
1332
|
+
timer = setTimeout(finish, 240);
|
|
1333
|
+
element.addEventListener("transitionend", onEnd);
|
|
1334
|
+
};
|
|
1335
|
+
const held = batch;
|
|
1336
|
+
if (!held) startTransition();
|
|
1161
1337
|
running.set(element, finish);
|
|
1338
|
+
const box = {
|
|
1339
|
+
element,
|
|
1340
|
+
height,
|
|
1341
|
+
marginTop,
|
|
1342
|
+
fromHeight: 0,
|
|
1343
|
+
fromMarginTop: 0,
|
|
1344
|
+
closing: false,
|
|
1345
|
+
held,
|
|
1346
|
+
finish,
|
|
1347
|
+
release: () => {
|
|
1348
|
+
box.held = false;
|
|
1349
|
+
startTransition();
|
|
1350
|
+
},
|
|
1351
|
+
take: () => {
|
|
1352
|
+
element.removeEventListener("transitionend", onEnd);
|
|
1353
|
+
clearTimeout(timer);
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
boxes.set(element, box);
|
|
1162
1357
|
}
|
|
1163
1358
|
function clear() {
|
|
1359
|
+
clearEpoch++;
|
|
1360
|
+
batchScheduled = false;
|
|
1361
|
+
batch = false;
|
|
1362
|
+
cancelled = false;
|
|
1363
|
+
if (frameRequest !== null) cancelAnimationFrame(frameRequest);
|
|
1364
|
+
frameRequest = null;
|
|
1365
|
+
batchCleanup?.();
|
|
1366
|
+
batchCleanup = null;
|
|
1367
|
+
cancelEmptyBatch = null;
|
|
1164
1368
|
foldIdleListeners.clear();
|
|
1165
|
-
pendingReserve.clear();
|
|
1166
|
-
pendingGrowth = 0;
|
|
1167
1369
|
for (const cancel of [...running.values()]) cancel();
|
|
1168
1370
|
}
|
|
1169
1371
|
return {
|
|
@@ -1172,7 +1374,10 @@ window.__ModuleLoader__.load({
|
|
|
1172
1374
|
cancelMotion,
|
|
1173
1375
|
foldActive,
|
|
1174
1376
|
onFoldIdle,
|
|
1175
|
-
|
|
1377
|
+
cancelInput,
|
|
1378
|
+
resumeInput,
|
|
1379
|
+
clear,
|
|
1380
|
+
inputActive: () => batch || batchScheduled && [...boxes.values()].some((box) => box.closing && batchMember(box))
|
|
1176
1381
|
};
|
|
1177
1382
|
}
|
|
1178
1383
|
function useFlowTransition(motion, grow) {
|
|
@@ -1182,11 +1387,12 @@ window.__ModuleLoader__.load({
|
|
|
1182
1387
|
current.current = null;
|
|
1183
1388
|
}, [motion]);
|
|
1184
1389
|
const transition = (0, react.useCallback)((element, hidden, commit) => {
|
|
1185
|
-
const
|
|
1390
|
+
const mounted = current.current === element;
|
|
1391
|
+
const animate = mounted && motionEnabled(element);
|
|
1186
1392
|
current.current = element;
|
|
1187
1393
|
if (hidden) {
|
|
1188
|
-
if (element
|
|
1189
|
-
if (
|
|
1394
|
+
if (hiddenOrCollapsing(element)) return;
|
|
1395
|
+
if (mounted && element.closest(MOTION_SCOPE) !== null && motion !== void 0) motion.collapse(element, commit);
|
|
1190
1396
|
else commit();
|
|
1191
1397
|
return;
|
|
1192
1398
|
}
|
|
@@ -1201,7 +1407,7 @@ window.__ModuleLoader__.load({
|
|
|
1201
1407
|
* Apply searchable hiding with the containing Chat viewport's optional fold animation.
|
|
1202
1408
|
* @param hidden - desired visibility.
|
|
1203
1409
|
* @param reveal - browser-find and focus-protection callback.
|
|
1204
|
-
* @param motion - owning viewport's row callbacks;
|
|
1410
|
+
* @param motion - owning viewport's row callbacks; undefined applies visibility synchronously.
|
|
1205
1411
|
* @returns the stable subtree ref.
|
|
1206
1412
|
*/
|
|
1207
1413
|
function useFlowHidden(hidden, reveal, motion) {
|
|
@@ -1230,7 +1436,7 @@ window.__ModuleLoader__.load({
|
|
|
1230
1436
|
}
|
|
1231
1437
|
//#endregion
|
|
1232
1438
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-chat/src/client/chat/ChatView.module.css.mjs
|
|
1233
|
-
const css$17 = ".JJ8Zsq_frame{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative;container-type:inline-size}.JJ8Zsq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative;overflow:visible clip}.JJ8Zsq_scroll{min-height:0;padding:16px calc(var(--qilin-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}.JJ8Zsq_root[data-chat-following-tail] .JJ8Zsq_scroll,[data-conversation-scroll]:has(.JJ8Zsq_root[data-chat-following-tail]){overflow-anchor:none}[data-conversation-scroll] .JJ8Zsq_frame,[data-conversation-scroll] .JJ8Zsq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .JJ8Zsq_scroll{flex:none;min-height:auto;overflow:visible}.JJ8Zsq_column{max-width:var(--qilin-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty)))~:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))),.JJ8Zsq_column:has(>.JJ8Zsq_older)>[data-slot=\"conversation.chat.flow\"]>:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))){margin-top:var(--qilin-chat-flow-gap,6px)}.JJ8Zsq_flowItem[data-chat-group-part=response],:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>[data-chat-group-part=response]:not([hidden]):not(:empty)+:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))):not(.JJ8Zsq_running){--qilin-chat-flow-gap:12px}.JJ8Zsq_flowItem{min-width:0}.JJ8Zsq_turnSpacer{height:0}.JJ8Zsq_column[data-chat-motion]>:not([data-chat-motion]),.JJ8Zsq_column[data-chat-motion]>[data-slot=\"conversation.chat.flow\"]>:not([data-chat-motion]){transition:margin-top .16s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){.JJ8Zsq_column[data-chat-motion]>:not([data-chat-motion]),.JJ8Zsq_column[data-chat-motion]>[data-slot=\"conversation.chat.flow\"]>:not([data-chat-motion]){transition:none}}.JJ8Zsq_flowItem[data-chat-flow-kind=turn-process],.JJ8Zsq_flowItem[data-turn-process-answer],:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>[data-chat-flow-kind=turn-process]+:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))):not(.JJ8Zsq_running){--qilin-chat-flow-gap:16px}.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty)){height:0}.JJ8Zsq_callRow{border-radius:var(--dsw-radius-sm)}.JJ8Zsq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px))}.JJ8Zsq_running{--qilin-chat-flow-gap:12px;--dsw-alias-label-shimmer:var(--dsw-alias-label-deep-diving-shimmer);color:var(--dsw-alias-label-deep-diving);font-size:calc(var(--qilin-content-font-size,14px) - 2px);line-height:calc(22px + var(--qilin-content-font-delta,0px));flex-direction:column;align-items:flex-start;display:flex}.JJ8Zsq_modalAction{min-width:72px}.JJ8Zsq_running{--qilin-chat-flow-gap:12px;--qilin-alias-label-shimmer:var(--qilin-alias-label-
|
|
1439
|
+
const css$17 = ".JJ8Zsq_frame{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative;container-type:inline-size}.JJ8Zsq_root{flex-direction:column;flex:auto;min-height:0;display:flex;position:relative;overflow:visible clip}.JJ8Zsq_scroll{min-height:0;padding:16px calc(var(--qilin-composer-side-clearance) + 16px);flex:auto;overflow-y:auto;container-type:inline-size}.JJ8Zsq_root[data-chat-following-tail] .JJ8Zsq_scroll,[data-conversation-scroll]:has(.JJ8Zsq_root[data-chat-following-tail]){overflow-anchor:none}[data-conversation-scroll] .JJ8Zsq_frame,[data-conversation-scroll] .JJ8Zsq_root{flex:none;height:auto;min-height:auto}[data-conversation-scroll] .JJ8Zsq_scroll{flex:none;min-height:auto;overflow:visible}.JJ8Zsq_column{max-width:var(--qilin-chat-content-width);flex-direction:column;width:100%;margin:0 auto;display:flex}:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty)))~:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))),.JJ8Zsq_column:has(>.JJ8Zsq_older)>[data-slot=\"conversation.chat.flow\"]>:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))){margin-top:var(--qilin-chat-flow-gap,6px)}.JJ8Zsq_older{justify-content:center;display:flex}.JJ8Zsq_older button{border-radius:var(--qilin-radius-sm);color:var(--qilin-alias-label-secondary);background:var(--qilin-alias-interactive-bg-hover-solid);cursor:pointer;border:none;padding:4px 12px;font-size:12px}.JJ8Zsq_older button:disabled{cursor:default;opacity:.6}.JJ8Zsq_flowItem[data-chat-group-part=response],:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>[data-chat-group-part=response]:not([hidden]):not(:empty)+:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))):not(.JJ8Zsq_running){--qilin-chat-flow-gap:12px}.JJ8Zsq_flowItem{min-width:0}.JJ8Zsq_turnSpacer{height:0}.JJ8Zsq_column[data-chat-motion]>:not([data-chat-motion]),.JJ8Zsq_column[data-chat-motion]>[data-slot=\"conversation.chat.flow\"]>:not([data-chat-motion]){transition:margin-top .16s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){.JJ8Zsq_column[data-chat-motion]>:not([data-chat-motion]),.JJ8Zsq_column[data-chat-motion]>[data-slot=\"conversation.chat.flow\"]>:not([data-chat-motion]){transition:none}}.JJ8Zsq_flowItem[data-chat-flow-kind=turn-process],.JJ8Zsq_flowItem[data-turn-process-answer],:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>[data-chat-flow-kind=turn-process]+:not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty))):not(.JJ8Zsq_running){--qilin-chat-flow-gap:16px}.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty)){height:0}.JJ8Zsq_callRow{border-radius:var(--dsw-radius-sm)}.JJ8Zsq_hint{color:var(--dsw-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px))}.JJ8Zsq_running{--qilin-chat-flow-gap:12px;--dsw-alias-label-shimmer:var(--dsw-alias-label-deep-diving-shimmer);color:var(--dsw-alias-label-deep-diving);font-size:calc(var(--qilin-content-font-size,14px) - 2px);line-height:calc(22px + var(--qilin-content-font-delta,0px));flex-direction:column;align-items:flex-start;display:flex}.JJ8Zsq_modalAction{min-width:72px}.JJ8Zsq_running{--qilin-chat-flow-gap:12px;--qilin-alias-label-shimmer:var(--qilin-alias-label-running-shimmer);color:var(--qilin-alias-label-running,var(--qilin-alias-label-tertiary));font-size:calc(var(--qilin-content-font-size,14px) - 2px);line-height:calc(22px + var(--qilin-content-font-delta,0px));flex-direction:column;align-items:flex-start;display:flex}:is(.JJ8Zsq_column,[data-slot=\"conversation.chat.flow\"])>:nth-last-child(2 of :not([hidden]):not(.JJ8Zsq_flowItem:is(:empty,:has(>[data-slot=\"conversation.chat.node\"]:empty)))):is(.JJ8Zsq_flowItem:not([data-chat-flow-kind=user]):not([data-chat-flow-kind=steering]):not([data-chat-flow-kind=turn-trigger]),[data-chat-group-key])~.JJ8Zsq_running>.JJ8Zsq_runningDivider{display:block}.JJ8Zsq_runningDivider{background:color-mix(in srgb, var(--qilin-alias-border-l1) 75%, var(--qilin-alias-border-l2));pointer-events:none;width:100%;height:.5px;margin:8px 0 10px;display:none}.JJ8Zsq_runningContent{align-items:center;gap:6px;min-width:0;display:inline-flex}.JJ8Zsq_toBottomSlot{z-index:8;justify-content:center;height:0;display:flex;position:absolute;bottom:16px;left:0;right:0}[data-conversation-scroll] .JJ8Zsq_toBottomSlot{bottom:calc(var(--qilin-composer-height,152px) + 16px);position:sticky}.JJ8Zsq_toBottom{--qilin-elevation-stroke-color:var(--qilin-alias-border-l3);corner-shape:round;width:34px;height:34px;color:var(--qilin-alias-label-primary);background:var(--qilin-alias-button-floating-fill);box-shadow:var(--qilin-shadow-lv1);cursor:pointer;pointer-events:auto;border:0;border-radius:100px;justify-content:center;align-items:center;margin-top:-34px;padding:0;display:flex}.JJ8Zsq_toBottom:hover{background:var(--qilin-alias-button-floating-hover)}";
|
|
1234
1440
|
const tagId$17 = "@qilin-agent/client-ui-chat/ChatView.module.css";
|
|
1235
1441
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$17) + "]") === null) {
|
|
1236
1442
|
const tag = document.createElement("style");
|
|
@@ -1271,7 +1477,7 @@ window.__ModuleLoader__.load({
|
|
|
1271
1477
|
* Policy reads select this seat's own conclusion, so a mode change re-renders
|
|
1272
1478
|
* only seats whose visibility actually changes.
|
|
1273
1479
|
*/
|
|
1274
|
-
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, groupPart, useChatNode, useChatNodeProcess, usePresentation, cwd, openFile, openSkill, inspectCall, forkAt, editUserMessage, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t, useChatNodeBottom, deferCollapse, useGroupAction }) {
|
|
1480
|
+
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, groupPart, depth, useChatNode, useChatNodeProcess, usePresentation, cwd, openFile, openSkill, inspectCall, forkAt, editUserMessage, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t, useChatNodeBottom, deferCollapse, useGroupAction }) {
|
|
1275
1481
|
const bottom = useChatNodeBottom(nodeKey);
|
|
1276
1482
|
const node = useChatNode(nodeKey);
|
|
1277
1483
|
const routedNode = node;
|
|
@@ -1374,6 +1580,7 @@ window.__ModuleLoader__.load({
|
|
|
1374
1580
|
"data-chat-flow-key": flowKey,
|
|
1375
1581
|
"data-chat-paging-anchor": routedNode.kind !== "turn-process" || void 0,
|
|
1376
1582
|
"data-chat-node-key": routedNode.key,
|
|
1583
|
+
"data-chat-depth": depth,
|
|
1377
1584
|
"data-chat-group-part": groupPart,
|
|
1378
1585
|
"data-chat-flow-kind": routedNode.kind,
|
|
1379
1586
|
"data-chat-turn": turn,
|
|
@@ -1769,7 +1976,7 @@ window.__ModuleLoader__.load({
|
|
|
1769
1976
|
}
|
|
1770
1977
|
//#endregion
|
|
1771
1978
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-chat/src/client/chat/ChatGroupSeat.module.css.mjs
|
|
1772
|
-
const css$16 = ".nsI7mW_root{min-width:0}.nsI7mW_title{max-width:100%;color:var(--qilin-alias-label-secondary);font:inherit;font-size:var(--dsh-content-font-size,14px);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0;transition:color .1s;display:flex}.nsI7mW_title:hover{color:var(--qilin-alias-label-primary)}.nsI7mW_leading{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex;position:relative}.nsI7mW_leading svg{width:calc(14px + var(--qilin-content-font-delta,0px));height:calc(14px + var(--qilin-content-font-delta,0px))}.nsI7mW_leading svg[width=\"16\"]{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px))}.nsI7mW_activityIcon,.nsI7mW_chevron{justify-content:center;align-items:center;transition:opacity .1s;display:inline-flex;position:absolute;inset:0}.nsI7mW_activityIcon{opacity:1}.nsI7mW_chevron,.nsI7mW_title:is(:hover,:focus-visible) .nsI7mW_activityIcon{opacity:0}.nsI7mW_title:is(:hover,:focus-visible) .nsI7mW_chevron{opacity:1}.nsI7mW_title[aria-expanded=true] .nsI7mW_activityIcon{opacity:0}.nsI7mW_title[aria-expanded=true] .nsI7mW_chevron{opacity:1}.nsI7mW_title[aria-expanded=true]{padding-bottom:8px}.nsI7mW_body{--dsh-chat-flow-gap:6px;overscroll-behavior-y:auto;scrollbar-gutter:stable;max-height:min(400px,50vh);overflow-y:auto}.nsI7mW_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.nsI7mW_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.nsI7mW_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.nsI7mW_fadeTop.nsI7mW_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}@media (prefers-reduced-motion:reduce){.nsI7mW_title,.nsI7mW_activityIcon,.nsI7mW_chevron{transition:none}}.nsI7mW_content{flex-direction:column;display:flex}.nsI7mW_content>*{flex-shrink:0}.nsI7mW_content>:not([hidden]):not(:empty)~:not([hidden]):not(:empty){margin-top:var(--dsh-chat-flow-gap,6px)}.nsI7mW_expandedBody{--dsh-chat-flow-gap:16px;scrollbar-gutter:auto;max-height:none;overflow:visible}[data-chat-motion] .nsI7mW_content>:not([data-chat-motion]){transition:margin-top .16s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){[data-chat-motion] .nsI7mW_content>:not([data-chat-motion]){transition:none}}";
|
|
1979
|
+
const css$16 = ".nsI7mW_root{min-width:0}.nsI7mW_title{max-width:100%;color:var(--qilin-alias-label-secondary);font:inherit;font-size:var(--dsh-content-font-size,14px);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:0;transition:color .1s;display:flex}.nsI7mW_title:hover{color:var(--qilin-alias-label-primary)}.nsI7mW_leading{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex;position:relative}.nsI7mW_leading svg{width:calc(14px + var(--qilin-content-font-delta,0px));height:calc(14px + var(--qilin-content-font-delta,0px))}.nsI7mW_leading svg[width=\"16\"]{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px))}.nsI7mW_activityIcon,.nsI7mW_chevron{justify-content:center;align-items:center;transition:opacity .1s;display:inline-flex;position:absolute;inset:0}.nsI7mW_activityIcon{opacity:1}.nsI7mW_chevron,.nsI7mW_title:is(:hover,:focus-visible) .nsI7mW_activityIcon{opacity:0}.nsI7mW_title:is(:hover,:focus-visible) .nsI7mW_chevron{opacity:1}.nsI7mW_title[aria-expanded=true] .nsI7mW_activityIcon{opacity:0}.nsI7mW_title[aria-expanded=true] .nsI7mW_chevron{opacity:1}.nsI7mW_title[aria-expanded=true]{padding-bottom:8px}.nsI7mW_body{--dsh-chat-flow-gap:6px;overscroll-behavior-y:auto;scrollbar-gutter:stable;max-height:min(400px,50vh);overflow-y:auto}.nsI7mW_root:not([data-group-expanded-mode]) .nsI7mW_body{--dsh-chat-process-indent:24px}.nsI7mW_root:not([data-group-expanded-mode]) .nsI7mW_content>[data-chat-depth=\"1\"]{padding-inline-start:var(--dsh-chat-process-indent)}.nsI7mW_root:not([data-group-expanded-mode]) .nsI7mW_content>[data-chat-depth=\"2\"]{padding-inline-start:calc(var(--dsh-chat-process-indent) * 2)}.nsI7mW_label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.nsI7mW_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.nsI7mW_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.nsI7mW_fadeTop.nsI7mW_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}@media (prefers-reduced-motion:reduce){.nsI7mW_title,.nsI7mW_activityIcon,.nsI7mW_chevron{transition:none}}.nsI7mW_content{flex-direction:column;display:flex}.nsI7mW_content>*{flex-shrink:0}.nsI7mW_content>:not([hidden]):not(:empty)~:not([hidden]):not(:empty){margin-top:var(--dsh-chat-flow-gap,6px)}.nsI7mW_expandedBody{--dsh-chat-flow-gap:16px;scrollbar-gutter:auto;max-height:none;overflow:visible}[data-chat-motion] .nsI7mW_content>:not([data-chat-motion]){transition:margin-top .16s cubic-bezier(.4,0,.2,1)}@media (prefers-reduced-motion:reduce){[data-chat-motion] .nsI7mW_content>:not([data-chat-motion]){transition:none}}";
|
|
1773
1980
|
const tagId$16 = "@qilin-agent/client-ui-chat/ChatGroupSeat.module.css";
|
|
1774
1981
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$16) + "]") === null) {
|
|
1775
1982
|
const tag = document.createElement("style");
|
|
@@ -1845,11 +2052,21 @@ window.__ModuleLoader__.load({
|
|
|
1845
2052
|
]);
|
|
1846
2053
|
return active ? displayed : desired;
|
|
1847
2054
|
}
|
|
2055
|
+
/**
|
|
2056
|
+
* Nesting level of one member: a Step's own row reads one level in, and the
|
|
2057
|
+
* reasoning and Tool rows that belong to it read two.
|
|
2058
|
+
* @param member - group member reference.
|
|
2059
|
+
* @returns the member's depth below the group header.
|
|
2060
|
+
*/
|
|
2061
|
+
function memberDepth(member) {
|
|
2062
|
+
return member.groupPart === "response" ? 1 : 2;
|
|
2063
|
+
}
|
|
1848
2064
|
const GroupMembers = (0, react.memo)(function GroupMembers({ members, ...props }) {
|
|
1849
2065
|
return members.map((member) => (0, react.createElement)(ChatNodeSeat, {
|
|
1850
2066
|
...props,
|
|
1851
2067
|
key: chatRenderKey(member),
|
|
1852
2068
|
nodeKey: member.key,
|
|
2069
|
+
depth: memberDepth(member),
|
|
1853
2070
|
...member.groupPart === void 0 ? {} : { groupPart: member.groupPart }
|
|
1854
2071
|
}));
|
|
1855
2072
|
});
|
|
@@ -1911,7 +2128,7 @@ window.__ModuleLoader__.load({
|
|
|
1911
2128
|
});
|
|
1912
2129
|
const grouped = props.usePresentation((policy) => policy.stepGrouping === "collapsed" || policy.stepGrouping === "history" && turnLocation?.status !== "open" && !deferCollapse);
|
|
1913
2130
|
const reason = turnLocation?.end?.data.reason.kind;
|
|
1914
|
-
const alwaysOpen = presentation?.turnClosed === false || presentation?.hasInterleavedInput === true || reason === "aborted" || reason === "error";
|
|
2131
|
+
const alwaysOpen = presentation?.turnClosed === false || presentation?.hasInterleavedInput === true || reason === "aborted" || reason === "interrupted" || reason === "error";
|
|
1915
2132
|
const spec = presentation?.spec;
|
|
1916
2133
|
const selectOpen = (0, react.useCallback)((state) => spec !== void 0 && turnProcessOpen(state, spec, deferCollapse), [spec, deferCollapse]);
|
|
1917
2134
|
const storedOpen = props.useStore(selectOpen);
|
|
@@ -2023,7 +2240,7 @@ window.__ModuleLoader__.load({
|
|
|
2023
2240
|
}
|
|
2024
2241
|
//#endregion
|
|
2025
2242
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-chat/src/client/chat/MessageItem.module.css.mjs
|
|
2026
|
-
const css$15 = ".Icvj1a_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Icvj1a_userStack{min-width:0;max-width:min(calc(var(--qilin-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Icvj1a_bubble{background:var(--qilin-specific-bubble);max-width:100%;font-size:var(--qilin-content-font-size,14px);line-height:calc(22px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Icvj1a_referenceSummary{color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px))}.Icvj1a_contextRow{padding:2px 0}.Icvj1a_compactionRow{--qilin-compaction-header-height:calc(24px + var(--qilin-content-font-delta,0px));padding:2px 0}.Icvj1a_compactionButton{width:100%;height:var(--qilin-compaction-header-height);min-width:0;color:inherit;font:inherit;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;padding:0;display:flex}.Icvj1a_compactionRow:has(.Icvj1a_compactionBody) .Icvj1a_compactionButton{z-index:7;background:var(--qilin-alias-bg-base);border-radius:0;position:sticky;top:0}.Icvj1a_compactionBody :has(>[data-code-block-banner]){top:var(--qilin-compaction-header-height)}.Icvj1a_compactionRow:has(.Icvj1a_compactionBody) .Icvj1a_compactionButton:hover{background:var(--qilin-alias-interactive-bg-hover-solid)}.Icvj1a_compactionButton:not(:disabled){cursor:pointer}.Icvj1a_compactionButton:not(:disabled):hover{background:var(--qilin-alias-interactive-bg-hover)}.Icvj1a_compactionLeading{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Icvj1a_compactionLeading svg{width:calc(14px + var(--qilin-content-font-delta,0px));height:calc(14px + var(--qilin-content-font-delta,0px))}.Icvj1a_compactionContextIcon,.Icvj1a_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Icvj1a_compactionDisclosureIcon,.Icvj1a_compactionButton:not(:disabled):hover .Icvj1a_compactionContextIcon,.Icvj1a_compactionButton:not(:disabled):focus-visible .Icvj1a_compactionContextIcon{opacity:0}.Icvj1a_compactionButton:not(:disabled):hover .Icvj1a_compactionDisclosureIcon,.Icvj1a_compactionButton:not(:disabled):focus-visible .Icvj1a_compactionDisclosureIcon{opacity:1}.Icvj1a_compactionTitle{font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-primary-dimmed);flex:none}.Icvj1a_compactionSep{background:var(--qilin-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Icvj1a_compactionSummary{min-width:0;color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Icvj1a_compactionBody{padding:4px 0 4px calc(22px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px))}.Icvj1a_retryRow{color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(20px + var(--qilin-content-font-delta-secondary,0px))}.Icvj1a_retrySummary{width:fit-content;color:inherit;cursor:pointer;user-select:none;border-radius:3px;align-items:center;gap:7px;padding:2px 0;list-style:none;display:inline-flex}.Icvj1a_retrySummary::-webkit-details-marker{display:none}.Icvj1a_retrySummary:after{content:\"\";opacity:.8;border-bottom:1.5px solid;border-right:1.5px solid;width:6px;height:6px;transition:transform .12s;transform:rotate(-45deg)}.Icvj1a_retrySummary:hover{color:var(--qilin-alias-label-secondary)}.Icvj1a_retrySummary:focus-visible{outline:1.5px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}.Icvj1a_retryText{color:inherit}.Icvj1a_retryRow[data-active] .Icvj1a_retryText{background:linear-gradient(90deg, var(--qilin-alias-label-tertiary) 0%, var(--qilin-alias-label-tertiary) 40%, var(--qilin-alias-label-secondary) 50%, var(--qilin-alias-label-tertiary) 60%, var(--qilin-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Icvj1a_retry-shimmer}.Icvj1a_retryRow[open] .Icvj1a_retrySummary:after{transform:rotate(45deg)}.Icvj1a_retryDetails{overflow-wrap:anywhere;font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Icvj1a_retryDetailLabel{color:var(--qilin-alias-label-secondary)}.Icvj1a_turnErrorRow{font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(20px + var(--qilin-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Icvj1a_turnErrorDot{margin-top:5px}.Icvj1a_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Icvj1a_turnErrorTitle{color:var(--qilin-alias-state-error-primary);margin-right:6px;font-weight:600}.Icvj1a_turnErrorMessage{color:var(--qilin-alias-label-secondary)}.Icvj1a_turnErrorCode{color:var(--qilin-alias-label-tertiary);font:var(--qilin-font-markdown-code-block-small)}.Icvj1a_maxTokensTitle{color:var(--qilin-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Icvj1a_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Icvj1a_retryRow[data-active] .Icvj1a_retryText{color:inherit;background:0 0;animation:none}}.Icvj1a_attachmentRow{flex-wrap:wrap;justify-content:flex-end;gap:8px;max-width:100%;display:flex}.Icvj1a_fileCard{border:.5px solid var(--qilin-alias-border-l2,#0000001f);background:var(--qilin-specific-input-major,transparent);box-sizing:border-box;
|
|
2243
|
+
const css$15 = ".Icvj1a_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Icvj1a_userStack{min-width:0;max-width:min(calc(var(--qilin-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Icvj1a_bubble{background:var(--qilin-specific-bubble);max-width:100%;font-size:var(--qilin-content-font-size,14px);line-height:calc(22px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Icvj1a_referenceSummary{color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px))}.Icvj1a_contextRow{padding:2px 0}.Icvj1a_compactionRow{--qilin-compaction-header-height:calc(24px + var(--qilin-content-font-delta,0px));padding:2px 0}.Icvj1a_compactionButton{width:100%;height:var(--qilin-compaction-header-height);min-width:0;color:inherit;font:inherit;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;padding:0;display:flex}.Icvj1a_compactionRow:has(.Icvj1a_compactionBody) .Icvj1a_compactionButton{z-index:7;background:var(--qilin-alias-bg-base);border-radius:0;position:sticky;top:0}.Icvj1a_compactionBody :has(>[data-code-block-banner]){top:var(--qilin-compaction-header-height)}.Icvj1a_compactionRow:has(.Icvj1a_compactionBody) .Icvj1a_compactionButton:hover{background:var(--qilin-alias-interactive-bg-hover-solid)}.Icvj1a_compactionButton:not(:disabled){cursor:pointer}.Icvj1a_compactionButton:not(:disabled):hover{background:var(--qilin-alias-interactive-bg-hover)}.Icvj1a_compactionLeading{width:calc(16px + var(--qilin-content-font-delta,0px));height:calc(16px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Icvj1a_compactionLeading svg{width:calc(14px + var(--qilin-content-font-delta,0px));height:calc(14px + var(--qilin-content-font-delta,0px))}.Icvj1a_compactionContextIcon,.Icvj1a_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Icvj1a_compactionDisclosureIcon,.Icvj1a_compactionButton:not(:disabled):hover .Icvj1a_compactionContextIcon,.Icvj1a_compactionButton:not(:disabled):focus-visible .Icvj1a_compactionContextIcon{opacity:0}.Icvj1a_compactionButton:not(:disabled):hover .Icvj1a_compactionDisclosureIcon,.Icvj1a_compactionButton:not(:disabled):focus-visible .Icvj1a_compactionDisclosureIcon{opacity:1}.Icvj1a_compactionTitle{font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-primary-dimmed);flex:none}.Icvj1a_compactionSep{background:var(--qilin-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Icvj1a_compactionSummary{min-width:0;color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Icvj1a_compactionBody{padding:4px 0 4px calc(22px + var(--qilin-content-font-delta,0px));color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(24px + var(--qilin-content-font-delta,0px))}.Icvj1a_retryRow{color:var(--qilin-alias-label-tertiary);font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(20px + var(--qilin-content-font-delta-secondary,0px))}.Icvj1a_retrySummary{width:fit-content;color:inherit;cursor:pointer;user-select:none;border-radius:3px;align-items:center;gap:7px;padding:2px 0;list-style:none;display:inline-flex}.Icvj1a_retrySummary::-webkit-details-marker{display:none}.Icvj1a_retrySummary:after{content:\"\";opacity:.8;border-bottom:1.5px solid;border-right:1.5px solid;width:6px;height:6px;transition:transform .12s;transform:rotate(-45deg)}.Icvj1a_retrySummary:hover{color:var(--qilin-alias-label-secondary)}.Icvj1a_retrySummary:focus-visible{outline:1.5px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px}.Icvj1a_retryText{color:inherit}.Icvj1a_retryRow[data-active] .Icvj1a_retryText{background:linear-gradient(90deg, var(--qilin-alias-label-tertiary) 0%, var(--qilin-alias-label-tertiary) 40%, var(--qilin-alias-label-secondary) 50%, var(--qilin-alias-label-tertiary) 60%, var(--qilin-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Icvj1a_retry-shimmer}.Icvj1a_retryRow[open] .Icvj1a_retrySummary:after{transform:rotate(45deg)}.Icvj1a_retryDetails{overflow-wrap:anywhere;font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(18px + var(--qilin-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Icvj1a_retryDetailLabel{color:var(--qilin-alias-label-secondary)}.Icvj1a_turnErrorRow{font-size:var(--qilin-content-font-size-secondary,13px);line-height:calc(20px + var(--qilin-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Icvj1a_turnErrorDot{margin-top:5px}.Icvj1a_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Icvj1a_turnErrorTitle{color:var(--qilin-alias-state-error-primary);margin-right:6px;font-weight:600}.Icvj1a_turnErrorMessage{color:var(--qilin-alias-label-secondary)}.Icvj1a_turnErrorCode{color:var(--qilin-alias-label-tertiary);font:var(--qilin-font-markdown-code-block-small)}.Icvj1a_maxTokensTitle{color:var(--qilin-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Icvj1a_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Icvj1a_retryRow[data-active] .Icvj1a_retryText{color:inherit;background:0 0;animation:none}}.Icvj1a_attachmentRow{flex-wrap:wrap;justify-content:flex-end;gap:8px;max-width:100%;display:flex}.Icvj1a_fileCard{border:.5px solid var(--qilin-alias-border-l2,#0000001f);border-radius:var(--qilin-radius-lg);background:var(--qilin-specific-input-major,transparent);box-sizing:border-box;flex:0 0 240px;align-items:center;gap:10px;width:240px;min-height:64px;padding:8px 12px;display:inline-flex}.Icvj1a_fileIcon{flex:none;width:28px;height:28px}.Icvj1a_fileContent{flex-direction:column;flex:1;min-width:0;display:flex}.Icvj1a_fileName{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.Icvj1a_fileMeta{white-space:nowrap;text-overflow:ellipsis;color:var(--qilin-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}";
|
|
2027
2244
|
const tagId$15 = "@qilin-agent/client-ui-chat/MessageItem.module.css";
|
|
2028
2245
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$15) + "]") === null) {
|
|
2029
2246
|
const tag = document.createElement("style");
|
|
@@ -3036,6 +3253,10 @@ window.__ModuleLoader__.load({
|
|
|
3036
3253
|
return Math.max(1, Math.ceil(milliseconds / 1e3));
|
|
3037
3254
|
}
|
|
3038
3255
|
function failureMessage(message, code, t) {
|
|
3256
|
+
if (code === "ACCOUNT_SIGNED_OUT") return t("message.failure.accountSignedOut");
|
|
3257
|
+
if (code === "INTERRUPTED") return t("message.failure.interrupted");
|
|
3258
|
+
if (code === "ACCOUNT_SIGN_IN_REQUIRED") return t("message.failure.accountSignInRequired");
|
|
3259
|
+
if (code === "QUOTA" || code === "ACCOUNT_QUOTA") return t("message.failure.quota");
|
|
3039
3260
|
return code === "AUTH" ? t("message.failure.auth") : message;
|
|
3040
3261
|
}
|
|
3041
3262
|
function ModelRetryItem({ node, active, t }) {
|
|
@@ -3108,13 +3329,13 @@ window.__ModuleLoader__.load({
|
|
|
3108
3329
|
className: MessageItem_module_css_default.turnErrorCopy,
|
|
3109
3330
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
3110
3331
|
className: MessageItem_module_css_default.turnErrorTitle,
|
|
3111
|
-
children: t("message.turnError")
|
|
3332
|
+
children: node.code === "ACCOUNT_SIGNED_OUT" || node.code === "INTERRUPTED" ? t("message.taskStopped") : t("message.turnError")
|
|
3112
3333
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
3113
3334
|
className: MessageItem_module_css_default.turnErrorMessage,
|
|
3114
3335
|
children: failureMessage(node.message, node.code, t)
|
|
3115
3336
|
})]
|
|
3116
3337
|
}),
|
|
3117
|
-
node.code !== void 0 && (0, react_jsx_runtime.jsx)("code", {
|
|
3338
|
+
node.code !== void 0 && node.code !== "INTERRUPTED" && (0, react_jsx_runtime.jsx)("code", {
|
|
3118
3339
|
className: MessageItem_module_css_default.turnErrorCode,
|
|
3119
3340
|
children: node.code
|
|
3120
3341
|
})
|
|
@@ -3182,7 +3403,10 @@ window.__ModuleLoader__.load({
|
|
|
3182
3403
|
}),
|
|
3183
3404
|
showBubble && (0, react_jsx_runtime.jsxs)("div", {
|
|
3184
3405
|
className: MessageItem_module_css_default.bubble,
|
|
3185
|
-
children: [(0, _qilin_agent_client_ui_primitives.projectUserText)(text, referenceLabels, skillNames, "skill", references
|
|
3406
|
+
children: [(0, _qilin_agent_client_ui_primitives.projectUserText)(text, referenceLabels, skillNames, "skill", references, {
|
|
3407
|
+
reveal: t("secret.reveal"),
|
|
3408
|
+
hide: t("secret.hide")
|
|
3409
|
+
}), rest.map((block, i) => (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.JsonBlock, {
|
|
3186
3410
|
label: t("message.extraBlock"),
|
|
3187
3411
|
payload: block,
|
|
3188
3412
|
truncatedLabel: truncated
|
|
@@ -4666,7 +4890,7 @@ window.__ModuleLoader__.load({
|
|
|
4666
4890
|
}
|
|
4667
4891
|
//#endregion
|
|
4668
4892
|
//#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-chat/src/client/chat/TurnNavigator.module.css.mjs
|
|
4669
|
-
const css$10 = ".GYXNwG_slot{z-index:7;height:0;padding-inline:calc(var(--qilin-composer-side-clearance) + 16px);pointer-events:none;position:absolute;top:0;left:0;right:0;container-type:inline-size}[data-conversation-scroll] .GYXNwG_slot{position:sticky}.GYXNwG_frame{--turn-rail-band:calc(var(--qilin-conversation-viewport-height,100dvh) - var(--qilin-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);width:28px;max-height:min(max(0px, calc(var(--turn-rail-band) - 64px)), 420px);contain:layout;cursor:pointer;pointer-events:auto;position:absolute;
|
|
4893
|
+
const css$10 = ".GYXNwG_slot{z-index:7;height:0;padding-inline:calc(var(--qilin-composer-side-clearance) + 16px);pointer-events:none;position:absolute;top:0;left:0;right:0;container-type:inline-size}[data-conversation-scroll] .GYXNwG_slot{position:sticky}.GYXNwG_frame{--turn-rail-band:calc(var(--qilin-conversation-viewport-height,100dvh) - var(--qilin-composer-height,152px));--turn-preview-height:100px;top:calc(var(--turn-rail-band) / 2);width:28px;max-height:min(max(0px, calc(var(--turn-rail-band) - 64px)), 420px);contain:layout;cursor:pointer;pointer-events:auto;position:absolute;left:12px;transform:translateY(-50%)}.GYXNwG_scroller{max-height:inherit;overscroll-behavior:contain;scrollbar-width:none;position:relative;overflow-y:auto}.GYXNwG_scroller::-webkit-scrollbar{display:none}.GYXNwG_fadeTop{mask-image:linear-gradient(#0000 0,#000 24px 100%)}.GYXNwG_fadeBottom{mask-image:linear-gradient(#000 0 calc(100% - 24px),#0000 100%)}.GYXNwG_fadeTop.GYXNwG_fadeBottom{mask-image:linear-gradient(#0000 0,#000 24px calc(100% - 24px),#0000 100%)}.GYXNwG_marks{position:relative}.GYXNwG_mark{cursor:pointer;background:0 0;border:0;border-radius:8px;height:10px;padding:0;position:absolute;top:0;left:0;right:0}.GYXNwG_mark:before{background:var(--qilin-alias-border-l4);content:\"\";transform-origin:0;border-radius:2px;width:20px;height:2px;transition:transform .14s,background-color .14s;position:absolute;top:50%;left:0;transform:translateY(-50%)scaleX(.6)}.GYXNwG_markUnloaded:before{opacity:.6;transform:translateY(-50%)scaleX(.4)}.GYXNwG_markPreview:before{background:var(--qilin-alias-label-tertiary);transform:translateY(-50%)scaleX(.9)}.GYXNwG_markBusy:before{animation:1s ease-in-out infinite GYXNwG_qilin-turn-mark-busy}.GYXNwG_markActive:before{background:var(--qilin-alias-label-primary);transform:translateY(-50%)scaleX(1)}.GYXNwG_mark:focus-visible:before{background:var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));transform:translateY(-50%)scaleX(1)}.GYXNwG_mark:focus-visible{outline:none}.GYXNwG_mark:focus-visible:after{border-radius:inherit;outline:1px solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:-1px;content:\"\";width:20px;position:absolute;inset:0 auto 0 0}.GYXNwG_preview{top:clamp(0px, calc(var(--turn-preview-center) - 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);border-radius:var(--qilin-radius-lg);color:var(--qilin-alias-label-primary);background:var(--qilin-alias-bg-layer-1);box-shadow:var(--qilin-elevation-panel);pointer-events:none;border:0;padding:10px 12px;transition:top .14s cubic-bezier(.2,.8,.2,1);animation:.12s ease-out GYXNwG_qilin-turn-preview-enter;position:absolute;left:calc(100% + 10px);overflow:hidden}.GYXNwG_previewPrompt,.GYXNwG_previewResponse{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.GYXNwG_previewPrompt{font:var(--qilin-font-xs-strong-13);-webkit-line-clamp:1}.GYXNwG_previewResponse{color:var(--qilin-alias-label-caption);font:var(--qilin-font-xxs-12);-webkit-line-clamp:3;margin-top:4px}@keyframes GYXNwG_qilin-turn-preview-enter{0%{opacity:0;transform:translate(-4px)}to{opacity:1;transform:translate(0)}}@keyframes GYXNwG_qilin-turn-mark-busy{0%,to{opacity:1}50%{opacity:.35}}@container (width<=900px){.GYXNwG_frame{display:none}}@media (prefers-reduced-motion:reduce){.GYXNwG_frame,.GYXNwG_scroller,.GYXNwG_mark:before,.GYXNwG_markBusy:before,.GYXNwG_preview{scroll-behavior:auto;transition:none;animation:none}}";
|
|
4670
4894
|
const tagId$10 = "@qilin-agent/client-ui-chat/TurnNavigator.module.css";
|
|
4671
4895
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$10) + "]") === null) {
|
|
4672
4896
|
const tag = document.createElement("style");
|
|
@@ -5254,9 +5478,9 @@ window.__ModuleLoader__.load({
|
|
|
5254
5478
|
follow;
|
|
5255
5479
|
sampleTimer = null;
|
|
5256
5480
|
probeFrame = null;
|
|
5481
|
+
sampled = null;
|
|
5257
5482
|
/** Settled reader row and offset, re-aligned when a layout change moves it. */
|
|
5258
5483
|
readerPosition = null;
|
|
5259
|
-
sampled = null;
|
|
5260
5484
|
constructor(viewport, store, state, onChange, follow) {
|
|
5261
5485
|
this.viewport = viewport;
|
|
5262
5486
|
this.store = store;
|
|
@@ -5319,6 +5543,28 @@ window.__ModuleLoader__.load({
|
|
|
5319
5543
|
this.cancelPending();
|
|
5320
5544
|
this.commit(landing, true, this.viewport.latestTurn);
|
|
5321
5545
|
}
|
|
5546
|
+
/**
|
|
5547
|
+
* Follow the tail on the active fold's animation clock.
|
|
5548
|
+
* @returns whether a fold batch owns the tail movement instead of a separate scroll animation.
|
|
5549
|
+
*/
|
|
5550
|
+
followInputFold() {
|
|
5551
|
+
this.cancelPending();
|
|
5552
|
+
return this.viewport.followInputFold(this.follow);
|
|
5553
|
+
}
|
|
5554
|
+
/**
|
|
5555
|
+
* Let fold batches read follow intent and commit their tail landings.
|
|
5556
|
+
* @returns a disposer that disconnects this reading policy from the viewport.
|
|
5557
|
+
*/
|
|
5558
|
+
bindFolds() {
|
|
5559
|
+
return this.viewport.bindReader({
|
|
5560
|
+
follow: this.follow,
|
|
5561
|
+
landedAtTail: (landing) => {
|
|
5562
|
+
this.cancelPending();
|
|
5563
|
+
this.commit(landing, true, this.viewport.latestTurn);
|
|
5564
|
+
},
|
|
5565
|
+
pending: () => this.pending
|
|
5566
|
+
});
|
|
5567
|
+
}
|
|
5322
5568
|
/** Stop a native follow animation where it is; the next sampled position decides follow intent. */
|
|
5323
5569
|
interruptFollow() {
|
|
5324
5570
|
this.viewport.interruptFollow(this.follow);
|
|
@@ -5364,7 +5610,7 @@ window.__ModuleLoader__.load({
|
|
|
5364
5610
|
*/
|
|
5365
5611
|
onScroll = (scroll) => {
|
|
5366
5612
|
if (this.follow.animating) return;
|
|
5367
|
-
if (!scroll.movedByReader && this.state.followingTail || scroll.movedByReader && scroll.metrics.top
|
|
5613
|
+
if (!scroll.movedByReader && this.state.followingTail || scroll.movedByReader && Math.abs(scroll.metrics.top - scroll.metrics.floor) < 1) {
|
|
5368
5614
|
this.followTail();
|
|
5369
5615
|
this.sampled?.({
|
|
5370
5616
|
position: null,
|
|
@@ -5432,9 +5678,9 @@ window.__ModuleLoader__.load({
|
|
|
5432
5678
|
else this.probeFrame = requestAnimationFrame(this.probe);
|
|
5433
5679
|
}
|
|
5434
5680
|
commit(landing, followingTail, activeTurn, initialized = true) {
|
|
5681
|
+
this.readerPosition = followingTail ? null : landing.position;
|
|
5435
5682
|
if (followingTail) this.store.save(null);
|
|
5436
5683
|
else if (landing.position !== null) this.store.save(landing.position);
|
|
5437
|
-
this.readerPosition = followingTail ? null : landing.position;
|
|
5438
5684
|
this.publish({
|
|
5439
5685
|
initialized,
|
|
5440
5686
|
followingTail,
|
|
@@ -5520,6 +5766,7 @@ window.__ModuleLoader__.load({
|
|
|
5520
5766
|
(0, react.useLayoutEffect)(() => {
|
|
5521
5767
|
reading.setStore(store);
|
|
5522
5768
|
}, [reading, store]);
|
|
5769
|
+
(0, react.useLayoutEffect)(() => reading.bindFolds(), [reading]);
|
|
5523
5770
|
(0, react.useLayoutEffect)(() => () => {
|
|
5524
5771
|
reading.dispose();
|
|
5525
5772
|
}, [reading]);
|
|
@@ -5557,13 +5804,18 @@ window.__ModuleLoader__.load({
|
|
|
5557
5804
|
top: 0,
|
|
5558
5805
|
landing: null
|
|
5559
5806
|
};
|
|
5807
|
+
paging = null;
|
|
5808
|
+
reader = null;
|
|
5809
|
+
/** A transcript resize observed since the previous sample. */
|
|
5560
5810
|
resized = false;
|
|
5811
|
+
/** Reader input observed since the previous sample. */
|
|
5561
5812
|
readerIntent = false;
|
|
5562
|
-
|
|
5813
|
+
/** The pending or running fold batch lands at the tail. */
|
|
5814
|
+
tailRequested = false;
|
|
5815
|
+
/** Switches the running batch to a tail landing; null while no batch runs. */
|
|
5816
|
+
retarget = null;
|
|
5563
5817
|
/** Transition state and row callbacks owned by this viewport's attachment. */
|
|
5564
|
-
motion = createFlowMotion((
|
|
5565
|
-
this.reserveBelow(px);
|
|
5566
|
-
}, (active) => {
|
|
5818
|
+
motion = createFlowMotion(() => this.foldDriver(), (active) => {
|
|
5567
5819
|
if (this.elements !== null) this.elements.scroller.style.overflowAnchor = active ? "none" : "";
|
|
5568
5820
|
});
|
|
5569
5821
|
/**
|
|
@@ -5597,8 +5849,8 @@ window.__ModuleLoader__.load({
|
|
|
5597
5849
|
if (typeof ResizeObserver !== "undefined") {
|
|
5598
5850
|
this.observer = new ResizeObserver(() => {
|
|
5599
5851
|
if (this.elements !== elements) return;
|
|
5600
|
-
this.reclaimBelow();
|
|
5601
5852
|
this.resized = true;
|
|
5853
|
+
this.reclaimBelow();
|
|
5602
5854
|
this.invalidate();
|
|
5603
5855
|
this.events?.resize();
|
|
5604
5856
|
});
|
|
@@ -5619,13 +5871,13 @@ window.__ModuleLoader__.load({
|
|
|
5619
5871
|
this.observer = null;
|
|
5620
5872
|
this.elements = null;
|
|
5621
5873
|
this.events = null;
|
|
5874
|
+
this.tailRequested = false;
|
|
5875
|
+
this.retarget = null;
|
|
5622
5876
|
this.turns = [];
|
|
5623
5877
|
this.observation = {
|
|
5624
5878
|
top: 0,
|
|
5625
5879
|
landing: null
|
|
5626
5880
|
};
|
|
5627
|
-
this.resized = false;
|
|
5628
|
-
this.readerIntent = false;
|
|
5629
5881
|
}
|
|
5630
5882
|
/**
|
|
5631
5883
|
* Connect business policy without changing DOM listener ownership.
|
|
@@ -5667,13 +5919,271 @@ window.__ModuleLoader__.load({
|
|
|
5667
5919
|
if (spacer.style.height !== next) spacer.style.height = next;
|
|
5668
5920
|
}
|
|
5669
5921
|
/**
|
|
5670
|
-
*
|
|
5671
|
-
*
|
|
5672
|
-
* @
|
|
5922
|
+
* Connect the reading policy that fold batches consult.
|
|
5923
|
+
* @param reader - follow intent and the tail-landing commit.
|
|
5924
|
+
* @returns a disposer that disconnects only this reader.
|
|
5925
|
+
*/
|
|
5926
|
+
bindReader(reader) {
|
|
5927
|
+
this.reader = reader;
|
|
5928
|
+
return () => {
|
|
5929
|
+
if (this.reader === reader) this.reader = null;
|
|
5930
|
+
};
|
|
5931
|
+
}
|
|
5932
|
+
/**
|
|
5933
|
+
* Land the pending or running fold batch at the tail instead of starting a separate scroll.
|
|
5934
|
+
* @param follow - follow controller whose native animation yields to the batch.
|
|
5935
|
+
* @returns whether a fold owns the tail movement.
|
|
5936
|
+
*/
|
|
5937
|
+
followInputFold(follow) {
|
|
5938
|
+
if (this.elements === null || this.reader === null || !this.motion.inputActive()) return false;
|
|
5939
|
+
this.interruptFollow(follow);
|
|
5940
|
+
this.tailRequested = true;
|
|
5941
|
+
this.retarget?.();
|
|
5942
|
+
return true;
|
|
5943
|
+
}
|
|
5944
|
+
/**
|
|
5945
|
+
* Drive one fold batch on its frame clock. A tail landing ends at the floor, never above the reader's
|
|
5946
|
+
* compensated position; a reader landing keeps the visible content still. Both install only the room
|
|
5947
|
+
* the landing lacks.
|
|
5948
|
+
* @returns the batch driver, or null while detached or without a reading policy.
|
|
5949
|
+
*/
|
|
5950
|
+
foldDriver() {
|
|
5951
|
+
const elements = this.elements;
|
|
5952
|
+
const reader = this.reader;
|
|
5953
|
+
if (elements === null || reader === null) return null;
|
|
5954
|
+
const { follow } = reader;
|
|
5955
|
+
let tail = false;
|
|
5956
|
+
let start = 0;
|
|
5957
|
+
let base = 0;
|
|
5958
|
+
let target = 0;
|
|
5959
|
+
let removed = 0;
|
|
5960
|
+
let growth = 0;
|
|
5961
|
+
let initialHeight = 0;
|
|
5962
|
+
let finalRoom = 0;
|
|
5963
|
+
let previousColumnHeight = 0;
|
|
5964
|
+
let previousProgress = 0;
|
|
5965
|
+
let segmentProgress = 0;
|
|
5966
|
+
let segmentTop = 0;
|
|
5967
|
+
let written = 0;
|
|
5968
|
+
const closing = [];
|
|
5969
|
+
const travelling = /* @__PURE__ */ new Set();
|
|
5970
|
+
let reference = null;
|
|
5971
|
+
let referenceTop = 0;
|
|
5972
|
+
let viewportTop = 0;
|
|
5973
|
+
const screenTop = (element) => element.getBoundingClientRect().top - viewportTop;
|
|
5974
|
+
const aim = () => {
|
|
5975
|
+
const finalHeight = initialHeight - removed + growth;
|
|
5976
|
+
const height = elements.scroller.clientHeight;
|
|
5977
|
+
target = tail ? Math.max(base, finalHeight - height, 0) : base;
|
|
5978
|
+
finalRoom = target === 0 ? 0 : Math.max(0, target + height - finalHeight);
|
|
5979
|
+
};
|
|
5980
|
+
const restart = () => {
|
|
5981
|
+
segmentTop = elements.scroller.scrollTop;
|
|
5982
|
+
segmentProgress = previousProgress;
|
|
5983
|
+
};
|
|
5984
|
+
const automatic = (cancelled) => !(cancelled && tail);
|
|
5985
|
+
const position = (progress, cancelled) => {
|
|
5986
|
+
if (!automatic(cancelled)) return elements.scroller.scrollTop;
|
|
5987
|
+
const remaining = segmentProgress === 1 ? 1 : (progress - segmentProgress) / (1 - segmentProgress);
|
|
5988
|
+
return segmentTop + (target - segmentTop) * remaining;
|
|
5989
|
+
};
|
|
5990
|
+
const room = (top, progress, cancelled) => Math.max(automatic(cancelled) ? finalRoom : 0, top + elements.scroller.clientHeight - (initialHeight + (growth - removed) * progress));
|
|
5991
|
+
return {
|
|
5992
|
+
begin: (boxes) => {
|
|
5993
|
+
tail = this.tailRequested || follow.active && !reader.pending();
|
|
5994
|
+
this.tailRequested = false;
|
|
5995
|
+
viewportTop = elements.scroller.getBoundingClientRect().top;
|
|
5996
|
+
start = elements.scroller.scrollTop;
|
|
5997
|
+
const originalRoom = this.spacerHeight();
|
|
5998
|
+
initialHeight = Math.max(elements.column.offsetHeight, elements.scroller.scrollHeight - originalRoom);
|
|
5999
|
+
let above = 0;
|
|
6000
|
+
const below = [];
|
|
6001
|
+
for (const box of boxes) {
|
|
6002
|
+
const amount = box.height + box.marginTop;
|
|
6003
|
+
const top = box.element.getBoundingClientRect().top - box.marginTop;
|
|
6004
|
+
if (box.closing) {
|
|
6005
|
+
removed += amount;
|
|
6006
|
+
above += Math.max(0, Math.min(amount, viewportTop - top));
|
|
6007
|
+
if (top >= viewportTop) below.push(box.element);
|
|
6008
|
+
closing.push(box);
|
|
6009
|
+
} else {
|
|
6010
|
+
growth += amount;
|
|
6011
|
+
if (top < viewportTop) above -= amount;
|
|
6012
|
+
}
|
|
6013
|
+
}
|
|
6014
|
+
if (!tail) reference = this.readingReference();
|
|
6015
|
+
const referenceBefore = reference === null ? 0 : screenTop(reference);
|
|
6016
|
+
elements.column.dataset.inputFold = "";
|
|
6017
|
+
if (reference !== null) {
|
|
6018
|
+
referenceTop = screenTop(reference);
|
|
6019
|
+
above -= referenceTop - referenceBefore;
|
|
6020
|
+
}
|
|
6021
|
+
base = Math.max(0, start - above);
|
|
6022
|
+
segmentTop = start;
|
|
6023
|
+
written = start;
|
|
6024
|
+
previousColumnHeight = elements.column.offsetHeight;
|
|
6025
|
+
aim();
|
|
6026
|
+
this.setSpacer(Math.max(originalRoom, finalRoom, removed));
|
|
6027
|
+
if (tail) follow.setFollowing(true);
|
|
6028
|
+
this.retarget = () => {
|
|
6029
|
+
tail = true;
|
|
6030
|
+
follow.setFollowing(true);
|
|
6031
|
+
this.motion.resumeInput();
|
|
6032
|
+
aim();
|
|
6033
|
+
restart();
|
|
6034
|
+
if (target <= segmentTop) return;
|
|
6035
|
+
for (const box of closing) {
|
|
6036
|
+
const shift = Number.parseFloat(box.element.style.translate.split(" ")[1] ?? "") || 0;
|
|
6037
|
+
if (box.element.getBoundingClientRect().top - shift - box.marginTop >= viewportTop) travelling.add(box.element);
|
|
6038
|
+
}
|
|
6039
|
+
};
|
|
6040
|
+
if (tail && target > start) for (const element of below) travelling.add(element);
|
|
6041
|
+
return travelling;
|
|
6042
|
+
},
|
|
6043
|
+
prepare: (progress, cancelled) => {
|
|
6044
|
+
if (this.elements !== elements) return;
|
|
6045
|
+
if (!tail) {
|
|
6046
|
+
const drift = elements.scroller.scrollTop - written;
|
|
6047
|
+
if (Math.abs(drift) > .5) {
|
|
6048
|
+
base = Math.max(0, base + drift);
|
|
6049
|
+
segmentTop += drift;
|
|
6050
|
+
referenceTop -= drift;
|
|
6051
|
+
aim();
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
const added = elements.column.offsetHeight - previousColumnHeight;
|
|
6055
|
+
if (added !== 0) {
|
|
6056
|
+
initialHeight += added;
|
|
6057
|
+
aim();
|
|
6058
|
+
restart();
|
|
6059
|
+
}
|
|
6060
|
+
const top = position(progress, cancelled);
|
|
6061
|
+
this.setSpacer(Math.max(this.spacerHeight(), room(top, progress, cancelled)));
|
|
6062
|
+
},
|
|
6063
|
+
frame: (progress, cancelled) => {
|
|
6064
|
+
if (this.elements !== elements) return 0;
|
|
6065
|
+
const top = position(progress, cancelled);
|
|
6066
|
+
elements.scroller.scrollTop = top;
|
|
6067
|
+
this.setSpacer(room(top, progress, cancelled));
|
|
6068
|
+
written = elements.scroller.scrollTop;
|
|
6069
|
+
if (reference !== null && progress === 1) referenceTop = screenTop(reference);
|
|
6070
|
+
if (automatic(cancelled)) this.observation = {
|
|
6071
|
+
top: written,
|
|
6072
|
+
landing: null
|
|
6073
|
+
};
|
|
6074
|
+
previousColumnHeight = elements.column.offsetHeight;
|
|
6075
|
+
previousProgress = progress;
|
|
6076
|
+
return written - start;
|
|
6077
|
+
},
|
|
6078
|
+
finish: (cancelled) => {
|
|
6079
|
+
this.retarget = null;
|
|
6080
|
+
this.tailRequested = false;
|
|
6081
|
+
if (this.elements !== elements) return;
|
|
6082
|
+
elements.column.offsetHeight;
|
|
6083
|
+
delete elements.column.dataset.inputFold;
|
|
6084
|
+
if (!tail || cancelled) {
|
|
6085
|
+
if (!tail && reference?.isConnected === true && reference.closest("[hidden]") === null) {
|
|
6086
|
+
const shift = screenTop(reference) - referenceTop;
|
|
6087
|
+
if (Math.abs(shift) > .5) {
|
|
6088
|
+
const top = elements.scroller.scrollTop + shift;
|
|
6089
|
+
const content = elements.scroller.scrollHeight - this.spacerHeight();
|
|
6090
|
+
this.setSpacer(Math.max(this.spacerHeight(), top + elements.scroller.clientHeight - content));
|
|
6091
|
+
elements.scroller.scrollTop = top;
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
const metrics = scrollMetrics(elements.scroller);
|
|
6095
|
+
const height = elements.scroller.scrollHeight - this.spacerHeight();
|
|
6096
|
+
this.setSpacer(metrics.top === 0 ? 0 : Math.max(0, metrics.top + metrics.height - height));
|
|
6097
|
+
if (tail) this.invalidate();
|
|
6098
|
+
else this.observation = {
|
|
6099
|
+
top: elements.scroller.scrollTop,
|
|
6100
|
+
landing: null
|
|
6101
|
+
};
|
|
6102
|
+
return;
|
|
6103
|
+
}
|
|
6104
|
+
const content = elements.scroller.scrollHeight - this.spacerHeight();
|
|
6105
|
+
const clientHeight = elements.scroller.clientHeight;
|
|
6106
|
+
const top = Math.max(target, content - clientHeight, 0);
|
|
6107
|
+
this.setSpacer(top === 0 ? 0 : Math.max(0, top + clientHeight - content));
|
|
6108
|
+
elements.scroller.scrollTop = top;
|
|
6109
|
+
const metrics = scrollMetrics(elements.scroller);
|
|
6110
|
+
const landing = {
|
|
6111
|
+
metrics,
|
|
6112
|
+
position: null,
|
|
6113
|
+
turn: this.latestTurn
|
|
6114
|
+
};
|
|
6115
|
+
this.observation = {
|
|
6116
|
+
top: metrics.top,
|
|
6117
|
+
landing
|
|
6118
|
+
};
|
|
6119
|
+
reader.landedAtTail(landing);
|
|
6120
|
+
}
|
|
6121
|
+
};
|
|
6122
|
+
}
|
|
6123
|
+
/**
|
|
6124
|
+
* Find the first visible top-level row at or below the scrollport top that holds no batch box.
|
|
6125
|
+
* Binary search over the ordered top-level rows reads O(log n) boxes.
|
|
6126
|
+
* @returns the reference row, or null when every visible row folds.
|
|
6127
|
+
*/
|
|
6128
|
+
readingReference() {
|
|
6129
|
+
const elements = this.elements;
|
|
6130
|
+
if (elements === null) return null;
|
|
6131
|
+
const viewport = elements.scroller.getBoundingClientRect();
|
|
6132
|
+
const rows = (elements.column.querySelector(":scope > [data-slot=\"conversation.chat.flow\"]") ?? elements.column).children;
|
|
6133
|
+
let low = 0;
|
|
6134
|
+
let high = rows.length;
|
|
6135
|
+
while (low < high) {
|
|
6136
|
+
const middle = low + high >>> 1;
|
|
6137
|
+
if (rows[middle].getBoundingClientRect().bottom > viewport.top) high = middle;
|
|
6138
|
+
else low = middle + 1;
|
|
6139
|
+
}
|
|
6140
|
+
for (let index = low; index < rows.length; index++) {
|
|
6141
|
+
const row = rows[index];
|
|
6142
|
+
if (row.hasAttribute("hidden")) continue;
|
|
6143
|
+
const rect = row.getBoundingClientRect();
|
|
6144
|
+
if (rect.top >= viewport.bottom) return null;
|
|
6145
|
+
if (rect.height === 0 || rect.bottom <= viewport.top) continue;
|
|
6146
|
+
if (row.hasAttribute("data-chat-motion") || row.querySelector("[data-chat-motion]") !== null) continue;
|
|
6147
|
+
return row;
|
|
6148
|
+
}
|
|
6149
|
+
return null;
|
|
6150
|
+
}
|
|
6151
|
+
/**
|
|
6152
|
+
* Consume the pending transcript resize. A delivery that arrives with one is the
|
|
6153
|
+
* browser's layout compensation, not a reader choice, so it must not re-anchor the
|
|
6154
|
+
* semantic position.
|
|
6155
|
+
* @returns whether the transcript resized since the previous sample.
|
|
6156
|
+
*/
|
|
6157
|
+
consumeResize() {
|
|
6158
|
+
const resized = this.resized;
|
|
6159
|
+
this.resized = false;
|
|
6160
|
+
return resized;
|
|
6161
|
+
}
|
|
6162
|
+
/**
|
|
6163
|
+
* Consume reader input recorded since the previous sample. Geometry alone cannot
|
|
6164
|
+
* separate a reader scroll from the browser's layout compensation, so a transcript
|
|
6165
|
+
* that moved with reader input present is the reader's own choice.
|
|
6166
|
+
* @returns whether wheel, touch, pointer, key, or find-in-page input arrived.
|
|
5673
6167
|
*/
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
this.
|
|
6168
|
+
consumeReaderIntent() {
|
|
6169
|
+
const intent = this.readerIntent;
|
|
6170
|
+
this.readerIntent = false;
|
|
6171
|
+
return intent;
|
|
6172
|
+
}
|
|
6173
|
+
/**
|
|
6174
|
+
* Re-align the reader's own settled row after a layout change moved it. A missing row
|
|
6175
|
+
* leaves the scrollport untouched: the raw position is only meaningful for the row it
|
|
6176
|
+
* was sampled against.
|
|
6177
|
+
* @param position - semantic position sampled while the reader owned the transcript.
|
|
6178
|
+
* @returns the actual landing, or null when the row is absent or still aligned.
|
|
6179
|
+
*/
|
|
6180
|
+
restoreReaderRow(position) {
|
|
6181
|
+
if (position === null || this.elements === null) return null;
|
|
6182
|
+
const row = this.anchor(position.anchorKey);
|
|
6183
|
+
if (row === null) return null;
|
|
6184
|
+
const top = row.getBoundingClientRect().top - this.elements.scroller.getBoundingClientRect().top;
|
|
6185
|
+
if (Math.abs(top - position.anchorTop) < .5) return null;
|
|
6186
|
+
return this.align(row, position.anchorTop, null);
|
|
5677
6187
|
}
|
|
5678
6188
|
/** Clear fold reservations after a display-mode change, allowing the scroll range to shrink. */
|
|
5679
6189
|
resetBelow() {
|
|
@@ -5681,26 +6191,27 @@ window.__ModuleLoader__.load({
|
|
|
5681
6191
|
this.invalidate();
|
|
5682
6192
|
}
|
|
5683
6193
|
/**
|
|
5684
|
-
* Give reserved room back
|
|
5685
|
-
*
|
|
5686
|
-
* would let the next frame clamp.
|
|
6194
|
+
* Give reserved room back after acknowledged scrolling or content growth without clamping the reader.
|
|
6195
|
+
* Holds still during folds and unsampled movement; following includes the room that remains.
|
|
5687
6196
|
*/
|
|
5688
6197
|
reclaimBelow() {
|
|
5689
6198
|
const elements = this.elements;
|
|
5690
6199
|
if (elements === null || elements.spacer === null) return;
|
|
5691
6200
|
const current = this.spacerHeight();
|
|
5692
6201
|
if (current === 0 || this.motion.foldActive()) return;
|
|
5693
|
-
const
|
|
5694
|
-
|
|
5695
|
-
|
|
6202
|
+
const scroll = this.readScroll();
|
|
6203
|
+
if (scroll === null || scroll.movedByReader) return;
|
|
6204
|
+
const floorWithoutSpacer = scroll.metrics.floor - current;
|
|
6205
|
+
this.setSpacer(Math.min(current, Math.max(0, scroll.metrics.top - floorWithoutSpacer)));
|
|
5696
6206
|
}
|
|
5697
6207
|
/**
|
|
5698
6208
|
* Stop an outstanding native follow animation at its current position before a reading gesture.
|
|
5699
6209
|
* @param follow - follow controller bound to this scrollport.
|
|
5700
6210
|
*/
|
|
5701
6211
|
interruptFollow(follow) {
|
|
6212
|
+
if (!follow.animating) return;
|
|
5702
6213
|
const metrics = this.metrics();
|
|
5703
|
-
if (metrics === null || this.elements === null
|
|
6214
|
+
if (metrics === null || this.elements === null) return;
|
|
5704
6215
|
follow.interrupt(this.elements.scroller, metrics);
|
|
5705
6216
|
this.observation = {
|
|
5706
6217
|
top: metrics.top,
|
|
@@ -5716,29 +6227,7 @@ window.__ModuleLoader__.load({
|
|
|
5716
6227
|
top: metrics.top,
|
|
5717
6228
|
landing: null
|
|
5718
6229
|
};
|
|
5719
|
-
|
|
5720
|
-
/**
|
|
5721
|
-
* Consume the pending transcript resize.
|
|
5722
|
-
* A delivery that arrives with one is the browser's layout compensation,
|
|
5723
|
-
* not a reader choice, so it must not re-anchor the semantic position.
|
|
5724
|
-
* @returns whether the transcript resized since the previous sample.
|
|
5725
|
-
*/
|
|
5726
|
-
consumeResize() {
|
|
5727
|
-
const resized = this.resized;
|
|
5728
|
-
this.resized = false;
|
|
5729
|
-
return resized;
|
|
5730
|
-
}
|
|
5731
|
-
/**
|
|
5732
|
-
* Consume reader input recorded since the previous sample.
|
|
5733
|
-
* Geometry alone cannot separate a reader scroll from the browser's layout
|
|
5734
|
-
* compensation, so a transcript that moved with reader input present is the
|
|
5735
|
-
* reader's own choice.
|
|
5736
|
-
* @returns whether wheel, touch, pointer, key, or find-in-page input arrived.
|
|
5737
|
-
*/
|
|
5738
|
-
consumeReaderIntent() {
|
|
5739
|
-
const intent = this.readerIntent;
|
|
5740
|
-
this.readerIntent = false;
|
|
5741
|
-
return intent;
|
|
6230
|
+
this.reclaimBelow();
|
|
5742
6231
|
}
|
|
5743
6232
|
/**
|
|
5744
6233
|
* Compare the current scroll geometry with the last acknowledged position.
|
|
@@ -5822,7 +6311,7 @@ window.__ModuleLoader__.load({
|
|
|
5822
6311
|
const first = this.turns[0];
|
|
5823
6312
|
if (elements === null || metrics === null || first === void 0) return null;
|
|
5824
6313
|
const line = elements.scroller.getBoundingClientRect().top + Math.min(96, metrics.height * .2);
|
|
5825
|
-
const rows = elements.column.children;
|
|
6314
|
+
const rows = (elements.column.querySelector(":scope > [data-slot=\"conversation.chat.flow\"]") ?? elements.column).children;
|
|
5826
6315
|
let low = 0;
|
|
5827
6316
|
let high = rows.length;
|
|
5828
6317
|
let reading = first.turn;
|
|
@@ -5875,21 +6364,6 @@ window.__ModuleLoader__.load({
|
|
|
5875
6364
|
const metrics = this.metrics();
|
|
5876
6365
|
return metrics === null ? null : this.write(position.scrollTop, metrics, null);
|
|
5877
6366
|
}
|
|
5878
|
-
/**
|
|
5879
|
-
* Re-align the reader's own settled row after a layout change moved it.
|
|
5880
|
-
* A missing row leaves the scrollport untouched: the raw position is only
|
|
5881
|
-
* meaningful for the row it was sampled against.
|
|
5882
|
-
* @param position - semantic position sampled while the reader owned the transcript.
|
|
5883
|
-
* @returns the actual landing, or null when the row is absent or still aligned.
|
|
5884
|
-
*/
|
|
5885
|
-
restoreReaderRow(position) {
|
|
5886
|
-
if (position === null || this.elements === null) return null;
|
|
5887
|
-
const row = this.anchor(position.anchorKey);
|
|
5888
|
-
if (row === null) return null;
|
|
5889
|
-
const top = row.getBoundingClientRect().top - this.elements.scroller.getBoundingClientRect().top;
|
|
5890
|
-
if (Math.abs(top - position.anchorTop) < .5) return null;
|
|
5891
|
-
return this.align(row, position.anchorTop, null);
|
|
5892
|
-
}
|
|
5893
6367
|
/** Retain the first eligible transcript seat in DOM order; selection reads no geometry. */
|
|
5894
6368
|
beginPaging() {
|
|
5895
6369
|
this.stopPreserving();
|
|
@@ -5992,7 +6466,7 @@ window.__ModuleLoader__.load({
|
|
|
5992
6466
|
});
|
|
5993
6467
|
}
|
|
5994
6468
|
/**
|
|
5995
|
-
* Align the
|
|
6469
|
+
* Align with the physical floor, including fold room that newer content has not yet filled.
|
|
5996
6470
|
* @param follow - independent follow intent and scrolling controller.
|
|
5997
6471
|
* @param behavior - immediate positioning, or one native animation for a reader-caused tail change.
|
|
5998
6472
|
* @returns the actual floor landing, or null while detached. A smooth landing reports the starting
|
|
@@ -6001,8 +6475,13 @@ window.__ModuleLoader__.load({
|
|
|
6001
6475
|
scrollToBottom(follow, behavior = "instant") {
|
|
6002
6476
|
const metrics = this.metrics();
|
|
6003
6477
|
if (metrics === null || this.elements === null) return null;
|
|
6478
|
+
this.observation = {
|
|
6479
|
+
top: metrics.top,
|
|
6480
|
+
landing: null
|
|
6481
|
+
};
|
|
6482
|
+
this.reclaimBelow();
|
|
6004
6483
|
const landing = {
|
|
6005
|
-
metrics: follow.toBottom(this.elements.scroller,
|
|
6484
|
+
metrics: follow.toBottom(this.elements.scroller, scrollMetrics(this.elements.scroller), behavior),
|
|
6006
6485
|
position: null,
|
|
6007
6486
|
turn: this.latestTurn
|
|
6008
6487
|
};
|
|
@@ -6056,8 +6535,10 @@ window.__ModuleLoader__.load({
|
|
|
6056
6535
|
if (scroll !== null) this.events?.scroll(scroll);
|
|
6057
6536
|
};
|
|
6058
6537
|
onScrollEnd = (event) => {
|
|
6059
|
-
if (event.target === this.elements?.scroller)
|
|
6060
|
-
|
|
6538
|
+
if (event.target === this.elements?.scroller) {
|
|
6539
|
+
this.events?.scrollEnd(true);
|
|
6540
|
+
this.reclaimBelow();
|
|
6541
|
+
} else if (event.target instanceof HTMLElement && event.target.hasAttribute("data-step-process-body")) this.events?.scrollEnd(false);
|
|
6061
6542
|
};
|
|
6062
6543
|
onIntent = (event) => {
|
|
6063
6544
|
if (event.type === "keydown" || event.type === "pointerdown") {
|
|
@@ -6125,26 +6606,9 @@ window.__ModuleLoader__.load({
|
|
|
6125
6606
|
applied: null,
|
|
6126
6607
|
opened: false
|
|
6127
6608
|
});
|
|
6128
|
-
const cancelFollow = (0, react.useRef)(null);
|
|
6129
|
-
const clearPendingFollow = (0, react.useCallback)(() => {
|
|
6130
|
-
cancelFollow.current?.();
|
|
6131
|
-
cancelFollow.current = null;
|
|
6132
|
-
}, []);
|
|
6133
6609
|
const cancelPendingFollow = (0, react.useCallback)(() => {
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
cancelFollow.current = null;
|
|
6137
|
-
});
|
|
6138
|
-
}, [clearPendingFollow, viewport]);
|
|
6139
|
-
const followAfterFold = (0, react.useCallback)(() => {
|
|
6140
|
-
if (cancelFollow.current !== null) return;
|
|
6141
|
-
reading.interruptFollow();
|
|
6142
|
-
cancelFollow.current = viewport.motion.onFoldIdle(() => {
|
|
6143
|
-
cancelFollow.current = null;
|
|
6144
|
-
viewport.reclaimBelow();
|
|
6145
|
-
if (content.current.input.deferCompletedTurns) reading.followTail("smooth");
|
|
6146
|
-
});
|
|
6147
|
-
}, [reading, viewport]);
|
|
6610
|
+
viewport.motion.cancelInput();
|
|
6611
|
+
}, [viewport]);
|
|
6148
6612
|
const processContent = (0, react.useCallback)(() => {
|
|
6149
6613
|
const current = content.current.input;
|
|
6150
6614
|
if (!current.ready && !content.current.opened) return;
|
|
@@ -6159,10 +6623,9 @@ window.__ModuleLoader__.load({
|
|
|
6159
6623
|
return;
|
|
6160
6624
|
}
|
|
6161
6625
|
if (ownInput) {
|
|
6162
|
-
clearPendingFollow();
|
|
6163
6626
|
navigation.cancel();
|
|
6164
|
-
if (current.deferCompletedTurns &&
|
|
6165
|
-
|
|
6627
|
+
if (current.deferCompletedTurns && reading.followInputFold()) return;
|
|
6628
|
+
reading.followTail(current.deferCompletedTurns ? "smooth" : "instant");
|
|
6166
6629
|
return;
|
|
6167
6630
|
}
|
|
6168
6631
|
if (navigation.contentCommitted()) {
|
|
@@ -6171,16 +6634,10 @@ window.__ModuleLoader__.load({
|
|
|
6171
6634
|
}
|
|
6172
6635
|
if ((previous === null || current.ready !== previous.ready || current.firstSeq !== previous.firstSeq || current.lastKey !== previous.lastKey || current.order.length !== previous.order.length || current.running !== previous.running || current.steeringId !== previous.steeringId || current.submissionId !== previous.submissionId) && reading.followingTail) {
|
|
6173
6636
|
navigation.cancel();
|
|
6174
|
-
if (current.deferCompletedTurns &&
|
|
6175
|
-
|
|
6637
|
+
if (current.deferCompletedTurns && reading.followInputFold()) return;
|
|
6638
|
+
reading.followTail();
|
|
6176
6639
|
} else navigation.reconcile();
|
|
6177
|
-
}, [
|
|
6178
|
-
viewport,
|
|
6179
|
-
reading,
|
|
6180
|
-
navigation,
|
|
6181
|
-
followAfterFold,
|
|
6182
|
-
clearPendingFollow
|
|
6183
|
-
]);
|
|
6640
|
+
}, [reading, navigation]);
|
|
6184
6641
|
(0, react.useLayoutEffect)(() => {
|
|
6185
6642
|
const disconnectViewport = viewport.connect({
|
|
6186
6643
|
scroll: (event) => {
|
|
@@ -6205,9 +6662,7 @@ window.__ModuleLoader__.load({
|
|
|
6205
6662
|
navigation.reconcile();
|
|
6206
6663
|
return;
|
|
6207
6664
|
}
|
|
6208
|
-
if (content.current.input.deferCompletedTurns
|
|
6209
|
-
if (!reading.pending && reading.followingTail) followAfterFold();
|
|
6210
|
-
} else reading.onResize();
|
|
6665
|
+
if (!content.current.input.deferCompletedTurns || !viewport.motion.foldActive()) reading.onResize();
|
|
6211
6666
|
navigation.reconcile();
|
|
6212
6667
|
}
|
|
6213
6668
|
});
|
|
@@ -6216,7 +6671,6 @@ window.__ModuleLoader__.load({
|
|
|
6216
6671
|
processContent();
|
|
6217
6672
|
});
|
|
6218
6673
|
return () => {
|
|
6219
|
-
clearPendingFollow();
|
|
6220
6674
|
disconnectViewport();
|
|
6221
6675
|
disconnectReading();
|
|
6222
6676
|
content.current.opened = false;
|
|
@@ -6227,9 +6681,7 @@ window.__ModuleLoader__.load({
|
|
|
6227
6681
|
reading,
|
|
6228
6682
|
navigation,
|
|
6229
6683
|
processContent,
|
|
6230
|
-
|
|
6231
|
-
cancelPendingFollow,
|
|
6232
|
-
clearPendingFollow
|
|
6684
|
+
cancelPendingFollow
|
|
6233
6685
|
]);
|
|
6234
6686
|
(0, react.useLayoutEffect)(() => {
|
|
6235
6687
|
const previous = content.current.input;
|
|
@@ -6331,8 +6783,9 @@ window.__ModuleLoader__.load({
|
|
|
6331
6783
|
if (node === void 0 || node.kind !== "user" && node.kind !== "steering" && node.kind !== "turn-trigger") continue;
|
|
6332
6784
|
if (node.location.kind === "turn" || node.location.kind === "step") lastInputTurn = node.location.turn.turn;
|
|
6333
6785
|
if (node.kind === "turn-trigger") continue;
|
|
6334
|
-
const
|
|
6335
|
-
|
|
6786
|
+
const data = node.data;
|
|
6787
|
+
const source = typeof data === "object" && data !== null && "source" in data ? data.source : void 0;
|
|
6788
|
+
if (typeof source === "object" && source !== null && "kind" in source && source.kind === "user" && "rpcId" in source && typeof source.rpcId === "string") observed.add(source.rpcId);
|
|
6336
6789
|
}
|
|
6337
6790
|
for (const { source } of [...inbox?.["next-turn"] ?? [], ...inbox?.["next-step"] ?? []]) if (source.kind === "user" && "rpcId" in source) observed.add(source.rpcId);
|
|
6338
6791
|
return {
|
|
@@ -6627,6 +7080,8 @@ window.__ModuleLoader__.load({
|
|
|
6627
7080
|
"fileOpen.title": "无法打开文件",
|
|
6628
7081
|
"fileOpen.unknown": "无法打开此文件",
|
|
6629
7082
|
"message.extraBlock": "附加内容块",
|
|
7083
|
+
"secret.reveal": "显示密钥",
|
|
7084
|
+
"secret.hide": "隐藏密钥",
|
|
6630
7085
|
"message.systemPrompt": "系统提示词",
|
|
6631
7086
|
"message.systemPromptUpdate": "系统提示词更新",
|
|
6632
7087
|
"message.contextInjection": "上下文注入",
|
|
@@ -6739,6 +7194,11 @@ window.__ModuleLoader__.load({
|
|
|
6739
7194
|
"message.retry.delay": "重试延迟:",
|
|
6740
7195
|
"message.retry.failure": "失败原因:",
|
|
6741
7196
|
"message.failure.auth": "API 密钥无效",
|
|
7197
|
+
"message.taskStopped": "任务已停止",
|
|
7198
|
+
"message.failure.accountSignedOut": "任务已因退出 DeepSeek 登录而停止。",
|
|
7199
|
+
"message.failure.interrupted": "QiLin 进程在本轮完成前退出(例如被强制结束、崩溃或关闭超时),重新启动后本轮已中止。未完成的工具调用结果未知。",
|
|
7200
|
+
"message.failure.accountSignInRequired": "请先登录 DeepSeek,并确认请求地址支持账号认证。",
|
|
7201
|
+
"message.failure.quota": "当前请求的额度已用尽",
|
|
6742
7202
|
"message.turnError": "本轮运行失败",
|
|
6743
7203
|
"message.maxTokens": "已达到输出 token 上限",
|
|
6744
7204
|
"message.maxTokens.hint": "回答被截断,已有输出保留在对话中。发送“继续”可让模型接着输出。",
|
|
@@ -6817,6 +7277,8 @@ window.__ModuleLoader__.load({
|
|
|
6817
7277
|
"fileOpen.title": "Couldn’t open file",
|
|
6818
7278
|
"fileOpen.unknown": "Couldn’t open this file",
|
|
6819
7279
|
"message.extraBlock": "Extra content block",
|
|
7280
|
+
"secret.reveal": "Show secret",
|
|
7281
|
+
"secret.hide": "Hide secret",
|
|
6820
7282
|
"message.systemPrompt": "System prompt",
|
|
6821
7283
|
"message.systemPromptUpdate": "System prompt update",
|
|
6822
7284
|
"message.contextInjection": "Context injection",
|
|
@@ -6929,6 +7391,11 @@ window.__ModuleLoader__.load({
|
|
|
6929
7391
|
"message.retry.delay": "Retry delay: ",
|
|
6930
7392
|
"message.retry.failure": "Failure reason: ",
|
|
6931
7393
|
"message.failure.auth": "API key is invalid",
|
|
7394
|
+
"message.taskStopped": "Task stopped",
|
|
7395
|
+
"message.failure.accountSignedOut": "Stopped because you signed out of DeepSeek.",
|
|
7396
|
+
"message.failure.interrupted": "The QiLin process exited before this turn finished (for example, it was killed, crashed, or timed out while shutting down), so the turn was closed when QiLin restarted. Unfinished tool calls have unknown outcomes.",
|
|
7397
|
+
"message.failure.accountSignInRequired": "Sign in to DeepSeek and ensure the request destination supports account authentication.",
|
|
7398
|
+
"message.failure.quota": "Request quota exhausted.",
|
|
6932
7399
|
"message.turnError": "This turn failed",
|
|
6933
7400
|
"message.maxTokens": "Output token limit reached",
|
|
6934
7401
|
"message.maxTokens.hint": "The reply was cut off; earlier output is preserved in the conversation. Send \"continue\" to let the model resume.",
|
|
@@ -7448,10 +7915,11 @@ window.__ModuleLoader__.load({
|
|
|
7448
7915
|
if (turn?.status !== "closed") return null;
|
|
7449
7916
|
const canCollapse = turnProcess.foldable && turnProcess.hasContent && !turnProcessAlwaysOpen(node);
|
|
7450
7917
|
const reason = turn.end?.data.reason.kind;
|
|
7918
|
+
const stopped = reason === "aborted" || reason === "interrupted";
|
|
7451
7919
|
const elapsedMs = turn.start === void 0 || turn.end === void 0 ? void 0 : Math.max(1e3, turn.end.time - turn.start.time);
|
|
7452
|
-
const duration = elapsedMs === void 0 ||
|
|
7453
|
-
const label =
|
|
7454
|
-
const announcement =
|
|
7920
|
+
const duration = elapsedMs === void 0 || stopped || reason === "error" ? void 0 : formatRunDuration(elapsedMs, t);
|
|
7921
|
+
const label = stopped ? t("message.stopped") : reason === "error" ? t("message.turnProcess.failed") : duration === void 0 ? t("message.turnProcess.worked") : t("message.turnProcess.took");
|
|
7922
|
+
const announcement = stopped ? t("message.stopped") : reason === "error" ? t("message.turnProcess.failed") : t("message.turnProcess.worked");
|
|
7455
7923
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
|
|
7456
7924
|
className: accessibility_module_css_default.visuallyHidden,
|
|
7457
7925
|
role: "status",
|
|
@@ -8977,7 +9445,7 @@ window.__ModuleLoader__.load({
|
|
|
8977
9445
|
* @returns the item, or undefined when the Turn has no visible loaded node.
|
|
8978
9446
|
*/
|
|
8979
9447
|
function turnNavigationItem(turn, locations, nodes) {
|
|
8980
|
-
const loaded = locations.getTurn(turn).map((key) => nodes.get(key)).filter((node) => node !== void 0 && node
|
|
9448
|
+
const loaded = locations.getTurn(turn).map((key) => nodes.get(key)).filter((node) => node !== void 0 && isVisibleChatNode(node));
|
|
8981
9449
|
const user = loaded.find((node) => node.kind === "user");
|
|
8982
9450
|
const anchor = user ?? loaded[0];
|
|
8983
9451
|
if (anchor === void 0) return void 0;
|
|
@@ -9438,7 +9906,7 @@ window.__ModuleLoader__.load({
|
|
|
9438
9906
|
* @returns visible Nodes in presentation order.
|
|
9439
9907
|
*/
|
|
9440
9908
|
function orderedVisibleChatNodes(nodes) {
|
|
9441
|
-
const visible = nodes.filter((node) => node
|
|
9909
|
+
const visible = nodes.filter((node) => isVisibleChatNode(node));
|
|
9442
9910
|
const presentations = turnProcessPresentations(visible);
|
|
9443
9911
|
return visible.sort((left, right) => {
|
|
9444
9912
|
const leftPosition = presentationPosition(left, presentations);
|
|
@@ -11046,9 +11514,28 @@ window.__ModuleLoader__.load({
|
|
|
11046
11514
|
if (location?.kind !== "turn" && location?.kind !== "step") return 0;
|
|
11047
11515
|
return location.turn.steps.at(-1)?.step ?? 0;
|
|
11048
11516
|
}
|
|
11517
|
+
/**
|
|
11518
|
+
* Failure shown for a turn ending: a recorded error, a sign-out cancellation,
|
|
11519
|
+
* or a turn that restart recovery closed because the QiLin process exited mid-turn.
|
|
11520
|
+
*/
|
|
11521
|
+
function endFailure(reason) {
|
|
11522
|
+
switch (reason.kind) {
|
|
11523
|
+
case "error": return reason.error;
|
|
11524
|
+
case "aborted": return reason.reason.kind === "hook" && reason.reason.reason === "deepseek-account/signed-out" ? {
|
|
11525
|
+
message: "Stopped because you signed out of DeepSeek.",
|
|
11526
|
+
code: "ACCOUNT_SIGNED_OUT"
|
|
11527
|
+
} : void 0;
|
|
11528
|
+
case "interrupted": return {
|
|
11529
|
+
message: "The QiLin process exited before this turn finished.",
|
|
11530
|
+
code: "INTERRUPTED"
|
|
11531
|
+
};
|
|
11532
|
+
default: return;
|
|
11533
|
+
}
|
|
11534
|
+
}
|
|
11049
11535
|
function failureFrom(match) {
|
|
11050
|
-
if (match.event.type !== "turn/end"
|
|
11051
|
-
const failure = match.event.data.reason
|
|
11536
|
+
if (match.event.type !== "turn/end") return void 0;
|
|
11537
|
+
const failure = endFailure(match.event.data.reason);
|
|
11538
|
+
if (failure === void 0) return void 0;
|
|
11052
11539
|
const display = displayFailure(failure);
|
|
11053
11540
|
return {
|
|
11054
11541
|
seq: match.event.seq,
|
|
@@ -11080,7 +11567,7 @@ window.__ModuleLoader__.load({
|
|
|
11080
11567
|
id: String(event.data.turn),
|
|
11081
11568
|
role: "start"
|
|
11082
11569
|
};
|
|
11083
|
-
if (event.type === "turn/end" && event.data.reason
|
|
11570
|
+
if (event.type === "turn/end" && endFailure(event.data.reason) !== void 0) return {
|
|
11084
11571
|
id: String(event.data.turn),
|
|
11085
11572
|
role: "update"
|
|
11086
11573
|
};
|
|
@@ -11275,7 +11762,7 @@ window.__ModuleLoader__.load({
|
|
|
11275
11762
|
if (answer === null) return {
|
|
11276
11763
|
turn: turn.turn,
|
|
11277
11764
|
controlAnchorSeq,
|
|
11278
|
-
processStartSeq: controlAnchorSeq,
|
|
11765
|
+
processStartSeq: turn.start?.seq ?? controlAnchorSeq,
|
|
11279
11766
|
answerAnchorSeq: null,
|
|
11280
11767
|
answerStep: null,
|
|
11281
11768
|
inlineReasoning: false,
|
|
@@ -12000,6 +12487,55 @@ window.__ModuleLoader__.load({
|
|
|
12000
12487
|
function reply(node) {
|
|
12001
12488
|
return node.kind === "assistant-step" && hasAssistantReplyContent(node.data.blocks);
|
|
12002
12489
|
}
|
|
12490
|
+
/** Fallback range for a Turn whose control Node is outside the loaded window. */
|
|
12491
|
+
const WHOLE_TURN = {
|
|
12492
|
+
start: Number.NEGATIVE_INFINITY,
|
|
12493
|
+
answerAnchor: null,
|
|
12494
|
+
answerStep: null
|
|
12495
|
+
};
|
|
12496
|
+
function processRange(nodes) {
|
|
12497
|
+
const control = nodes.find((node) => node.kind === "turn-process");
|
|
12498
|
+
if (control === void 0) return WHOLE_TURN;
|
|
12499
|
+
return {
|
|
12500
|
+
start: control.data.processStartSeq,
|
|
12501
|
+
answerAnchor: control.data.answerAnchorSeq,
|
|
12502
|
+
answerStep: control.data.answerStep
|
|
12503
|
+
};
|
|
12504
|
+
}
|
|
12505
|
+
/**
|
|
12506
|
+
* Whether one Node's evidence falls inside the Turn's process range. A live
|
|
12507
|
+
* Turn has no answer boundary yet, so every node from the range start belongs.
|
|
12508
|
+
*/
|
|
12509
|
+
function inProcessRange(node, range, live) {
|
|
12510
|
+
return node.anchorSeq >= range.start && (live || range.answerAnchor === null || node.anchorSeq < range.answerAnchor);
|
|
12511
|
+
}
|
|
12512
|
+
/**
|
|
12513
|
+
* Whether one Node is the Turn's finalized answer step. A live Turn has no
|
|
12514
|
+
* answer boundary yet: its reply rows keep their own seat while streaming.
|
|
12515
|
+
*/
|
|
12516
|
+
function isAnswerStep(node, range, live) {
|
|
12517
|
+
return !live && range.answerStep !== null && node.kind === "assistant-step" && node.data.step === range.answerStep;
|
|
12518
|
+
}
|
|
12519
|
+
/** Whether a new Turn-process range must reshape the Turn's group. */
|
|
12520
|
+
function processRangeChanged(previous, current) {
|
|
12521
|
+
if (previous.kind !== "turn-process" || current.kind !== "turn-process") return false;
|
|
12522
|
+
return previous.data.processStartSeq !== current.data.processStartSeq || previous.data.answerAnchorSeq !== current.data.answerAnchorSeq || previous.data.answerStep !== current.data.answerStep;
|
|
12523
|
+
}
|
|
12524
|
+
/**
|
|
12525
|
+
* Whether one render part of a Node belongs to the Turn's group. The finalized
|
|
12526
|
+
* answer and a live Turn's reply keep their own rows: the answer owns the
|
|
12527
|
+
* Turn's seat, and the collapsed body would otherwise swallow the prose the
|
|
12528
|
+
* reader is watching.
|
|
12529
|
+
* @param part - renderer-owned part of the Node, or undefined for the whole Node.
|
|
12530
|
+
* @param answer - whether the Node is the Turn's finalized answer step.
|
|
12531
|
+
* @param member - whether the Node's evidence falls inside the process range.
|
|
12532
|
+
* @param closed - whether the Turn is closed.
|
|
12533
|
+
* @returns whether the part joins the Turn's group.
|
|
12534
|
+
*/
|
|
12535
|
+
function inGroup(part, answer, member, closed) {
|
|
12536
|
+
if (part === "response") return member && closed && !answer;
|
|
12537
|
+
return member;
|
|
12538
|
+
}
|
|
12003
12539
|
function sameSummary(left, right) {
|
|
12004
12540
|
return left.running === right.running && left.runningDetail === right.runningDetail && left.preparing === right.preparing && left.counts.length === right.counts.length && left.counts.every((value, index) => value.kind === right.counts[index]?.kind && value.count === right.counts[index].count);
|
|
12005
12541
|
}
|
|
@@ -12008,7 +12544,7 @@ window.__ModuleLoader__.load({
|
|
|
12008
12544
|
}
|
|
12009
12545
|
function structureChanged(previous, current) {
|
|
12010
12546
|
if (!isVisibleChatNode(current) && (previous === void 0 || !isVisibleChatNode(previous))) return false;
|
|
12011
|
-
return previous === void 0 || previous.kind !== current.kind || turnOf(previous) !== turnOf(current) || isVisibleChatNode(previous) !== isVisibleChatNode(current) || reasoning(previous) !== reasoning(current) || reply(previous) !== reply(current);
|
|
12547
|
+
return previous === void 0 || previous.kind !== current.kind || turnOf(previous) !== turnOf(current) || isVisibleChatNode(previous) !== isVisibleChatNode(current) || reasoning(previous) !== reasoning(current) || reply(previous) !== reply(current) || processRangeChanged(previous, current);
|
|
12012
12548
|
}
|
|
12013
12549
|
function readNode(input, key) {
|
|
12014
12550
|
const node = input.readNode(key);
|
|
@@ -12113,7 +12649,12 @@ window.__ModuleLoader__.load({
|
|
|
12113
12649
|
const emit = (key, entry) => {
|
|
12114
12650
|
roots.set(key, [...roots.get(key) ?? [], entry]);
|
|
12115
12651
|
};
|
|
12116
|
-
|
|
12652
|
+
/**
|
|
12653
|
+
* Install the accumulated members as the Turn's group.
|
|
12654
|
+
* @param complete - whether the members form a finished range; the Turn's own
|
|
12655
|
+
* lifecycle closes the last group of a live Turn.
|
|
12656
|
+
*/
|
|
12657
|
+
const commit = (complete) => {
|
|
12117
12658
|
const first = pending[0];
|
|
12118
12659
|
if (first === void 0) return;
|
|
12119
12660
|
const key = this.extendedGroup(pending, added)?.key ?? brandString(JSON.stringify([
|
|
@@ -12124,60 +12665,67 @@ window.__ModuleLoader__.load({
|
|
|
12124
12665
|
const previous = this.groups.get(key);
|
|
12125
12666
|
const before = previous?.snapshot;
|
|
12126
12667
|
const group = previous !== void 0 && sameMembers(previous.members, pending) ? previous : new ProcessGroup(key, this.turn, pending);
|
|
12127
|
-
group.refresh(input,
|
|
12668
|
+
group.refresh(input, complete || closed);
|
|
12128
12669
|
groups.set(group.key, group);
|
|
12129
|
-
|
|
12670
|
+
roots.set(first.key, [{
|
|
12130
12671
|
kind: "group",
|
|
12131
12672
|
key: group.key
|
|
12132
|
-
});
|
|
12673
|
+
}, ...roots.get(first.key) ?? []]);
|
|
12133
12674
|
for (const member of pending) membership.set(member.key, group.key);
|
|
12134
12675
|
if (group.snapshot !== before) upserts.push(group.snapshot);
|
|
12135
12676
|
pending = [];
|
|
12136
12677
|
};
|
|
12137
|
-
let previous;
|
|
12138
|
-
let followed = false;
|
|
12139
12678
|
const keys = input.readTurn(this.turn);
|
|
12679
|
+
const nodes = keys.map((key) => readNode(input, key));
|
|
12140
12680
|
const replies = questionReplyIds(input, keys);
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
|
|
12146
|
-
|
|
12681
|
+
const closed = input.timeline.turns.get(this.turn)?.status === "closed";
|
|
12682
|
+
const live = !closed;
|
|
12683
|
+
const range = processRange(nodes);
|
|
12684
|
+
const split = () => {
|
|
12685
|
+
if (!closed) commit(true);
|
|
12686
|
+
};
|
|
12687
|
+
for (const [index, key] of keys.entries()) {
|
|
12688
|
+
const node = nodes[index];
|
|
12147
12689
|
if (node.kind === "turn-trigger" && replies.has(node.id)) {
|
|
12148
|
-
|
|
12690
|
+
split();
|
|
12149
12691
|
continue;
|
|
12150
12692
|
}
|
|
12151
|
-
if (INDEPENDENT.has(node.kind)
|
|
12152
|
-
|
|
12693
|
+
if (INDEPENDENT.has(node.kind)) {
|
|
12694
|
+
split();
|
|
12153
12695
|
emit(key, {
|
|
12154
12696
|
kind: "node",
|
|
12155
12697
|
key
|
|
12156
12698
|
});
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
else if (node.kind === "assistant-step") {
|
|
12162
|
-
if (reasoning(node)) pending.push({
|
|
12699
|
+
continue;
|
|
12700
|
+
}
|
|
12701
|
+
if (node.kind === "turn-process") {
|
|
12702
|
+
emit(key, {
|
|
12163
12703
|
kind: "node",
|
|
12164
|
-
key
|
|
12165
|
-
groupPart: "reasoning"
|
|
12704
|
+
key
|
|
12166
12705
|
});
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
}
|
|
12706
|
+
continue;
|
|
12707
|
+
}
|
|
12708
|
+
const answer = isAnswerStep(node, range, live);
|
|
12709
|
+
const member = answer || inProcessRange(node, range, live);
|
|
12710
|
+
const parts = node.kind === "assistant-step" ? [...reasoning(node) ? [{
|
|
12711
|
+
kind: "node",
|
|
12712
|
+
key,
|
|
12713
|
+
groupPart: "reasoning"
|
|
12714
|
+
}] : [], ...reply(node) ? [{
|
|
12715
|
+
kind: "node",
|
|
12716
|
+
key,
|
|
12717
|
+
groupPart: "response"
|
|
12718
|
+
}] : []] : [{
|
|
12176
12719
|
kind: "node",
|
|
12177
12720
|
key
|
|
12178
|
-
}
|
|
12721
|
+
}];
|
|
12722
|
+
for (const reference of parts) if (inGroup(reference.groupPart, answer, member, closed)) pending.push(reference);
|
|
12723
|
+
else {
|
|
12724
|
+
if (reference.groupPart === "response") split();
|
|
12725
|
+
emit(key, reference);
|
|
12726
|
+
}
|
|
12179
12727
|
}
|
|
12180
|
-
|
|
12728
|
+
commit(closed);
|
|
12181
12729
|
const removes = [...this.groups.keys()].filter((key) => !groups.has(key));
|
|
12182
12730
|
this.groups = groups;
|
|
12183
12731
|
this.membership = membership;
|
|
@@ -12263,7 +12811,10 @@ window.__ModuleLoader__.load({
|
|
|
12263
12811
|
}
|
|
12264
12812
|
if (turn !== void 0) touch(turn).add(after.key);
|
|
12265
12813
|
}
|
|
12266
|
-
for (const turn of input.changedTurns)
|
|
12814
|
+
for (const turn of input.changedTurns) {
|
|
12815
|
+
touch(turn);
|
|
12816
|
+
if (input.timeline.turns.get(turn)?.status === "closed" && (this.turns.get(turn)?.snapshots().length ?? 0) > 1) regroup.add(turn);
|
|
12817
|
+
}
|
|
12267
12818
|
const upserts = [];
|
|
12268
12819
|
const removes = [];
|
|
12269
12820
|
for (const turn of regroup) {
|
|
@@ -13373,6 +13924,12 @@ window.__ModuleLoader__.load({
|
|
|
13373
13924
|
const CHAT_SETTINGS_NAMESPACE = "ui-chat";
|
|
13374
13925
|
/** Field carrying the work-details presentation mode. */
|
|
13375
13926
|
const TRANSCRIPT_VIEW_FIELD = "transcriptView";
|
|
13927
|
+
/** Field carrying the independent work-details collapse timing. */
|
|
13928
|
+
const COLLAPSE_TIMING_FIELD = "collapseTiming";
|
|
13929
|
+
/** Available points when a completed Turn returns to its historical presentation. */
|
|
13930
|
+
const COLLAPSE_TIMINGS = ["completion", "next-input"];
|
|
13931
|
+
/** Preserve completion-time folding when no timing preference is saved. */
|
|
13932
|
+
const DEFAULT_COLLAPSE_TIMING = "completion";
|
|
13376
13933
|
/** Work-details presentation modes a user can choose. */
|
|
13377
13934
|
const TRANSCRIPT_VIEW_MODES = [
|
|
13378
13935
|
"compact",
|
|
@@ -13399,9 +13956,12 @@ window.__ModuleLoader__.load({
|
|
|
13399
13956
|
const PERFORMANCE_USAGE_MODES = ["compact", "detailed"];
|
|
13400
13957
|
/** Preserve detailed accounting for users without an explicit preference. */
|
|
13401
13958
|
const DEFAULT_PERFORMANCE_USAGE = "detailed";
|
|
13959
|
+
/** Preserve the built-in browser for users without an explicit preference. */
|
|
13960
|
+
const DEFAULT_LINK_OPENING = "sidebar";
|
|
13402
13961
|
/** Durable Chat schema; also the wire envelope the browser scope validates against. */
|
|
13403
13962
|
const ChatSettingsFields = {
|
|
13404
|
-
|
|
13963
|
+
[COLLAPSE_TIMING_FIELD]: Schema.union([...COLLAPSE_TIMINGS]).default(DEFAULT_COLLAPSE_TIMING),
|
|
13964
|
+
linkOpening: Schema.union(["sidebar", "new-tab"]).default(DEFAULT_LINK_OPENING),
|
|
13405
13965
|
performanceUsage: Schema.union([...PERFORMANCE_USAGE_MODES]).default(DEFAULT_PERFORMANCE_USAGE),
|
|
13406
13966
|
[TRANSCRIPT_VIEW_FIELD]: Schema.union([...TRANSCRIPT_VIEW_SETTING_VALUES]).default(DEFAULT_TRANSCRIPT_VIEW_MODE).loose()
|
|
13407
13967
|
};
|
|
@@ -13419,7 +13979,7 @@ window.__ModuleLoader__.load({
|
|
|
13419
13979
|
"next-input": "settings.collapse.nextInput"
|
|
13420
13980
|
};
|
|
13421
13981
|
/**
|
|
13422
|
-
* Render work-details and
|
|
13982
|
+
* Render the independent, Host-backed work-details and collapse-timing selectors.
|
|
13423
13983
|
* @param props - composed Settings slot props.
|
|
13424
13984
|
* @returns the preference row.
|
|
13425
13985
|
*/
|
|
@@ -13454,7 +14014,7 @@ window.__ModuleLoader__.load({
|
|
|
13454
14014
|
}
|
|
13455
14015
|
//#endregion
|
|
13456
14016
|
//#region lib/types/client/transcript-view.js
|
|
13457
|
-
/**
|
|
14017
|
+
/** Independent work-details preferences backed by the same Host configuration form. */
|
|
13458
14018
|
/** Live work-details preference consumed by Chat and its Settings row. */
|
|
13459
14019
|
var TranscriptViewPolicy = class {
|
|
13460
14020
|
host;
|
|
@@ -13462,8 +14022,8 @@ window.__ModuleLoader__.load({
|
|
|
13462
14022
|
unsubscribe;
|
|
13463
14023
|
/** Reactive current mode, including the client default before Host settings arrive. */
|
|
13464
14024
|
mode;
|
|
13465
|
-
/**
|
|
13466
|
-
collapseTiming = (0, _qilin_agent_client_store.createSnapshotStore)(
|
|
14025
|
+
/** Reactive collapse timing, defaulting to completion until Host settings arrive. */
|
|
14026
|
+
collapseTiming = (0, _qilin_agent_client_store.createSnapshotStore)(DEFAULT_COLLAPSE_TIMING);
|
|
13467
14027
|
/**
|
|
13468
14028
|
* @param host - durable Chat settings scope.
|
|
13469
14029
|
* @param defaultMode - presentation used without an explicit saved mode.
|
|
@@ -13491,11 +14051,13 @@ window.__ModuleLoader__.load({
|
|
|
13491
14051
|
this.host.set(TRANSCRIPT_VIEW_FIELD, mode);
|
|
13492
14052
|
}
|
|
13493
14053
|
/**
|
|
13494
|
-
*
|
|
14054
|
+
* Publish and persist collapse timing without changing the work-details mode.
|
|
13495
14055
|
* @param timing - immediate completion folding or deferred folding at the next input.
|
|
13496
14056
|
*/
|
|
13497
14057
|
setCollapseTiming(timing) {
|
|
14058
|
+
if (this.collapseTiming.getSnapshot() === timing) return;
|
|
13498
14059
|
this.collapseTiming.set(timing);
|
|
14060
|
+
this.host.set(COLLAPSE_TIMING_FIELD, timing);
|
|
13499
14061
|
}
|
|
13500
14062
|
/** Adopt the latest accepted Host section without writing it back. */
|
|
13501
14063
|
adopt() {
|
|
@@ -13504,6 +14066,8 @@ window.__ModuleLoader__.load({
|
|
|
13504
14066
|
const saved = section.transcriptView;
|
|
13505
14067
|
const mode = saved === "normal" || saved === "expanded" ? "detailed" : saved ?? this.defaultMode;
|
|
13506
14068
|
if (this.mode.getSnapshot() !== mode) this.mode.set(mode);
|
|
14069
|
+
const timing = section.collapseTiming ?? "completion";
|
|
14070
|
+
if (this.collapseTiming.getSnapshot() !== timing) this.collapseTiming.set(timing);
|
|
13507
14071
|
}
|
|
13508
14072
|
};
|
|
13509
14073
|
//#endregion
|
|
@@ -13598,16 +14162,16 @@ window.__ModuleLoader__.load({
|
|
|
13598
14162
|
/**
|
|
13599
14163
|
* Resolve a stable policy for one detail mode and collapse timing.
|
|
13600
14164
|
* @param mode - persisted work-details mode.
|
|
13601
|
-
* @param collapseTiming -
|
|
14165
|
+
* @param collapseTiming - persisted timing; defaults to immediate completion folding.
|
|
13602
14166
|
* @returns the same policy object for the same pair of choices.
|
|
13603
14167
|
*/
|
|
13604
14168
|
function presentationPolicyFor(mode, collapseTiming = "completion") {
|
|
13605
14169
|
return TIMING_POLICIES[collapseTiming][mode];
|
|
13606
14170
|
}
|
|
13607
14171
|
/**
|
|
13608
|
-
* Combine Host-backed detail and
|
|
14172
|
+
* Combine Host-backed detail and persisted timing without owning subscriptions.
|
|
13609
14173
|
* @param mode - live work-details mode.
|
|
13610
|
-
* @param collapseTiming - live
|
|
14174
|
+
* @param collapseTiming - live Host-backed collapse timing.
|
|
13611
14175
|
* @returns observable policy whose subscriptions follow both preferences.
|
|
13612
14176
|
*/
|
|
13613
14177
|
function derivePresentationPolicy(mode, collapseTiming) {
|