clay-server 5.3.0-beta.2 → 5.3.0-beta.3
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/lib/public/css/split-view-layout.css +3 -2
- package/lib/public/modules/app-message-cards.js +1 -1
- package/lib/public/modules/app-messages.js +2 -1
- package/lib/public/modules/app-projects.js +2 -1
- package/lib/public/modules/app-rendering.js +2 -2
- package/lib/public/modules/chat-render-runtime.js +46 -6
- package/lib/public/modules/split-view-worker-activity.js +0 -56
- package/lib/public/modules/split-view-worker-transcript.js +19 -11
- package/lib/public/pane-assets/{app-2DRBYY3L.js → app-K4LGSKX5.js} +1 -1
- package/lib/public/pane-assets/{chunk-C4RVVYNT.js → chunk-6AJEGTWL.js} +1 -1
- package/lib/public/pane-assets/{chunk-UMGHINOT.js → chunk-AILOLDZA.js} +1 -1
- package/lib/public/pane-assets/{chunk-4BM7UVNG.js → chunk-BYSBUZDZ.js} +1 -1
- package/lib/public/pane-assets/{chunk-PO2JOHHW.js → chunk-QJPBAN5H.js} +1 -1
- package/lib/public/pane-assets/{chunk-O6MQL6MR.js → chunk-W34XSARI.js} +98 -98
- package/lib/public/pane-assets/manifest.json +320 -321
- package/lib/public/pane-assets/style-JVCOCG3W.css +1 -0
- package/lib/public/style.css +0 -1
- package/package.json +1 -1
- package/lib/public/css/split-view-worker-activity.css +0 -97
- package/lib/public/pane-assets/style-63EZCREE.css +0 -1
|
@@ -404,11 +404,12 @@ body.split-view-resizing .split-pane-frame { pointer-events: none; }
|
|
|
404
404
|
.split-view-worker-popover-header strong { flex: 1; min-width: 0; font-size: 12px; }
|
|
405
405
|
.split-view-worker-popover-source { padding: 0 13px 10px; color: var(--text-dimmer); font-size: 10px; }
|
|
406
406
|
.split-view-worker-popover-body { flex: 1; min-height: 0; overflow: auto; padding: 14px; }
|
|
407
|
-
.split-view-worker-popover-body .message { display:
|
|
407
|
+
.split-view-worker-popover-body .message { display: flex; flex-direction: column; align-items: stretch; margin: 0 0 18px; padding: 0; max-width: none; }
|
|
408
408
|
.split-view-worker-popover-body .author { display: block; margin-bottom: 4px; font-size: 11px; color: var(--text-muted); }
|
|
409
409
|
.split-view-worker-popover-body .message-body { white-space: normal; overflow-wrap: anywhere; font-size: 12px; line-height: 1.65; }
|
|
410
410
|
.split-view-worker-popover-body .message-body pre { white-space: pre-wrap; }
|
|
411
|
-
.split-view-worker-popover-body .worker-tool-message
|
|
411
|
+
.split-view-worker-popover-body .worker-tool-message pre { max-height: 280px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
412
|
+
.split-view-worker-popover-body .worker-tool-message summary { cursor: pointer; font-size: 13px; }
|
|
412
413
|
.split-view-worker-popover-body .worker-tool-message { padding: 6px 8px; border-radius: 5px; background: var(--bg-alt); }
|
|
413
414
|
.split-view-worker-popover-footer { padding: 8px 13px; border-top: 1px solid var(--border-subtle); color: var(--text-dimmer); font-size: 10px; }
|
|
414
415
|
.split-view-worker-page-status { display: block; margin-top: 3px; line-height: 1.4; }
|
|
@@ -96,7 +96,7 @@ import { renderGeneratedImage, renderImageGenerationProgress, clearImageGenerati
|
|
|
96
96
|
import { clearPairResultStatus, handlePairResultStatus } from './pair-result-status.js';
|
|
97
97
|
|
|
98
98
|
// --- App module imports ---
|
|
99
|
-
import { scrollToBottom, addToMessages, addUserMessage, addSystemMessage, removeMatePreThinking, resetStreamBuffer, appendDelta, flushStreamBuffer, finalizeAssistantBlock, addConflictMessage, addContextOverflowMessage, showSuggestionChips, armStickyBottom, VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
99
|
+
import { scrollToBottom, addToMessages, addUserMessage, addSystemMessage, removeMatePreThinking, resetStreamBuffer, appendDelta, flushStreamBuffer, finalizeAssistantBlock, addConflictMessage, addContextOverflowMessage, showSuggestionChips, armStickyBottom, releaseTurnAnchor, VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
100
100
|
import { setActivity, startUrgentBlink, stopUrgentBlink, blinkSessionDot, updateCrossProjectBlink } from './app-favicon.js';
|
|
101
101
|
import { setStatus } from './app-connection.js';
|
|
102
102
|
import { resolveSwitchedVendor } from './pane-session.js';
|
|
@@ -1498,6 +1498,7 @@ export function processMessage(msg) {
|
|
|
1498
1498
|
|
|
1499
1499
|
case "done":
|
|
1500
1500
|
store.set({ turnActivity: null });
|
|
1501
|
+
releaseTurnAnchor();
|
|
1501
1502
|
removeMatePreThinking();
|
|
1502
1503
|
setActivity(null);
|
|
1503
1504
|
finishThinkingTurn();
|
|
@@ -24,7 +24,7 @@ import { hideMemory } from './mate-memory.js';
|
|
|
24
24
|
import { isSchedulerOpen, closeScheduler, resetScheduler } from './scheduler.js';
|
|
25
25
|
import { closeScheduledTasks } from './scheduled-tasks.js';
|
|
26
26
|
import { connect, cancelReconnect, setStatus } from './app-connection.js';
|
|
27
|
-
import { setTurnCounter, setPrependAnchor, setActivityEl, setIsUserScrolledUp, hideSuggestionChips } from './app-rendering.js';
|
|
27
|
+
import { setTurnCounter, setPrependAnchor, setActivityEl, setIsUserScrolledUp, releaseTurnAnchor, hideSuggestionChips } from './app-rendering.js';
|
|
28
28
|
import { resetToolState, enableMainInput, resetTurnMetaCost } from './tools.js';
|
|
29
29
|
import { resetShellCommand } from './shell-command.js';
|
|
30
30
|
import { clearPendingImages } from './input.js';
|
|
@@ -210,6 +210,7 @@ export function resetClientState() {
|
|
|
210
210
|
setPrependAnchor(null);
|
|
211
211
|
store.set({ loadingMore: false });
|
|
212
212
|
setIsUserScrolledUp(false);
|
|
213
|
+
releaseTurnAnchor();
|
|
213
214
|
document.getElementById("new-msg-btn").classList.add("hidden");
|
|
214
215
|
setRewindMode(false);
|
|
215
216
|
setActivity(null);
|
|
@@ -8,10 +8,10 @@ import { refreshIcons } from './icons.js';
|
|
|
8
8
|
import { closeToolGroup } from './tools.js';
|
|
9
9
|
import { sendMessage, hasSendableContent } from './input.js';
|
|
10
10
|
import { getChatLayout } from './theme.js';
|
|
11
|
-
import { addToMessages, addHistoryIndex, scrollToBottom, forceScrollToBottom, getMsgTime, shouldGroupMessage, getTurnCounter, getActivityEl } from './chat-render-runtime.js';
|
|
11
|
+
import { addToMessages, addHistoryIndex, scrollToBottom, forceScrollToBottom, releaseTurnAnchor, getMsgTime, shouldGroupMessage, getTurnCounter, getActivityEl } from './chat-render-runtime.js';
|
|
12
12
|
import { resolveProjectAssistantIdentity, applyProjectAssistantIdentity } from './project-chat-identity.js';
|
|
13
13
|
export { VENDOR_ORDER, EXPERIMENTAL_VENDORS, isExperimentalVendor } from './vendor-priority.js';
|
|
14
|
-
export { initRendering, addToMessages, addHistoryIndex, scrollToBottom, forceScrollToBottom, getMsgTime, shouldGroupMessage, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp, getStickyBottom, armStickyBottom, disarmStickyBottom, VENDOR_AVATARS, VENDOR_NAMES, VENDOR_HOMEPAGES } from './chat-render-runtime.js';
|
|
14
|
+
export { initRendering, addToMessages, addHistoryIndex, scrollToBottom, forceScrollToBottom, releaseTurnAnchor, getMsgTime, shouldGroupMessage, getTurnCounter, setTurnCounter, getPrependAnchor, setPrependAnchor, getActivityEl, setActivityEl, getIsUserScrolledUp, setIsUserScrolledUp, getStickyBottom, armStickyBottom, disarmStickyBottom, VENDOR_AVATARS, VENDOR_NAMES, VENDOR_HOMEPAGES } from './chat-render-runtime.js';
|
|
15
15
|
export { addUserMessage, addSystemMessage, addConflictMessage, addContextOverflowMessage } from './app-message-cards.js';
|
|
16
16
|
|
|
17
17
|
// --- Module-owned state (not in store) ---
|
|
@@ -56,15 +56,25 @@ var stickyBottom = false;
|
|
|
56
56
|
var stickyBottomQuietTimer = null;
|
|
57
57
|
var stickyBottomCeilingTimer = null;
|
|
58
58
|
var stickyBottomQuietMs = 750;
|
|
59
|
+
var TURN_ANCHOR_MARGIN = 8;
|
|
59
60
|
var stickyBottomCeilingMs = 8000;
|
|
60
61
|
var stickyBottomResizeObs = null;
|
|
61
62
|
var stickyBottomInputBound = false;
|
|
63
|
+
// The sent user turn that the transcript aligns to while its reply arrives.
|
|
64
|
+
var turnAnchor = null;
|
|
65
|
+
// Completion keeps the clamp until the follow settles, so a final render or a
|
|
66
|
+
// 'done' inside the follow window cannot jump past the sent turn.
|
|
67
|
+
var turnAnchorEnded = false;
|
|
62
68
|
|
|
63
69
|
function layoutScrollLock() { return store.get('paneLayoutScrollLock'); }
|
|
64
70
|
|
|
65
71
|
export function beginPaneLayoutScrollLock(token, scrollTop) {
|
|
66
72
|
var messagesEl = getMessagesEl();
|
|
67
73
|
if (!messagesEl || !token) return false;
|
|
74
|
+
// A layout-only change must not undo a send that is still being followed:
|
|
75
|
+
// the stored reading position predates that explicit new turn, and the
|
|
76
|
+
// matching end receipt may never arrive. The follow keeps the turn visible.
|
|
77
|
+
if (stickyBottom || activeTurnAnchor(messagesEl)) return false;
|
|
68
78
|
disarmStickyBottom();
|
|
69
79
|
var userPosition = store.get('paneLastUserScrollTop');
|
|
70
80
|
var position = Number.isFinite(userPosition) ? userPosition : Number.isFinite(scrollTop) ? Math.max(0, scrollTop) : messagesEl.scrollTop;
|
|
@@ -88,10 +98,29 @@ export function endPaneLayoutScrollLock(token) {
|
|
|
88
98
|
|
|
89
99
|
export function getStickyBottom() { return stickyBottom; }
|
|
90
100
|
|
|
101
|
+
function activeTurnAnchor(messagesEl) {
|
|
102
|
+
if (turnAnchor && (!messagesEl || turnAnchor.parentNode !== messagesEl)) { turnAnchor = null; turnAnchorEnded = false; }
|
|
103
|
+
return turnAnchor;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Follow the tail, but never past the top of the sent turn: a long immediate
|
|
107
|
+
// reply grows below the user's message instead of pushing it out of view.
|
|
108
|
+
function followTarget(messagesEl) {
|
|
109
|
+
var anchor = activeTurnAnchor(messagesEl);
|
|
110
|
+
if (!anchor) return messagesEl.scrollHeight;
|
|
111
|
+
var top = anchor.getBoundingClientRect().top - messagesEl.getBoundingClientRect().top + messagesEl.scrollTop - TURN_ANCHOR_MARGIN;
|
|
112
|
+
return Math.min(messagesEl.scrollHeight, Math.max(0, top));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function releaseTurnAnchor() {
|
|
116
|
+
if (stickyBottom && turnAnchor) turnAnchorEnded = true;
|
|
117
|
+
else { turnAnchor = null; turnAnchorEnded = false; }
|
|
118
|
+
}
|
|
119
|
+
|
|
91
120
|
function pinToBottomNow() {
|
|
92
121
|
var messagesEl = getMessagesEl();
|
|
93
122
|
if (!messagesEl) return;
|
|
94
|
-
messagesEl.scrollTop = messagesEl
|
|
123
|
+
messagesEl.scrollTop = followTarget(messagesEl);
|
|
95
124
|
}
|
|
96
125
|
|
|
97
126
|
function ensureStickyInfrastructure() {
|
|
@@ -110,12 +139,13 @@ function ensureStickyInfrastructure() {
|
|
|
110
139
|
}
|
|
111
140
|
if (!stickyBottomInputBound) {
|
|
112
141
|
stickyBottomInputBound = true;
|
|
113
|
-
var disarmOnUserScroll = function () { disarmStickyBottom(); };
|
|
142
|
+
var disarmOnUserScroll = function () { disarmStickyBottom(); turnAnchor = null; turnAnchorEnded = false; };
|
|
114
143
|
messagesEl.addEventListener("wheel", disarmOnUserScroll, { passive: true });
|
|
115
144
|
messagesEl.addEventListener("touchmove", disarmOnUserScroll, { passive: true });
|
|
145
|
+
messagesEl.addEventListener("pointerdown", disarmOnUserScroll, { passive: true });
|
|
116
146
|
document.addEventListener("keydown", function (event) {
|
|
117
|
-
if (!stickyBottom) return;
|
|
118
|
-
if (event.key === "PageUp" || event.key === "Home" || event.key === "ArrowUp") disarmStickyBottom();
|
|
147
|
+
if (!stickyBottom && !turnAnchor) return;
|
|
148
|
+
if (event.key === "PageUp" || event.key === "Home" || event.key === "ArrowUp") { disarmStickyBottom(); turnAnchor = null; turnAnchorEnded = false; }
|
|
119
149
|
});
|
|
120
150
|
}
|
|
121
151
|
}
|
|
@@ -150,6 +180,7 @@ export function armStickyBottom(durationMs) {
|
|
|
150
180
|
|
|
151
181
|
export function disarmStickyBottom() {
|
|
152
182
|
stickyBottom = false;
|
|
183
|
+
if (turnAnchorEnded) { turnAnchor = null; turnAnchorEnded = false; }
|
|
153
184
|
if (stickyBottomQuietTimer) { clearTimeout(stickyBottomQuietTimer); stickyBottomQuietTimer = null; }
|
|
154
185
|
if (stickyBottomCeilingTimer) { clearTimeout(stickyBottomCeilingTimer); stickyBottomCeilingTimer = null; }
|
|
155
186
|
}
|
|
@@ -253,6 +284,11 @@ export function scrollToBottom() {
|
|
|
253
284
|
requestAnimationFrame(function () { if (stickyBottom && !layoutScrollLock()) pinToBottomNow(); });
|
|
254
285
|
return;
|
|
255
286
|
}
|
|
287
|
+
if (activeTurnAnchor(messagesEl) && !isUserScrolledUp) {
|
|
288
|
+
messagesEl.scrollTop = followTarget(messagesEl);
|
|
289
|
+
requestAnimationFrame(function () { if (!layoutScrollLock() && activeTurnAnchor(messagesEl)) messagesEl.scrollTop = followTarget(messagesEl); });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
256
292
|
var distFromBottom = messagesEl.scrollHeight - messagesEl.scrollTop - messagesEl.clientHeight;
|
|
257
293
|
if (distFromBottom > 150 || isUserScrolledUp) {
|
|
258
294
|
if (distFromBottom > 150) isUserScrolledUp = true;
|
|
@@ -274,10 +310,14 @@ export function scrollToBottom() {
|
|
|
274
310
|
});
|
|
275
311
|
}
|
|
276
312
|
|
|
277
|
-
export function forceScrollToBottom() {
|
|
313
|
+
export function forceScrollToBottom(sentTurnEl) {
|
|
278
314
|
if (prependAnchor || store.get('replayingHistory')) return;
|
|
279
|
-
// An explicit new turn supersedes a layout-only scroll receipt
|
|
315
|
+
// An explicit new turn supersedes a layout-only scroll receipt and any
|
|
316
|
+
// earlier reading position.
|
|
280
317
|
if (layoutScrollLock()) store.set({ paneLayoutScrollLock: null });
|
|
318
|
+
store.set({ paneLastUserScrollTop: null });
|
|
319
|
+
turnAnchor = sentTurnEl || null;
|
|
320
|
+
turnAnchorEnded = false;
|
|
281
321
|
armStickyBottom(750);
|
|
282
322
|
requestAnimationFrame(function () { if (stickyBottom && !layoutScrollLock()) pinToBottomNow(); });
|
|
283
323
|
}
|
|
@@ -20,71 +20,15 @@ export function workerActivityLabel(message, names) {
|
|
|
20
20
|
WebSearch: 'Search the web', WebFetch: 'Read web page' };
|
|
21
21
|
return definition ? definition.noun : (Object.prototype.hasOwnProperty.call(generic, name) ? generic[name] : null) || (typeof name === 'string' ? name.slice(0, 120) : 'Tool activity');
|
|
22
22
|
}
|
|
23
|
-
function workerActivityActionIcon(message, names) {
|
|
24
|
-
var match = message.toolId && names[message.toolId];
|
|
25
|
-
var name = message.toolName || match && match.name;
|
|
26
|
-
var definition = clayToolDefinition(name);
|
|
27
|
-
if (definition && typeof definition.icon === 'string' && definition.icon) return definition.icon;
|
|
28
|
-
var generic = { Read: 'file-text', read_file: 'file-text', Edit: 'pencil', Write: 'file-plus-2',
|
|
29
|
-
Bash: 'square-terminal', exec_command: 'square-terminal', Grep: 'search', Glob: 'search', WebSearch: 'globe', WebFetch: 'globe' };
|
|
30
|
-
return Object.prototype.hasOwnProperty.call(generic, name) ? generic[name] : null;
|
|
31
|
-
}
|
|
32
|
-
export function appendWorkerActivity(body, messages, names) {
|
|
33
|
-
var group = document.createElement('section'); group.className = 'worker-activity-group';
|
|
34
|
-
var key = String(messages[messages.length - 1].recordIndex);
|
|
35
|
-
group.dataset.activityKey = key;
|
|
36
|
-
var toggle = document.createElement('button'); toggle.type = 'button'; toggle.className = 'worker-activity-summary';
|
|
37
|
-
toggle.dataset.disclosureKey = 'activity-' + key;
|
|
38
|
-
var activityIcon = document.createElement('i'); activityIcon.setAttribute('data-lucide', 'activity'); activityIcon.setAttribute('aria-hidden', 'true');
|
|
39
|
-
var heading = document.createElement('span'); heading.className = 'worker-activity-heading'; heading.textContent = 'Activity';
|
|
40
|
-
var count = document.createElement('span'); count.className = 'worker-activity-count'; count.textContent = messages.length + (messages.length === 1 ? ' recorded step' : ' recorded steps');
|
|
41
|
-
var chevron = document.createElement('i'); chevron.className = 'worker-activity-chevron';
|
|
42
|
-
chevron.setAttribute('data-lucide', 'chevron-down'); chevron.setAttribute('aria-hidden', 'true');
|
|
43
|
-
toggle.append(activityIcon, heading, count, chevron);
|
|
44
|
-
toggle.setAttribute('aria-expanded', 'false'); toggle.disabled = messages.length <= 2;
|
|
45
|
-
var list = document.createElement('div'); list.className = 'worker-activity-list';
|
|
46
|
-
var items = [];
|
|
47
|
-
messages.forEach(function (message) {
|
|
48
|
-
var item = document.createElement('article'); item.className = 'worker-activity-item worker-tool-message';
|
|
49
|
-
item.dataset.recordIndex = String(message.recordIndex);
|
|
50
|
-
var phase = message.isError ? 'failed' : message.recordType === 'tool_result' ? 'returned' : 'recorded';
|
|
51
|
-
item.dataset.phase = phase;
|
|
52
|
-
var row = document.createElement('div'); row.className = 'worker-activity-row';
|
|
53
|
-
var actionIcon = workerActivityActionIcon(message, names);
|
|
54
|
-
var statusIcon = phase === 'failed' ? 'circle-alert' : phase === 'returned' ? 'corner-down-left' : 'circle-dot';
|
|
55
|
-
var glyph = document.createElement('i'); glyph.className = actionIcon ? 'worker-activity-glyph' : 'worker-activity-glyph worker-activity-status'; glyph.setAttribute('aria-hidden', 'true');
|
|
56
|
-
glyph.setAttribute('data-lucide', actionIcon || statusIcon);
|
|
57
|
-
var label = document.createElement('span'); label.className = 'worker-activity-label'; label.textContent = workerActivityLabel(message, names);
|
|
58
|
-
var detail = document.createElement('span'); detail.className = 'worker-activity-detail';
|
|
59
|
-
detail.textContent = phase === 'failed' ? 'Failed' : phase === 'returned' ? 'Result returned' : 'Call recorded';
|
|
60
|
-
row.append(glyph, label, detail);
|
|
61
|
-
if (actionIcon) {
|
|
62
|
-
var status = document.createElement('i'); status.className = 'worker-activity-status';
|
|
63
|
-
status.setAttribute('data-lucide', statusIcon); status.setAttribute('aria-hidden', 'true'); row.appendChild(status);
|
|
64
|
-
}
|
|
65
|
-
var evidence = document.createElement('details'); evidence.className = 'worker-activity-evidence'; evidence.dataset.disclosureKey = 'record-' + message.recordIndex;
|
|
66
|
-
var summary = document.createElement('summary'); summary.textContent = 'Technical details';
|
|
67
|
-
var output = document.createElement('pre'); output.textContent = message.text;
|
|
68
|
-
evidence.append(summary, output); item.append(row, evidence); items.push(item); list.appendChild(item);
|
|
69
|
-
});
|
|
70
|
-
function expand(open) {
|
|
71
|
-
toggle.setAttribute('aria-expanded', String(open));
|
|
72
|
-
items.forEach(function (item, index) { item.hidden = !open && index < items.length - 2; item.inert = item.hidden; });
|
|
73
|
-
}
|
|
74
|
-
toggle.addEventListener('click', function () { expand(toggle.getAttribute('aria-expanded') !== 'true'); });
|
|
75
|
-
expand(false); group.append(toggle, list); body.appendChild(group);
|
|
76
|
-
}
|
|
77
23
|
export function captureWorkerDisclosures(body) {
|
|
78
24
|
return {
|
|
79
25
|
open: Array.from(body.querySelectorAll('details[open]')).map(function (node) { return node.dataset.disclosureKey; }),
|
|
80
|
-
groups: Array.from(body.querySelectorAll('.worker-activity-summary[aria-expanded="true"]')).map(function (node) { return node.dataset.disclosureKey; }),
|
|
81
26
|
focus: document.activeElement && body.contains(document.activeElement) && (document.activeElement.dataset.disclosureKey || document.activeElement.parentElement && document.activeElement.parentElement.dataset.disclosureKey)
|
|
82
27
|
};
|
|
83
28
|
}
|
|
84
29
|
export function restoreWorkerDisclosures(body, saved) {
|
|
85
30
|
Array.from(body.querySelectorAll('[data-disclosure-key]')).forEach(function (node) {
|
|
86
31
|
var key = node.dataset.disclosureKey;
|
|
87
|
-
if (saved.groups.indexOf(key) >= 0 && node.getAttribute('aria-expanded') === 'false') node.click();
|
|
88
32
|
if (saved.open.indexOf(key) >= 0) node.open = true;
|
|
89
33
|
if (saved.focus === key) {
|
|
90
34
|
var target = node.tagName === 'DETAILS' ? node.querySelector('summary') : node;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { workerActivityLabel, workerActivityNames } from './split-view-worker-activity.js';
|
|
2
2
|
import { renderMarkdown } from './markdown.js';
|
|
3
3
|
|
|
4
4
|
// Reassemble bounded record fragments and contiguous streaming deltas before
|
|
@@ -17,13 +17,26 @@ export function workerTranscriptRows(messages) {
|
|
|
17
17
|
return rows;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function appendWorkerMessage(body, message) {
|
|
21
|
-
if (message.role === 'tool') {
|
|
20
|
+
export function appendWorkerMessage(body, message, names) {
|
|
21
|
+
if (message.role === 'tool') {
|
|
22
|
+
var article = document.createElement('article');
|
|
23
|
+
article.className = 'message worker-readonly-message worker-tool-message';
|
|
24
|
+
article.dataset.recordIndex = String(message.recordIndex);
|
|
25
|
+
article.dataset.phase = message.isError ? 'failed' : message.recordType === 'tool_result' ? 'returned' : 'recorded';
|
|
26
|
+
var details = document.createElement('details');
|
|
27
|
+
details.dataset.disclosureKey = 'record-' + message.recordIndex;
|
|
28
|
+
var summary = document.createElement('summary');
|
|
29
|
+
summary.textContent = workerActivityLabel(message, names || workerActivityNames([message])) +
|
|
30
|
+
(message.isError ? ' · Failed' : message.recordType === 'tool_result' ? ' · Result returned' : ' · Call recorded');
|
|
31
|
+
var output = document.createElement('pre'); output.textContent = message.text;
|
|
32
|
+
details.append(summary, output); article.appendChild(details); body.appendChild(article);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
22
35
|
var article = document.createElement('article');
|
|
23
36
|
article.className = 'message worker-readonly-message ' + (message.role === 'user' ? 'msg-user' : 'msg-assistant');
|
|
24
37
|
if (Number.isInteger(message.recordIndex)) article.dataset.recordIndex = String(message.recordIndex);
|
|
25
38
|
var author = document.createElement('strong'); author.className = 'author';
|
|
26
|
-
author.textContent = message.role === 'user' ? '
|
|
39
|
+
author.textContent = message.role === 'user' ? 'Driver' : 'Worker';
|
|
27
40
|
var content = document.createElement('div'); content.className = 'message-body md-content';
|
|
28
41
|
// Recorded HTML must not create controls, scoped overlays or active embeds.
|
|
29
42
|
// Keep the shared Markdown parser and its sanitization, with a narrower
|
|
@@ -36,11 +49,6 @@ export function appendWorkerMessage(body, message) {
|
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
export function appendWorkerTranscript(body, messages) {
|
|
39
|
-
var rows = workerTranscriptRows(messages), names = workerActivityNames(rows)
|
|
40
|
-
function
|
|
41
|
-
rows.forEach(function (message) {
|
|
42
|
-
if (message.role === 'tool') pending.push(message);
|
|
43
|
-
else { flush(); appendWorkerMessage(body, message); }
|
|
44
|
-
});
|
|
45
|
-
flush();
|
|
52
|
+
var rows = workerTranscriptRows(messages), names = workerActivityNames(rows);
|
|
53
|
+
rows.forEach(function (message) { appendWorkerMessage(body, message, names); });
|
|
46
54
|
}
|