@deepseek-ai/dsh-client-ui-chat 0.1.2-alpha.5 → 0.1.3-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/lib/client.js +400 -228
- package/lib/types/client/chat/ChatNodeSeat.d.ts +1 -1
- package/lib/types/client/contract/assistant-content.d.ts +1 -1
- package/lib/types/client/contract/slots.d.ts +9 -2
- package/lib/types/client/contract/turn-metrics.d.ts +1 -1
- package/lib/types/client/conversation-nodes/assistant.d.ts +1 -2
- package/lib/types/client/conversation-nodes/chat-snapshot-builder.d.ts +55 -1
- package/lib/types/client/conversation-nodes/command.d.ts +1 -2
- package/lib/types/client/conversation-nodes/compaction.d.ts +1 -2
- package/lib/types/client/conversation-nodes/event-projection.d.ts +6 -0
- package/lib/types/client/conversation-nodes/fallback.d.ts +1 -2
- package/lib/types/client/conversation-nodes/message.d.ts +5 -2
- package/lib/types/client/conversation-nodes/partial.d.ts +2 -2
- package/lib/types/client/conversation-nodes/retry.d.ts +1 -2
- package/lib/types/client/conversation-nodes/tool.d.ts +1 -2
- package/lib/types/client/conversation-nodes/turn-error.d.ts +1 -2
- package/lib/types/client/conversation-nodes/turn-max-tokens.d.ts +1 -2
- package/lib/types/client/model/conversation-context.d.ts +1 -2
- package/lib/types/client/model/tool-call-tree.d.ts +1 -1
- package/package.json +28 -28
package/lib/client.js
CHANGED
|
@@ -27,7 +27,8 @@ window.__ModuleLoader__.load({
|
|
|
27
27
|
function resolveWorkspacePath(cwd, path) {
|
|
28
28
|
if (path.startsWith("/") || isWindowsStylePath(path)) return path;
|
|
29
29
|
if (cwd === void 0 || cwd === "") return path;
|
|
30
|
-
|
|
30
|
+
const separator = isWindowsStylePath(cwd) && cwd.includes("\\") ? "\\" : "/";
|
|
31
|
+
return `${cwd.replace(/[/\\]+$/, "")}${separator}${path.replace(/^[/\\]+/, "")}`;
|
|
31
32
|
}
|
|
32
33
|
//#endregion
|
|
33
34
|
//#region lib/types/client/contract/snapshot.js
|
|
@@ -115,7 +116,7 @@ window.__ModuleLoader__.load({
|
|
|
115
116
|
}
|
|
116
117
|
//#endregion
|
|
117
118
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-chat/src/client/chat/MessageItem.module.css.mjs
|
|
118
|
-
const css$15 = ".Sixlwa_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Sixlwa_userStack{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Sixlwa_bubble{background:var(--dsw-specific-bubble);max-width:100%;font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Sixlwa_referenceSummary{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_contextRow,.Sixlwa_compactionRow{padding:2px 0}.Sixlwa_compactionButton{width:100%;height:calc(24px + var(--dsh-content-font-delta,0px));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}.Sixlwa_compactionButton:not(:disabled){cursor:pointer}.Sixlwa_compactionButton:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}.Sixlwa_compactionLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Sixlwa_compactionLeading svg{width:calc(14px + var(--dsh-content-font-delta,0px));height:calc(14px + var(--dsh-content-font-delta,0px))}.Sixlwa_compactionContextIcon,.Sixlwa_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionContextIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionContextIcon{opacity:0}.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionDisclosureIcon{opacity:1}.Sixlwa_compactionTitle{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary-dimmed);flex:none}.Sixlwa_compactionSep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Sixlwa_compactionSummary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Sixlwa_compactionBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px))}.Sixlwa_retryRow{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_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}.Sixlwa_retrySummary::-webkit-details-marker{display:none}.Sixlwa_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)}.Sixlwa_retrySummary:hover{color:var(--dsw-alias-label-secondary)}.Sixlwa_retrySummary:focus-visible{outline:1.5px solid var(--dsw-alias-button-info-fill);outline-offset:2px}.Sixlwa_retryText{color:inherit}.Sixlwa_retryRow[data-active] .Sixlwa_retryText{background:linear-gradient(90deg, var(--dsw-alias-label-tertiary) 0%, var(--dsw-alias-label-tertiary) 40%, var(--dsw-alias-label-secondary) 50%, var(--dsw-alias-label-tertiary) 60%, var(--dsw-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Sixlwa_retry-shimmer}.Sixlwa_retryRow[open] .Sixlwa_retrySummary:after{transform:rotate(45deg)}.Sixlwa_retryDetails{overflow-wrap:anywhere;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Sixlwa_retryDetailLabel{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorRow{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Sixlwa_turnErrorDot{margin-top:5px}.Sixlwa_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Sixlwa_turnErrorTitle{color:var(--dsw-alias-state-error-primary);margin-right:6px;font-weight:600}.Sixlwa_turnErrorMessage{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorCode{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-markdown-code-block-small)}.Sixlwa_maxTokensTitle{color:var(--dsw-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Sixlwa_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Sixlwa_retryRow[data-active] .Sixlwa_retryText{color:inherit;background:0 0;animation:none}}";
|
|
119
|
+
const css$15 = ".Sixlwa_userRow{flex-direction:column;align-items:flex-end;gap:6px;display:flex}.Sixlwa_userStack{min-width:0;max-width:min(calc(var(--dsh-chat-content-width,748px) * .702), 82%);flex-direction:column;align-items:flex-end;gap:8px;display:flex}.Sixlwa_bubble{background:var(--dsw-specific-bubble);max-width:100%;font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;border-radius:22px;padding:10px 16px}.Sixlwa_referenceSummary{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_contextRow,.Sixlwa_compactionRow{padding:2px 0}.Sixlwa_compactionButton{width:100%;height:calc(24px + var(--dsh-content-font-delta,0px));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}.Sixlwa_compactionButton:not(:disabled){cursor:pointer}.Sixlwa_compactionButton:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}.Sixlwa_compactionLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);flex:none;place-items:center;margin-right:6px;display:inline-grid}.Sixlwa_compactionLeading svg{width:calc(14px + var(--dsh-content-font-delta,0px));height:calc(14px + var(--dsh-content-font-delta,0px))}.Sixlwa_compactionContextIcon,.Sixlwa_compactionDisclosureIcon{grid-area:1/1;justify-content:center;align-items:center;display:inline-flex}.Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionContextIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionContextIcon{opacity:0}.Sixlwa_compactionButton:not(:disabled):hover .Sixlwa_compactionDisclosureIcon,.Sixlwa_compactionButton:not(:disabled):focus-visible .Sixlwa_compactionDisclosureIcon{opacity:1}.Sixlwa_compactionTitle{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-primary-dimmed);flex:none}.Sixlwa_compactionSep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.Sixlwa_compactionSummary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:auto;overflow:hidden}.Sixlwa_compactionBody{padding:4px 0 4px calc(22px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px))}.Sixlwa_retryRow{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px))}.Sixlwa_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}.Sixlwa_retrySummary::-webkit-details-marker{display:none}.Sixlwa_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)}.Sixlwa_retrySummary:hover{color:var(--dsw-alias-label-secondary)}.Sixlwa_retrySummary:focus-visible{outline:1.5px solid var(--dsw-alias-button-info-fill);outline-offset:2px}.Sixlwa_retryText{color:inherit}.Sixlwa_retryRow[data-active] .Sixlwa_retryText{background:linear-gradient(90deg, var(--dsw-alias-label-tertiary) 0%, var(--dsw-alias-label-tertiary) 40%, var(--dsw-alias-label-secondary) 50%, var(--dsw-alias-label-tertiary) 60%, var(--dsw-alias-label-tertiary) 100%);color:#0000;background-position:100%;background-size:200% 100%;background-clip:text;animation:1.6s ease-in-out infinite Sixlwa_retry-shimmer}.Sixlwa_retryRow[open] .Sixlwa_retrySummary:after{transform:rotate(45deg)}.Sixlwa_retryDetails{overflow-wrap:anywhere;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px));gap:2px;margin-top:3px;padding-left:14px;display:grid}.Sixlwa_retryDetailLabel{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorRow{font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));grid-template-columns:10px minmax(0,1fr) auto;align-items:start;gap:8px;padding:2px 0;display:grid}.Sixlwa_turnErrorDot{margin-top:5px}.Sixlwa_turnErrorCopy{overflow-wrap:anywhere;min-width:0}.Sixlwa_turnErrorTitle{color:var(--dsw-alias-state-error-primary);margin-right:6px;font-weight:600}.Sixlwa_turnErrorMessage{color:var(--dsw-alias-label-secondary)}.Sixlwa_turnErrorCode{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-markdown-code-block-small)}.Sixlwa_maxTokensTitle{color:var(--dsw-alias-state-warn-primary);margin-right:6px;font-weight:600}@keyframes Sixlwa_retry-shimmer{0%{background-position:100%}to{background-position:0}}@media (prefers-reduced-motion:reduce){.Sixlwa_retryRow[data-active] .Sixlwa_retryText{color:inherit;background:0 0;animation:none}}.Sixlwa_attachmentRow{flex-wrap:wrap;justify-content:flex-end;gap:8px;max-width:100%;display:flex}.Sixlwa_fileCard{border:.5px solid var(--dsw-alias-border-l2,#0000001f);background:var(--dsw-specific-input-major,transparent);box-sizing:border-box;border-radius:16px;flex:0 0 240px;align-items:center;gap:10px;width:240px;min-height:64px;padding:8px 12px;display:inline-flex}.Sixlwa_fileIcon{flex:none;width:24px;height:28px}.Sixlwa_fileContent{flex-direction:column;flex:1;min-width:0;display:flex}.Sixlwa_fileName{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;overflow:hidden}.Sixlwa_fileMeta{white-space:nowrap;text-overflow:ellipsis;color:var(--dsw-alias-label-tertiary,#00000073);font-size:12px;line-height:15px;overflow:hidden}";
|
|
119
120
|
const tagId$15 = "@deepseek-ai/dsh-client-ui-chat/MessageItem.module.css";
|
|
120
121
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$15) + "]") === null) {
|
|
121
122
|
const tag = document.createElement("style");
|
|
@@ -125,6 +126,7 @@ window.__ModuleLoader__.load({
|
|
|
125
126
|
document.head.appendChild(tag);
|
|
126
127
|
}
|
|
127
128
|
var MessageItem_module_css_default = {
|
|
129
|
+
"attachmentRow": "Sixlwa_attachmentRow",
|
|
128
130
|
"bubble": "Sixlwa_bubble",
|
|
129
131
|
"compactionBody": "Sixlwa_compactionBody",
|
|
130
132
|
"compactionButton": "Sixlwa_compactionButton",
|
|
@@ -136,6 +138,11 @@ window.__ModuleLoader__.load({
|
|
|
136
138
|
"compactionSummary": "Sixlwa_compactionSummary",
|
|
137
139
|
"compactionTitle": "Sixlwa_compactionTitle",
|
|
138
140
|
"contextRow": "Sixlwa_contextRow",
|
|
141
|
+
"fileCard": "Sixlwa_fileCard",
|
|
142
|
+
"fileContent": "Sixlwa_fileContent",
|
|
143
|
+
"fileIcon": "Sixlwa_fileIcon",
|
|
144
|
+
"fileMeta": "Sixlwa_fileMeta",
|
|
145
|
+
"fileName": "Sixlwa_fileName",
|
|
139
146
|
"maxTokensTitle": "Sixlwa_maxTokensTitle",
|
|
140
147
|
"referenceSummary": "Sixlwa_referenceSummary",
|
|
141
148
|
"retry-shimmer": "Sixlwa_retry-shimmer",
|
|
@@ -1054,19 +1061,31 @@ window.__ModuleLoader__.load({
|
|
|
1054
1061
|
}
|
|
1055
1062
|
//#endregion
|
|
1056
1063
|
//#region lib/types/client/chat/MessageItem.js
|
|
1064
|
+
function extensionOf(name) {
|
|
1065
|
+
const dot = name.lastIndexOf(".");
|
|
1066
|
+
if (dot <= 0 || dot === name.length - 1) return "";
|
|
1067
|
+
return name.slice(dot + 1).toUpperCase().slice(0, 8);
|
|
1068
|
+
}
|
|
1057
1069
|
function contentParts(content) {
|
|
1058
1070
|
const texts = [];
|
|
1059
|
-
const
|
|
1071
|
+
const attachments = [];
|
|
1060
1072
|
const rest = [];
|
|
1061
1073
|
for (const block of content) {
|
|
1062
1074
|
const b = block;
|
|
1063
1075
|
if (b.type === "text" && typeof b.text === "string") texts.push(b.text);
|
|
1064
|
-
else if (b.type === "image" && b.attachment !== void 0)
|
|
1076
|
+
else if (b.type === "image" && b.attachment !== void 0) attachments.push({
|
|
1077
|
+
type: "image",
|
|
1078
|
+
image: { attachment: b.attachment }
|
|
1079
|
+
});
|
|
1080
|
+
else if (b.type === "file" && b.attachment !== void 0) attachments.push({
|
|
1081
|
+
type: "file",
|
|
1082
|
+
file: b.attachment
|
|
1083
|
+
});
|
|
1065
1084
|
else rest.push(block);
|
|
1066
1085
|
}
|
|
1067
1086
|
return {
|
|
1068
1087
|
text: texts.join(""),
|
|
1069
|
-
|
|
1088
|
+
attachments,
|
|
1070
1089
|
rest
|
|
1071
1090
|
};
|
|
1072
1091
|
}
|
|
@@ -1180,9 +1199,10 @@ window.__ModuleLoader__.load({
|
|
|
1180
1199
|
});
|
|
1181
1200
|
}
|
|
1182
1201
|
/** Right-aligned bubble shared by user and steering rows. */
|
|
1183
|
-
function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [],
|
|
1184
|
-
const { text,
|
|
1185
|
-
const
|
|
1202
|
+
function UserStyleBubble({ content, renderMessageImages, actions, pending = false, echo = false, referenceLabels = [], skillNames = [], previewAttachments, t }) {
|
|
1203
|
+
const { text, attachments: contentAttachments, rest } = contentParts(content);
|
|
1204
|
+
const attachments = previewAttachments ?? contentAttachments;
|
|
1205
|
+
const compactImages = attachments.length > 1;
|
|
1186
1206
|
const truncated = (total) => t("json.truncated", { total });
|
|
1187
1207
|
const showBubble = text !== "" || rest.length > 0;
|
|
1188
1208
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1192,13 +1212,31 @@ window.__ModuleLoader__.load({
|
|
|
1192
1212
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
1193
1213
|
className: MessageItem_module_css_default.userStack,
|
|
1194
1214
|
children: [
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1215
|
+
attachments.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
1216
|
+
className: MessageItem_module_css_default.attachmentRow,
|
|
1217
|
+
"data-message-attachments": true,
|
|
1218
|
+
children: attachments.map((attachment, index) => attachment.type === "image" ? (0, react_jsx_runtime.jsx)(react.Fragment, { children: renderMessageImages({
|
|
1219
|
+
images: [attachment.image],
|
|
1220
|
+
align: "end",
|
|
1221
|
+
compact: compactImages
|
|
1222
|
+
}) }, `image:${index}`) : (0, react_jsx_runtime.jsxs)("span", {
|
|
1223
|
+
className: MessageItem_module_css_default.fileCard,
|
|
1224
|
+
title: attachment.file.name,
|
|
1225
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DocumentFileIcon, { className: MessageItem_module_css_default.fileIcon }), (0, react_jsx_runtime.jsxs)("span", {
|
|
1226
|
+
className: MessageItem_module_css_default.fileContent,
|
|
1227
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
1228
|
+
className: MessageItem_module_css_default.fileName,
|
|
1229
|
+
children: attachment.file.name
|
|
1230
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1231
|
+
className: MessageItem_module_css_default.fileMeta,
|
|
1232
|
+
children: [extensionOf(attachment.file.name), (0, _deepseek_ai_dsh_client_ui_primitives.fileSizeText)(attachment.file.bytes)].filter(Boolean).join(" ")
|
|
1233
|
+
})]
|
|
1234
|
+
})]
|
|
1235
|
+
}, `file:${index}`))
|
|
1198
1236
|
}),
|
|
1199
1237
|
showBubble && (0, react_jsx_runtime.jsxs)("div", {
|
|
1200
1238
|
className: MessageItem_module_css_default.bubble,
|
|
1201
|
-
children: [(0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(text, referenceLabels), rest.map((block, i) => (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
|
|
1239
|
+
children: [(0, _deepseek_ai_dsh_client_ui_primitives.projectUserText)(text, referenceLabels, skillNames), rest.map((block, i) => (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.JsonBlock, {
|
|
1202
1240
|
label: t("message.extraBlock"),
|
|
1203
1241
|
payload: block,
|
|
1204
1242
|
truncatedLabel: truncated
|
|
@@ -1246,12 +1284,18 @@ window.__ModuleLoader__.load({
|
|
|
1246
1284
|
type: "text",
|
|
1247
1285
|
text: submission.text
|
|
1248
1286
|
}], [submission.text]),
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1287
|
+
previewAttachments: (0, react.useMemo)(() => submission.attachments.map((attachment) => attachment.type === "image" ? {
|
|
1288
|
+
type: "image",
|
|
1289
|
+
image: { preview: {
|
|
1290
|
+
url: attachment.value.previewUrl,
|
|
1291
|
+
...attachment.value.name === void 0 ? {} : { name: attachment.value.name },
|
|
1292
|
+
...attachment.value.width === void 0 ? {} : { width: attachment.value.width },
|
|
1293
|
+
...attachment.value.height === void 0 ? {} : { height: attachment.value.height }
|
|
1294
|
+
} }
|
|
1295
|
+
} : {
|
|
1296
|
+
type: "file",
|
|
1297
|
+
file: attachment.value
|
|
1298
|
+
}), [submission.attachments]),
|
|
1255
1299
|
renderMessageImages,
|
|
1256
1300
|
pending: submission.placement === "steering",
|
|
1257
1301
|
echo: true,
|
|
@@ -1272,6 +1316,7 @@ window.__ModuleLoader__.load({
|
|
|
1272
1316
|
content: data.content,
|
|
1273
1317
|
renderMessageImages,
|
|
1274
1318
|
...data.referenceLabels === void 0 ? {} : { referenceLabels: data.referenceLabels },
|
|
1319
|
+
...data.skillNames === void 0 ? {} : { skillNames: data.skillNames },
|
|
1275
1320
|
t,
|
|
1276
1321
|
actions: (text) => (0, react_jsx_runtime.jsx)(MessageIconActions, {
|
|
1277
1322
|
text,
|
|
@@ -1470,7 +1515,7 @@ window.__ModuleLoader__.load({
|
|
|
1470
1515
|
return location?.kind === "turn" || location?.kind === "step" ? location.turn.turn : void 0;
|
|
1471
1516
|
}
|
|
1472
1517
|
/** Subscribe, apply Turn-process visibility, and dispatch one stable Context key. */
|
|
1473
|
-
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
|
|
1518
|
+
const ChatNodeSeat = (0, react.memo)(function ChatNodeSeat({ nodeKey, useChatNode, useChatNodeProcess, historyIncomplete, compactTranscript, selectedCallId, cwd, openFile, inspectCall, forkAt, loadImage, renderMessageImages, fileMentions, useStore, actions, renderSlot, t }) {
|
|
1474
1519
|
const node = useChatNode(nodeKey);
|
|
1475
1520
|
const routedNode = node;
|
|
1476
1521
|
const turn = turnOf(routedNode);
|
|
@@ -1509,6 +1554,7 @@ window.__ModuleLoader__.load({
|
|
|
1509
1554
|
openFile,
|
|
1510
1555
|
inspectCall,
|
|
1511
1556
|
forkAt,
|
|
1557
|
+
loadImage,
|
|
1512
1558
|
renderMessageImages,
|
|
1513
1559
|
fileMentions,
|
|
1514
1560
|
turnProcess
|
|
@@ -1519,6 +1565,7 @@ window.__ModuleLoader__.load({
|
|
|
1519
1565
|
openFile,
|
|
1520
1566
|
inspectCall,
|
|
1521
1567
|
forkAt,
|
|
1568
|
+
loadImage,
|
|
1522
1569
|
renderMessageImages,
|
|
1523
1570
|
fileMentions,
|
|
1524
1571
|
turnProcess
|
|
@@ -1860,6 +1907,10 @@ window.__ModuleLoader__.load({
|
|
|
1860
1907
|
function scrollerOf(from) {
|
|
1861
1908
|
return from.closest("[data-conversation-scroll]") ?? from;
|
|
1862
1909
|
}
|
|
1910
|
+
/** Browser shrink clamps and recorded writes do not transfer scroll ownership. */
|
|
1911
|
+
function readerMovedScroll(top, floor, observedTop) {
|
|
1912
|
+
return Math.abs(top - Math.min(observedTop, floor)) > .5;
|
|
1913
|
+
}
|
|
1863
1914
|
/** Find an already-rendered row without interpolating a selector. */
|
|
1864
1915
|
function anchorElement(list, key) {
|
|
1865
1916
|
for (const row of list.querySelectorAll("[data-chat-anchor-key]:not([hidden])")) if (row.dataset.chatAnchorKey === key) return row;
|
|
@@ -2261,7 +2312,7 @@ window.__ModuleLoader__.load({
|
|
|
2261
2312
|
if (local === null) return;
|
|
2262
2313
|
const el = scrollerOf(local);
|
|
2263
2314
|
const floor = Math.max(0, el.scrollHeight - el.clientHeight);
|
|
2264
|
-
const movedByReader =
|
|
2315
|
+
const movedByReader = readerMovedScroll(el.scrollTop, floor, observedTopRef.current);
|
|
2265
2316
|
const isAtBottom = movedByReader ? floor - el.scrollTop <= 25 : atBottomRef.current;
|
|
2266
2317
|
if (!movedByReader && isAtBottom) {
|
|
2267
2318
|
toBottom(el);
|
|
@@ -2296,6 +2347,13 @@ window.__ModuleLoader__.load({
|
|
|
2296
2347
|
};
|
|
2297
2348
|
const onScroll = () => {
|
|
2298
2349
|
scrollSamplePendingRef.current = true;
|
|
2350
|
+
if (atBottomRef.current) {
|
|
2351
|
+
const floor = Math.max(0, el.scrollHeight - el.clientHeight);
|
|
2352
|
+
if (!readerMovedScroll(el.scrollTop, floor, observedTopRef.current)) {
|
|
2353
|
+
sample();
|
|
2354
|
+
return;
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2299
2357
|
sampleTimer ??= window.setTimeout(sample, SCROLL_SAMPLE_INTERVAL_MS);
|
|
2300
2358
|
};
|
|
2301
2359
|
el.addEventListener("scroll", onScroll, { passive: true });
|
|
@@ -2468,6 +2526,7 @@ window.__ModuleLoader__.load({
|
|
|
2468
2526
|
openFile: requestOpenFile,
|
|
2469
2527
|
inspectCall,
|
|
2470
2528
|
forkAt,
|
|
2529
|
+
loadImage,
|
|
2471
2530
|
renderMessageImages,
|
|
2472
2531
|
fileMentions,
|
|
2473
2532
|
renderSlot,
|
|
@@ -3902,47 +3961,6 @@ window.__ModuleLoader__.load({
|
|
|
3902
3961
|
});
|
|
3903
3962
|
});
|
|
3904
3963
|
//#endregion
|
|
3905
|
-
//#region ../../core/session/src/surface.ts
|
|
3906
|
-
/** Runtime counterpart of the message-producing event union. */
|
|
3907
|
-
const SURFACE_EVENT_TYPES = new Set([
|
|
3908
|
-
"user/message",
|
|
3909
|
-
"assistant/message",
|
|
3910
|
-
"tool/result"
|
|
3911
|
-
]);
|
|
3912
|
-
/**
|
|
3913
|
-
* Narrow an event to a surface-eligible event carrying its required marker.
|
|
3914
|
-
* @param event - event to test.
|
|
3915
|
-
* @returns true when both the type and marker identify a surface event.
|
|
3916
|
-
*/
|
|
3917
|
-
function isSurfaceEvent(event) {
|
|
3918
|
-
if (!SURFACE_EVENT_TYPES.has(event.type)) return false;
|
|
3919
|
-
return event.surfaceOp !== void 0;
|
|
3920
|
-
}
|
|
3921
|
-
/**
|
|
3922
|
-
* Narrow an event to an append-origin surface event: one that entered the
|
|
3923
|
-
* surface at its own log position and was never itself a replacement copy.
|
|
3924
|
-
*
|
|
3925
|
-
* The model-visible surface deliberately shadows replaced ranges, so it is the
|
|
3926
|
-
* wrong source for a human transcript — a landed replacement would erase
|
|
3927
|
-
* conversation the user already saw. Append-origin events are that transcript's
|
|
3928
|
-
* durable source material; replacement copies stay model-only.
|
|
3929
|
-
* @param event - event to test.
|
|
3930
|
-
* @returns true when the event appended to the surface tail.
|
|
3931
|
-
*/
|
|
3932
|
-
function isAppendSurfaceEvent(event) {
|
|
3933
|
-
return isSurfaceEvent(event) && event.surfaceOp === "append";
|
|
3934
|
-
}
|
|
3935
|
-
/**
|
|
3936
|
-
* Narrow an event to a surface replacement: a node that shadowed an existing
|
|
3937
|
-
* surface range instead of appending to the tail. The counterpart of
|
|
3938
|
-
* {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants.
|
|
3939
|
-
* @param event - event to test.
|
|
3940
|
-
* @returns true when the event replaced a surface range.
|
|
3941
|
-
*/
|
|
3942
|
-
function isReplacementSurfaceEvent(event) {
|
|
3943
|
-
return isSurfaceEvent(event) && event.surfaceOp !== "append";
|
|
3944
|
-
}
|
|
3945
|
-
//#endregion
|
|
3946
3964
|
//#region lib/types/client/conversation-nodes/common.js
|
|
3947
3965
|
/**
|
|
3948
3966
|
* Relative positions in one durable event's seq neighborhood: interrupted
|
|
@@ -4075,6 +4093,16 @@ window.__ModuleLoader__.load({
|
|
|
4075
4093
|
return collect(record, "references", "label");
|
|
4076
4094
|
}
|
|
4077
4095
|
/**
|
|
4096
|
+
* Read the skill name a durable skill-invocation injection loaded.
|
|
4097
|
+
* @param source - Logged `user/message` source.
|
|
4098
|
+
* @returns The skill name, or null for every other source.
|
|
4099
|
+
*/
|
|
4100
|
+
function skillInvocationName(source) {
|
|
4101
|
+
const record = asRecord(source);
|
|
4102
|
+
if (record === null || readString(record, "kind") !== "skill-invocation") return null;
|
|
4103
|
+
return readString(record, "name");
|
|
4104
|
+
}
|
|
4105
|
+
/**
|
|
4078
4106
|
* Classify finalized Assistant content for Chat rendering.
|
|
4079
4107
|
* @param content - Core content blocks.
|
|
4080
4108
|
* @returns Chat blocks in source order.
|
|
@@ -4173,9 +4201,6 @@ window.__ModuleLoader__.load({
|
|
|
4173
4201
|
}
|
|
4174
4202
|
//#endregion
|
|
4175
4203
|
//#region lib/types/client/conversation-nodes/assistant.js
|
|
4176
|
-
function isChunkRunEvent$1(event) {
|
|
4177
|
-
return event.type === "chunkrow/text-chunks" || event.type === "chunkrow/reasoning-chunks" || event.type === "chunkrow/tool-call-chunks";
|
|
4178
|
-
}
|
|
4179
4204
|
function initialState(turn, step) {
|
|
4180
4205
|
return {
|
|
4181
4206
|
turn,
|
|
@@ -4219,9 +4244,7 @@ window.__ModuleLoader__.load({
|
|
|
4219
4244
|
hidden: true
|
|
4220
4245
|
};
|
|
4221
4246
|
}
|
|
4222
|
-
function updateChunk(state,
|
|
4223
|
-
if (match.event.type !== "assistant/chunk") return state;
|
|
4224
|
-
const chunk = match.event.data.chunk;
|
|
4247
|
+
function updateChunk(state, chunk, seq, time) {
|
|
4225
4248
|
const blocks = [...state.blocks];
|
|
4226
4249
|
let changedIndex = -1;
|
|
4227
4250
|
let previousVisible = false;
|
|
@@ -4288,78 +4311,21 @@ window.__ModuleLoader__.load({
|
|
|
4288
4311
|
visibleBlocks,
|
|
4289
4312
|
hidden: visibleBlocks > 0 ? false : state.hidden,
|
|
4290
4313
|
...visibleBlocks > 0 && state.firstVisibleSeq === void 0 ? {
|
|
4291
|
-
firstVisibleSeq:
|
|
4292
|
-
firstVisibleTime:
|
|
4314
|
+
firstVisibleSeq: seq,
|
|
4315
|
+
firstVisibleTime: time
|
|
4293
4316
|
} : {},
|
|
4294
|
-
...firstToken && state.firstTokenTime === void 0 ? { firstTokenTime:
|
|
4317
|
+
...firstToken && state.firstTokenTime === void 0 ? { firstTokenTime: time } : {}
|
|
4295
4318
|
};
|
|
4296
4319
|
}
|
|
4297
|
-
function
|
|
4298
|
-
const
|
|
4299
|
-
const nameStartsToken = event.type === "chunkrow/tool-call-chunks" && Object.hasOwn(event.data, "name");
|
|
4300
|
-
let firstTokenTime;
|
|
4301
|
-
let firstVisible;
|
|
4302
|
-
let time = event.time;
|
|
4303
|
-
for (let index = 0; index < fragments.length; index++) {
|
|
4304
|
-
const fragment = fragments[index];
|
|
4305
|
-
if (needsToken && firstTokenTime === void 0 && (nameStartsToken || fragment !== "")) firstTokenTime = time;
|
|
4306
|
-
if (needsVisible && firstVisible === void 0 && (visibleFromStart || event.type !== "chunkrow/tool-call-chunks" && fragment.trim() !== "")) firstVisible = {
|
|
4307
|
-
seq: event.seq + index,
|
|
4308
|
-
time
|
|
4309
|
-
};
|
|
4310
|
-
if ((!needsToken || firstTokenTime !== void 0) && (!needsVisible || firstVisible !== void 0)) break;
|
|
4311
|
-
time += event.data.dt[index] ?? 0;
|
|
4312
|
-
}
|
|
4313
|
-
return {
|
|
4314
|
-
firstTokenTime,
|
|
4315
|
-
firstVisible
|
|
4316
|
-
};
|
|
4317
|
-
}
|
|
4318
|
-
function updateChunkRun(state, event) {
|
|
4319
|
-
const blocks = [...state.blocks];
|
|
4320
|
-
const previous = blocks[event.data.index];
|
|
4321
|
-
const previousVisible = blockIsVisible(previous);
|
|
4322
|
-
let visibleFromStart = state.visibleBlocks - Number(previousVisible) > 0;
|
|
4323
|
-
if (event.type === "chunkrow/text-chunks") {
|
|
4324
|
-
const text = previous?.kind === "text" ? previous.text : "";
|
|
4325
|
-
visibleFromStart ||= text.trim() !== "";
|
|
4326
|
-
blocks[event.data.index] = {
|
|
4327
|
-
kind: "text",
|
|
4328
|
-
text: text + event.data.texts.join("")
|
|
4329
|
-
};
|
|
4330
|
-
} else if (event.type === "chunkrow/reasoning-chunks") {
|
|
4331
|
-
const text = previous?.kind === "reasoning" ? previous.text : "";
|
|
4332
|
-
visibleFromStart ||= text.trim() !== "";
|
|
4333
|
-
blocks[event.data.index] = {
|
|
4334
|
-
kind: "reasoning",
|
|
4335
|
-
text: text + event.data.texts.join("")
|
|
4336
|
-
};
|
|
4337
|
-
} else {
|
|
4338
|
-
const base = previous?.kind === "tool-call" ? previous : {
|
|
4339
|
-
kind: "tool-call",
|
|
4340
|
-
callId: "",
|
|
4341
|
-
name: "",
|
|
4342
|
-
argsRaw: ""
|
|
4343
|
-
};
|
|
4344
|
-
blocks[event.data.index] = {
|
|
4345
|
-
kind: "tool-call",
|
|
4346
|
-
callId: base.callId || String(event.data.id),
|
|
4347
|
-
name: Object.hasOwn(event.data, "name") ? event.data.name : base.name,
|
|
4348
|
-
argsRaw: base.argsRaw + event.data.args.join("")
|
|
4349
|
-
};
|
|
4350
|
-
}
|
|
4351
|
-
const boundaries = chunkRunBoundaries(event, state.firstTokenTime === void 0, state.firstVisibleSeq === void 0, visibleFromStart);
|
|
4352
|
-
const visibleBlocks = state.visibleBlocks - Number(previousVisible) + Number(blockIsVisible(blocks[event.data.index]));
|
|
4320
|
+
function settleMessage(state, match, event) {
|
|
4321
|
+
const blocks = toAssistantBlocks(event.data.message.content);
|
|
4353
4322
|
return {
|
|
4354
4323
|
...state,
|
|
4355
4324
|
blocks,
|
|
4356
|
-
visibleBlocks,
|
|
4357
|
-
hidden:
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
firstVisibleTime: boundaries.firstVisible.time
|
|
4361
|
-
},
|
|
4362
|
-
...boundaries.firstTokenTime === void 0 ? {} : { firstTokenTime: boundaries.firstTokenTime }
|
|
4325
|
+
visibleBlocks: countVisibleBlocks(blocks),
|
|
4326
|
+
hidden: false,
|
|
4327
|
+
final: match,
|
|
4328
|
+
usage: event.data.usage
|
|
4363
4329
|
};
|
|
4364
4330
|
}
|
|
4365
4331
|
function closedBoundary(location) {
|
|
@@ -4405,27 +4371,14 @@ window.__ModuleLoader__.load({
|
|
|
4405
4371
|
function fallbackState$5(context) {
|
|
4406
4372
|
let state;
|
|
4407
4373
|
for (const match of context.matches) {
|
|
4408
|
-
if (
|
|
4374
|
+
if (match.event.type === "assistant/live-chunk") {
|
|
4409
4375
|
state ??= initialState(match.event.data.turn, match.event.data.step);
|
|
4410
|
-
state =
|
|
4411
|
-
continue;
|
|
4412
|
-
}
|
|
4413
|
-
if (match.event.type === "assistant/chunk") {
|
|
4414
|
-
state ??= initialState(match.event.data.turn, match.event.data.step);
|
|
4415
|
-
state = updateChunk(state, match);
|
|
4376
|
+
state = updateChunk(state, match.event.data.chunk, match.event.seq, match.event.time);
|
|
4416
4377
|
continue;
|
|
4417
4378
|
}
|
|
4418
4379
|
if (match.event.type === "assistant/message") {
|
|
4419
4380
|
state ??= initialState(match.event.data.turn, match.event.data.step);
|
|
4420
|
-
|
|
4421
|
-
state = {
|
|
4422
|
-
...state,
|
|
4423
|
-
blocks,
|
|
4424
|
-
visibleBlocks: countVisibleBlocks(blocks),
|
|
4425
|
-
hidden: false,
|
|
4426
|
-
final: match,
|
|
4427
|
-
usage: match.event.data.usage
|
|
4428
|
-
};
|
|
4381
|
+
state = settleMessage(state, match, match.event);
|
|
4429
4382
|
continue;
|
|
4430
4383
|
}
|
|
4431
4384
|
if (match.event.type === "llm/retry" && state !== void 0) state = resetForRetry(state);
|
|
@@ -4469,11 +4422,7 @@ window.__ModuleLoader__.load({
|
|
|
4469
4422
|
id: `${event.data.turn}:${event.data.step}`,
|
|
4470
4423
|
role: "start"
|
|
4471
4424
|
};
|
|
4472
|
-
if (event.type === "assistant/chunk" || event.type === "assistant/message" &&
|
|
4473
|
-
id: `${event.data.turn}:${event.data.step}`,
|
|
4474
|
-
role: "update"
|
|
4475
|
-
};
|
|
4476
|
-
if (isChunkRunEvent$1(event)) return {
|
|
4425
|
+
if (event.type === "assistant/live-chunk" || event.type === "assistant/message" && event.surfaceOp === "append") return {
|
|
4477
4426
|
id: `${event.data.turn}:${event.data.step}`,
|
|
4478
4427
|
role: "update"
|
|
4479
4428
|
};
|
|
@@ -4488,26 +4437,14 @@ window.__ModuleLoader__.load({
|
|
|
4488
4437
|
return initialState(match.event.data.turn, match.event.data.step);
|
|
4489
4438
|
},
|
|
4490
4439
|
update: (context, match) => {
|
|
4491
|
-
if (
|
|
4492
|
-
if (match.event.type === "assistant/
|
|
4493
|
-
if (match.event.type === "assistant/message") {
|
|
4494
|
-
const blocks = toAssistantBlocks(match.event.data.message.content);
|
|
4495
|
-
return {
|
|
4496
|
-
...context.state,
|
|
4497
|
-
blocks,
|
|
4498
|
-
visibleBlocks: countVisibleBlocks(blocks),
|
|
4499
|
-
hidden: false,
|
|
4500
|
-
final: match,
|
|
4501
|
-
usage: match.event.data.usage
|
|
4502
|
-
};
|
|
4503
|
-
}
|
|
4440
|
+
if (match.event.type === "assistant/live-chunk") return updateChunk(context.state, match.event.data.chunk, match.event.seq, match.event.time);
|
|
4441
|
+
if (match.event.type === "assistant/message") return settleMessage(context.state, match, match.event);
|
|
4504
4442
|
if (match.event.type === "llm/retry") return resetForRetry(context.state);
|
|
4505
4443
|
return context.state;
|
|
4506
4444
|
},
|
|
4507
4445
|
publication: (match) => {
|
|
4508
4446
|
if (match.event.type === "step/start") return "none";
|
|
4509
|
-
if (
|
|
4510
|
-
if (match.event.type !== "assistant/chunk") return "immediate";
|
|
4447
|
+
if (match.event.type !== "assistant/live-chunk") return "immediate";
|
|
4511
4448
|
const type = match.event.data.chunk.type;
|
|
4512
4449
|
return type === "usage" || type === "finish" ? "none" : "animation-frame";
|
|
4513
4450
|
},
|
|
@@ -5107,6 +5044,194 @@ window.__ModuleLoader__.load({
|
|
|
5107
5044
|
return [...byKey.values()];
|
|
5108
5045
|
}
|
|
5109
5046
|
};
|
|
5047
|
+
function withSkillNames(node, names) {
|
|
5048
|
+
const candidate = node;
|
|
5049
|
+
if (candidate.kind !== "user" && candidate.kind !== "steering") return node;
|
|
5050
|
+
const current = candidate.data.skillNames ?? EMPTY_KEYS;
|
|
5051
|
+
const hasNames = Object.hasOwn(candidate.data, "skillNames");
|
|
5052
|
+
if (sameReferences$1(current, names) && hasNames === names.length > 0) return node;
|
|
5053
|
+
const data = { ...candidate.data };
|
|
5054
|
+
if (names.length === 0) delete data.skillNames;
|
|
5055
|
+
else data.skillNames = names;
|
|
5056
|
+
return {
|
|
5057
|
+
...candidate,
|
|
5058
|
+
data
|
|
5059
|
+
};
|
|
5060
|
+
}
|
|
5061
|
+
/**
|
|
5062
|
+
* Classify one Node for batching: a direct message, a `skill-invocation`
|
|
5063
|
+
* context, or a boundary of any other kind. A context that injects no skill
|
|
5064
|
+
* (workspace rules, the catalog, a recall) is transparent and yields null.
|
|
5065
|
+
*/
|
|
5066
|
+
function slashEntryOf(node) {
|
|
5067
|
+
const candidate = node;
|
|
5068
|
+
if (candidate.kind === "user" || candidate.kind === "steering") return {
|
|
5069
|
+
key: node.key,
|
|
5070
|
+
seq: node.anchorSeq,
|
|
5071
|
+
kind: "message",
|
|
5072
|
+
name: null
|
|
5073
|
+
};
|
|
5074
|
+
if (candidate.kind === "context") {
|
|
5075
|
+
const name = skillInvocationName(candidate.data.source);
|
|
5076
|
+
return name === null ? null : {
|
|
5077
|
+
key: node.key,
|
|
5078
|
+
seq: node.anchorSeq,
|
|
5079
|
+
kind: "skill",
|
|
5080
|
+
name
|
|
5081
|
+
};
|
|
5082
|
+
}
|
|
5083
|
+
return {
|
|
5084
|
+
key: node.key,
|
|
5085
|
+
seq: node.anchorSeq,
|
|
5086
|
+
kind: "boundary",
|
|
5087
|
+
name: null
|
|
5088
|
+
};
|
|
5089
|
+
}
|
|
5090
|
+
function sameSlashEntry(left, right) {
|
|
5091
|
+
return left.seq === right.seq && left.kind === right.kind && left.name === right.name;
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* Attaches each direct message's step-loaded skill names to its Node.
|
|
5095
|
+
*
|
|
5096
|
+
* A step's `skill-invocation` injections follow the direct messages the host
|
|
5097
|
+
* scanned for `/name` gestures and precede the step's first Node of any other
|
|
5098
|
+
* kind, so every non-message, non-context Node closes a batch. Every ended
|
|
5099
|
+
* Turn publishes its `turn-tail` Node on `turn/end` whatever the reason, so a
|
|
5100
|
+
* batch never spans Turns, and `step/start` precedes the direct message in
|
|
5101
|
+
* the log, so no boundary separates a message from its injections. Names
|
|
5102
|
+
* attach to every direct message of the batch: the bubble decorates only the
|
|
5103
|
+
* tokens its own text carries.
|
|
5104
|
+
*
|
|
5105
|
+
* The index holds only messages, skill injections, and boundaries, ordered by
|
|
5106
|
+
* `anchorSeq`. An apply re-reads just the batches around the Nodes whose
|
|
5107
|
+
* classification changed and never scans the store, so an assistant
|
|
5108
|
+
* streaming frame costs nothing here (the append hot path never scans the
|
|
5109
|
+
* Chat Nodes).
|
|
5110
|
+
*/
|
|
5111
|
+
var SkillNameProjector = class {
|
|
5112
|
+
entries = /* @__PURE__ */ new Map();
|
|
5113
|
+
/** Every indexed entry in `anchorSeq` order. */
|
|
5114
|
+
sorted = [];
|
|
5115
|
+
/**
|
|
5116
|
+
* Rebuild the index from a whole Node set and attach names to its messages.
|
|
5117
|
+
* @param nodes - every materialized Chat Node, in any order.
|
|
5118
|
+
* @returns the same Nodes, direct messages carrying their batch's names.
|
|
5119
|
+
*/
|
|
5120
|
+
replace(nodes) {
|
|
5121
|
+
this.entries.clear();
|
|
5122
|
+
this.sorted = [];
|
|
5123
|
+
for (const node of nodes) {
|
|
5124
|
+
const entry = slashEntryOf(node);
|
|
5125
|
+
if (entry === null) continue;
|
|
5126
|
+
this.entries.set(entry.key, entry);
|
|
5127
|
+
this.sorted.push(entry);
|
|
5128
|
+
}
|
|
5129
|
+
this.sorted.sort((left, right) => left.seq - right.seq);
|
|
5130
|
+
const names = /* @__PURE__ */ new Map();
|
|
5131
|
+
for (let index = 0; index < this.sorted.length; index++) {
|
|
5132
|
+
if (this.sorted[index]?.kind === "boundary") continue;
|
|
5133
|
+
const end = this.runEnd(index);
|
|
5134
|
+
this.assignRun(index, end, names);
|
|
5135
|
+
index = end;
|
|
5136
|
+
}
|
|
5137
|
+
return nodes.map((node) => withSkillNames(node, names.get(node.key) ?? EMPTY_KEYS));
|
|
5138
|
+
}
|
|
5139
|
+
/**
|
|
5140
|
+
* Fold one incremental upsert set: re-read only the batches around the
|
|
5141
|
+
* Nodes whose classification changed.
|
|
5142
|
+
* @param upserts - the changed Nodes.
|
|
5143
|
+
* @param store - the resident Nodes, read by key for the messages of an affected batch.
|
|
5144
|
+
* @returns the upserts plus any resident message whose names changed.
|
|
5145
|
+
*/
|
|
5146
|
+
apply(upserts, store) {
|
|
5147
|
+
const dirty = [];
|
|
5148
|
+
for (const node of upserts) {
|
|
5149
|
+
const next = slashEntryOf(node);
|
|
5150
|
+
const previous = this.entries.get(node.key);
|
|
5151
|
+
if (previous !== void 0) {
|
|
5152
|
+
if (next !== null && sameSlashEntry(previous, next)) {
|
|
5153
|
+
if (next.kind === "message") dirty.push(next.seq);
|
|
5154
|
+
continue;
|
|
5155
|
+
}
|
|
5156
|
+
this.remove(previous);
|
|
5157
|
+
dirty.push(previous.seq);
|
|
5158
|
+
}
|
|
5159
|
+
if (next === null) continue;
|
|
5160
|
+
this.insert(next);
|
|
5161
|
+
dirty.push(next.seq);
|
|
5162
|
+
}
|
|
5163
|
+
if (dirty.length === 0) return upserts;
|
|
5164
|
+
const names = /* @__PURE__ */ new Map();
|
|
5165
|
+
for (const seq of dirty) this.collectAround(seq, names);
|
|
5166
|
+
const byKey = new Map(upserts.map((node) => [node.key, node]));
|
|
5167
|
+
for (const [key, list] of names) {
|
|
5168
|
+
const node = byKey.get(key) ?? store.get(key);
|
|
5169
|
+
if (node === void 0) continue;
|
|
5170
|
+
const next = withSkillNames(node, list);
|
|
5171
|
+
if (next !== node || byKey.has(key)) byKey.set(key, next);
|
|
5172
|
+
}
|
|
5173
|
+
return [...byKey.values()];
|
|
5174
|
+
}
|
|
5175
|
+
insert(entry) {
|
|
5176
|
+
this.sorted.splice(this.lowerBound(entry.seq), 0, entry);
|
|
5177
|
+
this.entries.set(entry.key, entry);
|
|
5178
|
+
}
|
|
5179
|
+
remove(entry) {
|
|
5180
|
+
this.sorted.splice(this.sorted.indexOf(entry), 1);
|
|
5181
|
+
this.entries.delete(entry.key);
|
|
5182
|
+
}
|
|
5183
|
+
/** First index whose seq is at least `seq`. */
|
|
5184
|
+
lowerBound(seq) {
|
|
5185
|
+
let low = 0;
|
|
5186
|
+
let high = this.sorted.length;
|
|
5187
|
+
while (low < high) {
|
|
5188
|
+
const middle = low + high >>> 1;
|
|
5189
|
+
if ((this.sorted[middle]?.seq ?? Number.POSITIVE_INFINITY) < seq) low = middle + 1;
|
|
5190
|
+
else high = middle;
|
|
5191
|
+
}
|
|
5192
|
+
return low;
|
|
5193
|
+
}
|
|
5194
|
+
/** Last index of the boundary-free run containing `index`. */
|
|
5195
|
+
runEnd(index) {
|
|
5196
|
+
let end = index;
|
|
5197
|
+
while (end + 1 < this.sorted.length && this.sorted[end + 1]?.kind !== "boundary") end++;
|
|
5198
|
+
return end;
|
|
5199
|
+
}
|
|
5200
|
+
/** First index of the boundary-free run containing `index`. */
|
|
5201
|
+
runStart(index) {
|
|
5202
|
+
let start = index;
|
|
5203
|
+
while (start - 1 >= 0 && this.sorted[start - 1]?.kind !== "boundary") start--;
|
|
5204
|
+
return start;
|
|
5205
|
+
}
|
|
5206
|
+
/** Record the names every message of the run `[start, end]` carries. */
|
|
5207
|
+
assignRun(start, end, names) {
|
|
5208
|
+
const list = [];
|
|
5209
|
+
for (let index = start; index <= end; index++) {
|
|
5210
|
+
const entry = this.sorted[index];
|
|
5211
|
+
if (entry?.kind === "skill" && entry.name !== null && !list.includes(entry.name)) list.push(entry.name);
|
|
5212
|
+
}
|
|
5213
|
+
for (let index = start; index <= end; index++) {
|
|
5214
|
+
const entry = this.sorted[index];
|
|
5215
|
+
if (entry?.kind === "message") names.set(entry.key, list);
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
/**
|
|
5219
|
+
* Re-read the run(s) around one changed seq: the run holding a message or
|
|
5220
|
+
* skill entry, or — for a boundary, or a seq that left the index — the runs
|
|
5221
|
+
* on both sides of that position.
|
|
5222
|
+
*/
|
|
5223
|
+
collectAround(seq, names) {
|
|
5224
|
+
const at = this.lowerBound(seq);
|
|
5225
|
+
const here = this.sorted[at];
|
|
5226
|
+
if (here !== void 0 && here.seq === seq && here.kind !== "boundary") {
|
|
5227
|
+
this.assignRun(this.runStart(at), this.runEnd(at), names);
|
|
5228
|
+
return;
|
|
5229
|
+
}
|
|
5230
|
+
if (at - 1 >= 0 && this.sorted[at - 1]?.kind !== "boundary") this.assignRun(this.runStart(at - 1), at - 1, names);
|
|
5231
|
+
const right = here !== void 0 && here.seq === seq ? at + 1 : at;
|
|
5232
|
+
if (right < this.sorted.length && this.sorted[right]?.kind !== "boundary") this.assignRun(right, this.runEnd(right), names);
|
|
5233
|
+
}
|
|
5234
|
+
};
|
|
5110
5235
|
const EMPTY_CONTRIBUTION = {
|
|
5111
5236
|
anchorSeq: 0,
|
|
5112
5237
|
nodes: EMPTY_LIST,
|
|
@@ -5300,6 +5425,7 @@ window.__ModuleLoader__.load({
|
|
|
5300
5425
|
navigation = new MutableTurnNavigationIndex();
|
|
5301
5426
|
legacy = new LegacySliceBuilder();
|
|
5302
5427
|
referenceLabels = new ReferenceLabelProjector();
|
|
5428
|
+
skillNames = new SkillNameProjector();
|
|
5303
5429
|
order = EMPTY_KEYS;
|
|
5304
5430
|
/** Last published timeline: a Turn boundary can land without a new node. */
|
|
5305
5431
|
timeline = null;
|
|
@@ -5311,7 +5437,7 @@ window.__ModuleLoader__.load({
|
|
|
5311
5437
|
});
|
|
5312
5438
|
}
|
|
5313
5439
|
replace(input) {
|
|
5314
|
-
const nodes = this.referenceLabels.replace(input.nodes);
|
|
5440
|
+
const nodes = this.skillNames.replace(this.referenceLabels.replace(input.nodes));
|
|
5315
5441
|
this.store.replace(nodes);
|
|
5316
5442
|
this.order = orderedVisibleChatNodes(nodes).map((node) => node.key);
|
|
5317
5443
|
this.locations.rebuild(this.order, this.store);
|
|
@@ -5323,7 +5449,7 @@ window.__ModuleLoader__.load({
|
|
|
5323
5449
|
return snapshot;
|
|
5324
5450
|
}
|
|
5325
5451
|
apply(input) {
|
|
5326
|
-
const upserts = this.referenceLabels.apply(input.upserts, this.store);
|
|
5452
|
+
const upserts = this.skillNames.apply(this.referenceLabels.apply(input.upserts, this.store), this.store);
|
|
5327
5453
|
const processTurns = /* @__PURE__ */ new Set();
|
|
5328
5454
|
let structural = false;
|
|
5329
5455
|
const contentOnly = [];
|
|
@@ -5392,6 +5518,47 @@ window.__ModuleLoader__.load({
|
|
|
5392
5518
|
ctx.uiConversation.views.register(chatViewDefinition);
|
|
5393
5519
|
}
|
|
5394
5520
|
//#endregion
|
|
5521
|
+
//#region ../../core/session/src/surface.ts
|
|
5522
|
+
/** Runtime counterpart of the message-producing event union. */
|
|
5523
|
+
const SURFACE_EVENT_TYPES = new Set([
|
|
5524
|
+
"user/message",
|
|
5525
|
+
"assistant/message",
|
|
5526
|
+
"tool/result"
|
|
5527
|
+
]);
|
|
5528
|
+
/**
|
|
5529
|
+
* Narrow an event to a surface-eligible event carrying its required marker.
|
|
5530
|
+
* @param event - event to test.
|
|
5531
|
+
* @returns true when both the type and marker identify a surface event.
|
|
5532
|
+
*/
|
|
5533
|
+
function isSurfaceEvent(event) {
|
|
5534
|
+
if (!SURFACE_EVENT_TYPES.has(event.type)) return false;
|
|
5535
|
+
return event.surfaceOp !== void 0;
|
|
5536
|
+
}
|
|
5537
|
+
/**
|
|
5538
|
+
* Narrow an event to an append-origin surface event: one that entered the
|
|
5539
|
+
* surface at its own log position and was never itself a replacement copy.
|
|
5540
|
+
*
|
|
5541
|
+
* The model-visible surface deliberately shadows replaced ranges, so it is the
|
|
5542
|
+
* wrong source for a human transcript — a landed replacement would erase
|
|
5543
|
+
* conversation the user already saw. Append-origin events are that transcript's
|
|
5544
|
+
* durable source material; replacement copies stay model-only.
|
|
5545
|
+
* @param event - event to test.
|
|
5546
|
+
* @returns true when the event appended to the surface tail.
|
|
5547
|
+
*/
|
|
5548
|
+
function isAppendSurfaceEvent(event) {
|
|
5549
|
+
return isSurfaceEvent(event) && event.surfaceOp === "append";
|
|
5550
|
+
}
|
|
5551
|
+
/**
|
|
5552
|
+
* Narrow an event to a surface replacement: a node that shadowed an existing
|
|
5553
|
+
* surface range instead of appending to the tail. The counterpart of
|
|
5554
|
+
* {@link isAppendSurfaceEvent} over the two {@link SurfaceOp} variants.
|
|
5555
|
+
* @param event - event to test.
|
|
5556
|
+
* @returns true when the event replaced a surface range.
|
|
5557
|
+
*/
|
|
5558
|
+
function isReplacementSurfaceEvent(event) {
|
|
5559
|
+
return isSurfaceEvent(event) && event.surfaceOp !== "append";
|
|
5560
|
+
}
|
|
5561
|
+
//#endregion
|
|
5395
5562
|
//#region lib/types/client/conversation-nodes/command.js
|
|
5396
5563
|
const COMPACT_PLUGIN = "compact";
|
|
5397
5564
|
function commandFromRun(match) {
|
|
@@ -5615,13 +5782,10 @@ window.__ModuleLoader__.load({
|
|
|
5615
5782
|
const unknownFallbackDefinition = {
|
|
5616
5783
|
kind: "unknown-surface",
|
|
5617
5784
|
target: "chat",
|
|
5618
|
-
match: (event) => {
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
role: "start"
|
|
5623
|
-
} : null;
|
|
5624
|
-
},
|
|
5785
|
+
match: (event) => event.type !== "assistant/live-chunk" && isAppendSurfaceEvent(event) ? {
|
|
5786
|
+
id: String(event.seq),
|
|
5787
|
+
role: "start"
|
|
5788
|
+
} : null,
|
|
5625
5789
|
start: (_context, match) => ({
|
|
5626
5790
|
kind: "unknown",
|
|
5627
5791
|
seq: match.event.seq,
|
|
@@ -5818,7 +5982,7 @@ window.__ModuleLoader__.load({
|
|
|
5818
5982
|
const change = inspection.change?.kind;
|
|
5819
5983
|
return {
|
|
5820
5984
|
anchorSeq: stableRequestPromptAnchor(context, match, previous, match.event.data.reason === "initial"),
|
|
5821
|
-
showsPrompt: previous === void 0 || match.event.data.reason
|
|
5985
|
+
showsPrompt: previous === void 0 || match.event.data.reason === "series" || match.event.data.startsSeries === true || change === "system" || change === "system-and-tools",
|
|
5822
5986
|
...location,
|
|
5823
5987
|
...inspection
|
|
5824
5988
|
};
|
|
@@ -5826,8 +5990,11 @@ window.__ModuleLoader__.load({
|
|
|
5826
5990
|
update: (context) => context.state,
|
|
5827
5991
|
buildViewNode: (context) => {
|
|
5828
5992
|
const state = context.state;
|
|
5829
|
-
if (state === void 0
|
|
5830
|
-
|
|
5993
|
+
if (state === void 0) return null;
|
|
5994
|
+
const current = context.current.get("chat");
|
|
5995
|
+
const visible = state.showsPrompt && state.prompt.system !== "";
|
|
5996
|
+
if (!visible && current?.kind !== "system-prompt") return null;
|
|
5997
|
+
return chatNode(context, "system-prompt", state.anchorSeq, { text: state.prompt.system }, { visibility: visible ? "visible" : "hidden" });
|
|
5831
5998
|
}
|
|
5832
5999
|
};
|
|
5833
6000
|
}
|
|
@@ -6336,49 +6503,38 @@ window.__ModuleLoader__.load({
|
|
|
6336
6503
|
}
|
|
6337
6504
|
//#endregion
|
|
6338
6505
|
//#region lib/types/client/conversation-nodes/turn-process.js
|
|
6339
|
-
function isChunkRunEvent(event) {
|
|
6340
|
-
return event.type === "chunkrow/text-chunks" || event.type === "chunkrow/reasoning-chunks" || event.type === "chunkrow/tool-call-chunks";
|
|
6341
|
-
}
|
|
6342
6506
|
function eventTurn(event) {
|
|
6343
6507
|
const data = event.data;
|
|
6344
6508
|
return typeof data.turn === "number" ? data.turn : void 0;
|
|
6345
6509
|
}
|
|
6510
|
+
function visibleChunk(chunk) {
|
|
6511
|
+
if (chunk.type === "text-delta" || chunk.type === "reasoning-delta") return chunk.text.trim() !== "";
|
|
6512
|
+
if (chunk.type === "block-start") return chunk.blockType !== "text" && chunk.blockType !== "reasoning" && chunk.blockType !== "tool-call";
|
|
6513
|
+
if (chunk.type !== "block-end") return false;
|
|
6514
|
+
const block = chunk.block;
|
|
6515
|
+
if (block.type === "tool-call") return false;
|
|
6516
|
+
if (block.type === "text" || block.type === "reasoning") return block.text.trim() !== "";
|
|
6517
|
+
return true;
|
|
6518
|
+
}
|
|
6346
6519
|
function visibleAssistantEvent(event) {
|
|
6347
|
-
if (event.type === "assistant/chunk")
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
if (chunk.type === "block-start") return chunk.blockType !== "text" && chunk.blockType !== "reasoning" && chunk.blockType !== "tool-call";
|
|
6351
|
-
if (chunk.type !== "block-end") return false;
|
|
6352
|
-
const block = chunk.block;
|
|
6353
|
-
if (block.type === "tool-call") return false;
|
|
6354
|
-
if (block.type === "text" || block.type === "reasoning") return block.text.trim() !== "";
|
|
6355
|
-
return true;
|
|
6356
|
-
}
|
|
6357
|
-
return event.type === "assistant/message" && isAppendSurfaceEvent(event) && toAssistantBlocks(event.data.message.content).some((block) => {
|
|
6520
|
+
if (event.type === "assistant/live-chunk") return visibleChunk(event.data.chunk);
|
|
6521
|
+
if (event.type === "assistant/attempt") return false;
|
|
6522
|
+
return event.type === "assistant/message" && event.surfaceOp === "append" && toAssistantBlocks(event.data.message.content).some((block) => {
|
|
6358
6523
|
if (block.kind === "tool-call") return false;
|
|
6359
6524
|
if (block.kind === "text" || block.kind === "reasoning") return block.text.trim() !== "";
|
|
6360
6525
|
return true;
|
|
6361
6526
|
});
|
|
6362
6527
|
}
|
|
6363
6528
|
function processEvidence(event) {
|
|
6364
|
-
if (isChunkRunEvent(event)) {
|
|
6365
|
-
if (event.type === "chunkrow/tool-call-chunks") return void 0;
|
|
6366
|
-
const firstVisible = event.data.texts.findIndex((text) => text.trim() !== "");
|
|
6367
|
-
return firstVisible < 0 ? void 0 : {
|
|
6368
|
-
kind: "assistant",
|
|
6369
|
-
seq: event.seq + firstVisible,
|
|
6370
|
-
step: event.data.step
|
|
6371
|
-
};
|
|
6372
|
-
}
|
|
6373
6529
|
if (visibleAssistantEvent(event)) {
|
|
6374
|
-
if (event.type !== "assistant/chunk" && event.type !== "assistant/message") return void 0;
|
|
6530
|
+
if (event.type !== "assistant/live-chunk" && event.type !== "assistant/message" && event.type !== "assistant/attempt") return void 0;
|
|
6375
6531
|
return {
|
|
6376
6532
|
kind: "assistant",
|
|
6377
6533
|
seq: event.seq,
|
|
6378
6534
|
step: event.data.step
|
|
6379
6535
|
};
|
|
6380
6536
|
}
|
|
6381
|
-
if (event.type === "tool/call" || event.type === "tool/result" &&
|
|
6537
|
+
if (event.type === "tool/call" || event.type === "tool/result" && event.surfaceOp === "append" || event.type === "llm/retry") return {
|
|
6382
6538
|
kind: "other",
|
|
6383
6539
|
seq: event.seq
|
|
6384
6540
|
};
|
|
@@ -6442,7 +6598,7 @@ window.__ModuleLoader__.load({
|
|
|
6442
6598
|
}
|
|
6443
6599
|
function updateProcessState(state, event) {
|
|
6444
6600
|
let current = state;
|
|
6445
|
-
if (event.type === "assistant/message" &&
|
|
6601
|
+
if (event.type === "assistant/message" && event.surfaceOp === "append" && hasAssistantReplyContent(toAssistantBlocks(event.data.message.content))) {
|
|
6446
6602
|
const messageCountByStep = new Map(current.messageCountByStep);
|
|
6447
6603
|
messageCountByStep.set(event.data.step, (messageCountByStep.get(event.data.step) ?? 0) + 1);
|
|
6448
6604
|
current = {
|
|
@@ -6486,7 +6642,7 @@ window.__ModuleLoader__.load({
|
|
|
6486
6642
|
};
|
|
6487
6643
|
const turn = eventTurn(event);
|
|
6488
6644
|
if (turn === void 0) return null;
|
|
6489
|
-
if (event.type === "assistant/chunk" || event.type === "assistant/message" ||
|
|
6645
|
+
if (event.type === "assistant/live-chunk" || event.type === "assistant/message" || event.type === "tool/call" || event.type === "tool/result" || event.type === "llm/retry" || event.type === "step/start" || event.type === "step/end" || event.type === "turn/end") return {
|
|
6490
6646
|
id: String(turn),
|
|
6491
6647
|
role: "update"
|
|
6492
6648
|
};
|
|
@@ -6505,8 +6661,7 @@ window.__ModuleLoader__.load({
|
|
|
6505
6661
|
},
|
|
6506
6662
|
update: (context, match) => updateProcessState(context.state, match.event),
|
|
6507
6663
|
publication: (match) => {
|
|
6508
|
-
if (
|
|
6509
|
-
if (match.event.type === "assistant/chunk") {
|
|
6664
|
+
if (match.event.type === "assistant/live-chunk") {
|
|
6510
6665
|
const type = match.event.data.chunk.type;
|
|
6511
6666
|
return type === "usage" || type === "finish" ? "none" : "animation-frame";
|
|
6512
6667
|
}
|
|
@@ -6549,6 +6704,20 @@ window.__ModuleLoader__.load({
|
|
|
6549
6704
|
ctx.uiConversation.events.register(turnProcessDefinition);
|
|
6550
6705
|
}
|
|
6551
6706
|
//#endregion
|
|
6707
|
+
//#region ../../llm/llm/src/assistant-stream.ts
|
|
6708
|
+
/**
|
|
6709
|
+
* The last raw chunk of one never-packed type, scanning backwards and stopping at the first hit.
|
|
6710
|
+
* @param stream - compact records from one durable Assistant settlement.
|
|
6711
|
+
* @param type - chunk type that only appears as a raw record.
|
|
6712
|
+
* @returns the stream's final chunk of that type, or undefined when it has none.
|
|
6713
|
+
*/
|
|
6714
|
+
function lastAssistantStreamChunk(stream, type) {
|
|
6715
|
+
for (let index = stream.length - 1; index >= 0; index -= 1) {
|
|
6716
|
+
const record = stream[index];
|
|
6717
|
+
if (record.type === "chunk" && record.chunk.type === type) return record.chunk;
|
|
6718
|
+
}
|
|
6719
|
+
}
|
|
6720
|
+
//#endregion
|
|
6552
6721
|
//#region ../../llm/token-meter/src/turn-usage.ts
|
|
6553
6722
|
function isCount(value) {
|
|
6554
6723
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -6568,6 +6737,9 @@ window.__ModuleLoader__.load({
|
|
|
6568
6737
|
model
|
|
6569
6738
|
} : void 0;
|
|
6570
6739
|
}
|
|
6740
|
+
function streamUsage(stream) {
|
|
6741
|
+
return lastAssistantStreamChunk(stream, "usage")?.usage;
|
|
6742
|
+
}
|
|
6571
6743
|
function normalizeUsage(usage, route) {
|
|
6572
6744
|
const { inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens, reasoningTokens, totalTokens } = usage;
|
|
6573
6745
|
if (!isCount(inputTokens) || !isCount(outputTokens)) return void 0;
|
|
@@ -6695,16 +6867,19 @@ window.__ModuleLoader__.load({
|
|
|
6695
6867
|
};
|
|
6696
6868
|
continue;
|
|
6697
6869
|
}
|
|
6698
|
-
if (event.type === "assistant/
|
|
6870
|
+
if (event.type === "assistant/attempt") {
|
|
6699
6871
|
if (event.data.turn !== turn || state.kind !== "open" || !sameAttempt(state, event.data.turn, event.data.step)) {
|
|
6700
6872
|
invalid = true;
|
|
6701
6873
|
continue;
|
|
6702
6874
|
}
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6875
|
+
const sample = streamUsage(event.data.stream) ?? state.sample;
|
|
6876
|
+
state = {
|
|
6877
|
+
kind: "open",
|
|
6878
|
+
turn,
|
|
6879
|
+
step: event.data.step,
|
|
6880
|
+
...sample === void 0 ? {} : { sample }
|
|
6706
6881
|
};
|
|
6707
|
-
|
|
6882
|
+
if (!closeOpen()) invalid = true;
|
|
6708
6883
|
else state = {
|
|
6709
6884
|
kind: "finishClosed",
|
|
6710
6885
|
turn,
|
|
@@ -6717,9 +6892,10 @@ window.__ModuleLoader__.load({
|
|
|
6717
6892
|
invalid = true;
|
|
6718
6893
|
continue;
|
|
6719
6894
|
}
|
|
6720
|
-
|
|
6895
|
+
const sample = event.data.usage ?? streamUsage(event.data.stream);
|
|
6896
|
+
if (sample !== void 0) state = {
|
|
6721
6897
|
...state,
|
|
6722
|
-
sample
|
|
6898
|
+
sample
|
|
6723
6899
|
};
|
|
6724
6900
|
if (!closeOpen(messageRoute(event.data.message))) invalid = true;
|
|
6725
6901
|
else state = {
|
|
@@ -6758,21 +6934,17 @@ window.__ModuleLoader__.load({
|
|
|
6758
6934
|
//#endregion
|
|
6759
6935
|
//#region lib/types/client/conversation-nodes/turn-tail.js
|
|
6760
6936
|
function isSessionEvent(event) {
|
|
6761
|
-
return event.type !== "
|
|
6937
|
+
return event.type !== "assistant/live-chunk";
|
|
6762
6938
|
}
|
|
6763
6939
|
function hasTextAssistant(event) {
|
|
6764
|
-
return event.type === "assistant/message" &&
|
|
6940
|
+
return event.type === "assistant/message" && event.surfaceOp === "append" && toAssistantBlocks(event.data.message.content).some((block) => block.kind === "text" && block.text.trim() !== "");
|
|
6765
6941
|
}
|
|
6766
|
-
function chunkHasText(
|
|
6767
|
-
if (event.type === "chunkrow/text-chunks") return event.data.texts.some((text) => text.trim() !== "");
|
|
6768
|
-
if (event.type === "chunkrow/reasoning-chunks" || event.type === "chunkrow/tool-call-chunks") return false;
|
|
6769
|
-
if (event.type !== "assistant/chunk") return false;
|
|
6770
|
-
const chunk = event.data.chunk;
|
|
6942
|
+
function chunkHasText(chunk) {
|
|
6771
6943
|
if (chunk.type === "text-delta") return chunk.text.trim() !== "";
|
|
6772
6944
|
return chunk.type === "block-end" && chunk.block.type === "text" && chunk.block.text.trim() !== "";
|
|
6773
6945
|
}
|
|
6774
6946
|
function turnCoordinates(event) {
|
|
6775
|
-
if (event.type === "assistant/message" || event.type === "assistant/
|
|
6947
|
+
if (event.type === "assistant/message" || event.type === "assistant/attempt" || event.type === "assistant/live-chunk" || event.type === "step/start" || event.type === "step/end") return {
|
|
6776
6948
|
turn: event.data.turn,
|
|
6777
6949
|
step: event.data.step
|
|
6778
6950
|
};
|
|
@@ -6793,10 +6965,10 @@ window.__ModuleLoader__.load({
|
|
|
6793
6965
|
streamedText: false,
|
|
6794
6966
|
finalized: false
|
|
6795
6967
|
};
|
|
6796
|
-
if (event.type === "assistant/chunk"
|
|
6968
|
+
if (event.type === "assistant/live-chunk") {
|
|
6797
6969
|
steps.set(coordinates.step, {
|
|
6798
6970
|
...previous,
|
|
6799
|
-
streamedText: previous.streamedText || chunkHasText(event)
|
|
6971
|
+
streamedText: previous.streamedText || chunkHasText(event.data.chunk)
|
|
6800
6972
|
});
|
|
6801
6973
|
continue;
|
|
6802
6974
|
}
|
|
@@ -6836,7 +7008,7 @@ window.__ModuleLoader__.load({
|
|
|
6836
7008
|
let latestTranscriptSeq = finalized.at(-1)?.finalNode.seq;
|
|
6837
7009
|
for (const match of context.matches) {
|
|
6838
7010
|
const event = match.event;
|
|
6839
|
-
const candidate = event.type === "tool/call" || event.type === "tool/result" &&
|
|
7011
|
+
const candidate = event.type === "tool/call" || event.type === "tool/result" && event.surfaceOp === "append" || event.type === "turn/end" && event.data.reason.kind === "error" || event.type === "llm/retry" ? event.seq : void 0;
|
|
6840
7012
|
if (candidate !== void 0 && (latestTranscriptSeq === void 0 || candidate > latestTranscriptSeq)) latestTranscriptSeq = candidate;
|
|
6841
7013
|
}
|
|
6842
7014
|
const metrics = deriveTurnMetrics(finalized.map((candidate) => candidate.finalNode)).get(end.event.data.turn);
|