@eyeclaw/eyeclaw 2.0.2 → 2.0.5
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/src/channel.ts +83 -20
- package/src/client.ts +15 -0
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -183,33 +183,96 @@ export const eyeclawPlugin: ChannelPlugin<ResolvedEyeClawAccount> = {
|
|
|
183
183
|
try {
|
|
184
184
|
ctx.log?.info(`🤖 Sending message to OpenClaw Agent: ${message}`)
|
|
185
185
|
|
|
186
|
-
// Call OpenClaw Agent via
|
|
186
|
+
// Call OpenClaw Agent via spawn for streaming output
|
|
187
187
|
const { spawn } = await import('child_process')
|
|
188
|
-
const { promisify } = await import('util')
|
|
189
|
-
const exec = promisify((await import('child_process')).exec)
|
|
190
188
|
|
|
191
189
|
try {
|
|
192
|
-
//
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
// Spawn openclaw agent process for streaming output
|
|
191
|
+
const agentProcess = spawn('openclaw', [
|
|
192
|
+
'agent',
|
|
193
|
+
'--session-id', 'eyeclaw-web-chat',
|
|
194
|
+
'--message', message,
|
|
195
|
+
'--json'
|
|
196
|
+
])
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
let outputBuffer = ''
|
|
199
|
+
let streamId = Date.now().toString()
|
|
200
|
+
|
|
201
|
+
// Send stream_start event
|
|
202
|
+
client.sendStreamChunk('stream_start', streamId, '')
|
|
203
|
+
|
|
204
|
+
// Handle stdout (streaming response)
|
|
205
|
+
agentProcess.stdout?.on('data', (data: Buffer) => {
|
|
206
|
+
const text = data.toString()
|
|
207
|
+
outputBuffer += text
|
|
208
|
+
|
|
209
|
+
// For streaming text output, send each chunk immediately
|
|
210
|
+
// Try to parse as JSON first
|
|
199
211
|
try {
|
|
200
|
-
const parsed = JSON.parse(
|
|
201
|
-
//
|
|
202
|
-
const response = parsed.result?.payloads?.[0]?.text
|
|
203
|
-
|
|
204
|
-
|
|
212
|
+
const parsed = JSON.parse(outputBuffer)
|
|
213
|
+
// If we can parse the complete JSON, extract the text
|
|
214
|
+
const response = parsed.result?.payloads?.[0]?.text
|
|
215
|
+
if (response) {
|
|
216
|
+
// Send the text in chunks
|
|
217
|
+
const chunkSize = 50 // Send ~50 chars at a time
|
|
218
|
+
for (let i = 0; i < response.length; i += chunkSize) {
|
|
219
|
+
const chunk = response.substring(i, i + chunkSize)
|
|
220
|
+
client.sendStreamChunk('stream_chunk', streamId, chunk)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
outputBuffer = '' // Clear buffer after successful parse
|
|
205
224
|
} catch (e) {
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
225
|
+
// Not valid JSON yet, check if we have complete lines to send
|
|
226
|
+
const lines = outputBuffer.split('\n')
|
|
227
|
+
// Keep last incomplete line in buffer
|
|
228
|
+
if (lines.length > 1) {
|
|
229
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
230
|
+
if (lines[i].trim()) {
|
|
231
|
+
client.sendStreamChunk('stream_chunk', streamId, lines[i] + '\n')
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
outputBuffer = lines[lines.length - 1]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
// Handle stderr (errors)
|
|
240
|
+
agentProcess.stderr?.on('data', (data: Buffer) => {
|
|
241
|
+
const errorText = data.toString()
|
|
242
|
+
ctx.log?.error(`Agent stderr: ${errorText}`)
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// Handle process completion
|
|
246
|
+
agentProcess.on('close', (code: number) => {
|
|
247
|
+
// Send any remaining buffered content
|
|
248
|
+
if (outputBuffer.trim()) {
|
|
249
|
+
try {
|
|
250
|
+
const parsed = JSON.parse(outputBuffer)
|
|
251
|
+
const response = parsed.result?.payloads?.[0]?.text || outputBuffer.trim()
|
|
252
|
+
client.sendStreamChunk('stream_chunk', streamId, response)
|
|
253
|
+
} catch (e) {
|
|
254
|
+
client.sendStreamChunk('stream_chunk', streamId, outputBuffer.trim())
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Send stream_end event
|
|
259
|
+
client.sendStreamChunk('stream_end', streamId, '')
|
|
260
|
+
|
|
261
|
+
if (code === 0) {
|
|
262
|
+
ctx.log?.info(`✅ Agent completed successfully`)
|
|
263
|
+
} else {
|
|
264
|
+
ctx.log?.error(`Agent exited with code ${code}`)
|
|
265
|
+
client.sendLog('error', `❌ Agent error: process exited with code ${code}`)
|
|
209
266
|
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
// Handle process errors
|
|
270
|
+
agentProcess.on('error', (error: Error) => {
|
|
271
|
+
ctx.log?.error(`Failed to start agent process: ${error.message}`)
|
|
272
|
+
client.sendStreamChunk('stream_error', streamId, error.message)
|
|
273
|
+
client.sendLog('error', `❌ Failed to start agent: ${error.message}`)
|
|
274
|
+
})
|
|
275
|
+
|
|
213
276
|
} catch (error) {
|
|
214
277
|
const errorMsg = error instanceof Error ? error.message : String(error)
|
|
215
278
|
ctx.log?.error(`Failed to execute openclaw agent: ${errorMsg}`)
|
package/src/client.ts
CHANGED
|
@@ -119,6 +119,12 @@ export class EyeClawClient {
|
|
|
119
119
|
this.logger.info(`[Server Log] ${message.level}: ${message.message}`)
|
|
120
120
|
break
|
|
121
121
|
|
|
122
|
+
case 'stream_chunk':
|
|
123
|
+
// Forward stream chunks to handler (will be handled by web UI)
|
|
124
|
+
const chunkPreview = typeof message.chunk === 'string' ? message.chunk.substring(0, 50) : String(message.chunk || '').substring(0, 50)
|
|
125
|
+
this.logger.debug(`Stream chunk: ${message.type} - ${chunkPreview}...`)
|
|
126
|
+
break
|
|
127
|
+
|
|
122
128
|
default:
|
|
123
129
|
this.logger.warn(`Unknown message type: ${type}`)
|
|
124
130
|
}
|
|
@@ -274,6 +280,15 @@ export class EyeClawClient {
|
|
|
274
280
|
})
|
|
275
281
|
}
|
|
276
282
|
|
|
283
|
+
sendStreamChunk(type: string, streamId: string, chunk: string): void {
|
|
284
|
+
this.sendChannelMessage('stream_chunk', {
|
|
285
|
+
type,
|
|
286
|
+
stream_id: streamId,
|
|
287
|
+
chunk,
|
|
288
|
+
timestamp: new Date().toISOString(),
|
|
289
|
+
})
|
|
290
|
+
}
|
|
291
|
+
|
|
277
292
|
sendCommandResult(command: string, result: unknown, error?: string): void {
|
|
278
293
|
this.sendChannelMessage('command_result', {
|
|
279
294
|
command,
|