@yeaft/webchat-agent 0.1.197 → 0.1.198
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/sdk/query.js +62 -1
package/package.json
CHANGED
package/sdk/query.js
CHANGED
|
@@ -70,10 +70,19 @@ export class Query {
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Read messages from Claude process stdout
|
|
73
|
+
*
|
|
74
|
+
* With --include-partial-messages, the CLI emits stream_event messages
|
|
75
|
+
* containing incremental text deltas (content_block_delta / text_delta).
|
|
76
|
+
* We convert these to assistant-format messages for real-time streaming,
|
|
77
|
+
* then deduplicate when the final complete assistant message arrives.
|
|
73
78
|
*/
|
|
74
79
|
async readMessages() {
|
|
75
80
|
const rl = createInterface({ input: this.childStdout });
|
|
76
81
|
|
|
82
|
+
// Track whether we've forwarded text deltas for the current assistant turn.
|
|
83
|
+
// When true, the next complete `assistant` message's text blocks are redundant.
|
|
84
|
+
let hasStreamedTextDeltas = false;
|
|
85
|
+
|
|
77
86
|
try {
|
|
78
87
|
for await (const line of rl) {
|
|
79
88
|
if (line.trim()) {
|
|
@@ -100,6 +109,58 @@ export class Query {
|
|
|
100
109
|
continue;
|
|
101
110
|
}
|
|
102
111
|
|
|
112
|
+
// Handle stream_event messages (from --include-partial-messages)
|
|
113
|
+
if (message.type === 'stream_event') {
|
|
114
|
+
const event = message.event;
|
|
115
|
+
if (!event) continue;
|
|
116
|
+
|
|
117
|
+
// content_block_delta with text_delta → convert to assistant message for streaming
|
|
118
|
+
if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta' && event.delta.text) {
|
|
119
|
+
hasStreamedTextDeltas = true;
|
|
120
|
+
this.inputStream.enqueue({
|
|
121
|
+
type: 'assistant',
|
|
122
|
+
message: {
|
|
123
|
+
role: 'assistant',
|
|
124
|
+
content: [{ type: 'text', text: event.delta.text }]
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// All other stream events (message_start, content_block_start,
|
|
129
|
+
// input_json_delta, content_block_stop, message_stop) are ignored.
|
|
130
|
+
// tool_use is handled via the complete assistant message.
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Deduplicate: when a complete assistant message arrives after we've
|
|
135
|
+
// already streamed text deltas, strip the text blocks (already sent).
|
|
136
|
+
// Keep tool_use blocks which are NOT sent incrementally.
|
|
137
|
+
if (message.type === 'assistant' && hasStreamedTextDeltas) {
|
|
138
|
+
hasStreamedTextDeltas = false; // Reset for next assistant turn
|
|
139
|
+
|
|
140
|
+
const content = message.message?.content;
|
|
141
|
+
if (Array.isArray(content)) {
|
|
142
|
+
const nonTextBlocks = content.filter(b => b.type !== 'text');
|
|
143
|
+
if (nonTextBlocks.length > 0) {
|
|
144
|
+
// Forward only tool_use blocks (text already sent via deltas)
|
|
145
|
+
message.message.content = nonTextBlocks;
|
|
146
|
+
this.inputStream.enqueue(message);
|
|
147
|
+
}
|
|
148
|
+
// If only text blocks: skip entirely (all content already streamed)
|
|
149
|
+
} else if (typeof content === 'string') {
|
|
150
|
+
// String content was already streamed — skip
|
|
151
|
+
} else {
|
|
152
|
+
// Unknown format — forward as-is to be safe
|
|
153
|
+
this.inputStream.enqueue(message);
|
|
154
|
+
}
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Reset delta tracking on non-assistant messages
|
|
159
|
+
// (e.g., user, result, system — a new turn boundary)
|
|
160
|
+
if (message.type !== 'assistant') {
|
|
161
|
+
hasStreamedTextDeltas = false;
|
|
162
|
+
}
|
|
163
|
+
|
|
103
164
|
this.inputStream.enqueue(message);
|
|
104
165
|
} catch (e) {
|
|
105
166
|
logDebug(`Non-JSON line: ${line.substring(0, 100)}`);
|
|
@@ -284,7 +345,7 @@ export function query(config) {
|
|
|
284
345
|
} = config;
|
|
285
346
|
|
|
286
347
|
// Build command arguments
|
|
287
|
-
const args = ['--output-format', 'stream-json', '--verbose'];
|
|
348
|
+
const args = ['--output-format', 'stream-json', '--verbose', '--include-partial-messages'];
|
|
288
349
|
|
|
289
350
|
if (customSystemPrompt) args.push('--system-prompt', customSystemPrompt);
|
|
290
351
|
if (appendSystemPrompt) args.push('--append-system-prompt', appendSystemPrompt);
|