claude-code-watch 0.0.12 → 0.0.15
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/public/index.html +94 -24
- package/src/parser/parser.js +56 -7
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -147,18 +147,27 @@ body {
|
|
|
147
147
|
|
|
148
148
|
/* ── Tree node styles ── */
|
|
149
149
|
.tree-row {
|
|
150
|
-
display: flex; align-items:
|
|
150
|
+
display: flex; align-items: flex-start;
|
|
151
|
+
}
|
|
152
|
+
.tree-content {
|
|
153
|
+
flex: 1; min-width: 0;
|
|
151
154
|
}
|
|
155
|
+
.tree-content:hover { background: rgba(255,255,255,0.05); }
|
|
156
|
+
.tree-row.selected > .tree-content { background: rgba(124,58,237,0.3); }
|
|
157
|
+
.tree-content.dim { opacity: 0.4; }
|
|
152
158
|
.tree-node {
|
|
153
|
-
|
|
159
|
+
display: flex; align-items: center;
|
|
154
160
|
padding: 3px 2px 3px 0;
|
|
155
161
|
cursor: pointer; white-space: nowrap; gap: 4px;
|
|
156
|
-
|
|
162
|
+
overflow: hidden;
|
|
157
163
|
}
|
|
158
|
-
.tree-node:hover { background: rgba(255,255,255,0.05); }
|
|
159
|
-
.tree-node.selected { background: rgba(124,58,237,0.3); }
|
|
160
|
-
.tree-node.dim { opacity: 0.4; }
|
|
161
164
|
.tree-prefix { color: var(--dim); font-size: 12px; flex-shrink: 0; letter-spacing: 0; font-family: monospace; }
|
|
165
|
+
.tree-activity {
|
|
166
|
+
font-size: 10px; color: var(--dim); white-space: nowrap;
|
|
167
|
+
overflow: hidden; text-overflow: ellipsis;
|
|
168
|
+
padding: 0 2px 2px; line-height: 1.2;
|
|
169
|
+
cursor: pointer;
|
|
170
|
+
}
|
|
162
171
|
.tree-node .ctx-pct { font-size: 10px; margin-left: 4px; flex-shrink: 0; }
|
|
163
172
|
.tree-node .ctx-pct.warn { color: var(--yellow); }
|
|
164
173
|
.tree-node .ctx-pct.danger { color: var(--red); }
|
|
@@ -194,9 +203,11 @@ body {
|
|
|
194
203
|
.stream-line.diag { color: var(--red); }
|
|
195
204
|
.stream-line.debug { color: var(--gray); }
|
|
196
205
|
.stream-line.marker { color: var(--dim); }
|
|
197
|
-
.stream-line.agent-tag { font-weight: bold; }
|
|
206
|
+
.stream-line.agent-tag { font-weight: bold; display: flex; justify-content: space-between; align-items: baseline; white-space: nowrap; }
|
|
198
207
|
.stream-line.agent-main { color: var(--blue); }
|
|
199
208
|
.stream-line.agent-sub { color: var(--magenta); }
|
|
209
|
+
.stream-line.agent-tag .tag-label { flex-shrink: 0; }
|
|
210
|
+
.stream-line.agent-tag .timestamp { font-weight: normal; font-size: 0.85em; color: var(--dim); white-space: nowrap; }
|
|
200
211
|
.stream-line.separator { color: var(--dim); }
|
|
201
212
|
|
|
202
213
|
/* ── Footer ── */
|
|
@@ -247,8 +258,8 @@ body {
|
|
|
247
258
|
:root[data-theme="light"] .btn.on:hover { background: var(--purple2); color: #fff; }
|
|
248
259
|
:root[data-theme="light"] .btn.on:hover::after { background: var(--purple2); color: #fff; }
|
|
249
260
|
:root[data-theme="light"] .hljs { background: #f0f0f0 !important; }
|
|
250
|
-
:root[data-theme="light"] .tree-
|
|
251
|
-
:root[data-theme="light"] .tree-
|
|
261
|
+
:root[data-theme="light"] .tree-content:hover { background: rgba(0,0,0,0.06); }
|
|
262
|
+
:root[data-theme="light"] .tree-row.selected > .tree-content { background: rgba(124,58,237,0.2); }
|
|
252
263
|
:root[data-theme="light"] .tree-node .active-dot.off { color: #bbb; }
|
|
253
264
|
:root[data-theme="light"] #tree-resize-handle:hover,
|
|
254
265
|
:root[data-theme="light"] #tree-resize-handle.active { background: var(--purple); }
|
|
@@ -286,6 +297,7 @@ body {
|
|
|
286
297
|
<button class="btn btn-icon" onclick="selectAll()" data-tooltip="Show all sessions/agents">⊞</button>
|
|
287
298
|
<button class="btn btn-icon accent" onclick="soloSelected()" data-tooltip="Solo selected">⊙</button>
|
|
288
299
|
<button class="btn btn-icon danger" onclick="removeSelectedSession()" data-tooltip="Remove session">✕</button>
|
|
300
|
+
<button class="btn btn-icon on" id="btn-activity" onclick="toggleActivity()" data-tooltip="Toggle activity info">💬</button>
|
|
289
301
|
<span style="flex:1"></span>
|
|
290
302
|
<span id="tree-cursor-info" style="font-size:10px;color:var(--dim)"></span>
|
|
291
303
|
</div>
|
|
@@ -355,6 +367,9 @@ class LRUCache {
|
|
|
355
367
|
}
|
|
356
368
|
const seenToolIDs = new LRUCache(5000);
|
|
357
369
|
const toolNameMap = new LRUCache(2000);
|
|
370
|
+
const agentActivity = new Map(); // "sessionID:agentID" → { toolName, content }
|
|
371
|
+
const taskDescriptions = new Map(); // toolID → description string
|
|
372
|
+
const MAX_DESC_STORE = 200;
|
|
358
373
|
let filters = new Map();
|
|
359
374
|
|
|
360
375
|
let showThinking = true;
|
|
@@ -362,6 +377,7 @@ let showToolInput = true;
|
|
|
362
377
|
let showToolOutput = true;
|
|
363
378
|
let showText = true;
|
|
364
379
|
let showHook = true;
|
|
380
|
+
let showActivity = true;
|
|
365
381
|
let autoDiscovery = true;
|
|
366
382
|
|
|
367
383
|
let renderPending = false;
|
|
@@ -644,6 +660,20 @@ function pushItem(item) {
|
|
|
644
660
|
toolNameMap.set(item.toolID, item.toolName);
|
|
645
661
|
}
|
|
646
662
|
|
|
663
|
+
if (item.type === 'tool_input') {
|
|
664
|
+
// Main 代理不追踪工具调用,只显示用户 prompt
|
|
665
|
+
if (item.agentID) {
|
|
666
|
+
agentActivity.set(item.sessionID + ':' + item.agentID, { toolName: item.toolName || '', content: (item.content || '').slice(0, MAX_DESC_STORE) });
|
|
667
|
+
}
|
|
668
|
+
if (item.toolID) {
|
|
669
|
+
taskDescriptions.set(item.toolID, (item.content || '').slice(0, MAX_DESC_STORE));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (item.type === 'user_text') {
|
|
674
|
+
agentActivity.set(item.sessionID + ':' + (item.agentID || ''), { toolName: '', content: (item.content || '').slice(0, MAX_DESC_STORE) });
|
|
675
|
+
}
|
|
676
|
+
|
|
647
677
|
if (item.toolID) {
|
|
648
678
|
const key = `${item.toolID}:${item.type}`;
|
|
649
679
|
if (seenToolIDs.has(key)) return;
|
|
@@ -669,6 +699,7 @@ function isItemVisible(item) {
|
|
|
669
699
|
case 'tool_output': return showToolOutput;
|
|
670
700
|
case 'text': return showText;
|
|
671
701
|
case 'hook_output': return showHook;
|
|
702
|
+
case 'user_text': return false;
|
|
672
703
|
default: return true;
|
|
673
704
|
}
|
|
674
705
|
}
|
|
@@ -692,14 +723,23 @@ function rebuildNodes() {
|
|
|
692
723
|
);
|
|
693
724
|
const lastTaskIdx = tasks.length - 1;
|
|
694
725
|
const hasTasks = tasks.length > 0;
|
|
695
|
-
|
|
726
|
+
const actKey = s.id + ':' + a.id;
|
|
727
|
+
const act = agentActivity.get(actKey);
|
|
728
|
+
treeNodes.push({
|
|
729
|
+
type: a.type, id: a.id, name: a.name, sessionID: s.id,
|
|
730
|
+
level: 1, isLast: isLastAgent && !hasTasks,
|
|
731
|
+
activityTool: act ? act.toolName : '',
|
|
732
|
+
activityDesc: act ? act.content : '',
|
|
733
|
+
});
|
|
696
734
|
for (let ti = 0; ti < tasks.length; ti++) {
|
|
697
735
|
const t = tasks[ti];
|
|
736
|
+
const tDesc = taskDescriptions.get(t.id);
|
|
698
737
|
treeNodes.push({
|
|
699
738
|
type: 'task', id: t.id, name: t.toolName,
|
|
700
739
|
sessionID: s.id, parentAgentID: t.parentAgentID,
|
|
701
740
|
outputPath: t.outputPath, isComplete: t.isComplete,
|
|
702
741
|
level: 2, isLast: isLastAgent && ti === lastTaskIdx,
|
|
742
|
+
description: tDesc || '',
|
|
703
743
|
});
|
|
704
744
|
}
|
|
705
745
|
}
|
|
@@ -734,10 +774,12 @@ function getNodeHTML(node, idx) {
|
|
|
734
774
|
const subInfo = parts.length > 0 ? ` <span style="color:#6b7280;font-size:10px">${parts.join(' · ')}</span>` : '';
|
|
735
775
|
const agentCount = node.agents ? node.agents.filter(a => a.type === 'agent').length : 0;
|
|
736
776
|
return `<div class="tree-row${selClass ? ' selected' : ''}">
|
|
737
|
-
<div class="tree-
|
|
738
|
-
<
|
|
739
|
-
|
|
740
|
-
|
|
777
|
+
<div class="tree-content" onclick="treeClick(${idx})" data-idx="${idx}">
|
|
778
|
+
<div class="tree-node">
|
|
779
|
+
<span class="tree-prefix">${treePrefix(node)}</span>${activeDot} ${node.collapsed ? '▸' : '▾'} ${esc(displayName)}
|
|
780
|
+
${node.collapsed && agentCount > 0 ? `(${esc(String(agentCount))})` : ''}
|
|
781
|
+
${subInfo}
|
|
782
|
+
</div>
|
|
741
783
|
</div>
|
|
742
784
|
<span class="tree-actions">
|
|
743
785
|
<button class="btn btn-icon accent" onclick="event.stopPropagation();selectIndex(${idx});soloSelected()" data-tooltip="Solo">⊙</button>
|
|
@@ -758,9 +800,19 @@ function getNodeHTML(node, idx) {
|
|
|
758
800
|
ctxPct = `<span class="ctx-pct ${cls}">${pct}%</span>`;
|
|
759
801
|
}
|
|
760
802
|
const activeDot = ctx && (Date.now() - ctx.lastActivity < 120000) ? '<span class="active-dot on">🟢</span>' : '<span class="active-dot off">⚪</span>';
|
|
803
|
+
const actIcon = node.type === 'main' ? '🗣' : '⚡';
|
|
804
|
+
const actText = showActivity && (node.activityTool || node.activityDesc)
|
|
805
|
+
? (node.activityTool && node.activityDesc ? `${node.activityTool}: ${node.activityDesc}` : (node.activityTool || node.activityDesc))
|
|
806
|
+
: '';
|
|
807
|
+
const activityHTML = actText
|
|
808
|
+
? `<div class="tree-activity">${actIcon} ${esc(actText)}</div>`
|
|
809
|
+
: '';
|
|
761
810
|
return `<div class="tree-row${selClass ? ' selected' : ''}">
|
|
762
|
-
<div class="tree-
|
|
811
|
+
<div class="tree-content${enabled ? '' : ' dim'}" onclick="treeClick(${idx})" data-idx="${idx}">
|
|
812
|
+
<div class="tree-node">
|
|
763
813
|
<span class="tree-prefix">${treePrefix(node)}</span>${activeDot} ${icon} ${esc(node.name || '')}${ctxPct}
|
|
814
|
+
</div>
|
|
815
|
+
${activityHTML}
|
|
764
816
|
</div>
|
|
765
817
|
<span class="tree-actions">
|
|
766
818
|
<button class="btn btn-icon accent" onclick="event.stopPropagation();selectIndex(${idx});soloSelected()" data-tooltip="Solo">⊙</button>
|
|
@@ -771,9 +823,15 @@ function getNodeHTML(node, idx) {
|
|
|
771
823
|
|
|
772
824
|
if (node.type === 'task') {
|
|
773
825
|
const icon = node.isComplete ? '✓' : '⏳';
|
|
826
|
+
const descHTML = showActivity && node.description
|
|
827
|
+
? `<div class="tree-activity">📋 ${esc(node.description)}</div>`
|
|
828
|
+
: '';
|
|
774
829
|
return `<div class="tree-row${selClass ? ' selected' : ''}">
|
|
775
|
-
<div class="tree-
|
|
830
|
+
<div class="tree-content dim" onclick="treeClick(${idx})" data-idx="${idx}">
|
|
831
|
+
<div class="tree-node">
|
|
776
832
|
<span class="tree-prefix">${treePrefix(node)}</span>${icon} ${esc(node.name || 'bg-task')}
|
|
833
|
+
</div>
|
|
834
|
+
${descHTML}
|
|
777
835
|
</div>
|
|
778
836
|
<span class="tree-actions">
|
|
779
837
|
<button class="btn btn-icon" onclick="event.stopPropagation();selectIndex(${idx});loadBgTask(${idx})" data-tooltip="Load output">▶</button>
|
|
@@ -797,7 +855,7 @@ function renderTree() {
|
|
|
797
855
|
treeEl.innerHTML = html;
|
|
798
856
|
|
|
799
857
|
// Scroll selected into view
|
|
800
|
-
const sel = treeEl.querySelector('.tree-
|
|
858
|
+
const sel = treeEl.querySelector('.tree-row.selected');
|
|
801
859
|
if (sel) sel.scrollIntoView({ block: 'nearest' });
|
|
802
860
|
|
|
803
861
|
treeCursorInfo.textContent = `${treeCursor + 1}/${treeNodes.length}`;
|
|
@@ -894,14 +952,15 @@ function renderItem(item) {
|
|
|
894
952
|
}
|
|
895
953
|
|
|
896
954
|
const agentName = item.agentName || 'Main';
|
|
955
|
+
const tsHtml = item.timestamp ? `<span class="timestamp">${fmtTimestamp(item.timestamp)}</span>` : '';
|
|
897
956
|
|
|
898
957
|
switch (item.type) {
|
|
899
958
|
case 'thinking':
|
|
900
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + '🧠 Thinking' });
|
|
959
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + '🧠 Thinking')}</span>${tsHtml}`, html: true });
|
|
901
960
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line thinking', text: l });
|
|
902
961
|
break;
|
|
903
962
|
case 'tool_input':
|
|
904
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + `🔧 ${item.toolName || ''}` });
|
|
963
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + `🔧 ${item.toolName || ''}`)}</span>${tsHtml}`, html: true });
|
|
905
964
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line tool-input', text: l });
|
|
906
965
|
break;
|
|
907
966
|
case 'tool_output': {
|
|
@@ -911,33 +970,33 @@ function renderItem(item) {
|
|
|
911
970
|
}
|
|
912
971
|
let label = tn ? `📤 ${tn} result` : '📤 Output';
|
|
913
972
|
if (item.durationMs > 0) label += ' ' + fmtDur(item.durationMs);
|
|
914
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + label });
|
|
973
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + label)}</span>${tsHtml}`, html: true });
|
|
915
974
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line tool-output', text: l });
|
|
916
975
|
break;
|
|
917
976
|
}
|
|
918
977
|
case 'text':
|
|
919
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + '💬 Response' });
|
|
978
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + '💬 Response')}</span>${tsHtml}`, html: true });
|
|
920
979
|
lines.push({ cls: 'stream-line text md-content', text: mdRender(item.content), html: true });
|
|
921
980
|
break;
|
|
922
981
|
case 'hook_output': {
|
|
923
982
|
let label = '🪝 Hook';
|
|
924
983
|
if (item.toolName) label += ' ' + item.toolName;
|
|
925
984
|
if (item.durationMs > 0) label += ' ' + fmtDur(item.durationMs);
|
|
926
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + label });
|
|
985
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + label)}</span>${tsHtml}`, html: true });
|
|
927
986
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line hook', text: l });
|
|
928
987
|
break;
|
|
929
988
|
}
|
|
930
989
|
case 'diagnostics': {
|
|
931
990
|
let label = '⚠ Diagnostics';
|
|
932
991
|
if (item.toolName) label += ' ' + item.toolName;
|
|
933
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + label });
|
|
992
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + label)}</span>${tsHtml}`, html: true });
|
|
934
993
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line diag', text: l });
|
|
935
994
|
break;
|
|
936
995
|
}
|
|
937
996
|
case 'debug': {
|
|
938
997
|
let label = '🔍 Debug';
|
|
939
998
|
if (item.toolName) label += ' ' + item.toolName;
|
|
940
|
-
lines.push({ cls: agentTagCls, text: agentName + sep + label });
|
|
999
|
+
lines.push({ cls: agentTagCls, text: `<span class="tag-label">${esc(agentName + sep + label)}</span>${tsHtml}`, html: true });
|
|
941
1000
|
for (const l of truncContent(item.content)) lines.push({ cls: 'stream-line debug', text: l });
|
|
942
1001
|
break;
|
|
943
1002
|
}
|
|
@@ -962,6 +1021,7 @@ function refreshButtons() {
|
|
|
962
1021
|
document.getElementById('btn-tool-output').classList.toggle('on', showToolOutput);
|
|
963
1022
|
document.getElementById('btn-text').classList.toggle('on', showText);
|
|
964
1023
|
document.getElementById('btn-hook').classList.toggle('on', showHook);
|
|
1024
|
+
document.getElementById('btn-activity').classList.toggle('on', showActivity);
|
|
965
1025
|
document.getElementById('btn-autoscroll').classList.toggle('on', autoScroll);
|
|
966
1026
|
document.getElementById('btn-tree-toggle').classList.toggle('on', showTree);
|
|
967
1027
|
document.getElementById('btn-autodisco').classList.toggle('on', autoDiscovery);
|
|
@@ -1141,6 +1201,7 @@ function toggleText() { showText = !showText; needsFullRender = true;
|
|
|
1141
1201
|
visibleDirty = true; renderStream(); refreshButtons(); }
|
|
1142
1202
|
function toggleHook() { showHook = !showHook; needsFullRender = true;
|
|
1143
1203
|
visibleDirty = true; renderStream(); refreshButtons(); }
|
|
1204
|
+
function toggleActivity() { showActivity = !showActivity; rebuildNodes(); scheduleRender(); refreshButtons(); }
|
|
1144
1205
|
function toggleAutoScroll() { autoScroll = !autoScroll; if (autoScroll) streamEl.scrollTop = streamEl.scrollHeight; renderAll(); }
|
|
1145
1206
|
function toggleTree() { showTree = !showTree; document.getElementById('tree-panel').classList.toggle('hidden', !showTree); }
|
|
1146
1207
|
function toggleAutoDiscovery() { sendCmd('toggleAutoDiscovery'); }
|
|
@@ -1272,6 +1333,15 @@ function fmtDur(ms) {
|
|
|
1272
1333
|
return `(${(ms / 60000).toFixed(1)}m)`;
|
|
1273
1334
|
}
|
|
1274
1335
|
|
|
1336
|
+
function fmtTimestamp(ts) {
|
|
1337
|
+
if (!ts) return '';
|
|
1338
|
+
const d = ts instanceof Date ? ts : new Date(ts);
|
|
1339
|
+
if (isNaN(d.getTime())) return '';
|
|
1340
|
+
const pad = (n, len) => String(n).padStart(len, '0');
|
|
1341
|
+
const ms = pad(d.getMilliseconds(), 3);
|
|
1342
|
+
return `${pad(d.getFullYear(),4)}-${pad(d.getMonth()+1,2)}-${pad(d.getDate(),2)} ${pad(d.getHours(),2)}:${pad(d.getMinutes(),2)}:${pad(d.getSeconds(),2)}.${ms}`;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1275
1345
|
function fmtTok(n) {
|
|
1276
1346
|
if (!n) return '0';
|
|
1277
1347
|
if (n < 1000) return String(n);
|
package/src/parser/parser.js
CHANGED
|
@@ -9,6 +9,7 @@ var StreamItemType = {
|
|
|
9
9
|
TOOL_INPUT: 'tool_input',
|
|
10
10
|
TOOL_OUTPUT: 'tool_output',
|
|
11
11
|
TEXT: 'text',
|
|
12
|
+
USER_TEXT: 'user_text',
|
|
12
13
|
TURN_MARKER: 'turn_marker',
|
|
13
14
|
COMPACT_MARKER: 'compact_marker',
|
|
14
15
|
HOOK_OUTPUT: 'hook_output',
|
|
@@ -368,7 +369,7 @@ function parseAssistantMessage(raw, timestamp) {
|
|
|
368
369
|
|
|
369
370
|
function parseUserMessage(raw, timestamp) {
|
|
370
371
|
const msg = raw.message;
|
|
371
|
-
if (!msg
|
|
372
|
+
if (!msg) return [];
|
|
372
373
|
|
|
373
374
|
// Parse toolUseResult for duration
|
|
374
375
|
let durationMs = 0;
|
|
@@ -379,20 +380,54 @@ function parseUserMessage(raw, timestamp) {
|
|
|
379
380
|
const items = [];
|
|
380
381
|
const name = agentDisplayName(raw.agentId);
|
|
381
382
|
|
|
382
|
-
|
|
383
|
-
|
|
383
|
+
// String content — user prompt
|
|
384
|
+
if (typeof msg.content === 'string' && msg.content) {
|
|
385
|
+
const text = stripNonUserContent(msg.content);
|
|
386
|
+
if (text) {
|
|
384
387
|
items.push(makeItem({
|
|
385
|
-
type: StreamItemType.
|
|
388
|
+
type: StreamItemType.USER_TEXT,
|
|
386
389
|
agentID: raw.agentId || '',
|
|
387
390
|
agentName: name,
|
|
388
|
-
content:
|
|
389
|
-
toolID: result.tool_use_id || '',
|
|
390
|
-
durationMs,
|
|
391
|
+
content: text,
|
|
391
392
|
timestamp,
|
|
392
393
|
}));
|
|
393
394
|
}
|
|
394
395
|
}
|
|
395
396
|
|
|
397
|
+
// Array content — mixed text blocks and tool_result blocks
|
|
398
|
+
if (Array.isArray(msg.content)) {
|
|
399
|
+
const textParts = [];
|
|
400
|
+
for (const block of msg.content) {
|
|
401
|
+
if (block.type === 'text' && block.text) {
|
|
402
|
+
const text = stripNonUserContent(block.text);
|
|
403
|
+
if (text) textParts.push(text);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (textParts.length > 0) {
|
|
407
|
+
items.push(makeItem({
|
|
408
|
+
type: StreamItemType.USER_TEXT,
|
|
409
|
+
agentID: raw.agentId || '',
|
|
410
|
+
agentName: name,
|
|
411
|
+
content: textParts.join('\n'),
|
|
412
|
+
timestamp,
|
|
413
|
+
}));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
for (const result of msg.content) {
|
|
417
|
+
if (result.type === 'tool_result') {
|
|
418
|
+
items.push(makeItem({
|
|
419
|
+
type: StreamItemType.TOOL_OUTPUT,
|
|
420
|
+
agentID: raw.agentId || '',
|
|
421
|
+
agentName: name,
|
|
422
|
+
content: extractToolResultContent(result.content),
|
|
423
|
+
toolID: result.tool_use_id || '',
|
|
424
|
+
durationMs,
|
|
425
|
+
timestamp,
|
|
426
|
+
}));
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
396
431
|
return items;
|
|
397
432
|
}
|
|
398
433
|
|
|
@@ -413,6 +448,19 @@ function extractToolResultContent(content) {
|
|
|
413
448
|
}
|
|
414
449
|
}
|
|
415
450
|
|
|
451
|
+
function stripNonUserContent(text) {
|
|
452
|
+
if (!text) return '';
|
|
453
|
+
// Remove tags that wrap non-user content
|
|
454
|
+
let s = text;
|
|
455
|
+
s = s.replace(/<local-command-caveat>[\s\S]*?<\/local-command-caveat>/g, '');
|
|
456
|
+
s = s.replace(/<command-name>[\s\S]*?<\/command-name>/g, '');
|
|
457
|
+
s = s.replace(/<command-message>[\s\S]*?<\/command-message>/g, '');
|
|
458
|
+
s = s.replace(/<command-args>[\s\S]*?<\/command-args>/g, '');
|
|
459
|
+
s = s.replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g, '');
|
|
460
|
+
// Trim and return; empty string means no real user content
|
|
461
|
+
return s.trim();
|
|
462
|
+
}
|
|
463
|
+
|
|
416
464
|
// ============================================================================
|
|
417
465
|
// Tool Input Formatting
|
|
418
466
|
// ============================================================================
|
|
@@ -497,5 +545,6 @@ module.exports = {
|
|
|
497
545
|
formatToolInput,
|
|
498
546
|
prettyToolName,
|
|
499
547
|
agentDisplayName,
|
|
548
|
+
stripNonUserContent,
|
|
500
549
|
MAX_TOOL_INPUT_LENGTH,
|
|
501
550
|
};
|