agentgui 1.0.817 → 1.0.818
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 +1 -0
- package/lib/jsonl-parser.js +179 -0
- package/lib/jsonl-watcher.js +9 -164
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
export class JsonlParser {
|
|
4
|
+
constructor({ broadcastSync, queries, ownedSessionIds }) {
|
|
5
|
+
this._bc = broadcastSync;
|
|
6
|
+
this._q = queries;
|
|
7
|
+
this._owned = ownedSessionIds;
|
|
8
|
+
this._convMap = new Map();
|
|
9
|
+
this._emitted = new Map();
|
|
10
|
+
this._seqs = new Map();
|
|
11
|
+
this._streaming = new Set();
|
|
12
|
+
this._sessions = new Map();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
clear() {
|
|
16
|
+
this._convMap.clear();
|
|
17
|
+
this._emitted.clear();
|
|
18
|
+
this._seqs.clear();
|
|
19
|
+
this._streaming.clear();
|
|
20
|
+
this._sessions.clear();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
removeSid(sid) {
|
|
24
|
+
this._convMap.delete(sid);
|
|
25
|
+
this._seqs.delete(sid);
|
|
26
|
+
this._streaming.delete(sid);
|
|
27
|
+
this._sessions.delete(sid);
|
|
28
|
+
for (const key of [...this._emitted.keys()]) if (key.startsWith(`${sid}:`)) this._emitted.delete(key);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
endAllStreaming() {
|
|
32
|
+
for (const sid of [...this._streaming]) this._endStreaming(this._convMap.get(sid), sid);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_line(fp, line) {
|
|
36
|
+
line = line.trim(); if (!line) return;
|
|
37
|
+
let e; try { e = JSON.parse(line); } catch (_) { return; }
|
|
38
|
+
if (!e || !e.sessionId) return;
|
|
39
|
+
if (this._owned?.has(e.sessionId)) return;
|
|
40
|
+
const cid = this._conv(e.sessionId, e, fp);
|
|
41
|
+
if (cid) this._route(cid, e.sessionId, e);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_conv(sid, e) {
|
|
45
|
+
if (this._convMap.has(sid)) return this._convMap.get(sid);
|
|
46
|
+
const found = this._q.getConversations().find(c => c.claudeSessionId === sid);
|
|
47
|
+
if (found) { this._convMap.set(sid, found.id); return found.id; }
|
|
48
|
+
if (e.type === 'queue-operation' || e.type === 'last-prompt') return null;
|
|
49
|
+
if (e.type === 'user' && e.isMeta) return null;
|
|
50
|
+
const cwd = e.cwd || process.cwd();
|
|
51
|
+
const branch = e.gitBranch || '';
|
|
52
|
+
const base = path.basename(cwd);
|
|
53
|
+
const title = branch ? `${branch} @ ${base}` : base;
|
|
54
|
+
const conv = this._q.createConversation('claude-code', title, cwd);
|
|
55
|
+
this._q.setClaudeSessionId(conv.id, sid);
|
|
56
|
+
this._convMap.set(sid, conv.id);
|
|
57
|
+
this._bc({ type: 'conversation_created', conversation: conv, timestamp: Date.now() });
|
|
58
|
+
return conv.id;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_seq(sid) { const n = (this._seqs.get(sid) || 0) + 1; this._seqs.set(sid, n); return n; }
|
|
62
|
+
|
|
63
|
+
_dbSession(cid, sid) {
|
|
64
|
+
if (this._sessions.has(sid)) return this._sessions.get(sid);
|
|
65
|
+
const sess = this._q.createSession(cid);
|
|
66
|
+
this._q.updateSession(sess.id, { status: 'active' });
|
|
67
|
+
this._sessions.set(sid, sess.id);
|
|
68
|
+
return sess.id;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
_emit(cid, sid, block, role, extra) {
|
|
72
|
+
const dbSid = this._dbSession(cid, sid);
|
|
73
|
+
const seq = this._seq(sid);
|
|
74
|
+
try { this._q.createChunk(dbSid, cid, seq, block.type || 'unknown', block); } catch (_) {}
|
|
75
|
+
this._bc({ type: 'streaming_progress', sessionId: dbSid, conversationId: cid, block, blockRole: role, seq, timestamp: Date.now(), ...extra });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_emitBlocks(cid, sid, blocks, role) {
|
|
79
|
+
for (const b of blocks) {
|
|
80
|
+
if (!b || !b.type) continue;
|
|
81
|
+
this._emit(cid, sid, b, role);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_startStreaming(cid, sid) {
|
|
86
|
+
if (this._streaming.has(sid)) return;
|
|
87
|
+
this._streaming.add(sid);
|
|
88
|
+
const dbSid = this._dbSession(cid, sid);
|
|
89
|
+
this._q.setIsStreaming(cid, true);
|
|
90
|
+
this._bc({ type: 'streaming_start', sessionId: dbSid, conversationId: cid, agentId: 'cli-claude', timestamp: Date.now() });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
_endStreaming(cid, sid) {
|
|
94
|
+
if (!this._streaming.has(sid)) return;
|
|
95
|
+
this._streaming.delete(sid);
|
|
96
|
+
const dbSid = this._sessions.get(sid);
|
|
97
|
+
if (dbSid) {
|
|
98
|
+
try { this._q.updateSession(dbSid, { status: 'completed', completed_at: Date.now() }); } catch (_) {}
|
|
99
|
+
}
|
|
100
|
+
this._q.setIsStreaming(cid, false);
|
|
101
|
+
this._bc({ type: 'streaming_complete', sessionId: dbSid || sid, conversationId: cid, agentId: 'cli-claude', eventCount: 0, seq: this._seq(sid), timestamp: Date.now() });
|
|
102
|
+
this._sessions.delete(sid);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_route(cid, sid, e) {
|
|
106
|
+
if (e.type === 'queue-operation' || e.type === 'last-prompt' || (e.type === 'user' && e.isMeta)) return;
|
|
107
|
+
|
|
108
|
+
if (e.isApiErrorMessage && e.error === 'rate_limit') {
|
|
109
|
+
this._bc({ type: 'streaming_error', sessionId: this._sessions.get(sid) || sid, conversationId: cid, error: 'Rate limit hit', recoverable: true, timestamp: Date.now() });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (e.type === 'system') {
|
|
114
|
+
if (e.subtype === 'init') { this._startStreaming(cid, sid); return; }
|
|
115
|
+
if (e.subtype === 'turn_duration' || e.subtype === 'stop_hook_summary') { this._endStreaming(cid, sid); return; }
|
|
116
|
+
this._startStreaming(cid, sid);
|
|
117
|
+
this._emit(cid, sid, { type: 'system', subtype: e.subtype, model: e.model, cwd: e.cwd, tools: e.tools, preTokens: e.compactMetadata?.preTokens }, 'system');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (e.type === 'assistant' && e.message?.content) {
|
|
122
|
+
this._startStreaming(cid, sid);
|
|
123
|
+
const key = `${sid}:${e.message.id}`;
|
|
124
|
+
const prev = this._emitted.get(key) || 0;
|
|
125
|
+
const content = e.message.content;
|
|
126
|
+
const newBlocks = content.slice(prev);
|
|
127
|
+
if (newBlocks.length > 0) {
|
|
128
|
+
this._emitted.set(key, content.length);
|
|
129
|
+
this._emitBlocks(cid, sid, newBlocks, 'assistant');
|
|
130
|
+
}
|
|
131
|
+
if (e.message.stop_reason) this._emitted.delete(key);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (e.type === 'user' && e.message?.content) {
|
|
136
|
+
if (e.isCompactSummary) { this._emit(cid, sid, { type: 'compact_summary', content: e.message.content }, 'system'); return; }
|
|
137
|
+
this._startStreaming(cid, sid);
|
|
138
|
+
const content = e.message.content;
|
|
139
|
+
const textParts = Array.isArray(content)
|
|
140
|
+
? content.filter(b => b.type === 'text' && b.text && !b.text.startsWith('<task-notification>')).map(b => b.text).join('\n')
|
|
141
|
+
: (typeof content === 'string' && !content.startsWith('<task-notification>') ? content : '');
|
|
142
|
+
if (textParts) {
|
|
143
|
+
try { this._q.createMessage(cid, 'user', textParts); } catch (_) {}
|
|
144
|
+
}
|
|
145
|
+
const blocks = Array.isArray(content) ? content : [];
|
|
146
|
+
for (const b of blocks) if (b.type === 'tool_result') this._emit(cid, sid, b, 'tool_result');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (e.type === 'progress') {
|
|
151
|
+
this._startStreaming(cid, sid);
|
|
152
|
+
const d = e.data || {};
|
|
153
|
+
if (d.type === 'agent_progress') {
|
|
154
|
+
const inner = d.message?.message || d.message;
|
|
155
|
+
const content = inner?.content;
|
|
156
|
+
if (Array.isArray(content)) {
|
|
157
|
+
const role = inner.role === 'user' ? 'tool_result' : 'assistant';
|
|
158
|
+
this._emitBlocks(cid, sid, content, role);
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (d.type === 'hook_progress') {
|
|
163
|
+
this._emit(cid, sid, { type: 'hook_progress', hookEvent: d.hookEvent, hookName: d.hookName }, 'system');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (d.type === 'mcp_progress') {
|
|
167
|
+
this._emit(cid, sid, { type: 'mcp_progress', status: d.status, serverName: d.serverName, toolName: d.toolName }, 'system');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this._emit(cid, sid, { type: d.type || e.subtype || 'progress', content: e.content || d }, 'progress');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (e.type === 'result') {
|
|
175
|
+
this._emit(cid, sid, { type: 'result', result: e.result, subtype: e.subtype, duration_ms: e.duration_ms, total_cost_usd: e.total_cost_usd, is_error: e.is_error || false }, 'result', { isResult: true });
|
|
176
|
+
this._endStreaming(cid, sid);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
package/lib/jsonl-watcher.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
|
+
import { JsonlParser } from './jsonl-parser.js';
|
|
4
5
|
|
|
5
6
|
const PROJECTS_DIR = path.join(os.homedir(), '.claude', 'projects');
|
|
6
7
|
const DEBOUNCE_MS = 16;
|
|
7
8
|
|
|
8
9
|
export class JsonlWatcher {
|
|
9
10
|
constructor({ broadcastSync, queries, ownedSessionIds }) {
|
|
10
|
-
this.
|
|
11
|
-
this._q = queries;
|
|
12
|
-
this._owned = ownedSessionIds;
|
|
11
|
+
this._parser = new JsonlParser({ broadcastSync, queries, ownedSessionIds });
|
|
13
12
|
this._tails = new Map();
|
|
14
|
-
this._convMap = new Map();
|
|
15
|
-
this._emitted = new Map();
|
|
16
13
|
this._timers = new Map();
|
|
17
|
-
this._seqs = new Map();
|
|
18
|
-
this._streaming = new Set();
|
|
19
|
-
this._sessions = new Map();
|
|
20
14
|
this._watcher = null;
|
|
21
15
|
}
|
|
22
16
|
|
|
@@ -24,7 +18,7 @@ export class JsonlWatcher {
|
|
|
24
18
|
if (!fs.existsSync(PROJECTS_DIR)) return;
|
|
25
19
|
this._scanDir(PROJECTS_DIR, 0);
|
|
26
20
|
for (const [fp, t] of this._timers.entries()) { clearTimeout(t); this._timers.delete(fp); this._read(fp); }
|
|
27
|
-
|
|
21
|
+
this._parser.endAllStreaming();
|
|
28
22
|
try {
|
|
29
23
|
this._watcher = fs.watch(PROJECTS_DIR, { recursive: true }, (_, f) => {
|
|
30
24
|
if (f && f.endsWith('.jsonl')) this._debounce(path.join(PROJECTS_DIR, f));
|
|
@@ -40,13 +34,9 @@ export class JsonlWatcher {
|
|
|
40
34
|
}
|
|
41
35
|
|
|
42
36
|
removeConversation(conversationId) {
|
|
43
|
-
const sids = [...this._convMap.entries()].filter(([, cid]) => cid === conversationId).map(([sid]) => sid);
|
|
37
|
+
const sids = [...this._parser._convMap.entries()].filter(([, cid]) => cid === conversationId).map(([sid]) => sid);
|
|
44
38
|
for (const sid of sids) {
|
|
45
|
-
this.
|
|
46
|
-
this._seqs.delete(sid);
|
|
47
|
-
this._streaming.delete(sid);
|
|
48
|
-
this._sessions.delete(sid);
|
|
49
|
-
for (const key of [...this._emitted.keys()]) if (key.startsWith(`${sid}:`)) this._emitted.delete(key);
|
|
39
|
+
this._parser.removeSid(sid);
|
|
50
40
|
for (const [fp, s] of this._tails.entries()) {
|
|
51
41
|
if (!fp.includes(sid)) continue;
|
|
52
42
|
if (s.fd !== null) try { fs.closeSync(s.fd); } catch (_) {}
|
|
@@ -60,9 +50,9 @@ export class JsonlWatcher {
|
|
|
60
50
|
removeAllConversations() {
|
|
61
51
|
for (const s of this._tails.values()) if (s.fd !== null) try { fs.closeSync(s.fd); } catch (_) {}
|
|
62
52
|
for (const t of this._timers.values()) clearTimeout(t);
|
|
63
|
-
this._tails.clear();
|
|
64
|
-
this._timers.clear();
|
|
65
|
-
this.
|
|
53
|
+
this._tails.clear();
|
|
54
|
+
this._timers.clear();
|
|
55
|
+
this._parser.clear();
|
|
66
56
|
}
|
|
67
57
|
|
|
68
58
|
_scanDir(dir, depth) {
|
|
@@ -99,155 +89,10 @@ export class JsonlWatcher {
|
|
|
99
89
|
s.partial = text.slice(start);
|
|
100
90
|
const ms = Number(process.hrtime.bigint() - t0) / 1e6;
|
|
101
91
|
if (ms > 5) console.warn(`[JsonlWatcher] hot path ${ms.toFixed(1)}ms (${lines.length} lines)`);
|
|
102
|
-
for (const l of lines) this._line(fp, l);
|
|
92
|
+
for (const l of lines) this._parser._line(fp, l);
|
|
103
93
|
} catch (e) {
|
|
104
94
|
if (e.code !== 'ENOENT') console.error('[JsonlWatcher] read error:', e.message);
|
|
105
95
|
if (s.fd !== null) { try { fs.closeSync(s.fd); } catch (_) {} s.fd = null; }
|
|
106
96
|
}
|
|
107
97
|
}
|
|
108
|
-
|
|
109
|
-
_line(fp, line) {
|
|
110
|
-
line = line.trim(); if (!line) return;
|
|
111
|
-
let e; try { e = JSON.parse(line); } catch (_) { return; }
|
|
112
|
-
if (!e || !e.sessionId) return;
|
|
113
|
-
if (this._owned?.has(e.sessionId)) return;
|
|
114
|
-
const cid = this._conv(e.sessionId, e, fp);
|
|
115
|
-
if (cid) this._route(cid, e.sessionId, e);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
_conv(sid, e) {
|
|
119
|
-
if (this._convMap.has(sid)) return this._convMap.get(sid);
|
|
120
|
-
const found = this._q.getConversations().find(c => c.claudeSessionId === sid);
|
|
121
|
-
if (found) { this._convMap.set(sid, found.id); return found.id; }
|
|
122
|
-
if (e.type === 'queue-operation' || e.type === 'last-prompt') return null;
|
|
123
|
-
if (e.type === 'user' && e.isMeta) return null;
|
|
124
|
-
const cwd = e.cwd || process.cwd();
|
|
125
|
-
const branch = e.gitBranch || '';
|
|
126
|
-
const base = path.basename(cwd);
|
|
127
|
-
const title = branch ? `${branch} @ ${base}` : base;
|
|
128
|
-
const conv = this._q.createConversation('claude-code', title, cwd);
|
|
129
|
-
this._q.setClaudeSessionId(conv.id, sid);
|
|
130
|
-
this._convMap.set(sid, conv.id);
|
|
131
|
-
this._bc({ type: 'conversation_created', conversation: conv, timestamp: Date.now() });
|
|
132
|
-
return conv.id;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
_seq(sid) { const n = (this._seqs.get(sid) || 0) + 1; this._seqs.set(sid, n); return n; }
|
|
136
|
-
|
|
137
|
-
_dbSession(cid, sid) {
|
|
138
|
-
if (this._sessions.has(sid)) return this._sessions.get(sid);
|
|
139
|
-
const sess = this._q.createSession(cid);
|
|
140
|
-
this._q.updateSession(sess.id, { status: 'active' });
|
|
141
|
-
this._sessions.set(sid, sess.id);
|
|
142
|
-
return sess.id;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
_emit(cid, sid, block, role, extra) {
|
|
146
|
-
const dbSid = this._dbSession(cid, sid);
|
|
147
|
-
const seq = this._seq(sid);
|
|
148
|
-
try { this._q.createChunk(dbSid, cid, seq, block.type || 'unknown', block); } catch (_) {}
|
|
149
|
-
this._bc({ type: 'streaming_progress', sessionId: dbSid, conversationId: cid, block, blockRole: role, seq, timestamp: Date.now(), ...extra });
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
_emitBlocks(cid, sid, blocks, role) {
|
|
153
|
-
for (const b of blocks) {
|
|
154
|
-
if (!b || !b.type) continue;
|
|
155
|
-
this._emit(cid, sid, b, role);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
_startStreaming(cid, sid) {
|
|
160
|
-
if (this._streaming.has(sid)) return;
|
|
161
|
-
this._streaming.add(sid);
|
|
162
|
-
const dbSid = this._dbSession(cid, sid);
|
|
163
|
-
this._q.setIsStreaming(cid, true);
|
|
164
|
-
this._bc({ type: 'streaming_start', sessionId: dbSid, conversationId: cid, agentId: 'cli-claude', timestamp: Date.now() });
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
_endStreaming(cid, sid) {
|
|
168
|
-
if (!this._streaming.has(sid)) return;
|
|
169
|
-
this._streaming.delete(sid);
|
|
170
|
-
const dbSid = this._sessions.get(sid);
|
|
171
|
-
if (dbSid) {
|
|
172
|
-
try { this._q.updateSession(dbSid, { status: 'completed', completed_at: Date.now() }); } catch (_) {}
|
|
173
|
-
}
|
|
174
|
-
this._q.setIsStreaming(cid, false);
|
|
175
|
-
this._bc({ type: 'streaming_complete', sessionId: dbSid || sid, conversationId: cid, agentId: 'cli-claude', eventCount: 0, seq: this._seq(sid), timestamp: Date.now() });
|
|
176
|
-
this._sessions.delete(sid);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
_route(cid, sid, e) {
|
|
180
|
-
if (e.type === 'queue-operation' || e.type === 'last-prompt' || (e.type === 'user' && e.isMeta)) return;
|
|
181
|
-
|
|
182
|
-
if (e.isApiErrorMessage && e.error === 'rate_limit') {
|
|
183
|
-
this._bc({ type: 'streaming_error', sessionId: this._sessions.get(sid) || sid, conversationId: cid, error: 'Rate limit hit', recoverable: true, timestamp: Date.now() });
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (e.type === 'system') {
|
|
188
|
-
if (e.subtype === 'init') { this._startStreaming(cid, sid); return; }
|
|
189
|
-
if (e.subtype === 'turn_duration' || e.subtype === 'stop_hook_summary') { this._endStreaming(cid, sid); return; }
|
|
190
|
-
this._startStreaming(cid, sid);
|
|
191
|
-
this._emit(cid, sid, { type: 'system', subtype: e.subtype, model: e.model, cwd: e.cwd, tools: e.tools, preTokens: e.compactMetadata?.preTokens }, 'system');
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (e.type === 'assistant' && e.message?.content) {
|
|
196
|
-
this._startStreaming(cid, sid);
|
|
197
|
-
const key = `${sid}:${e.message.id}`;
|
|
198
|
-
const prev = this._emitted.get(key) || 0;
|
|
199
|
-
const content = e.message.content;
|
|
200
|
-
const newBlocks = content.slice(prev);
|
|
201
|
-
if (newBlocks.length > 0) {
|
|
202
|
-
this._emitted.set(key, content.length);
|
|
203
|
-
this._emitBlocks(cid, sid, newBlocks, 'assistant');
|
|
204
|
-
}
|
|
205
|
-
if (e.message.stop_reason) this._emitted.delete(key);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (e.type === 'user' && e.message?.content) {
|
|
210
|
-
if (e.isCompactSummary) { this._emit(cid, sid, { type: 'compact_summary', content: e.message.content }, 'system'); return; }
|
|
211
|
-
this._startStreaming(cid, sid);
|
|
212
|
-
const content = e.message.content;
|
|
213
|
-
const textParts = Array.isArray(content)
|
|
214
|
-
? content.filter(b => b.type === 'text' && b.text && !b.text.startsWith('<task-notification>')).map(b => b.text).join('\n')
|
|
215
|
-
: (typeof content === 'string' && !content.startsWith('<task-notification>') ? content : '');
|
|
216
|
-
if (textParts) {
|
|
217
|
-
try { this._q.createMessage(cid, 'user', textParts); } catch (_) {}
|
|
218
|
-
}
|
|
219
|
-
const blocks = Array.isArray(content) ? content : [];
|
|
220
|
-
for (const b of blocks) if (b.type === 'tool_result') this._emit(cid, sid, b, 'tool_result');
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (e.type === 'progress') {
|
|
225
|
-
this._startStreaming(cid, sid);
|
|
226
|
-
const d = e.data || {};
|
|
227
|
-
if (d.type === 'agent_progress') {
|
|
228
|
-
const inner = d.message?.message || d.message;
|
|
229
|
-
const content = inner?.content;
|
|
230
|
-
if (Array.isArray(content)) {
|
|
231
|
-
const role = inner.role === 'user' ? 'tool_result' : 'assistant';
|
|
232
|
-
this._emitBlocks(cid, sid, content, role);
|
|
233
|
-
}
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (d.type === 'hook_progress') {
|
|
237
|
-
this._emit(cid, sid, { type: 'hook_progress', hookEvent: d.hookEvent, hookName: d.hookName }, 'system');
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
if (d.type === 'mcp_progress') {
|
|
241
|
-
this._emit(cid, sid, { type: 'mcp_progress', status: d.status, serverName: d.serverName, toolName: d.toolName }, 'system');
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
this._emit(cid, sid, { type: d.type || e.subtype || 'progress', content: e.content || d }, 'progress');
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (e.type === 'result') {
|
|
249
|
-
this._emit(cid, sid, { type: 'result', result: e.result, subtype: e.subtype, duration_ms: e.duration_ms, total_cost_usd: e.total_cost_usd, is_error: e.is_error || false }, 'result', { isResult: true });
|
|
250
|
-
this._endStreaming(cid, sid);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
98
|
}
|