agentgui 1.0.826 → 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.
@@ -0,0 +1,189 @@
1
+ Object.assign(StreamingRenderer.prototype, {
2
+ getToolIcon(toolName) {
3
+ const icons = {
4
+ Read: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4z"/></svg>',
5
+ Write: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z"/></svg>',
6
+ Edit: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"/><path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd"/></svg>',
7
+ Bash: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M2 5a2 2 0 012-2h12a2 2 0 012 2v10a2 2 0 01-2 2H4a2 2 0 01-2-2V5zm3.293 1.293a1 1 0 011.414 0l3 3a1 1 0 010 1.414l-3 3a1 1 0 01-1.414-1.414L7.586 10 5.293 7.707a1 1 0 010-1.414zM11 12a1 1 0 100 2h3a1 1 0 100-2h-3z" clip-rule="evenodd"/></svg>',
8
+ Glob: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z"/></svg>',
9
+ Grep: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/></svg>',
10
+ WebFetch: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM4.332 8.027a6.012 6.012 0 011.912-2.706C6.512 5.73 6.974 6 7.5 6A1.5 1.5 0 019 7.5V8a2 2 0 004 0 2 2 0 012 2v1a2 2 0 01-2 2 2 2 0 01-2 2v.5a6.003 6.003 0 01-6.668-7.473z" clip-rule="evenodd"/></svg>',
11
+ WebSearch: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" clip-rule="evenodd"/></svg>',
12
+ TodoWrite: '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 011 1v3.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 111.414-1.414L6 11.586V8a1 1 0 011-1z" clip-rule="evenodd"/></svg>',
13
+ Task: '<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>',
14
+ NotebookEdit: '<svg viewBox="0 0 20 20" fill="currentColor"><path d="M9 4.804A7.968 7.968 0 005.5 4c-1.255 0-2.443.29-3.5.804v10A7.969 7.969 0 015.5 14c1.669 0 3.218.51 4.5 1.385A7.962 7.962 0 0114.5 14c1.255 0 2.443.29 3.5.804v-10A7.968 7.968 0 0014.5 4c-1.255 0-2.443.29-3.5.804V12a1 1 0 11-2 0V4.804z"/></svg>'
15
+ };
16
+ return icons[toolName] || '<svg viewBox="0 0 20 20" fill="currentColor"><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>';
17
+ },
18
+
19
+ renderFilePath(filePath) {
20
+ if (!filePath) return '';
21
+ const parts = pathSplit(filePath);
22
+ const fileName = parts.pop();
23
+ const dir = parts.join('/');
24
+ return `<div class="tool-param-file"><span class="file-icon">&#128196;</span>${dir ? `<span class="file-dir">${this.escapeHtml(dir)}/</span>` : ''}<span class="file-name">${this.escapeHtml(fileName)}</span></div>`;
25
+ },
26
+
27
+ renderSmartParams(toolName, input) {
28
+ if (!input || Object.keys(input).length === 0) return '';
29
+
30
+ const normalizedName = toolName.replace(/^mcp__.*?__/, '');
31
+
32
+ switch (normalizedName) {
33
+ case 'Read':
34
+ return `<div class="tool-params">${this.renderFilePath(input.file_path)}${input.offset ? `<div style="margin-top:0.375rem;font-size:0.75rem;color:var(--color-text-secondary)">Lines ${input.offset}${input.limit ? '–' + (input.offset + input.limit) : '+'}</div>` : ''}</div>`;
35
+
36
+ case 'Write':
37
+ return `<div class="tool-params">${this.renderFilePath(input.file_path)}${input.content ? this.renderContentPreview(input.content, 'Content') : ''}</div>`;
38
+
39
+ case 'Edit': {
40
+ let html = `<div class="tool-params">${this.renderFilePath(input.file_path)}`;
41
+ if (input.old_string || input.new_string) {
42
+ html += `<div class="tool-param-diff" style="margin-top:0.5rem">`;
43
+ if (input.old_string) {
44
+ html += `<div class="diff-header">Remove</div><div class="diff-old">${this.escapeHtml(this.truncateContent(input.old_string, 500))}</div>`;
45
+ }
46
+ if (input.new_string) {
47
+ html += `<div class="diff-header">Add</div><div class="diff-new">${this.escapeHtml(this.truncateContent(input.new_string, 500))}</div>`;
48
+ }
49
+ html += '</div>';
50
+ }
51
+ return html + '</div>';
52
+ }
53
+
54
+ case 'Bash': {
55
+ const cmd = input.command || input.commands || '';
56
+ const cmdText = typeof cmd === 'string' ? cmd : JSON.stringify(cmd);
57
+ let html = `<div class="tool-params"><div class="tool-param-command"><span class="prompt-char">$</span><span class="command-text">${this.escapeHtml(cmdText)}</span></div>`;
58
+ if (input.description) html += `<div style="margin-top:0.375rem;font-size:0.75rem;color:var(--color-text-secondary)">${this.escapeHtml(input.description)}</div>`;
59
+ return html + '</div>';
60
+ }
61
+
62
+ case 'Glob':
63
+ return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">&#128193;</span><code style="font-size:0.85rem">${this.escapeHtml(input.pattern || '')}</code></div>${input.path ? `<div style="margin-top:0.25rem;font-size:0.75rem;color:var(--color-text-secondary)">in ${this.escapeHtml(input.path)}</div>` : ''}</div>`;
64
+
65
+ case 'Grep':
66
+ return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">&#128269;</span><code style="font-size:0.85rem">${this.escapeHtml(input.pattern || '')}</code></div>${input.path ? `<div style="margin-top:0.25rem;font-size:0.75rem;color:var(--color-text-secondary)">in ${this.escapeHtml(input.path)}</div>` : ''}${input.glob ? `<div style="margin-top:0.125rem;font-size:0.7rem;color:var(--color-text-secondary)">files: ${this.escapeHtml(input.glob)}</div>` : ''}</div>`;
67
+
68
+ case 'WebFetch':
69
+ return `<div class="tool-params"><div class="tool-param-url"><span class="url-icon">&#127760;</span>${this.escapeHtml(input.url || '')}</div>${input.prompt ? `<div style="margin-top:0.375rem;font-size:0.8rem;color:var(--color-text-secondary)">${this.escapeHtml(this.truncateContent(input.prompt, 150))}</div>` : ''}</div>`;
70
+
71
+ case 'WebSearch':
72
+ return `<div class="tool-params"><div class="tool-param-query"><span class="query-icon">&#128269;</span><strong style="font-size:0.85rem">${this.escapeHtml(input.query || '')}</strong></div></div>`;
73
+
74
+ case 'TodoWrite':
75
+ if (input.todos && Array.isArray(input.todos)) {
76
+ const statusIcons = { completed: '&#9989;', in_progress: '&#9881;', pending: '&#9744;' };
77
+ const completedCount = input.todos.filter(t => t.status === 'completed').length;
78
+ const totalCount = input.todos.length;
79
+ const items = input.todos.map(t => `<div class="todo-item"><span class="todo-status">${statusIcons[t.status] || '&#9744;'}</span><span class="todo-text">${this.escapeHtml(t.content || '')}</span></div>`).join('');
80
+ const summary = `<summary class="folded-tool-bar" style="cursor:pointer;padding:0.5rem;background:var(--color-bg-secondary);border-radius:0.25rem;user-select:none"><span style="font-weight:600;font-size:0.9rem">📋 Tasks</span><span style="margin-left:0.5rem;font-size:0.8rem;color:var(--color-text-secondary)">${completedCount}/${totalCount} complete</span></summary>`;
81
+ return `<details class="folded-tool" open>${summary}<div class="folded-tool-body tool-param-todos" style="padding:0.75rem">${items}</div></details>`;
82
+ }
83
+ return this.renderJsonParams(input);
84
+
85
+ case 'Task':
86
+ return `<div class="tool-params">${input.description ? `<div style="font-weight:600;font-size:0.85rem;margin-bottom:0.375rem">${this.escapeHtml(input.description)}</div>` : ''}${input.prompt ? `<div style="font-size:0.8rem;color:var(--color-text-secondary);max-height:100px;overflow-y:auto;white-space:pre-wrap;word-break:break-word">${this.escapeHtml(this.truncateContent(input.prompt, 300))}</div>` : ''}${input.subagent_type ? `<div style="margin-top:0.375rem;font-size:0.7rem"><code style="background:var(--color-bg-secondary);padding:0.125rem 0.375rem;border-radius:0.25rem">${this.escapeHtml(input.subagent_type)}</code></div>` : ''}</div>`;
87
+
88
+ case 'NotebookEdit':
89
+ return `<div class="tool-params">${this.renderFilePath(input.notebook_path)}${input.new_source ? this.renderContentPreview(input.new_source, 'Cell content') : ''}</div>`;
90
+
91
+ case 'dev__execute':
92
+ case 'dev_execute':
93
+ case 'execute': {
94
+ let html = '<div class="tool-params">';
95
+
96
+ if (input.workingDirectory) {
97
+ html += `<div style="margin-bottom:0.5rem;font-size:0.75rem;color:var(--color-text-secondary)"><span style="opacity:0.7">📁</span> ${this.escapeHtml(input.workingDirectory)}</div>`;
98
+ }
99
+
100
+ if (input.timeout) {
101
+ html += `<div style="margin-bottom:0.5rem;font-size:0.75rem;color:var(--color-text-secondary)"><span style="opacity:0.7">⏱️</span> Timeout: ${Math.round(input.timeout / 1000)}s</div>`;
102
+ }
103
+
104
+ if (input.code) {
105
+ const codeLines = input.code.split('\n');
106
+ const lineCount = codeLines.length;
107
+ const truncated = lineCount > 50;
108
+ const displayCode = truncated ? codeLines.slice(0, 50).join('\n') : input.code;
109
+ const lang = input.runtime || 'javascript';
110
+ html += `<div style="margin-top:0.5rem"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.25rem"><span style="font-size:0.7rem;font-weight:600;color:#0891b2;text-transform:uppercase">${this.escapeHtml(lang)}</span><span style="font-size:0.7rem;color:var(--color-text-secondary)">${lineCount} lines</span></div>${StreamingRenderer.renderCodeWithHighlight(displayCode, this.escapeHtml.bind(this), true)}${truncated ? `<div style="font-size:0.7rem;color:var(--color-text-secondary);text-align:center;padding:0.25rem">... ${lineCount - 50} more lines</div>` : ''}</div>`;
111
+ }
112
+
113
+ if (input.commands) {
114
+ const cmds = Array.isArray(input.commands) ? input.commands : [input.commands];
115
+ cmds.forEach(cmd => {
116
+ html += `<div style="margin-top:0.375rem"><div class="tool-param-command"><span class="prompt-char">$</span><span class="command-text">${this.escapeHtml(typeof cmd === 'string' ? cmd : JSON.stringify(cmd))}</span></div></div>`;
117
+ });
118
+ }
119
+
120
+ html += '</div>';
121
+ return html;
122
+ }
123
+
124
+ default:
125
+ return this.renderJsonParams(input);
126
+ }
127
+ },
128
+
129
+ renderContentPreview(content, label) {
130
+ const maxLen = 500;
131
+ const truncated = content.length > maxLen;
132
+ const displayContent = truncated ? content.substring(0, maxLen) : content;
133
+ const lineCount = content.split('\n').length;
134
+ const codeBody = StreamingRenderer.detectCodeContent(displayContent)
135
+ ? StreamingRenderer.renderCodeWithHighlight(displayContent, this.escapeHtml.bind(this), true)
136
+ : `<div class="preview-body">${this.escapeHtml(displayContent)}</div>`;
137
+ return `<div class="tool-param-content-preview" style="margin-top:0.5rem"><div class="preview-header"><span>${this.escapeHtml(label)}</span><span style="font-weight:400">${lineCount} lines${truncated ? ' (truncated)' : ''}</span></div>${codeBody}${truncated ? '<div class="preview-truncated">... ' + (content.length - maxLen) + ' more characters</div>' : ''}</div>`;
138
+ },
139
+
140
+ renderJsonParams(input) {
141
+ return `<div class="tool-params">${this.renderParametersBeautiful(input)}</div>`;
142
+ },
143
+
144
+ getToolUseTitle(toolName, input) {
145
+ const normalizedName = toolName.replace(/^mcp__.*?__/, '');
146
+ if (normalizedName === 'Edit' && input.file_path) {
147
+ const parts = pathSplit(input.file_path);
148
+ const fileName = parts.pop();
149
+ const dir = parts.slice(-2).join('/');
150
+ return dir ? `${dir}/${fileName}` : fileName;
151
+ }
152
+ if (normalizedName === 'Read' && input.file_path) {
153
+ return pathBasename(input.file_path);
154
+ }
155
+ if (normalizedName === 'Write' && input.file_path) {
156
+ return pathBasename(input.file_path);
157
+ }
158
+ if (normalizedName === 'Bash' || normalizedName === 'bash') {
159
+ const cmd = input.command || input.commands || '';
160
+ const cmdText = typeof cmd === 'string' ? cmd : JSON.stringify(cmd);
161
+ return cmdText.length > 60 ? cmdText.substring(0, 57) + '...' : cmdText;
162
+ }
163
+ if (normalizedName === 'Glob' && input.pattern) return input.pattern;
164
+ if (normalizedName === 'Grep' && input.pattern) return input.pattern;
165
+ if (normalizedName === 'WebFetch' && input.url) {
166
+ try { return new URL(input.url).hostname; } catch (e) { return input.url.substring(0, 40); }
167
+ }
168
+ if (normalizedName === 'WebSearch' && input.query) return input.query.substring(0, 50);
169
+ if (input.file_path) return pathBasename(input.file_path);
170
+ if (input.command) {
171
+ const c = typeof input.command === 'string' ? input.command : JSON.stringify(input.command);
172
+ return c.length > 50 ? c.substring(0, 47) + '...' : c;
173
+ }
174
+ if (input.query) return input.query.substring(0, 50);
175
+ return '';
176
+ },
177
+
178
+ getToolUseDisplayName(toolName) {
179
+ const normalized = toolName.replace(/^mcp__.*?__/, '');
180
+ const knownTools = ['Read','Write','Edit','Bash','Glob','Grep','WebFetch','WebSearch','TodoWrite','Task','NotebookEdit'];
181
+ if (knownTools.includes(normalized)) return normalized;
182
+ if (toolName.startsWith('mcp__')) {
183
+ const parts = toolName.split('__');
184
+ return parts.length >= 3 ? parts[2] : parts[parts.length - 1];
185
+ }
186
+ return normalized || toolName;
187
+ }
188
+
189
+ });
@@ -0,0 +1,92 @@
1
+ Object.assign(StreamingRenderer.prototype, {
2
+ renderBlockToolUse(block, context) {
3
+ const toolName = block.name || 'unknown';
4
+ const input = block.input || {};
5
+
6
+ const details = document.createElement('details');
7
+ details.className = 'block-tool-use folded-tool';
8
+ if (block.id) details.dataset.toolUseId = block.id;
9
+ details.dataset.startedAt = Date.now();
10
+ details.classList.add(this._getBlockTypeClass('tool_use'));
11
+ details.classList.add(this._getToolColorClass(toolName));
12
+ const normalizedForOpen = toolName.replace(/^mcp__.*?__/, '');
13
+ if (normalizedForOpen === 'TodoWrite') details.open = true;
14
+ const summary = document.createElement('summary');
15
+ summary.className = 'folded-tool-bar';
16
+ const displayName = this.getToolUseDisplayName(toolName);
17
+ const titleInfo = this.getToolUseTitle(toolName, input);
18
+ summary.innerHTML = `
19
+ <span class="folded-tool-icon">${this.getToolIcon(toolName)}</span>
20
+ <span class="folded-tool-name">${this.escapeHtml(displayName)}</span>
21
+ ${titleInfo ? `<span class="folded-tool-desc">${this.escapeHtml(titleInfo)}</span>` : ''}
22
+ `;
23
+ details.appendChild(summary);
24
+ if (Object.keys(input).length > 0) {
25
+ const paramsDiv = document.createElement('div');
26
+ paramsDiv.className = 'folded-tool-body';
27
+ paramsDiv.innerHTML = this.renderSmartParams(toolName, input);
28
+ details.appendChild(paramsDiv);
29
+ }
30
+ return details;
31
+ },
32
+
33
+ renderSmartContent(contentStr) {
34
+ const trimmed = contentStr.trim();
35
+
36
+ if (trimmed.startsWith('data:image/')) {
37
+ return `<div style="padding:0.5rem"><img src="${this.escapeHtml(trimmed)}" style="max-width:100%;max-height:24rem;border-radius:0.375rem" loading="lazy"></div>`;
38
+ }
39
+
40
+ if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
41
+ try {
42
+ const parsed = JSON.parse(trimmed);
43
+ return `<div style="padding:0.625rem 1rem">${this.renderParametersBeautiful(parsed)}</div>`;
44
+ } catch (e) {}
45
+ }
46
+
47
+ const lines = trimmed.split('\n');
48
+ const allFilePaths = lines.length > 1 && lines.every(l => {
49
+ const t = l.trim();
50
+ return t === '' || t.startsWith('/') || /^[A-Za-z]:[\\\/]/.test(t);
51
+ });
52
+ if (allFilePaths && lines.filter(l => l.trim()).length > 0) {
53
+ const fileHtml = lines.filter(l => l.trim()).map(l => {
54
+ const p = l.trim();
55
+ const parts = pathSplit(p);
56
+ const name = parts.pop();
57
+ const dir = parts.join('/');
58
+ return `<div style="display:flex;align-items:center;gap:0.375rem;padding:0.1875rem 0;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem"><span style="opacity:0.5">&#128196;</span><span style="color:var(--color-text-secondary)">${this.escapeHtml(dir)}/</span><span style="font-weight:600">${this.escapeHtml(name)}</span></div>`;
59
+ }).join('');
60
+ return `<div style="padding:0.625rem 1rem">${fileHtml}</div>`;
61
+ }
62
+
63
+ if (trimmed.length > 1500) {
64
+ return `<div class="result-body collapsed" style="padding:0.625rem 1rem;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;line-height:1.5">${this.escapeHtml(trimmed)}</div><button class="expand-btn" onclick="this.previousElementSibling.classList.toggle('collapsed');this.textContent=this.textContent==='Show more'?'Show less':'Show more'">Show more</button>`;
65
+ }
66
+
67
+ return `<div style="padding:0.625rem 1rem;font-family:'Monaco','Menlo','Ubuntu Mono',monospace;font-size:0.75rem;white-space:pre-wrap;word-break:break-all;line-height:1.5">${this.escapeHtml(trimmed)}</div>`;
68
+ },
69
+ renderBlockToolResult(block, context) {
70
+ const content = block.content || '';
71
+ const toolName = block.tool_name || block.name || '';
72
+
73
+ if (toolName.includes('TodoWrite') || (typeof content === 'object' && Array.isArray(content?.todos))) {
74
+ return null;
75
+ }
76
+
77
+ const contentStr = typeof content === 'string' ? content : JSON.stringify(content, null, 2);
78
+ const isError = (block.is_error || false) && !contentStr.trimStart().startsWith('exec ran successfully.');
79
+
80
+ const container = document.createElement('div');
81
+ container.className = 'tool-result-pending';
82
+ container.dataset.eventType = 'tool_result';
83
+ container.dataset.isError = isError ? '1' : '0';
84
+ if (block.tool_use_id) container.dataset.toolUseId = block.tool_use_id;
85
+ container.style.display = 'none';
86
+
87
+ const renderedContent = StreamingRenderer.renderSmartContentHTML(contentStr, this.escapeHtml.bind(this), true);
88
+ container.innerHTML = renderedContent;
89
+
90
+ return container;
91
+ }
92
+ });