opc-agent 4.0.10 → 4.0.11
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/dist/providers/index.js +65 -25
- package/package.json +1 -1
- package/src/providers/index.ts +65 -26
package/dist/providers/index.js
CHANGED
|
@@ -406,17 +406,7 @@ class ClaudeCLIProvider {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
async *chatStream(messages, systemPrompt) {
|
|
409
|
-
|
|
410
|
-
const parts = [];
|
|
411
|
-
if (systemPrompt) {
|
|
412
|
-
parts.push(`[System]: ${systemPrompt}`);
|
|
413
|
-
}
|
|
414
|
-
for (const m of messages) {
|
|
415
|
-
const role = m.role === 'user' ? 'Human' : 'Assistant';
|
|
416
|
-
parts.push(`${role}: ${m.content}`);
|
|
417
|
-
}
|
|
418
|
-
const prompt = parts.join('\n\n');
|
|
419
|
-
const args = ['-p', '--output-format', 'text'];
|
|
409
|
+
const args = ['-p', '--output-format', 'stream-json', '--include-partial-messages'];
|
|
420
410
|
if (this.model) {
|
|
421
411
|
args.push('--model', this.model);
|
|
422
412
|
}
|
|
@@ -431,7 +421,7 @@ class ClaudeCLIProvider {
|
|
|
431
421
|
args.push('--system-prompt-file', tmpFile);
|
|
432
422
|
}
|
|
433
423
|
const lastMsg = messages[messages.length - 1];
|
|
434
|
-
args.push(lastMsg?.content ??
|
|
424
|
+
args.push(lastMsg?.content ?? '');
|
|
435
425
|
const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
436
426
|
try {
|
|
437
427
|
const proc = spawn('claude', args, {
|
|
@@ -439,21 +429,71 @@ class ClaudeCLIProvider {
|
|
|
439
429
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
440
430
|
});
|
|
441
431
|
proc.stdin.end();
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
for await (const chunk of
|
|
445
|
-
|
|
432
|
+
let buffer = '';
|
|
433
|
+
let lastContent = '';
|
|
434
|
+
for await (const chunk of proc.stdout) {
|
|
435
|
+
buffer += chunk.toString();
|
|
436
|
+
const lines = buffer.split('\n');
|
|
437
|
+
buffer = lines.pop() ?? '';
|
|
438
|
+
for (const line of lines) {
|
|
439
|
+
const trimmed = line.trim();
|
|
440
|
+
if (!trimmed)
|
|
441
|
+
continue;
|
|
442
|
+
try {
|
|
443
|
+
const event = JSON.parse(trimmed);
|
|
444
|
+
// Handle partial message chunks (content_block_delta style)
|
|
445
|
+
if (event.type === 'content' && event.content) {
|
|
446
|
+
const newContent = event.content;
|
|
447
|
+
if (newContent.length > lastContent.length) {
|
|
448
|
+
yield newContent.slice(lastContent.length);
|
|
449
|
+
lastContent = newContent;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
// Handle assistant message with content array
|
|
453
|
+
if (event.type === 'assistant' && event.message?.content) {
|
|
454
|
+
for (const block of event.message.content) {
|
|
455
|
+
if (block.type === 'text' && block.text) {
|
|
456
|
+
const newText = block.text;
|
|
457
|
+
if (newText.length > lastContent.length) {
|
|
458
|
+
yield newText.slice(lastContent.length);
|
|
459
|
+
lastContent = newText;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
// Handle result message
|
|
465
|
+
if (event.type === 'result' && event.result) {
|
|
466
|
+
const resultText = typeof event.result === 'string' ? event.result : '';
|
|
467
|
+
if (resultText && resultText.length > lastContent.length) {
|
|
468
|
+
yield resultText.slice(lastContent.length);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
// Not JSON, might be raw text
|
|
474
|
+
}
|
|
475
|
+
}
|
|
446
476
|
}
|
|
447
|
-
//
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
477
|
+
// Process remaining buffer
|
|
478
|
+
if (buffer.trim()) {
|
|
479
|
+
try {
|
|
480
|
+
const event = JSON.parse(buffer.trim());
|
|
481
|
+
if (event.type === 'result' && event.result) {
|
|
482
|
+
const resultText = typeof event.result === 'string' ? event.result : '';
|
|
483
|
+
if (resultText && resultText.length > lastContent.length) {
|
|
484
|
+
yield resultText.slice(lastContent.length);
|
|
485
|
+
}
|
|
453
486
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
489
|
+
// If not JSON, yield as raw text if we haven't yielded anything
|
|
490
|
+
if (!lastContent && buffer.trim()) {
|
|
491
|
+
yield buffer.trim();
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
await new Promise((resolve) => {
|
|
496
|
+
proc.on('close', () => resolve());
|
|
457
497
|
});
|
|
458
498
|
}
|
|
459
499
|
finally {
|
package/package.json
CHANGED
package/src/providers/index.ts
CHANGED
|
@@ -410,18 +410,7 @@ class ClaudeCLIProvider implements LLMProvider {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
async *chatStream(messages: Message[], systemPrompt?: string): AsyncIterable<string> {
|
|
413
|
-
|
|
414
|
-
const parts: string[] = [];
|
|
415
|
-
if (systemPrompt) {
|
|
416
|
-
parts.push(`[System]: ${systemPrompt}`);
|
|
417
|
-
}
|
|
418
|
-
for (const m of messages) {
|
|
419
|
-
const role = m.role === 'user' ? 'Human' : 'Assistant';
|
|
420
|
-
parts.push(`${role}: ${m.content}`);
|
|
421
|
-
}
|
|
422
|
-
const prompt = parts.join('\n\n');
|
|
423
|
-
|
|
424
|
-
const args = ['-p', '--output-format', 'text'];
|
|
413
|
+
const args = ['-p', '--output-format', 'stream-json', '--include-partial-messages'];
|
|
425
414
|
if (this.model) {
|
|
426
415
|
args.push('--model', this.model);
|
|
427
416
|
}
|
|
@@ -438,7 +427,7 @@ class ClaudeCLIProvider implements LLMProvider {
|
|
|
438
427
|
}
|
|
439
428
|
|
|
440
429
|
const lastMsg = messages[messages.length - 1];
|
|
441
|
-
args.push(lastMsg?.content ??
|
|
430
|
+
args.push(lastMsg?.content ?? '');
|
|
442
431
|
|
|
443
432
|
const { spawn } = await import('child_process');
|
|
444
433
|
|
|
@@ -449,22 +438,72 @@ class ClaudeCLIProvider implements LLMProvider {
|
|
|
449
438
|
});
|
|
450
439
|
proc.stdin.end();
|
|
451
440
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
441
|
+
let buffer = '';
|
|
442
|
+
let lastContent = '';
|
|
443
|
+
|
|
444
|
+
for await (const chunk of proc.stdout) {
|
|
445
|
+
buffer += (chunk as Buffer).toString();
|
|
446
|
+
const lines = buffer.split('\n');
|
|
447
|
+
buffer = lines.pop() ?? '';
|
|
448
|
+
|
|
449
|
+
for (const line of lines) {
|
|
450
|
+
const trimmed = line.trim();
|
|
451
|
+
if (!trimmed) continue;
|
|
452
|
+
try {
|
|
453
|
+
const event = JSON.parse(trimmed);
|
|
454
|
+
// Handle partial message chunks (content_block_delta style)
|
|
455
|
+
if (event.type === 'content' && event.content) {
|
|
456
|
+
const newContent = event.content;
|
|
457
|
+
if (newContent.length > lastContent.length) {
|
|
458
|
+
yield newContent.slice(lastContent.length);
|
|
459
|
+
lastContent = newContent;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Handle assistant message with content array
|
|
463
|
+
if (event.type === 'assistant' && event.message?.content) {
|
|
464
|
+
for (const block of event.message.content) {
|
|
465
|
+
if (block.type === 'text' && block.text) {
|
|
466
|
+
const newText = block.text;
|
|
467
|
+
if (newText.length > lastContent.length) {
|
|
468
|
+
yield newText.slice(lastContent.length);
|
|
469
|
+
lastContent = newText;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// Handle result message
|
|
475
|
+
if (event.type === 'result' && event.result) {
|
|
476
|
+
const resultText = typeof event.result === 'string' ? event.result : '';
|
|
477
|
+
if (resultText && resultText.length > lastContent.length) {
|
|
478
|
+
yield resultText.slice(lastContent.length);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
} catch {
|
|
482
|
+
// Not JSON, might be raw text
|
|
483
|
+
}
|
|
484
|
+
}
|
|
456
485
|
}
|
|
457
486
|
|
|
458
|
-
//
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
487
|
+
// Process remaining buffer
|
|
488
|
+
if (buffer.trim()) {
|
|
489
|
+
try {
|
|
490
|
+
const event = JSON.parse(buffer.trim());
|
|
491
|
+
if (event.type === 'result' && event.result) {
|
|
492
|
+
const resultText = typeof event.result === 'string' ? event.result : '';
|
|
493
|
+
if (resultText && resultText.length > lastContent.length) {
|
|
494
|
+
yield resultText.slice(lastContent.length);
|
|
495
|
+
}
|
|
464
496
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
497
|
+
} catch {
|
|
498
|
+
// If not JSON, yield as raw text if we haven't yielded anything
|
|
499
|
+
if (!lastContent && buffer.trim()) {
|
|
500
|
+
yield buffer.trim();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
await new Promise<void>((resolve) => {
|
|
506
|
+
proc.on('close', () => resolve());
|
|
468
507
|
});
|
|
469
508
|
} finally {
|
|
470
509
|
if (tmpFile) {
|