agentgui 1.0.253 → 1.0.255
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/package.json +1 -1
- package/server.js +51 -14
- package/static/index.html +58 -7
- package/static/js/client.js +23 -39
- package/static/js/streaming-renderer.js +26 -14
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -306,6 +306,7 @@ const discoveredAgents = discoverAgents();
|
|
|
306
306
|
const modelCache = new Map();
|
|
307
307
|
|
|
308
308
|
const AGENT_MODEL_COMMANDS = {
|
|
309
|
+
'claude-code': 'claude models',
|
|
309
310
|
'opencode': 'opencode models',
|
|
310
311
|
'kilo': 'kilo models',
|
|
311
312
|
};
|
|
@@ -317,6 +318,7 @@ const AGENT_DEFAULT_MODELS = {
|
|
|
317
318
|
{ id: 'opus', label: 'Opus' },
|
|
318
319
|
{ id: 'haiku', label: 'Haiku' },
|
|
319
320
|
{ id: 'claude-sonnet-4-5-20250929', label: 'Sonnet 4.5' },
|
|
321
|
+
{ id: 'claude-sonnet-4-6-20260219', label: 'Sonnet 4.6' },
|
|
320
322
|
{ id: 'claude-opus-4-6', label: 'Opus 4.6' },
|
|
321
323
|
{ id: 'claude-haiku-4-5-20251001', label: 'Haiku 4.5' }
|
|
322
324
|
],
|
|
@@ -390,25 +392,25 @@ async function getModelsForAgent(agentId) {
|
|
|
390
392
|
return models;
|
|
391
393
|
}
|
|
392
394
|
|
|
393
|
-
if (AGENT_DEFAULT_MODELS[agentId]) {
|
|
394
|
-
const models = AGENT_DEFAULT_MODELS[agentId];
|
|
395
|
-
modelCache.set(agentId, { models, timestamp: Date.now() });
|
|
396
|
-
return models;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
395
|
if (AGENT_MODEL_COMMANDS[agentId]) {
|
|
400
396
|
try {
|
|
401
397
|
const result = execSync(AGENT_MODEL_COMMANDS[agentId], { encoding: 'utf-8', timeout: 15000 });
|
|
402
398
|
const lines = result.split('\n').map(l => l.trim()).filter(Boolean);
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
399
|
+
if (lines.length > 0) {
|
|
400
|
+
const models = [{ id: '', label: 'Default' }];
|
|
401
|
+
for (const line of lines) {
|
|
402
|
+
models.push({ id: line, label: line });
|
|
403
|
+
}
|
|
404
|
+
modelCache.set(agentId, { models, timestamp: Date.now() });
|
|
405
|
+
return models;
|
|
406
406
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
407
|
+
} catch (_) {}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
if (AGENT_DEFAULT_MODELS[agentId]) {
|
|
411
|
+
const models = AGENT_DEFAULT_MODELS[agentId];
|
|
412
|
+
modelCache.set(agentId, { models, timestamp: Date.now() });
|
|
413
|
+
return models;
|
|
412
414
|
}
|
|
413
415
|
|
|
414
416
|
const { getRegisteredAgents } = await import('./lib/claude-runner.js');
|
|
@@ -1970,6 +1972,41 @@ const server = http.createServer(async (req, res) => {
|
|
|
1970
1972
|
return;
|
|
1971
1973
|
}
|
|
1972
1974
|
|
|
1975
|
+
const agentUpdateMatch = pathOnly.match(/^\/api\/agents\/([^/]+)\/update$/);
|
|
1976
|
+
if (agentUpdateMatch && req.method === 'POST') {
|
|
1977
|
+
const agentId = agentUpdateMatch[1];
|
|
1978
|
+
const updateCommands = {
|
|
1979
|
+
'claude-code': { cmd: 'claude', args: ['update', '--yes'] },
|
|
1980
|
+
};
|
|
1981
|
+
const updateCmd = updateCommands[agentId];
|
|
1982
|
+
if (!updateCmd) { sendJSON(req, res, 400, { error: 'No update command for this agent' }); return; }
|
|
1983
|
+
const conversationId = '__agent_update__';
|
|
1984
|
+
if (activeScripts.has(conversationId)) { sendJSON(req, res, 409, { error: 'Update already running' }); return; }
|
|
1985
|
+
const child = spawn(updateCmd.cmd, updateCmd.args, {
|
|
1986
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1987
|
+
env: { ...process.env, FORCE_COLOR: '1' },
|
|
1988
|
+
shell: os.platform() === 'win32'
|
|
1989
|
+
});
|
|
1990
|
+
activeScripts.set(conversationId, { process: child, script: 'update-' + agentId, startTime: Date.now() });
|
|
1991
|
+
broadcastSync({ type: 'script_started', conversationId, script: 'update-' + agentId, agentId, timestamp: Date.now() });
|
|
1992
|
+
const onData = (stream) => (chunk) => {
|
|
1993
|
+
broadcastSync({ type: 'script_output', conversationId, data: chunk.toString(), stream, timestamp: Date.now() });
|
|
1994
|
+
};
|
|
1995
|
+
child.stdout.on('data', onData('stdout'));
|
|
1996
|
+
child.stderr.on('data', onData('stderr'));
|
|
1997
|
+
child.on('error', (err) => {
|
|
1998
|
+
activeScripts.delete(conversationId);
|
|
1999
|
+
broadcastSync({ type: 'script_stopped', conversationId, code: 1, error: err.message, timestamp: Date.now() });
|
|
2000
|
+
});
|
|
2001
|
+
child.on('close', (code) => {
|
|
2002
|
+
activeScripts.delete(conversationId);
|
|
2003
|
+
modelCache.delete(agentId);
|
|
2004
|
+
broadcastSync({ type: 'script_stopped', conversationId, code: code || 0, timestamp: Date.now() });
|
|
2005
|
+
});
|
|
2006
|
+
sendJSON(req, res, 200, { ok: true, agentId, pid: child.pid });
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1973
2010
|
if (pathOnly === '/api/auth/configs' && req.method === 'GET') {
|
|
1974
2011
|
const configs = getProviderConfigs();
|
|
1975
2012
|
sendJSON(req, res, 200, configs);
|
package/static/index.html
CHANGED
|
@@ -1753,11 +1753,11 @@
|
|
|
1753
1753
|
display: flex;
|
|
1754
1754
|
align-items: center;
|
|
1755
1755
|
gap: 0.375rem;
|
|
1756
|
-
padding: 0.
|
|
1756
|
+
padding: 0.4rem 0.75rem;
|
|
1757
1757
|
cursor: pointer;
|
|
1758
1758
|
user-select: none;
|
|
1759
1759
|
list-style: none;
|
|
1760
|
-
font-size: 0.
|
|
1760
|
+
font-size: 0.85rem;
|
|
1761
1761
|
line-height: 1.3;
|
|
1762
1762
|
background: #dcfce7;
|
|
1763
1763
|
transition: background 0.15s;
|
|
@@ -1784,24 +1784,24 @@
|
|
|
1784
1784
|
display: flex;
|
|
1785
1785
|
align-items: center;
|
|
1786
1786
|
color: #16a34a;
|
|
1787
|
-
width:
|
|
1788
|
-
height:
|
|
1787
|
+
width: 1rem;
|
|
1788
|
+
height: 1rem;
|
|
1789
1789
|
flex-shrink: 0;
|
|
1790
1790
|
}
|
|
1791
1791
|
html.dark .folded-tool-icon { color: #4ade80; }
|
|
1792
|
-
.folded-tool-icon svg { width:
|
|
1792
|
+
.folded-tool-icon svg { width: 1rem; height: 1rem; }
|
|
1793
1793
|
.folded-tool-name {
|
|
1794
1794
|
font-weight: 600;
|
|
1795
1795
|
color: #166534;
|
|
1796
1796
|
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1797
|
-
font-size: 0.
|
|
1797
|
+
font-size: 0.8rem;
|
|
1798
1798
|
flex-shrink: 0;
|
|
1799
1799
|
}
|
|
1800
1800
|
html.dark .folded-tool-name { color: #86efac; }
|
|
1801
1801
|
.folded-tool-desc {
|
|
1802
1802
|
color: #15803d;
|
|
1803
1803
|
font-family: 'Monaco','Menlo','Ubuntu Mono', monospace;
|
|
1804
|
-
font-size: 0.
|
|
1804
|
+
font-size: 0.8rem;
|
|
1805
1805
|
overflow: hidden;
|
|
1806
1806
|
text-overflow: ellipsis;
|
|
1807
1807
|
white-space: nowrap;
|
|
@@ -1874,6 +1874,33 @@
|
|
|
1874
1874
|
.folded-tool-info > .folded-tool-body { border-top-color: #c7d2fe; }
|
|
1875
1875
|
html.dark .folded-tool-info > .folded-tool-body { border-top-color: #3730a3; }
|
|
1876
1876
|
|
|
1877
|
+
/* --- Consecutive block joining --- */
|
|
1878
|
+
.folded-tool + .folded-tool,
|
|
1879
|
+
.block-tool-use + .block-tool-use {
|
|
1880
|
+
margin-top: -1px;
|
|
1881
|
+
border-radius: 0;
|
|
1882
|
+
}
|
|
1883
|
+
.folded-tool + .folded-tool > .folded-tool-bar,
|
|
1884
|
+
.block-tool-use + .block-tool-use > .folded-tool-bar {
|
|
1885
|
+
border-top: 1px solid rgba(0,0,0,0.06);
|
|
1886
|
+
}
|
|
1887
|
+
html.dark .folded-tool + .folded-tool > .folded-tool-bar,
|
|
1888
|
+
html.dark .block-tool-use + .block-tool-use > .folded-tool-bar {
|
|
1889
|
+
border-top: 1px solid rgba(255,255,255,0.06);
|
|
1890
|
+
}
|
|
1891
|
+
.folded-tool:first-child,
|
|
1892
|
+
.block-tool-use:first-child {
|
|
1893
|
+
border-radius: 0.375rem 0.375rem 0 0;
|
|
1894
|
+
}
|
|
1895
|
+
.folded-tool:last-child,
|
|
1896
|
+
.block-tool-use:last-child {
|
|
1897
|
+
border-radius: 0 0 0.375rem 0.375rem;
|
|
1898
|
+
}
|
|
1899
|
+
.folded-tool:only-child,
|
|
1900
|
+
.block-tool-use:only-child {
|
|
1901
|
+
border-radius: 0.375rem;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1877
1904
|
/* --- Inline Tool Result (nested inside tool_use) --- */
|
|
1878
1905
|
.tool-result-inline {
|
|
1879
1906
|
border-top: 1px solid #bbf7d0;
|
|
@@ -1905,6 +1932,30 @@
|
|
|
1905
1932
|
.tool-result-error > .folded-tool-body { border-top-color: #fecaca; }
|
|
1906
1933
|
html.dark .tool-result-error > .folded-tool-body { border-top-color: #991b1b; }
|
|
1907
1934
|
|
|
1935
|
+
/* --- Consecutive Block Joining --- */
|
|
1936
|
+
.streaming-blocks > * + *,
|
|
1937
|
+
.message-blocks > * + * {
|
|
1938
|
+
margin-top: 0;
|
|
1939
|
+
}
|
|
1940
|
+
.streaming-blocks > *,
|
|
1941
|
+
.message-blocks > * {
|
|
1942
|
+
border-radius: 0;
|
|
1943
|
+
}
|
|
1944
|
+
.streaming-blocks > *:first-child,
|
|
1945
|
+
.message-blocks > *:first-child {
|
|
1946
|
+
border-top-left-radius: 0.375rem;
|
|
1947
|
+
border-top-right-radius: 0.375rem;
|
|
1948
|
+
}
|
|
1949
|
+
.streaming-blocks > *:last-child,
|
|
1950
|
+
.message-blocks > *:last-child {
|
|
1951
|
+
border-bottom-left-radius: 0.375rem;
|
|
1952
|
+
border-bottom-right-radius: 0.375rem;
|
|
1953
|
+
}
|
|
1954
|
+
.streaming-blocks > *:only-child,
|
|
1955
|
+
.message-blocks > *:only-child {
|
|
1956
|
+
border-radius: 0.375rem;
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1908
1959
|
/* --- Collapsible Code Summary --- */
|
|
1909
1960
|
.collapsible-code {
|
|
1910
1961
|
margin: 0;
|
package/static/js/client.js
CHANGED
|
@@ -315,14 +315,24 @@ class AgentGUIClient {
|
|
|
315
315
|
const scrollContainer = document.getElementById(this.config.scrollContainerId);
|
|
316
316
|
if (!scrollContainer) return;
|
|
317
317
|
|
|
318
|
+
this._userScrolledUp = false;
|
|
318
319
|
let scrollTimer = null;
|
|
320
|
+
let lastScrollTop = scrollContainer.scrollTop;
|
|
319
321
|
scrollContainer.addEventListener('scroll', () => {
|
|
322
|
+
const distFromBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight;
|
|
323
|
+
if (scrollContainer.scrollTop < lastScrollTop && distFromBottom > 200) {
|
|
324
|
+
this._userScrolledUp = true;
|
|
325
|
+
} else if (distFromBottom < 50) {
|
|
326
|
+
this._userScrolledUp = false;
|
|
327
|
+
this._removeNewContentPill();
|
|
328
|
+
}
|
|
329
|
+
lastScrollTop = scrollContainer.scrollTop;
|
|
320
330
|
if (scrollTimer) clearTimeout(scrollTimer);
|
|
321
331
|
scrollTimer = setTimeout(() => {
|
|
322
332
|
if (this.state.currentConversation?.id) {
|
|
323
333
|
this.saveScrollPosition(this.state.currentConversation.id);
|
|
324
334
|
}
|
|
325
|
-
}, 500);
|
|
335
|
+
}, 500);
|
|
326
336
|
});
|
|
327
337
|
}
|
|
328
338
|
|
|
@@ -706,50 +716,21 @@ class AgentGUIClient {
|
|
|
706
716
|
if (!scrollContainer) return;
|
|
707
717
|
const distFromBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight;
|
|
708
718
|
|
|
709
|
-
if (
|
|
719
|
+
if (this._userScrolledUp && !force) {
|
|
710
720
|
this._unseenCount = (this._unseenCount || 0) + 1;
|
|
711
721
|
this._showNewContentPill();
|
|
712
722
|
return;
|
|
713
723
|
}
|
|
714
724
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if (!isStreaming || !this._scrollKalman || Math.abs(maxScroll - scrollContainer.scrollTop) > 2000 || force) {
|
|
719
|
-
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
720
|
-
this._removeNewContentPill();
|
|
721
|
-
this._scrollAnimating = false;
|
|
725
|
+
if (!force && distFromBottom > 150) {
|
|
726
|
+
this._unseenCount = (this._unseenCount || 0) + 1;
|
|
727
|
+
this._showNewContentPill();
|
|
722
728
|
return;
|
|
723
729
|
}
|
|
724
730
|
|
|
725
|
-
|
|
726
|
-
this.
|
|
727
|
-
|
|
728
|
-
const conf = this._chunkArrivalConfidence();
|
|
729
|
-
if (conf > 0.5) {
|
|
730
|
-
const estHeight = this._estimatedBlockHeight('text') * 0.5 * conf;
|
|
731
|
-
this._scrollTarget += estHeight;
|
|
732
|
-
const trueMax = scrollContainer.scrollHeight - scrollContainer.clientHeight;
|
|
733
|
-
if (this._scrollTarget > trueMax + 100) this._scrollTarget = trueMax + 100;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
if (!this._scrollAnimating) {
|
|
737
|
-
this._scrollAnimating = true;
|
|
738
|
-
const animate = () => {
|
|
739
|
-
if (!this._scrollAnimating) return;
|
|
740
|
-
const sc = document.getElementById('output-scroll');
|
|
741
|
-
if (!sc) { this._scrollAnimating = false; return; }
|
|
742
|
-
const diff = this._scrollTarget - sc.scrollTop;
|
|
743
|
-
if (Math.abs(diff) < 1) {
|
|
744
|
-
sc.scrollTop = this._scrollTarget;
|
|
745
|
-
if (this.state.streamingConversations.size === 0) { this._scrollAnimating = false; return; }
|
|
746
|
-
}
|
|
747
|
-
sc.scrollTop += diff * this._scrollLerpFactor;
|
|
748
|
-
this._removeNewContentPill();
|
|
749
|
-
requestAnimationFrame(animate);
|
|
750
|
-
};
|
|
751
|
-
requestAnimationFrame(animate);
|
|
752
|
-
}
|
|
731
|
+
scrollContainer.scrollTop = scrollContainer.scrollHeight;
|
|
732
|
+
this._removeNewContentPill();
|
|
733
|
+
this._scrollAnimating = false;
|
|
753
734
|
}
|
|
754
735
|
|
|
755
736
|
_showNewContentPill() {
|
|
@@ -1205,11 +1186,11 @@ class AgentGUIClient {
|
|
|
1205
1186
|
const tTitle = hasRenderer && block.input ? StreamingRenderer.getToolTitle(tn, block.input) : '';
|
|
1206
1187
|
const iconHtml = hasRenderer && this.renderer ? `<span class="folded-tool-icon">${this.renderer.getToolIcon(tn)}</span>` : '';
|
|
1207
1188
|
const colorIdx = hasRenderer && this.renderer ? this.renderer._getBlockColorIndex('tool_use') : 1;
|
|
1208
|
-
html += `<details class="block-tool-use folded-tool"
|
|
1189
|
+
html += `<details class="block-tool-use folded-tool" style="border-left:3px solid var(--block-color-${colorIdx})"><summary class="folded-tool-bar">${iconHtml}<span class="folded-tool-name">${this.escapeHtml(dName)}</span>${tTitle ? `<span class="folded-tool-desc">${this.escapeHtml(tTitle)}</span>` : ''}</summary>${inputHtml}`;
|
|
1209
1190
|
pendingToolUseClose = true;
|
|
1210
1191
|
} else if (block.type === 'tool_result') {
|
|
1211
1192
|
const content = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
1212
|
-
const smartHtml = typeof StreamingRenderer !== 'undefined' ? StreamingRenderer.renderSmartContentHTML(content, this.escapeHtml.bind(this)) : `<pre class="tool-result-pre">${this.escapeHtml(content.length > 2000 ? content.substring(0, 2000) + '\n... (truncated)' : content)}</pre>`;
|
|
1193
|
+
const smartHtml = typeof StreamingRenderer !== 'undefined' ? StreamingRenderer.renderSmartContentHTML(content, this.escapeHtml.bind(this), true) : `<pre class="tool-result-pre">${this.escapeHtml(content.length > 2000 ? content.substring(0, 2000) + '\n... (truncated)' : content)}</pre>`;
|
|
1213
1194
|
const resultPreview = content.length > 80 ? content.substring(0, 77).replace(/\n/g, ' ') + '...' : content.replace(/\n/g, ' ');
|
|
1214
1195
|
const resultIcon = block.is_error
|
|
1215
1196
|
? '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/></svg>'
|
|
@@ -2235,6 +2216,9 @@ class AgentGUIClient {
|
|
|
2235
2216
|
|
|
2236
2217
|
this.cacheCurrentConversation();
|
|
2237
2218
|
this.stopChunkPolling();
|
|
2219
|
+
if (this.renderer.resetScrollState) this.renderer.resetScrollState();
|
|
2220
|
+
this._userScrolledUp = false;
|
|
2221
|
+
this._removeNewContentPill();
|
|
2238
2222
|
var prevId = this.state.currentConversation?.id;
|
|
2239
2223
|
if (prevId && prevId !== conversationId) {
|
|
2240
2224
|
if (this.wsManager.isConnected && !this.state.streamingConversations.has(prevId)) {
|
|
@@ -98,6 +98,14 @@ class StreamingRenderer {
|
|
|
98
98
|
* Setup scroll optimization and auto-scroll
|
|
99
99
|
*/
|
|
100
100
|
setupScrollOptimization() {
|
|
101
|
+
if (!this.scrollContainer) return;
|
|
102
|
+
this._userScrolledUp = false;
|
|
103
|
+
this.scrollContainer.addEventListener('scroll', () => {
|
|
104
|
+
if (this._programmaticScroll) return;
|
|
105
|
+
const sc = this.scrollContainer;
|
|
106
|
+
const distFromBottom = sc.scrollHeight - sc.scrollTop - sc.clientHeight;
|
|
107
|
+
this._userScrolledUp = distFromBottom > 80;
|
|
108
|
+
});
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
/**
|
|
@@ -749,7 +757,6 @@ class StreamingRenderer {
|
|
|
749
757
|
|
|
750
758
|
const details = document.createElement('details');
|
|
751
759
|
details.className = 'block-tool-use folded-tool';
|
|
752
|
-
details.setAttribute('open', '');
|
|
753
760
|
if (block.id) details.dataset.toolUseId = block.id;
|
|
754
761
|
const colorIndex = this._getBlockColorIndex('tool_use');
|
|
755
762
|
details.style.borderLeft = `3px solid var(--block-color-${colorIndex})`;
|
|
@@ -856,7 +863,7 @@ class StreamingRenderer {
|
|
|
856
863
|
/**
|
|
857
864
|
* Static HTML version of smart content rendering for use in string templates
|
|
858
865
|
*/
|
|
859
|
-
static renderSmartContentHTML(contentStr, escapeHtml) {
|
|
866
|
+
static renderSmartContentHTML(contentStr, escapeHtml, flat = false) {
|
|
860
867
|
const trimmed = contentStr.trim();
|
|
861
868
|
const esc = escapeHtml || window._escHtml;
|
|
862
869
|
|
|
@@ -874,8 +881,7 @@ class StreamingRenderer {
|
|
|
874
881
|
const textParts = parsed.filter(b => b.type === 'text' && b.text);
|
|
875
882
|
if (textParts.length > 0) {
|
|
876
883
|
const combined = textParts.map(b => b.text).join('\n');
|
|
877
|
-
|
|
878
|
-
return StreamingRenderer.renderSmartContentHTML(combined, esc);
|
|
884
|
+
return StreamingRenderer.renderSmartContentHTML(combined, esc, flat);
|
|
879
885
|
}
|
|
880
886
|
}
|
|
881
887
|
|
|
@@ -905,7 +911,7 @@ class StreamingRenderer {
|
|
|
905
911
|
const cleanedContent = cleanedLines.join('\n');
|
|
906
912
|
|
|
907
913
|
// Try to detect and highlight code based on content patterns
|
|
908
|
-
return StreamingRenderer.renderCodeWithHighlight(cleanedContent, esc);
|
|
914
|
+
return StreamingRenderer.renderCodeWithHighlight(cleanedContent, esc, flat);
|
|
909
915
|
}
|
|
910
916
|
|
|
911
917
|
// Check for system reminder tags and format them specially
|
|
@@ -1001,7 +1007,7 @@ class StreamingRenderer {
|
|
|
1001
1007
|
|
|
1002
1008
|
// Add highlighted code
|
|
1003
1009
|
if (codeContent.trim()) {
|
|
1004
|
-
html += StreamingRenderer.renderCodeWithHighlight(codeContent, esc);
|
|
1010
|
+
html += StreamingRenderer.renderCodeWithHighlight(codeContent, esc, flat);
|
|
1005
1011
|
}
|
|
1006
1012
|
|
|
1007
1013
|
// Add system reminders if any
|
|
@@ -1021,7 +1027,7 @@ class StreamingRenderer {
|
|
|
1021
1027
|
if (contentWithoutReminders) {
|
|
1022
1028
|
// Check if remaining content looks like code
|
|
1023
1029
|
if (StreamingRenderer.detectCodeContent(contentWithoutReminders)) {
|
|
1024
|
-
html += StreamingRenderer.renderCodeWithHighlight(contentWithoutReminders, esc);
|
|
1030
|
+
html += StreamingRenderer.renderCodeWithHighlight(contentWithoutReminders, esc, flat);
|
|
1025
1031
|
} else {
|
|
1026
1032
|
html += `<pre class="tool-result-pre">${esc(contentWithoutReminders)}</pre>`;
|
|
1027
1033
|
}
|
|
@@ -1050,7 +1056,7 @@ class StreamingRenderer {
|
|
|
1050
1056
|
// Check if this looks like code
|
|
1051
1057
|
const looksLikeCode = StreamingRenderer.detectCodeContent(trimmed);
|
|
1052
1058
|
if (looksLikeCode) {
|
|
1053
|
-
return StreamingRenderer.renderCodeWithHighlight(trimmed, esc);
|
|
1059
|
+
return StreamingRenderer.renderCodeWithHighlight(trimmed, esc, flat);
|
|
1054
1060
|
}
|
|
1055
1061
|
|
|
1056
1062
|
const displayContent = trimmed.length > 2000 ? trimmed.substring(0, 2000) + '\n... (truncated)' : trimmed;
|
|
@@ -1109,11 +1115,12 @@ class StreamingRenderer {
|
|
|
1109
1115
|
/**
|
|
1110
1116
|
* Render code with basic syntax highlighting
|
|
1111
1117
|
*/
|
|
1112
|
-
static renderCodeWithHighlight(code, esc) {
|
|
1113
|
-
const preStyle = "background:#1e293b;padding:1rem;border-radius:0
|
|
1118
|
+
static renderCodeWithHighlight(code, esc, flat = false) {
|
|
1119
|
+
const preStyle = "background:#1e293b;padding:1rem;border-radius:0.375rem;overflow-x:auto;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.875rem;line-height:1.6;color:#e2e8f0;border:1px solid #334155;margin:0";
|
|
1120
|
+
const codeHtml = `<pre style="${preStyle}"><code class="lazy-hl">${esc(code)}</code></pre>`;
|
|
1121
|
+
if (flat) return codeHtml;
|
|
1114
1122
|
const lineCount = code.split('\n').length;
|
|
1115
1123
|
const summaryLabel = `code - ${lineCount} line${lineCount !== 1 ? 's' : ''}`;
|
|
1116
|
-
const codeHtml = `<pre style="${preStyle}"><code class="lazy-hl">${esc(code)}</code></pre>`;
|
|
1117
1124
|
return `<details class="collapsible-code"><summary class="collapsible-code-summary">${summaryLabel}</summary>${codeHtml}</details>`;
|
|
1118
1125
|
}
|
|
1119
1126
|
|
|
@@ -1240,7 +1247,7 @@ class StreamingRenderer {
|
|
|
1240
1247
|
`;
|
|
1241
1248
|
wrapper.appendChild(header);
|
|
1242
1249
|
|
|
1243
|
-
const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this));
|
|
1250
|
+
const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this), true);
|
|
1244
1251
|
const body = document.createElement('div');
|
|
1245
1252
|
body.className = 'folded-tool-body';
|
|
1246
1253
|
if (!parentIsOpen) {
|
|
@@ -1348,7 +1355,6 @@ class StreamingRenderer {
|
|
|
1348
1355
|
const details = document.createElement('details');
|
|
1349
1356
|
details.className = isError ? 'folded-tool folded-tool-error' : 'folded-tool';
|
|
1350
1357
|
details.dataset.eventType = 'result';
|
|
1351
|
-
if (!isError) details.setAttribute('open', '');
|
|
1352
1358
|
const colorIndex = this._getBlockColorIndex(isError ? 'error' : 'result');
|
|
1353
1359
|
details.style.borderLeft = `3px solid var(--block-color-${colorIndex})`;
|
|
1354
1360
|
|
|
@@ -2003,16 +2009,22 @@ class StreamingRenderer {
|
|
|
2003
2009
|
* Auto-scroll to bottom of container
|
|
2004
2010
|
*/
|
|
2005
2011
|
autoScroll() {
|
|
2006
|
-
if (this._scrollRafPending) return;
|
|
2012
|
+
if (this._scrollRafPending || this._userScrolledUp) return;
|
|
2007
2013
|
this._scrollRafPending = true;
|
|
2008
2014
|
requestAnimationFrame(() => {
|
|
2009
2015
|
this._scrollRafPending = false;
|
|
2010
2016
|
if (this.scrollContainer) {
|
|
2017
|
+
this._programmaticScroll = true;
|
|
2011
2018
|
try { this.scrollContainer.scrollTop = this.scrollContainer.scrollHeight; } catch (_) {}
|
|
2019
|
+
this._programmaticScroll = false;
|
|
2012
2020
|
}
|
|
2013
2021
|
});
|
|
2014
2022
|
}
|
|
2015
2023
|
|
|
2024
|
+
resetScrollState() {
|
|
2025
|
+
this._userScrolledUp = false;
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2016
2028
|
updateVirtualScroll() {
|
|
2017
2029
|
}
|
|
2018
2030
|
|