opc-agent 4.0.9 → 4.0.10
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 +59 -3
- package/package.json +1 -1
- package/src/providers/index.ts +61 -3
package/dist/providers/index.js
CHANGED
|
@@ -406,9 +406,65 @@ class ClaudeCLIProvider {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
async *chatStream(messages, systemPrompt) {
|
|
409
|
-
//
|
|
410
|
-
const
|
|
411
|
-
|
|
409
|
+
// Build prompt same as chat()
|
|
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'];
|
|
420
|
+
if (this.model) {
|
|
421
|
+
args.push('--model', this.model);
|
|
422
|
+
}
|
|
423
|
+
// Write system prompt to temp file if needed
|
|
424
|
+
let tmpFile;
|
|
425
|
+
if (systemPrompt) {
|
|
426
|
+
const { writeFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
427
|
+
const { join } = await Promise.resolve().then(() => __importStar(require('path')));
|
|
428
|
+
const { tmpdir } = await Promise.resolve().then(() => __importStar(require('os')));
|
|
429
|
+
tmpFile = join(tmpdir(), `opc-claude-stream-${Date.now()}.txt`);
|
|
430
|
+
writeFileSync(tmpFile, systemPrompt);
|
|
431
|
+
args.push('--system-prompt-file', tmpFile);
|
|
432
|
+
}
|
|
433
|
+
const lastMsg = messages[messages.length - 1];
|
|
434
|
+
args.push(lastMsg?.content ?? prompt);
|
|
435
|
+
const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
436
|
+
try {
|
|
437
|
+
const proc = spawn('claude', args, {
|
|
438
|
+
env: { ...process.env },
|
|
439
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
440
|
+
});
|
|
441
|
+
proc.stdin.end();
|
|
442
|
+
// Yield chunks as they arrive from stdout
|
|
443
|
+
const readable = proc.stdout;
|
|
444
|
+
for await (const chunk of readable) {
|
|
445
|
+
yield chunk.toString();
|
|
446
|
+
}
|
|
447
|
+
// Wait for process to finish
|
|
448
|
+
await new Promise((resolve, reject) => {
|
|
449
|
+
proc.on('close', (code) => {
|
|
450
|
+
if (code !== 0 && code !== null) {
|
|
451
|
+
// Already yielded content, just log
|
|
452
|
+
console.warn(`[ClaudeCLI] Process exited with code ${code}`);
|
|
453
|
+
}
|
|
454
|
+
resolve();
|
|
455
|
+
});
|
|
456
|
+
proc.on('error', reject);
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
finally {
|
|
460
|
+
if (tmpFile) {
|
|
461
|
+
try {
|
|
462
|
+
const { unlinkSync } = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
463
|
+
unlinkSync(tmpFile);
|
|
464
|
+
}
|
|
465
|
+
catch { }
|
|
466
|
+
}
|
|
467
|
+
}
|
|
412
468
|
}
|
|
413
469
|
}
|
|
414
470
|
function createProvider(name = 'openai', model, baseUrl, apiKey) {
|
package/package.json
CHANGED
package/src/providers/index.ts
CHANGED
|
@@ -410,9 +410,67 @@ class ClaudeCLIProvider implements LLMProvider {
|
|
|
410
410
|
}
|
|
411
411
|
|
|
412
412
|
async *chatStream(messages: Message[], systemPrompt?: string): AsyncIterable<string> {
|
|
413
|
-
//
|
|
414
|
-
const
|
|
415
|
-
|
|
413
|
+
// Build prompt same as chat()
|
|
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'];
|
|
425
|
+
if (this.model) {
|
|
426
|
+
args.push('--model', this.model);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Write system prompt to temp file if needed
|
|
430
|
+
let tmpFile: string | undefined;
|
|
431
|
+
if (systemPrompt) {
|
|
432
|
+
const { writeFileSync } = await import('fs');
|
|
433
|
+
const { join } = await import('path');
|
|
434
|
+
const { tmpdir } = await import('os');
|
|
435
|
+
tmpFile = join(tmpdir(), `opc-claude-stream-${Date.now()}.txt`);
|
|
436
|
+
writeFileSync(tmpFile, systemPrompt);
|
|
437
|
+
args.push('--system-prompt-file', tmpFile);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const lastMsg = messages[messages.length - 1];
|
|
441
|
+
args.push(lastMsg?.content ?? prompt);
|
|
442
|
+
|
|
443
|
+
const { spawn } = await import('child_process');
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
const proc = spawn('claude', args, {
|
|
447
|
+
env: { ...process.env },
|
|
448
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
449
|
+
});
|
|
450
|
+
proc.stdin.end();
|
|
451
|
+
|
|
452
|
+
// Yield chunks as they arrive from stdout
|
|
453
|
+
const readable = proc.stdout;
|
|
454
|
+
for await (const chunk of readable) {
|
|
455
|
+
yield (chunk as Buffer).toString();
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Wait for process to finish
|
|
459
|
+
await new Promise<void>((resolve, reject) => {
|
|
460
|
+
proc.on('close', (code) => {
|
|
461
|
+
if (code !== 0 && code !== null) {
|
|
462
|
+
// Already yielded content, just log
|
|
463
|
+
console.warn(`[ClaudeCLI] Process exited with code ${code}`);
|
|
464
|
+
}
|
|
465
|
+
resolve();
|
|
466
|
+
});
|
|
467
|
+
proc.on('error', reject);
|
|
468
|
+
});
|
|
469
|
+
} finally {
|
|
470
|
+
if (tmpFile) {
|
|
471
|
+
try { const { unlinkSync } = await import('fs'); unlinkSync(tmpFile); } catch {}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
416
474
|
}
|
|
417
475
|
}
|
|
418
476
|
|