agentgui 1.0.827 → 1.0.828
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/CHANGELOG.md +3 -0
- package/package.json +1 -1
- package/static/index.html +14 -0
- package/static/js/streaming-renderer-dispatch.js +144 -0
- package/static/js/streaming-renderer-events.js +163 -0
- package/static/js/streaming-renderer-events2.js +125 -0
- package/static/js/streaming-renderer-params.js +38 -0
- package/static/js/streaming-renderer-render-misc.js +107 -0
- package/static/js/streaming-renderer-render.js +181 -0
- package/static/js/streaming-renderer-render2.js +149 -0
- package/static/js/streaming-renderer-render3.js +142 -0
- package/static/js/streaming-renderer-static.js +181 -0
- package/static/js/streaming-renderer-static2.js +140 -0
- package/static/js/streaming-renderer-stream.js +170 -0
- package/static/js/streaming-renderer-text.js +185 -0
- package/static/js/streaming-renderer-tools.js +189 -0
- package/static/js/streaming-renderer-tools2.js +92 -0
- package/static/js/streaming-renderer.js +4 -1996
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
## 2026-04-12
|
|
2
|
+
- refactor: split streaming-renderer.js (2193L) into 15 files ≤200L each; all 75 prototype methods and 8 static methods preserved; index.html updated with correct load order
|
|
3
|
+
|
|
1
4
|
## 2026-04-11
|
|
2
5
|
- refactor: replace jsonl-watcher.js with @lanmower/cc-tail npm package (subclass CCTailWatcher, override _line() via JsonlParser); remove custom file-watching logic
|
|
3
6
|
- refactor: split syntax-highlighter.js (216L) into syntax-highlighter.js (132L) + syntax-highlighter-render.js (73L)
|
package/package.json
CHANGED
package/static/index.html
CHANGED
|
@@ -281,6 +281,20 @@
|
|
|
281
281
|
</script>
|
|
282
282
|
<script defer src="/gm/js/event-processor.js"></script>
|
|
283
283
|
<script defer src="/gm/js/streaming-renderer.js"></script>
|
|
284
|
+
<script defer src="/gm/js/streaming-renderer-static.js"></script>
|
|
285
|
+
<script defer src="/gm/js/streaming-renderer-static2.js"></script>
|
|
286
|
+
<script defer src="/gm/js/streaming-renderer-dispatch.js"></script>
|
|
287
|
+
<script defer src="/gm/js/streaming-renderer-text.js"></script>
|
|
288
|
+
<script defer src="/gm/js/streaming-renderer-tools.js"></script>
|
|
289
|
+
<script defer src="/gm/js/streaming-renderer-tools2.js"></script>
|
|
290
|
+
<script defer src="/gm/js/streaming-renderer-params.js"></script>
|
|
291
|
+
<script defer src="/gm/js/streaming-renderer-events.js"></script>
|
|
292
|
+
<script defer src="/gm/js/streaming-renderer-events2.js"></script>
|
|
293
|
+
<script defer src="/gm/js/streaming-renderer-stream.js"></script>
|
|
294
|
+
<script defer src="/gm/js/streaming-renderer-render.js"></script>
|
|
295
|
+
<script defer src="/gm/js/streaming-renderer-render-misc.js"></script>
|
|
296
|
+
<script defer src="/gm/js/streaming-renderer-render2.js"></script>
|
|
297
|
+
<script defer src="/gm/js/streaming-renderer-render3.js"></script>
|
|
284
298
|
<script defer src="/gm/js/image-loader.js"></script>
|
|
285
299
|
<script defer src="/gm/js/image-loader-element.js"></script>
|
|
286
300
|
<script defer src="/gm/lib/webjsx.js"></script>
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Object.assign(StreamingRenderer.prototype, {
|
|
2
|
+
renderBatch(batch) {
|
|
3
|
+
if (!this.outputContainer) return;
|
|
4
|
+
|
|
5
|
+
this.emit('render:start', { eventCount: batch.length });
|
|
6
|
+
const renderStart = performance.now();
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const fragment = document.createDocumentFragment();
|
|
10
|
+
let nodeCount = 0;
|
|
11
|
+
|
|
12
|
+
for (const event of batch) {
|
|
13
|
+
try {
|
|
14
|
+
const element = this.renderEvent(event);
|
|
15
|
+
if (element) {
|
|
16
|
+
fragment.appendChild(element);
|
|
17
|
+
nodeCount++;
|
|
18
|
+
}
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error('Event render error:', error, event);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (nodeCount > 0) {
|
|
25
|
+
this.outputContainer.appendChild(fragment);
|
|
26
|
+
this.domNodeCount += nodeCount;
|
|
27
|
+
|
|
28
|
+
this.nestToolResultsInToolUses();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.autoScroll();
|
|
32
|
+
|
|
33
|
+
const renderTime = performance.now() - renderStart;
|
|
34
|
+
this.lastRenderTime = renderTime;
|
|
35
|
+
|
|
36
|
+
this.emit('render:complete', {
|
|
37
|
+
eventCount: batch.length,
|
|
38
|
+
nodeCount,
|
|
39
|
+
renderTime
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('Batch render error:', error);
|
|
43
|
+
this.emit('error:render', { error, batch });
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
renderEvent(event) {
|
|
48
|
+
if (!event.type) return null;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
if (event.type === 'streaming_progress' && event.block) {
|
|
52
|
+
return this.renderBlock(event.block, event);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (event.type === 'streaming_error' && event.isPrematureEnd) {
|
|
56
|
+
return this.renderBlockPremature({ type: 'premature', error: event.error, exitCode: event.exitCode });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
switch (event.type) {
|
|
60
|
+
case 'streaming_start':
|
|
61
|
+
return this.renderStreamingStart(event);
|
|
62
|
+
case 'streaming_progress':
|
|
63
|
+
return this.renderStreamingProgress(event);
|
|
64
|
+
case 'streaming_complete':
|
|
65
|
+
return this.renderStreamingComplete(event);
|
|
66
|
+
case 'file_read':
|
|
67
|
+
return this.renderFileRead(event);
|
|
68
|
+
case 'file_write':
|
|
69
|
+
return this.renderFileWrite(event);
|
|
70
|
+
case 'git_status':
|
|
71
|
+
return this.renderGitStatus(event);
|
|
72
|
+
case 'command_execute':
|
|
73
|
+
return this.renderCommand(event);
|
|
74
|
+
case 'error':
|
|
75
|
+
return this.renderError(event);
|
|
76
|
+
case 'text_block':
|
|
77
|
+
return this.renderText(event);
|
|
78
|
+
case 'code_block':
|
|
79
|
+
return this.renderCode(event);
|
|
80
|
+
case 'thinking_block':
|
|
81
|
+
return null;
|
|
82
|
+
case 'tool_use':
|
|
83
|
+
return this.renderToolUse(event);
|
|
84
|
+
case 'compact_boundary':
|
|
85
|
+
return this.renderCompactBoundary(event);
|
|
86
|
+
case 'compact_summary':
|
|
87
|
+
return this.renderCompactBoundary(event);
|
|
88
|
+
case 'turn_duration':
|
|
89
|
+
return this.renderTurnDuration(event);
|
|
90
|
+
case 'agent_progress':
|
|
91
|
+
return this.renderAgentProgress(event);
|
|
92
|
+
case 'mcp_progress':
|
|
93
|
+
return this.renderMcpProgress(event);
|
|
94
|
+
default:
|
|
95
|
+
return this.renderGeneric(event);
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error('Event render error:', error, event);
|
|
99
|
+
return this.renderError({ message: error.message, event });
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
renderBlock(block, context = {}, targetContainer = null) {
|
|
104
|
+
if (!block || !block.type) return null;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
switch (block.type) {
|
|
108
|
+
case 'text':
|
|
109
|
+
return this.renderBlockText(block, context, targetContainer);
|
|
110
|
+
case 'code':
|
|
111
|
+
return this.renderBlockCode(block, context);
|
|
112
|
+
case 'thinking':
|
|
113
|
+
return this.renderBlockThinking(block, context);
|
|
114
|
+
case 'tool_use':
|
|
115
|
+
return this.renderBlockToolUse(block, context);
|
|
116
|
+
case 'tool_result':
|
|
117
|
+
return this.renderBlockToolResult(block, context);
|
|
118
|
+
case 'image':
|
|
119
|
+
return this.renderBlockImage(block, context);
|
|
120
|
+
case 'bash':
|
|
121
|
+
return this.renderBlockBash(block, context);
|
|
122
|
+
case 'system':
|
|
123
|
+
return this.renderBlockSystem(block, context);
|
|
124
|
+
case 'result':
|
|
125
|
+
return this.renderBlockResult(block, context);
|
|
126
|
+
case 'tool_status':
|
|
127
|
+
return this.renderBlockToolStatus(block, context);
|
|
128
|
+
case 'usage':
|
|
129
|
+
return this.renderBlockUsage(block, context);
|
|
130
|
+
case 'plan':
|
|
131
|
+
return this.renderBlockPlan(block, context);
|
|
132
|
+
case 'premature':
|
|
133
|
+
return this.renderBlockPremature(block, context);
|
|
134
|
+
case 'hook_progress':
|
|
135
|
+
return this.renderBlockHookProgress(block, context);
|
|
136
|
+
default:
|
|
137
|
+
return this.renderBlockGeneric(block, context);
|
|
138
|
+
}
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('Block render error:', error, block);
|
|
141
|
+
return this.renderBlockError(block, error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
Object.assign(StreamingRenderer.prototype, {
|
|
2
|
+
renderBlockImage(block, context) {
|
|
3
|
+
const div = document.createElement('div');
|
|
4
|
+
div.className = 'block-image';
|
|
5
|
+
div.classList.add(this._getBlockTypeClass('image'));
|
|
6
|
+
|
|
7
|
+
let src = block.image || block.src || '';
|
|
8
|
+
const alt = block.alt || 'Image';
|
|
9
|
+
|
|
10
|
+
if (block.data && block.media_type) {
|
|
11
|
+
src = `data:${block.media_type};base64,${block.data}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
div.innerHTML = `
|
|
15
|
+
<img src="${this.escapeHtml(src)}" alt="${this.escapeHtml(alt)}" loading="lazy">
|
|
16
|
+
${block.alt ? `<div class="image-caption">${this.escapeHtml(alt)}</div>` : ''}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
return div;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
renderBlockBash(block, context) {
|
|
23
|
+
const div = document.createElement('div');
|
|
24
|
+
div.className = 'block-bash';
|
|
25
|
+
div.classList.add(this._getBlockTypeClass('bash'));
|
|
26
|
+
|
|
27
|
+
const command = block.command || block.code || '';
|
|
28
|
+
const output = block.output || '';
|
|
29
|
+
|
|
30
|
+
let html = `<div class="bash-command"><span class="prompt">$</span><code>${this.escapeHtml(command)}</code></div>`;
|
|
31
|
+
|
|
32
|
+
if (output) {
|
|
33
|
+
if (StreamingRenderer.detectCodeContent(output)) {
|
|
34
|
+
html += StreamingRenderer.renderCodeWithHighlight(output, this.escapeHtml.bind(this), true);
|
|
35
|
+
} else {
|
|
36
|
+
html += `<pre class="bash-output"><code>${this.escapeHtml(output)}</code></pre>`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
div.innerHTML = html;
|
|
41
|
+
return div;
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
renderBlockSystem(block, context) {
|
|
45
|
+
if (block.subtype === 'compact_boundary') return this.renderCompactBoundary(block);
|
|
46
|
+
if (block.subtype === 'turn_duration') return this.renderTurnDuration(block);
|
|
47
|
+
if (!block.model && !block.cwd && !block.tools) return null;
|
|
48
|
+
const details = document.createElement('details');
|
|
49
|
+
details.className = 'folded-tool folded-tool-info permanently-expanded';
|
|
50
|
+
details.dataset.eventType = 'system';
|
|
51
|
+
details.classList.add(this._getBlockTypeClass('system'));
|
|
52
|
+
const desc = block.model ? this.escapeHtml(block.model) : 'Session';
|
|
53
|
+
const summary = document.createElement('summary');
|
|
54
|
+
summary.className = 'folded-tool-bar';
|
|
55
|
+
summary.innerHTML = `
|
|
56
|
+
<span class="folded-tool-icon"><svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/></svg></span>
|
|
57
|
+
<span class="folded-tool-name">Session</span>
|
|
58
|
+
<span class="folded-tool-desc">${desc}</span>
|
|
59
|
+
`;
|
|
60
|
+
details.appendChild(summary);
|
|
61
|
+
const body = document.createElement('div');
|
|
62
|
+
body.className = 'folded-tool-body block-system';
|
|
63
|
+
body.innerHTML = `
|
|
64
|
+
<div class="system-body">
|
|
65
|
+
${block.model ? `<div class="sys-field"><span class="sys-label">Model</span><span class="sys-value"><code>${this.escapeHtml(block.model)}</code></span></div>` : ''}
|
|
66
|
+
${block.cwd ? `<div class="sys-field"><span class="sys-label">Directory</span><span class="sys-value"><code>${this.escapeHtml(block.cwd)}</code></span></div>` : ''}
|
|
67
|
+
${block.session_id ? `<div class="sys-field"><span class="sys-label">Session</span><span class="sys-value"><code>${this.escapeHtml(block.session_id)}</code></span></div>` : ''}
|
|
68
|
+
${block.tools && Array.isArray(block.tools) ? `<div class="sys-field" style="flex-direction:column;gap:0.375rem"><span class="sys-label">Tools (${block.tools.length})</span><div class="tools-list">${block.tools.map(t => `<span class="tool-badge">${this.escapeHtml(t)}</span>`).join('')}</div></div>` : ''}
|
|
69
|
+
</div>
|
|
70
|
+
`;
|
|
71
|
+
details.appendChild(body);
|
|
72
|
+
return details;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
renderBlockResult(block, context) {
|
|
76
|
+
const isError = block.is_error || false;
|
|
77
|
+
const duration = block.duration_ms ? (block.duration_ms / 1000).toFixed(1) + 's' : '';
|
|
78
|
+
const cost = block.total_cost_usd ? '$' + block.total_cost_usd.toFixed(4) : '';
|
|
79
|
+
const turns = block.num_turns || '';
|
|
80
|
+
const statsDesc = [duration, cost, turns ? turns + ' turns' : ''].filter(Boolean).join(' / ');
|
|
81
|
+
|
|
82
|
+
const details = document.createElement('details');
|
|
83
|
+
details.className = isError ? 'folded-tool folded-tool-error permanently-expanded' : 'folded-tool permanently-expanded';
|
|
84
|
+
details.dataset.eventType = 'result';
|
|
85
|
+
details.classList.add(this._getBlockTypeClass(isError ? 'error' : 'result'));
|
|
86
|
+
|
|
87
|
+
const iconSvg = isError
|
|
88
|
+
? '<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>'
|
|
89
|
+
: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/></svg>';
|
|
90
|
+
|
|
91
|
+
const summary = document.createElement('summary');
|
|
92
|
+
summary.className = 'folded-tool-bar';
|
|
93
|
+
summary.innerHTML = `
|
|
94
|
+
<span class="folded-tool-icon">${iconSvg}</span>
|
|
95
|
+
<span class="folded-tool-name">${isError ? 'Failed' : 'Complete'}</span>
|
|
96
|
+
<span class="folded-tool-desc">${this.escapeHtml(statsDesc)}</span>
|
|
97
|
+
`;
|
|
98
|
+
details.appendChild(summary);
|
|
99
|
+
|
|
100
|
+
if (block.result || duration || cost || turns) {
|
|
101
|
+
const body = document.createElement('div');
|
|
102
|
+
body.className = 'folded-tool-body';
|
|
103
|
+
let bodyHtml = '';
|
|
104
|
+
if (duration || cost || turns) {
|
|
105
|
+
bodyHtml += `<div class="block-result"><div class="result-stats">
|
|
106
|
+
${duration ? `<div class="result-stat"><span class="stat-icon">⏲</span><span class="stat-value">${this.escapeHtml(duration)}</span><span class="stat-label">duration</span></div>` : ''}
|
|
107
|
+
${cost ? `<div class="result-stat"><span class="stat-icon">💰</span><span class="stat-value">${this.escapeHtml(cost)}</span><span class="stat-label">cost</span></div>` : ''}
|
|
108
|
+
${turns ? `<div class="result-stat"><span class="stat-icon">🔄</span><span class="stat-value">${this.escapeHtml(String(turns))}</span><span class="stat-label">turns</span></div>` : ''}
|
|
109
|
+
</div></div>`;
|
|
110
|
+
}
|
|
111
|
+
if (block.result) {
|
|
112
|
+
const r = typeof block.result === 'string' ? block.result : JSON.stringify(block.result, null, 2);
|
|
113
|
+
const rendered = this.containsHtmlTags(r) ? '<div class="html-content">' + this.sanitizeHtml(r) + '</div>' : `<div style="font-size:0.8rem;white-space:pre-wrap;word-break:break-word;line-height:1.5">${this.escapeHtml(r)}</div>`;
|
|
114
|
+
bodyHtml += rendered;
|
|
115
|
+
}
|
|
116
|
+
body.innerHTML = bodyHtml;
|
|
117
|
+
details.appendChild(body);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return details;
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
renderBlockToolStatus(block, context) {
|
|
124
|
+
const status = block.status || 'pending';
|
|
125
|
+
const statusIcons = {
|
|
126
|
+
pending: '<svg viewBox="0 0 20 20" fill="currentColor" style="color:var(--color-text-secondary)"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/></svg>',
|
|
127
|
+
in_progress: '<svg viewBox="0 0 20 20" fill="currentColor" class="animate-spin" style="color:var(--color-info)"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/></svg>'
|
|
128
|
+
};
|
|
129
|
+
const statusLabels = {
|
|
130
|
+
pending: 'Pending',
|
|
131
|
+
in_progress: 'Running...'
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const div = document.createElement('div');
|
|
135
|
+
div.className = 'block-tool-status';
|
|
136
|
+
div.dataset.toolUseId = block.tool_use_id || '';
|
|
137
|
+
div.classList.add(this._getBlockTypeClass('tool_status'));
|
|
138
|
+
div.innerHTML = `
|
|
139
|
+
<div style="display:flex;align-items:center;gap:0.5rem;padding:0.25rem 0.5rem;font-size:0.75rem;color:var(--color-text-secondary)">
|
|
140
|
+
${statusIcons[status] || statusIcons.pending}
|
|
141
|
+
<span>${statusLabels[status] || this.escapeHtml(status)}</span>
|
|
142
|
+
</div>
|
|
143
|
+
`;
|
|
144
|
+
return div;
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
renderBlockHookProgress(block, context) {
|
|
148
|
+
const hookEvent = block.hookEvent || block.hookName || '';
|
|
149
|
+
const hookIcons = {
|
|
150
|
+
PreToolUse: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10.666a1 1 0 11-1.64-1.118L9.687 10H5a1 1 0 01-.82-1.573l7-10.666a1 1 0 011.12-.373z" clip-rule="evenodd"/></svg>',
|
|
151
|
+
PostToolUse: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>',
|
|
152
|
+
Stop: '<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8 7a1 1 0 00-1 1v4a1 1 0 001 1h4a1 1 0 001-1V8a1 1 0 00-1-1H8z" clip-rule="evenodd"/></svg>'
|
|
153
|
+
};
|
|
154
|
+
const icon = hookIcons[hookEvent.split(':')[0]] || hookIcons.PreToolUse;
|
|
155
|
+
const label = hookEvent.includes(':') ? hookEvent.split(':').pop() : hookEvent;
|
|
156
|
+
const div = document.createElement('div');
|
|
157
|
+
div.className = 'block-hook-progress';
|
|
158
|
+
div.dataset.hookEvent = hookEvent;
|
|
159
|
+
div.style.cssText = 'display:none';
|
|
160
|
+
div.innerHTML = '<span class="hook-badge" style="display:inline-flex;align-items:center;gap:0.25rem;padding:0.125rem 0.5rem;font-size:0.65rem;color:var(--color-text-secondary);opacity:0.5">' + icon + '<span>' + this.escapeHtml(label) + '</span></span>';
|
|
161
|
+
return div;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Object.assign(StreamingRenderer.prototype, {
|
|
2
|
+
renderBlockUsage(block, context) {
|
|
3
|
+
const usage = block.usage || {};
|
|
4
|
+
const used = usage.used || 0;
|
|
5
|
+
const size = usage.size || 0;
|
|
6
|
+
const cost = usage.cost ? '$' + usage.cost.toFixed(4) : '';
|
|
7
|
+
|
|
8
|
+
const div = document.createElement('div');
|
|
9
|
+
div.className = 'block-usage';
|
|
10
|
+
div.classList.add(this._getBlockTypeClass('usage'));
|
|
11
|
+
div.innerHTML = `
|
|
12
|
+
<div style="display:flex;gap:1rem;padding:0.25rem 0.5rem;font-size:0.7rem;color:var(--color-text-secondary);background:var(--color-bg-secondary);border-radius:0.25rem">
|
|
13
|
+
${used ? `<span><strong>Used:</strong> ${used.toLocaleString()}</span>` : ''}
|
|
14
|
+
${size ? `<span><strong>Context:</strong> ${size.toLocaleString()}</span>` : ''}
|
|
15
|
+
${cost ? `<span><strong>Cost:</strong> ${cost}</span>` : ''}
|
|
16
|
+
</div>
|
|
17
|
+
`;
|
|
18
|
+
return div;
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
renderBlockPlan(block, context) {
|
|
22
|
+
const entries = block.entries || [];
|
|
23
|
+
if (entries.length === 0) return null;
|
|
24
|
+
|
|
25
|
+
const priorityColors = {
|
|
26
|
+
high: '#ef4444',
|
|
27
|
+
medium: '#f59e0b',
|
|
28
|
+
low: '#6b7280'
|
|
29
|
+
};
|
|
30
|
+
const statusIcons = {
|
|
31
|
+
pending: '○',
|
|
32
|
+
in_progress: '◐',
|
|
33
|
+
completed: '●'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const div = document.createElement('div');
|
|
37
|
+
div.className = 'block-plan';
|
|
38
|
+
div.classList.add(this._getBlockTypeClass('plan'));
|
|
39
|
+
div.innerHTML = `
|
|
40
|
+
<details class="folded-tool folded-tool-info">
|
|
41
|
+
<summary class="folded-tool-bar">
|
|
42
|
+
<span class="folded-tool-icon"><svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg></span>
|
|
43
|
+
<span class="folded-tool-name">Plan</span>
|
|
44
|
+
<span class="folded-tool-desc">${entries.length} tasks</span>
|
|
45
|
+
</summary>
|
|
46
|
+
<div class="folded-tool-body">
|
|
47
|
+
<div style="display:flex;flex-direction:column;gap:0.375rem">
|
|
48
|
+
${entries.map(e => `
|
|
49
|
+
<div style="display:flex;align-items:center;gap:0.5rem;font-size:0.8rem">
|
|
50
|
+
<span style="color:${priorityColors[e.priority] || priorityColors.low}">${statusIcons[e.status] || statusIcons.pending}</span>
|
|
51
|
+
<span style="${e.status === 'completed' ? 'text-decoration:line-through;opacity:0.6' : ''}">${this.escapeHtml(e.content || '')}</span>
|
|
52
|
+
</div>
|
|
53
|
+
`).join('')}
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</details>
|
|
57
|
+
`;
|
|
58
|
+
return div;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
renderBlockPremature(block, context) {
|
|
62
|
+
const div = document.createElement('div');
|
|
63
|
+
div.className = 'folded-tool folded-tool-error block-premature';
|
|
64
|
+
div.classList.add(this._getBlockTypeClass('premature'));
|
|
65
|
+
const code = block.exitCode != null ? ` (exit ${block.exitCode})` : '';
|
|
66
|
+
const stderrDisplay = block.stderrText ? `<div class="folded-tool-content" style="margin-top:8px;padding:8px;background:rgba(0,0,0,0.05);border-radius:4px;font-family:monospace;font-size:0.9em;white-space:pre-wrap;">${this.escapeHtml(block.stderrText)}</div>` : '';
|
|
67
|
+
div.innerHTML = `
|
|
68
|
+
<div class="folded-tool-bar" style="background:rgba(245,158,11,0.1)">
|
|
69
|
+
<span class="folded-tool-icon" style="color:#f59e0b"><svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg></span>
|
|
70
|
+
<span class="folded-tool-name" style="color:#f59e0b">ACP Ended Prematurely${this.escapeHtml(code)}</span>
|
|
71
|
+
<span class="folded-tool-desc">${this.escapeHtml(block.error || 'Process exited without output')}</span>
|
|
72
|
+
</div>
|
|
73
|
+
${stderrDisplay}
|
|
74
|
+
`;
|
|
75
|
+
return div;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
renderBlockGeneric(block, context) {
|
|
79
|
+
const div = document.createElement('div');
|
|
80
|
+
div.className = 'block-generic';
|
|
81
|
+
div.classList.add(this._getBlockTypeClass('generic'));
|
|
82
|
+
|
|
83
|
+
const fieldsHtml = Object.entries(block)
|
|
84
|
+
.filter(([key]) => key !== 'type')
|
|
85
|
+
.map(([key, value]) => {
|
|
86
|
+
let displayValue;
|
|
87
|
+
if (typeof value === 'string') {
|
|
88
|
+
displayValue = value.length > 200 ? value.substring(0, 200) + '...' : value;
|
|
89
|
+
} else if (typeof value === 'number' || typeof value === 'boolean') {
|
|
90
|
+
displayValue = String(value);
|
|
91
|
+
} else {
|
|
92
|
+
displayValue = JSON.stringify(value, null, 2);
|
|
93
|
+
if (displayValue.length > 200) displayValue = displayValue.substring(0, 200) + '...';
|
|
94
|
+
}
|
|
95
|
+
return `<div class="generic-field"><span class="field-key">${this.escapeHtml(key)}:</span><span class="field-value">${this.escapeHtml(displayValue)}</span></div>`;
|
|
96
|
+
}).join('');
|
|
97
|
+
|
|
98
|
+
div.innerHTML = `
|
|
99
|
+
<div class="generic-type">${this.escapeHtml(block.type)}</div>
|
|
100
|
+
<div class="generic-fields">${fieldsHtml}</div>
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
return div;
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
renderBlockError(block, error) {
|
|
107
|
+
const div = document.createElement('div');
|
|
108
|
+
div.className = 'block-error';
|
|
109
|
+
div.classList.add(this._getBlockTypeClass('error'));
|
|
110
|
+
|
|
111
|
+
div.innerHTML = `
|
|
112
|
+
<div style="display:flex;align-items:flex-start;gap:0.625rem">
|
|
113
|
+
<svg viewBox="0 0 20 20" fill="currentColor" style="color:#ef4444;flex-shrink:0;margin-top:0.125rem">
|
|
114
|
+
<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"/>
|
|
115
|
+
</svg>
|
|
116
|
+
<div>
|
|
117
|
+
<div style="font-weight:600;color:#991b1b">Render Error</div>
|
|
118
|
+
<div style="font-size:0.85rem;color:#7f1d1d;margin-top:0.25rem">${this.escapeHtml(error.message)}</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
return div;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Object.assign(StreamingRenderer.prototype, {
|
|
2
|
+
renderParametersBeautiful(data, depth = 0) {
|
|
3
|
+
if (data === null || data === undefined) return `<span style="color:var(--color-text-secondary);font-style:italic">null</span>`;
|
|
4
|
+
if (typeof data === 'boolean') return `<span style="color:#d97706;font-weight:600">${data}</span>`;
|
|
5
|
+
if (typeof data === 'number') return `<span style="color:#7c3aed;font-weight:600">${data}</span>`;
|
|
6
|
+
|
|
7
|
+
if (typeof data === 'string') {
|
|
8
|
+
if (data.length > 200 && StreamingRenderer.detectCodeContent(data)) {
|
|
9
|
+
const displayData = data.length > 1000 ? data.substring(0, 1000) : data;
|
|
10
|
+
const suffix = data.length > 1000 ? `<div style="font-size:0.7rem;color:var(--color-text-secondary);text-align:center;padding:0.25rem">... ${data.length - 1000} more characters</div>` : '';
|
|
11
|
+
return `<div style="max-height:200px;overflow-y:auto">${StreamingRenderer.renderCodeWithHighlight(displayData, this.escapeHtml.bind(this), true)}${suffix}</div>`;
|
|
12
|
+
}
|
|
13
|
+
if (data.length > 500) {
|
|
14
|
+
const lines = data.split('\n').length;
|
|
15
|
+
return `<div style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;background:var(--color-bg-code);color:var(--color-code-text);padding:0.5rem;border-radius:0.375rem;line-height:1.5">${this.escapeHtml(data.substring(0, 1000))}${data.length > 1000 ? '\n... (' + (data.length - 1000) + ' more chars, ' + lines + ' lines)' : ''}</div>`;
|
|
16
|
+
}
|
|
17
|
+
const looksLikePath = data.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(data);
|
|
18
|
+
if (looksLikePath && !data.includes(' ') && data.includes('.')) return this.renderFilePath(data);
|
|
19
|
+
return `<span style="color:var(--color-text-primary)">${this.escapeHtml(data)}</span>`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (Array.isArray(data)) {
|
|
23
|
+
if (data.length === 0) return `<span style="color:var(--color-text-secondary)">[]</span>`;
|
|
24
|
+
if (data.every(i => typeof i === 'string') && data.length <= 20) {
|
|
25
|
+
return `<div style="display:flex;flex-direction:column;gap:0.125rem;${depth > 0 ? 'padding-left:1rem' : ''}">${data.map((i, idx) => `<div style="display:flex;align-items:center;gap:0.375rem"><span style="color:var(--color-text-secondary);font-size:0.65rem;opacity:0.5">•</span><span style="font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem">${this.escapeHtml(i)}</span></div>`).join('')}</div>`;
|
|
26
|
+
}
|
|
27
|
+
return `<div style="display:flex;flex-direction:column;gap:0.25rem;${depth > 0 ? 'padding-left:1rem' : ''}">${data.map((item, i) => `<div style="display:flex;gap:0.5rem;align-items:flex-start"><span style="color:var(--color-text-secondary);font-size:0.7rem;min-width:1.5rem;text-align:right;flex-shrink:0">${i}</span><div style="flex:1;min-width:0">${this.renderParametersBeautiful(item, depth + 1)}</div></div>`).join('')}</div>`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (typeof data === 'object') {
|
|
31
|
+
const entries = Object.entries(data);
|
|
32
|
+
if (entries.length === 0) return `<span style="color:var(--color-text-secondary)">{}</span>`;
|
|
33
|
+
return `<div style="display:flex;flex-direction:column;gap:0.375rem;${depth > 0 ? 'padding-left:1rem' : ''}">${entries.map(([k, v]) => `<div style="display:flex;gap:0.5rem;align-items:flex-start"><span style="font-weight:600;font-size:0.75rem;color:#0891b2;flex-shrink:0;min-width:fit-content;font-family:'Monaco','Menlo','Ubuntu Mono',monospace">${this.escapeHtml(k)}</span><div style="flex:1;min-width:0;font-size:0.8rem">${this.renderParametersBeautiful(v, depth + 1)}</div></div>`).join('')}</div>`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return `<span>${this.escapeHtml(String(data))}</span>`;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Object.assign(StreamingRenderer.prototype, {
|
|
2
|
+
renderCode(event) {
|
|
3
|
+
const div = document.createElement('div');
|
|
4
|
+
div.className = 'event-code mb-3';
|
|
5
|
+
div.dataset.eventId = event.id || '';
|
|
6
|
+
div.dataset.eventType = 'code_block';
|
|
7
|
+
|
|
8
|
+
const code = event.code || event.content || '';
|
|
9
|
+
const language = event.language || 'plaintext';
|
|
10
|
+
|
|
11
|
+
if (language === 'html') {
|
|
12
|
+
div.innerHTML = `
|
|
13
|
+
<div class="html-rendered-container alert alert-info text-xs mb-2">
|
|
14
|
+
Rendered HTML
|
|
15
|
+
</div>
|
|
16
|
+
<div class="html-content">
|
|
17
|
+
${code}
|
|
18
|
+
</div>
|
|
19
|
+
`;
|
|
20
|
+
} else {
|
|
21
|
+
const codeLineCount = code.split('\n').length;
|
|
22
|
+
div.innerHTML = `
|
|
23
|
+
<details class="collapsible-code">
|
|
24
|
+
<summary class="collapsible-code-summary">${this.escapeHtml(language)} - ${codeLineCount} line${codeLineCount !== 1 ? 's' : ''}</summary>
|
|
25
|
+
<pre class="bg-base-300 text-base-content p-4 overflow-x-auto" style="margin:0;border-radius:0 0 0.375rem 0.375rem"><code class="language-${this.escapeHtml(language)}">${this.escapeHtml(code)}</code></pre>
|
|
26
|
+
</details>
|
|
27
|
+
`;
|
|
28
|
+
}
|
|
29
|
+
return div;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
renderThinking(event) {
|
|
33
|
+
const div = document.createElement('div');
|
|
34
|
+
div.className = 'event-thinking mb-3 p-4 alert rounded';
|
|
35
|
+
div.dataset.eventId = event.id || '';
|
|
36
|
+
div.dataset.eventType = 'thinking_block';
|
|
37
|
+
|
|
38
|
+
const text = event.thinking || event.content || '';
|
|
39
|
+
div.innerHTML = `
|
|
40
|
+
<details>
|
|
41
|
+
<summary class="cursor-pointer font-semibold text-base-content">Thinking</summary>
|
|
42
|
+
<p class="mt-3 text-sm text-base-content/80 whitespace-pre-wrap">${this.escapeHtml(text)}</p>
|
|
43
|
+
</details>
|
|
44
|
+
`;
|
|
45
|
+
return div;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
renderToolUse(event) {
|
|
49
|
+
const block = {
|
|
50
|
+
type: 'tool_use',
|
|
51
|
+
name: event.toolName || event.tool || 'unknown',
|
|
52
|
+
input: event.input || {}
|
|
53
|
+
};
|
|
54
|
+
const div = this.renderBlockToolUse(block, event);
|
|
55
|
+
div.className = 'event-tool-use mb-3';
|
|
56
|
+
div.dataset.eventId = event.id || '';
|
|
57
|
+
div.dataset.eventType = 'tool_use';
|
|
58
|
+
return div;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
renderCompactBoundary(event) {
|
|
64
|
+
const preTokens = event._preTokens || event.compactMetadata?.preTokens;
|
|
65
|
+
const div = document.createElement('div');
|
|
66
|
+
div.className = 'event-compact-boundary';
|
|
67
|
+
div.dataset.eventType = 'compact_boundary';
|
|
68
|
+
div.innerHTML = `
|
|
69
|
+
<div style="display:flex;align-items:center;gap:0.75rem;padding:0.5rem 0.75rem;margin:0.5rem 0;background:var(--color-bg-secondary);border-radius:0.375rem;font-size:0.75rem;color:var(--color-text-secondary)">
|
|
70
|
+
<svg viewBox="0 0 20 20" fill="currentColor" style="width:1rem;height:1rem;flex-shrink:0;opacity:0.6"><path fill-rule="evenodd" d="M3 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm0 4a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"/></svg>
|
|
71
|
+
<span>Conversation compacted${preTokens ? ` (${preTokens.toLocaleString()} tokens before)` : ''}</span>
|
|
72
|
+
</div>
|
|
73
|
+
`;
|
|
74
|
+
return div;
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
renderTurnDuration(event) {
|
|
78
|
+
const ms = event._turnDurationMs || event.durationMs;
|
|
79
|
+
if (!ms) return null;
|
|
80
|
+
const sec = (ms / 1000).toFixed(1);
|
|
81
|
+
const div = document.createElement('div');
|
|
82
|
+
div.className = 'event-turn-duration';
|
|
83
|
+
div.dataset.eventType = 'turn_duration';
|
|
84
|
+
div.innerHTML = `
|
|
85
|
+
<div style="display:flex;align-items:center;gap:0.5rem;padding:0.25rem 0.75rem;font-size:0.7rem;color:var(--color-text-secondary);opacity:0.7">
|
|
86
|
+
<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.75rem;height:0.75rem;flex-shrink:0"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd"/></svg>
|
|
87
|
+
<span>${sec}s</span>
|
|
88
|
+
</div>
|
|
89
|
+
`;
|
|
90
|
+
return div;
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
renderAgentProgress(event) {
|
|
94
|
+
const msg = event.data?.message || event.message || '';
|
|
95
|
+
if (!msg) return null;
|
|
96
|
+
const div = document.createElement('div');
|
|
97
|
+
div.className = 'event-agent-progress';
|
|
98
|
+
div.dataset.eventType = 'agent_progress';
|
|
99
|
+
div.innerHTML = `
|
|
100
|
+
<div style="display:flex;align-items:flex-start;gap:0.5rem;padding:0.375rem 0.75rem;margin:0.25rem 0;background:var(--color-bg-secondary);border-left:2px solid #7c3aed;border-radius:0 0.25rem 0.25rem 0;font-size:0.75rem;color:var(--color-text-secondary)">
|
|
101
|
+
<svg viewBox="0 0 20 20" fill="currentColor" style="width:0.875rem;height:0.875rem;flex-shrink:0;margin-top:0.125rem;color:#7c3aed"><path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"/><path fill-rule="evenodd" d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5z" clip-rule="evenodd"/></svg>
|
|
102
|
+
<span>${this.escapeHtml(msg)}</span>
|
|
103
|
+
</div>
|
|
104
|
+
`;
|
|
105
|
+
return div;
|
|
106
|
+
}
|
|
107
|
+
});
|