@ai-devkit/agent-manager 0.28.1 → 0.30.0
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/__tests__/adapters/ClaudeCodeAdapter.test.js +1 -342
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +343 -0
- package/dist/__tests__/capacity/codex.test.js.map +1 -0
- package/dist/__tests__/capacity/index.test.js +50 -0
- package/dist/__tests__/capacity/index.test.js.map +1 -0
- package/dist/__tests__/database/DurableAgentsDatabase.test.js +31 -3
- package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +1 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js +129 -0
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -0
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +84 -0
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +126 -0
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintAgentService.test.js +271 -0
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintRunner.test.js +393 -0
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -0
- package/dist/__tests__/print/ClaudeCliProbe.test.js +3 -7
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +33 -27
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +65 -0
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +4 -10
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +79 -0
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +436 -0
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +76 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +43 -0
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +202 -0
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +119 -0
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +386 -0
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +34 -0
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -0
- package/dist/__tests__/utils/ClaudeSessionParser.test.js +2 -2
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +36 -0
- package/dist/capacity/codex.d.ts.map +1 -0
- package/dist/capacity/codex.js +317 -0
- package/dist/capacity/codex.js.map +1 -0
- package/dist/capacity/index.d.ts +11 -0
- package/dist/capacity/index.d.ts.map +1 -0
- package/dist/capacity/index.js +49 -0
- package/dist/capacity/index.js.map +1 -0
- package/dist/capacity/types.d.ts +17 -0
- package/dist/capacity/types.d.ts.map +1 -0
- package/dist/capacity/types.js +3 -0
- package/dist/capacity/types.js.map +1 -0
- package/dist/database/migrations/004_codex_durable_sessions.sql +1 -0
- package/dist/durable/DurableAgent.d.ts +23 -3
- package/dist/durable/DurableAgent.d.ts.map +1 -1
- package/dist/durable/DurableAgent.js +12 -0
- package/dist/durable/DurableAgent.js.map +1 -1
- package/dist/durable/DurableAgentRepository.d.ts +6 -7
- package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
- package/dist/durable/DurableAgentRepository.js +73 -42
- package/dist/durable/DurableAgentRepository.js.map +1 -1
- package/dist/durable/process.d.ts +8 -0
- package/dist/durable/process.d.ts.map +1 -0
- package/dist/durable/process.js +40 -0
- package/dist/durable/process.js.map +1 -0
- package/dist/durable/run.d.ts +32 -0
- package/dist/durable/run.d.ts.map +1 -0
- package/dist/durable/run.js +46 -0
- package/dist/durable/run.js.map +1 -0
- package/dist/durable/utils.d.ts +19 -0
- package/dist/durable/utils.d.ts.map +1 -0
- package/dist/durable/utils.js +52 -0
- package/dist/durable/utils.js.map +1 -0
- package/dist/index.d.ts +19 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.d.ts +21 -0
- package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -0
- package/dist/providers/claude/ClaudeAgentMapper.js +42 -0
- package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -0
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts +29 -0
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -0
- package/dist/providers/claude/ClaudeCodeAdapter.js +129 -0
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -0
- package/dist/{adapters/ClaudeCodeAdapter.d.ts → providers/claude/ClaudeSessionLocator.d.ts} +68 -52
- package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -0
- package/dist/{adapters/ClaudeCodeAdapter.js → providers/claude/ClaudeSessionLocator.js} +71 -189
- package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -0
- package/dist/{utils → providers/claude}/ClaudeSessionParser.d.ts +2 -2
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -0
- package/dist/{utils → providers/claude}/ClaudeSessionParser.js +1 -1
- package/dist/providers/claude/ClaudeSessionParser.js.map +1 -0
- package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudeCliProbe.js +4 -9
- package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudePrintAgentService.d.ts +4 -9
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudePrintAgentService.js +45 -0
- package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudePrintRunner.d.ts +3 -3
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudePrintRunner.js +75 -0
- package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +17 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.js +69 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts +20 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.js +61 -0
- package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +40 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.js +50 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -0
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts +34 -0
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexPrintRunner.js +78 -0
- package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -0
- package/dist/providers/codex/durable/CodexStreamParser.d.ts +21 -0
- package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexStreamParser.js +86 -0
- package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts +20 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.js +51 -0
- package/dist/providers/pi/durable/PiCliProbe.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts +39 -0
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintAgentService.js +47 -0
- package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts +4 -0
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintProtocol.js +44 -0
- package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintRunner.d.ts +32 -0
- package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintRunner.js +61 -0
- package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -0
- package/dist/providers/pi/durable/PiStreamParser.d.ts +21 -0
- package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiStreamParser.js +71 -0
- package/dist/providers/pi/durable/PiStreamParser.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1 -307
- package/src/__tests__/capacity/codex.test.ts +184 -0
- package/src/__tests__/capacity/index.test.ts +38 -0
- package/src/__tests__/database/DurableAgentsDatabase.test.ts +28 -3
- package/src/__tests__/durable/CodexCliProbe.test.ts +63 -0
- package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +54 -0
- package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +79 -0
- package/src/__tests__/durable/CodexPrintAgentService.test.ts +139 -0
- package/src/__tests__/durable/CodexPrintRunner.test.ts +189 -0
- package/src/__tests__/fixtures/fake-codex.cjs +45 -0
- package/src/__tests__/print/ClaudeCliProbe.test.ts +3 -7
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +19 -22
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +33 -1
- package/src/__tests__/print/ClaudePrintRunner.test.ts +4 -10
- package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +84 -0
- package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +411 -0
- package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +38 -0
- package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +32 -0
- package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +69 -0
- package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +33 -0
- package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +107 -0
- package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +24 -0
- package/src/__tests__/utils/ClaudeSessionParser.test.ts +2 -2
- package/src/adapters/index.ts +1 -1
- package/src/capacity/codex.ts +320 -0
- package/src/capacity/index.ts +57 -0
- package/src/capacity/types.ts +18 -0
- package/src/database/migrations/004_codex_durable_sessions.sql +1 -0
- package/src/durable/DurableAgent.ts +51 -3
- package/src/durable/DurableAgentRepository.ts +60 -31
- package/src/durable/process.ts +28 -0
- package/src/durable/run.ts +74 -0
- package/src/durable/utils.ts +61 -0
- package/src/index.ts +37 -15
- package/src/providers/claude/ClaudeAgentMapper.ts +62 -0
- package/src/providers/claude/ClaudeCodeAdapter.ts +160 -0
- package/src/{adapters/ClaudeCodeAdapter.ts → providers/claude/ClaudeSessionLocator.ts} +97 -239
- package/src/{utils → providers/claude}/ClaudeSessionParser.ts +2 -2
- package/src/{durable → providers/claude/durable}/ClaudeCliProbe.ts +4 -10
- package/src/providers/claude/durable/ClaudePrintAgentService.ts +66 -0
- package/src/providers/claude/durable/ClaudePrintRunner.ts +92 -0
- package/src/providers/claude/durable/ClaudeStreamParser.ts +79 -0
- package/src/providers/codex/durable/CodexCliProbe.ts +60 -0
- package/src/providers/codex/durable/CodexPrintAgentService.ts +65 -0
- package/src/providers/codex/durable/CodexPrintRunner.ts +94 -0
- package/src/providers/codex/durable/CodexStreamParser.ts +104 -0
- package/src/providers/pi/durable/PiCliProbe.ts +48 -0
- package/src/providers/pi/durable/PiPrintAgentService.ts +69 -0
- package/src/providers/pi/durable/PiPrintProtocol.ts +39 -0
- package/src/providers/pi/durable/PiPrintRunner.ts +88 -0
- package/src/providers/pi/durable/PiStreamParser.ts +84 -0
- package/dist/adapters/ClaudeCodeAdapter.d.ts.map +0 -1
- package/dist/adapters/ClaudeCodeAdapter.js.map +0 -1
- package/dist/durable/ClaudeCliProbe.d.ts.map +0 -1
- package/dist/durable/ClaudeCliProbe.js.map +0 -1
- package/dist/durable/ClaudePrintAgentService.d.ts.map +0 -1
- package/dist/durable/ClaudePrintAgentService.js +0 -66
- package/dist/durable/ClaudePrintAgentService.js.map +0 -1
- package/dist/durable/ClaudePrintRunner.d.ts.map +0 -1
- package/dist/durable/ClaudePrintRunner.js +0 -128
- package/dist/durable/ClaudePrintRunner.js.map +0 -1
- package/dist/utils/ClaudeSessionParser.d.ts.map +0 -1
- package/dist/utils/ClaudeSessionParser.js.map +0 -1
- package/src/durable/ClaudePrintAgentService.ts +0 -94
- package/src/durable/ClaudePrintRunner.ts +0 -139
- /package/dist/{durable → providers/claude/durable}/ClaudeCliProbe.d.ts +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CodexPrintError } from '../../../durable/DurableAgent.js';
|
|
2
|
+
import { isUuid, LineBuffer } from '../../../durable/utils.js';
|
|
3
|
+
export class CodexStreamParser {
|
|
4
|
+
expectedSessionId;
|
|
5
|
+
onSession;
|
|
6
|
+
lines;
|
|
7
|
+
sessionId = null;
|
|
8
|
+
turnCompleted = false;
|
|
9
|
+
messages = [];
|
|
10
|
+
protocolError = null;
|
|
11
|
+
constructor(expectedSessionId, onSession, maxLineBytes){
|
|
12
|
+
this.expectedSessionId = expectedSessionId;
|
|
13
|
+
this.onSession = onSession;
|
|
14
|
+
this.lines = new LineBuffer(maxLineBytes, ()=>new CodexPrintError('Codex stream line exceeded the safety limit.', 'CODEX_PROTOCOL'));
|
|
15
|
+
}
|
|
16
|
+
hasFailed() {
|
|
17
|
+
return this.protocolError !== null;
|
|
18
|
+
}
|
|
19
|
+
async accept(chunk) {
|
|
20
|
+
for (const line of this.lines.accept(chunk)){
|
|
21
|
+
await this.processLine(line);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
fail(error) {
|
|
25
|
+
this.protocolError = error instanceof CodexPrintError ? error : new CodexPrintError('Codex stream processing failed.', 'CODEX_PROTOCOL');
|
|
26
|
+
}
|
|
27
|
+
result(close) {
|
|
28
|
+
if (this.protocolError) throw this.protocolError;
|
|
29
|
+
this.lines.assertComplete(()=>new CodexPrintError('Codex stream ended with incomplete JSON.', 'CODEX_PROTOCOL'));
|
|
30
|
+
if (close.code !== 0) {
|
|
31
|
+
throw new CodexPrintError(`Codex print run failed${close.signal ? ` (${close.signal})` : '.'}`, 'CODEX_PROCESS');
|
|
32
|
+
}
|
|
33
|
+
if (this.sessionId === null) throw new CodexPrintError('Codex stream ended without a thread identity.', 'CODEX_PROTOCOL');
|
|
34
|
+
if (!this.turnCompleted) throw new CodexPrintError('Codex stream ended before turn completion.', 'CODEX_PROTOCOL');
|
|
35
|
+
if (this.messages.length === 0) throw new CodexPrintError('Codex stream ended without an assistant result.', 'CODEX_RESULT_MISSING');
|
|
36
|
+
return {
|
|
37
|
+
sessionId: this.sessionId,
|
|
38
|
+
result: this.messages.at(-1),
|
|
39
|
+
messages: this.messages,
|
|
40
|
+
exitCode: close.code
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async processLine(line) {
|
|
44
|
+
if (this.protocolError || line.length === 0) return;
|
|
45
|
+
const event = this.parseEvent(line);
|
|
46
|
+
if (event.type === 'thread.started') {
|
|
47
|
+
await this.recordSession(event);
|
|
48
|
+
} else if (event.type === 'item.completed') {
|
|
49
|
+
this.recordAssistantMessage(event.item);
|
|
50
|
+
} else if (event.type === 'turn.completed') {
|
|
51
|
+
this.turnCompleted = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
parseEvent(line) {
|
|
55
|
+
let value;
|
|
56
|
+
try {
|
|
57
|
+
value = JSON.parse(line.toString('utf8'));
|
|
58
|
+
} catch {
|
|
59
|
+
throw new CodexPrintError('Codex emitted malformed stream JSON.', 'CODEX_PROTOCOL');
|
|
60
|
+
}
|
|
61
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
62
|
+
throw new CodexPrintError('Codex emitted a non-object stream message.', 'CODEX_PROTOCOL');
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
async recordSession(event) {
|
|
67
|
+
const sessionId = String(event.thread_id ?? '');
|
|
68
|
+
if (this.sessionId !== null || !isUuid(sessionId)) {
|
|
69
|
+
throw new CodexPrintError('Codex emitted an invalid thread identity.', 'CODEX_PROTOCOL');
|
|
70
|
+
}
|
|
71
|
+
if (this.expectedSessionId !== null && this.expectedSessionId !== sessionId) {
|
|
72
|
+
throw new CodexPrintError('Codex returned a different session identity.', 'CODEX_SESSION_MISMATCH');
|
|
73
|
+
}
|
|
74
|
+
this.sessionId = sessionId;
|
|
75
|
+
await this.onSession(sessionId);
|
|
76
|
+
}
|
|
77
|
+
recordAssistantMessage(item) {
|
|
78
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) return;
|
|
79
|
+
const record = item;
|
|
80
|
+
if (record.type === 'agent_message' && typeof record.text === 'string' && record.text.trim()) {
|
|
81
|
+
this.messages.push(record.text);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=CodexStreamParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/codex/durable/CodexStreamParser.ts"],"sourcesContent":["import { CodexPrintError } from '../../../durable/DurableAgent.js';\nimport { isUuid, LineBuffer, type ChildCloseResult } from '../../../durable/utils.js';\nimport type { CodexPrintRunResult } from './CodexPrintRunner.js';\n\nexport class CodexStreamParser {\n private readonly lines: LineBuffer;\n private sessionId: string | null = null;\n private turnCompleted = false;\n private readonly messages: string[] = [];\n private protocolError: CodexPrintError | null = null;\n\n constructor(\n private readonly expectedSessionId: string | null,\n private readonly onSession: (providerSessionId: string) => Promise<void>,\n maxLineBytes: number,\n ) {\n this.lines = new LineBuffer(\n maxLineBytes,\n () => new CodexPrintError('Codex stream line exceeded the safety limit.', 'CODEX_PROTOCOL'),\n );\n }\n\n hasFailed(): boolean {\n return this.protocolError !== null;\n }\n\n async accept(chunk: Buffer | string): Promise<void> {\n for (const line of this.lines.accept(chunk)) {\n await this.processLine(line);\n }\n }\n\n fail(error: unknown): void {\n this.protocolError = error instanceof CodexPrintError\n ? error\n : new CodexPrintError('Codex stream processing failed.', 'CODEX_PROTOCOL');\n }\n\n result(close: ChildCloseResult): CodexPrintRunResult {\n if (this.protocolError) throw this.protocolError;\n this.lines.assertComplete(\n () => new CodexPrintError('Codex stream ended with incomplete JSON.', 'CODEX_PROTOCOL'),\n );\n\n if (close.code !== 0) {\n throw new CodexPrintError(`Codex print run failed${close.signal ? ` (${close.signal})` : '.'}`, 'CODEX_PROCESS');\n }\n if (this.sessionId === null) throw new CodexPrintError('Codex stream ended without a thread identity.', 'CODEX_PROTOCOL');\n if (!this.turnCompleted) throw new CodexPrintError('Codex stream ended before turn completion.', 'CODEX_PROTOCOL');\n if (this.messages.length === 0) throw new CodexPrintError('Codex stream ended without an assistant result.', 'CODEX_RESULT_MISSING');\n return {\n sessionId: this.sessionId,\n result: this.messages.at(-1)!,\n messages: this.messages,\n exitCode: close.code,\n };\n }\n\n private async processLine(line: Buffer): Promise<void> {\n if (this.protocolError || line.length === 0) return;\n\n const event = this.parseEvent(line);\n if (event.type === 'thread.started') {\n await this.recordSession(event);\n } else if (event.type === 'item.completed') {\n this.recordAssistantMessage(event.item);\n } else if (event.type === 'turn.completed') {\n this.turnCompleted = true;\n }\n }\n\n private parseEvent(line: Buffer): Record<string, unknown> {\n let value: unknown;\n try {\n value = JSON.parse(line.toString('utf8'));\n } catch {\n throw new CodexPrintError('Codex emitted malformed stream JSON.', 'CODEX_PROTOCOL');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new CodexPrintError('Codex emitted a non-object stream message.', 'CODEX_PROTOCOL');\n }\n return value as Record<string, unknown>;\n }\n\n private async recordSession(event: Record<string, unknown>): Promise<void> {\n const sessionId = String(event.thread_id ?? '');\n if (this.sessionId !== null || !isUuid(sessionId)) {\n throw new CodexPrintError('Codex emitted an invalid thread identity.', 'CODEX_PROTOCOL');\n }\n if (this.expectedSessionId !== null && this.expectedSessionId !== sessionId) {\n throw new CodexPrintError('Codex returned a different session identity.', 'CODEX_SESSION_MISMATCH');\n }\n this.sessionId = sessionId;\n await this.onSession(sessionId);\n }\n\n private recordAssistantMessage(item: unknown): void {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return;\n const record = item as Record<string, unknown>;\n if (record.type === 'agent_message' && typeof record.text === 'string' && record.text.trim()) {\n this.messages.push(record.text);\n }\n }\n}\n"],"names":["CodexPrintError","isUuid","LineBuffer","CodexStreamParser","lines","sessionId","turnCompleted","messages","protocolError","expectedSessionId","onSession","maxLineBytes","hasFailed","accept","chunk","line","processLine","fail","error","result","close","assertComplete","code","signal","length","at","exitCode","event","parseEvent","type","recordSession","recordAssistantMessage","item","value","JSON","parse","toString","Array","isArray","String","thread_id","record","text","trim","push"],"mappings":"AAAA,SAASA,eAAe,QAAQ,mCAAmC;AACnE,SAASC,MAAM,EAAEC,UAAU,QAA+B,4BAA4B;AAGtF,OAAO,MAAMC;;;IACQC,MAAkB;IAC3BC,YAA2B,KAAK;IAChCC,gBAAgB,MAAM;IACbC,WAAqB,EAAE,CAAC;IACjCC,gBAAwC,KAAK;IAErD,YACI,AAAiBC,iBAAgC,EACjD,AAAiBC,SAAuD,EACxEC,YAAoB,CACtB;aAHmBF,oBAAAA;aACAC,YAAAA;QAGjB,IAAI,CAACN,KAAK,GAAG,IAAIF,WACbS,cACA,IAAM,IAAIX,gBAAgB,gDAAgD;IAElF;IAEAY,YAAqB;QACjB,OAAO,IAAI,CAACJ,aAAa,KAAK;IAClC;IAEA,MAAMK,OAAOC,KAAsB,EAAiB;QAChD,KAAK,MAAMC,QAAQ,IAAI,CAACX,KAAK,CAACS,MAAM,CAACC,OAAQ;YACzC,MAAM,IAAI,CAACE,WAAW,CAACD;QAC3B;IACJ;IAEAE,KAAKC,KAAc,EAAQ;QACvB,IAAI,CAACV,aAAa,GAAGU,iBAAiBlB,kBAChCkB,QACA,IAAIlB,gBAAgB,mCAAmC;IACjE;IAEAmB,OAAOC,KAAuB,EAAuB;QACjD,IAAI,IAAI,CAACZ,aAAa,EAAE,MAAM,IAAI,CAACA,aAAa;QAChD,IAAI,CAACJ,KAAK,CAACiB,cAAc,CACrB,IAAM,IAAIrB,gBAAgB,4CAA4C;QAG1E,IAAIoB,MAAME,IAAI,KAAK,GAAG;YAClB,MAAM,IAAItB,gBAAgB,CAAC,sBAAsB,EAAEoB,MAAMG,MAAM,GAAG,CAAC,EAAE,EAAEH,MAAMG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE;QACpG;QACA,IAAI,IAAI,CAAClB,SAAS,KAAK,MAAM,MAAM,IAAIL,gBAAgB,iDAAiD;QACxG,IAAI,CAAC,IAAI,CAACM,aAAa,EAAE,MAAM,IAAIN,gBAAgB,8CAA8C;QACjG,IAAI,IAAI,CAACO,QAAQ,CAACiB,MAAM,KAAK,GAAG,MAAM,IAAIxB,gBAAgB,mDAAmD;QAC7G,OAAO;YACHK,WAAW,IAAI,CAACA,SAAS;YACzBc,QAAQ,IAAI,CAACZ,QAAQ,CAACkB,EAAE,CAAC,CAAC;YAC1BlB,UAAU,IAAI,CAACA,QAAQ;YACvBmB,UAAUN,MAAME,IAAI;QACxB;IACJ;IAEA,MAAcN,YAAYD,IAAY,EAAiB;QACnD,IAAI,IAAI,CAACP,aAAa,IAAIO,KAAKS,MAAM,KAAK,GAAG;QAE7C,MAAMG,QAAQ,IAAI,CAACC,UAAU,CAACb;QAC9B,IAAIY,MAAME,IAAI,KAAK,kBAAkB;YACjC,MAAM,IAAI,CAACC,aAAa,CAACH;QAC7B,OAAO,IAAIA,MAAME,IAAI,KAAK,kBAAkB;YACxC,IAAI,CAACE,sBAAsB,CAACJ,MAAMK,IAAI;QAC1C,OAAO,IAAIL,MAAME,IAAI,KAAK,kBAAkB;YACxC,IAAI,CAACvB,aAAa,GAAG;QACzB;IACJ;IAEQsB,WAAWb,IAAY,EAA2B;QACtD,IAAIkB;QACJ,IAAI;YACAA,QAAQC,KAAKC,KAAK,CAACpB,KAAKqB,QAAQ,CAAC;QACrC,EAAE,OAAM;YACJ,MAAM,IAAIpC,gBAAgB,wCAAwC;QACtE;QACA,IAAI,CAACiC,SAAS,OAAOA,UAAU,YAAYI,MAAMC,OAAO,CAACL,QAAQ;YAC7D,MAAM,IAAIjC,gBAAgB,8CAA8C;QAC5E;QACA,OAAOiC;IACX;IAEA,MAAcH,cAAcH,KAA8B,EAAiB;QACvE,MAAMtB,YAAYkC,OAAOZ,MAAMa,SAAS,IAAI;QAC5C,IAAI,IAAI,CAACnC,SAAS,KAAK,QAAQ,CAACJ,OAAOI,YAAY;YAC/C,MAAM,IAAIL,gBAAgB,6CAA6C;QAC3E;QACA,IAAI,IAAI,CAACS,iBAAiB,KAAK,QAAQ,IAAI,CAACA,iBAAiB,KAAKJ,WAAW;YACzE,MAAM,IAAIL,gBAAgB,gDAAgD;QAC9E;QACA,IAAI,CAACK,SAAS,GAAGA;QACjB,MAAM,IAAI,CAACK,SAAS,CAACL;IACzB;IAEQ0B,uBAAuBC,IAAa,EAAQ;QAChD,IAAI,CAACA,QAAQ,OAAOA,SAAS,YAAYK,MAAMC,OAAO,CAACN,OAAO;QAC9D,MAAMS,SAAST;QACf,IAAIS,OAAOZ,IAAI,KAAK,mBAAmB,OAAOY,OAAOC,IAAI,KAAK,YAAYD,OAAOC,IAAI,CAACC,IAAI,IAAI;YAC1F,IAAI,CAACpC,QAAQ,CAACqC,IAAI,CAACH,OAAOC,IAAI;QAClC;IACJ;AACJ"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type ExecResult = {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
};
|
|
5
|
+
type Exec = (file: string, args: string[]) => Promise<ExecResult>;
|
|
6
|
+
export interface PiCliProbeOptions {
|
|
7
|
+
executable?: string;
|
|
8
|
+
exec?: Exec;
|
|
9
|
+
}
|
|
10
|
+
export declare class PiCliProbe {
|
|
11
|
+
private readonly executable;
|
|
12
|
+
private readonly exec;
|
|
13
|
+
constructor(options?: PiCliProbeOptions);
|
|
14
|
+
validate(): Promise<{
|
|
15
|
+
executable: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=PiCliProbe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PiCliProbe.d.ts","sourceRoot":"","sources":["../../../../src/providers/pi/durable/PiCliProbe.ts"],"names":[],"mappings":"AAKA,KAAK,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrD,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAIlE,MAAM,WAAW,iBAAiB;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;CACf;AAED,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;gBAEhB,OAAO,GAAE,iBAAsB;IAQrC,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAoBrE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { execFile } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { PiPrintError } from '../../../durable/DurableAgent.js';
|
|
4
|
+
import { sanitizeText } from '../../../durable/utils.js';
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
const REQUIRED = [
|
|
7
|
+
'--mode',
|
|
8
|
+
'json',
|
|
9
|
+
'--session-id',
|
|
10
|
+
'--session'
|
|
11
|
+
];
|
|
12
|
+
export class PiCliProbe {
|
|
13
|
+
executable;
|
|
14
|
+
exec;
|
|
15
|
+
constructor(options = {}){
|
|
16
|
+
this.executable = options.executable ?? 'pi';
|
|
17
|
+
this.exec = options.exec ?? (async (file, args)=>{
|
|
18
|
+
const result = await execFileAsync(file, args, {
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
maxBuffer: 1024 * 1024
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
stdout: result.stdout,
|
|
24
|
+
stderr: result.stderr
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async validate() {
|
|
29
|
+
try {
|
|
30
|
+
const version = await this.exec(this.executable, [
|
|
31
|
+
'--version'
|
|
32
|
+
]);
|
|
33
|
+
const help = await this.exec(this.executable, [
|
|
34
|
+
'--help'
|
|
35
|
+
]);
|
|
36
|
+
const missing = REQUIRED.filter((capability)=>!help.stdout.includes(capability));
|
|
37
|
+
if (missing.length > 0) {
|
|
38
|
+
throw new PiPrintError(`Pi CLI does not support required print-mode capabilities: ${missing.join(', ')}.`, 'PI_CLI_UNSUPPORTED');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
executable: this.executable,
|
|
42
|
+
version: sanitizeText(version.stdout, 256) || 'unknown'
|
|
43
|
+
};
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof PiPrintError) throw error;
|
|
46
|
+
throw new PiPrintError(`Pi CLI validation failed: ${sanitizeText(error.message, 512)}`, 'PI_CLI_UNAVAILABLE');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=PiCliProbe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/pi/durable/PiCliProbe.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { PiPrintError } from '../../../durable/DurableAgent.js';\nimport { sanitizeText } from '../../../durable/utils.js';\n\ntype ExecResult = { stdout: string; stderr: string };\ntype Exec = (file: string, args: string[]) => Promise<ExecResult>;\nconst execFileAsync = promisify(execFile);\nconst REQUIRED = ['--mode', 'json', '--session-id', '--session'];\n\nexport interface PiCliProbeOptions {\n executable?: string;\n exec?: Exec;\n}\n\nexport class PiCliProbe {\n private readonly executable: string;\n private readonly exec: Exec;\n\n constructor(options: PiCliProbeOptions = {}) {\n this.executable = options.executable ?? 'pi';\n this.exec = options.exec ?? (async (file, args) => {\n const result = await execFileAsync(file, args, { encoding: 'utf8', maxBuffer: 1024 * 1024 });\n return { stdout: result.stdout, stderr: result.stderr };\n });\n }\n\n async validate(): Promise<{ executable: string; version: string }> {\n try {\n const version = await this.exec(this.executable, ['--version']);\n const help = await this.exec(this.executable, ['--help']);\n const missing = REQUIRED.filter((capability) => !help.stdout.includes(capability));\n if (missing.length > 0) {\n throw new PiPrintError(\n `Pi CLI does not support required print-mode capabilities: ${missing.join(', ')}.`,\n 'PI_CLI_UNSUPPORTED',\n );\n }\n return { executable: this.executable, version: sanitizeText(version.stdout, 256) || 'unknown' };\n } catch (error) {\n if (error instanceof PiPrintError) throw error;\n throw new PiPrintError(\n `Pi CLI validation failed: ${sanitizeText((error as Error).message, 512)}`,\n 'PI_CLI_UNAVAILABLE',\n );\n }\n }\n}\n"],"names":["execFile","promisify","PiPrintError","sanitizeText","execFileAsync","REQUIRED","PiCliProbe","executable","exec","options","file","args","result","encoding","maxBuffer","stdout","stderr","validate","version","help","missing","filter","capability","includes","length","join","error","message"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,SAAS,QAAQ,OAAO;AACjC,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,YAAY,QAAQ,4BAA4B;AAIzD,MAAMC,gBAAgBH,UAAUD;AAChC,MAAMK,WAAW;IAAC;IAAU;IAAQ;IAAgB;CAAY;AAOhE,OAAO,MAAMC;IACQC,WAAmB;IACnBC,KAAW;IAE5B,YAAYC,UAA6B,CAAC,CAAC,CAAE;QACzC,IAAI,CAACF,UAAU,GAAGE,QAAQF,UAAU,IAAI;QACxC,IAAI,CAACC,IAAI,GAAGC,QAAQD,IAAI,IAAK,CAAA,OAAOE,MAAMC;YACtC,MAAMC,SAAS,MAAMR,cAAcM,MAAMC,MAAM;gBAAEE,UAAU;gBAAQC,WAAW,OAAO;YAAK;YAC1F,OAAO;gBAAEC,QAAQH,OAAOG,MAAM;gBAAEC,QAAQJ,OAAOI,MAAM;YAAC;QAC1D,CAAA;IACJ;IAEA,MAAMC,WAA6D;QAC/D,IAAI;YACA,MAAMC,UAAU,MAAM,IAAI,CAACV,IAAI,CAAC,IAAI,CAACD,UAAU,EAAE;gBAAC;aAAY;YAC9D,MAAMY,OAAO,MAAM,IAAI,CAACX,IAAI,CAAC,IAAI,CAACD,UAAU,EAAE;gBAAC;aAAS;YACxD,MAAMa,UAAUf,SAASgB,MAAM,CAAC,CAACC,aAAe,CAACH,KAAKJ,MAAM,CAACQ,QAAQ,CAACD;YACtE,IAAIF,QAAQI,MAAM,GAAG,GAAG;gBACpB,MAAM,IAAItB,aACN,CAAC,0DAA0D,EAAEkB,QAAQK,IAAI,CAAC,MAAM,CAAC,CAAC,EAClF;YAER;YACA,OAAO;gBAAElB,YAAY,IAAI,CAACA,UAAU;gBAAEW,SAASf,aAAae,QAAQH,MAAM,EAAE,QAAQ;YAAU;QAClG,EAAE,OAAOW,OAAO;YACZ,IAAIA,iBAAiBxB,cAAc,MAAMwB;YACzC,MAAM,IAAIxB,aACN,CAAC,0BAA0B,EAAEC,aAAa,AAACuB,MAAgBC,OAAO,EAAE,MAAM,EAC1E;QAER;IACJ;AACJ"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { DurableAgent, ProcessIdentity } from '../../../durable/DurableAgent.js';
|
|
2
|
+
import { PiPrintRunner, type PiPrintRunResult } from './PiPrintRunner.js';
|
|
3
|
+
import { type CreateDurableAgentInput } from '../../../durable/DurableAgentRepository.js';
|
|
4
|
+
import { type DurableRunRepository } from '../../../durable/run.js';
|
|
5
|
+
interface RepositoryLike extends DurableRunRepository {
|
|
6
|
+
create(input: CreateDurableAgentInput): Promise<DurableAgent>;
|
|
7
|
+
list(): Promise<DurableAgent[]>;
|
|
8
|
+
recordProviderProcess(id: string, token: string, identity: ProcessIdentity): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
interface ProbeLike {
|
|
11
|
+
validate(): Promise<{
|
|
12
|
+
executable: string;
|
|
13
|
+
version: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
interface RunnerLike {
|
|
17
|
+
run(request: Parameters<PiPrintRunner['run']>[0]): Promise<PiPrintRunResult>;
|
|
18
|
+
}
|
|
19
|
+
export interface PiPrintAgentServiceOptions {
|
|
20
|
+
repository?: RepositoryLike;
|
|
21
|
+
probe?: ProbeLike;
|
|
22
|
+
runner?: RunnerLike;
|
|
23
|
+
executable?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface PiPrintSendResult extends PiPrintRunResult {
|
|
26
|
+
agentId: string;
|
|
27
|
+
agentName: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class PiPrintAgentService {
|
|
30
|
+
readonly repository: RepositoryLike;
|
|
31
|
+
private readonly probe;
|
|
32
|
+
private readonly runner;
|
|
33
|
+
private readonly executable?;
|
|
34
|
+
constructor(options?: PiPrintAgentServiceOptions);
|
|
35
|
+
create(input: Omit<CreateDurableAgentInput, 'provider'>): Promise<DurableAgent>;
|
|
36
|
+
send(reference: string, prompt: string): Promise<PiPrintSendResult>;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=PiPrintAgentService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PiPrintAgentService.d.ts","sourceRoot":"","sources":["../../../../src/providers/pi/durable/PiPrintAgentService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGtF,OAAO,EAAE,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAA0B,KAAK,uBAAuB,EAAE,MAAM,4CAA4C,CAAC;AAClH,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAErF,UAAU,cAAe,SAAQ,oBAAoB;IACjD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9D,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChC,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9F;AAED,UAAU,SAAS;IAAG,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;AACpF,UAAU,UAAU;IAAG,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;CAAE;AAErG,MAAM,WAAW,0BAA0B;IACvC,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,mBAAmB;IAC5B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;gBAEzB,OAAO,GAAE,0BAA+B;IAO9C,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,uBAAuB,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAK/E,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAsB5E"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { PiPrintError } from '../../../durable/DurableAgent.js';
|
|
2
|
+
import { PiCliProbe } from './PiCliProbe.js';
|
|
3
|
+
import { PiPrintRunner } from './PiPrintRunner.js';
|
|
4
|
+
import { DurableAgentRepository } from '../../../durable/DurableAgentRepository.js';
|
|
5
|
+
import { runDurableAgent } from '../../../durable/run.js';
|
|
6
|
+
export class PiPrintAgentService {
|
|
7
|
+
repository;
|
|
8
|
+
probe;
|
|
9
|
+
runner;
|
|
10
|
+
executable;
|
|
11
|
+
constructor(options = {}){
|
|
12
|
+
this.repository = options.repository ?? new DurableAgentRepository();
|
|
13
|
+
this.probe = options.probe ?? new PiCliProbe();
|
|
14
|
+
this.runner = options.runner ?? new PiPrintRunner();
|
|
15
|
+
this.executable = options.executable;
|
|
16
|
+
}
|
|
17
|
+
async create(input) {
|
|
18
|
+
await this.probe.validate();
|
|
19
|
+
return this.repository.create({
|
|
20
|
+
...input,
|
|
21
|
+
provider: 'pi'
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async send(reference, prompt) {
|
|
25
|
+
const completed = await runDurableAgent({
|
|
26
|
+
reference,
|
|
27
|
+
provider: 'pi',
|
|
28
|
+
repository: this.repository,
|
|
29
|
+
ambiguousError: ()=>new PiPrintError('Multiple print agents match.', 'PI_UNSUPPORTED'),
|
|
30
|
+
providerError: ()=>new PiPrintError('Print agent provider is not Pi.', 'PI_UNSUPPORTED'),
|
|
31
|
+
execute: (agent, token)=>this.runner.run({
|
|
32
|
+
agent,
|
|
33
|
+
prompt,
|
|
34
|
+
executable: this.executable,
|
|
35
|
+
onSpawn: (identity)=>this.repository.recordProviderProcess(agent.id, token, identity)
|
|
36
|
+
}),
|
|
37
|
+
isSessionMismatch: (error)=>error instanceof PiPrintError && error.code === 'PI_SESSION_MISMATCH'
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
...completed.result,
|
|
41
|
+
agentId: completed.agent.id,
|
|
42
|
+
agentName: completed.agent.name
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=PiPrintAgentService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/pi/durable/PiPrintAgentService.ts"],"sourcesContent":["import type { DurableAgent, ProcessIdentity } from '../../../durable/DurableAgent.js';\nimport { PiPrintError } from '../../../durable/DurableAgent.js';\nimport { PiCliProbe } from './PiCliProbe.js';\nimport { PiPrintRunner, type PiPrintRunResult } from './PiPrintRunner.js';\nimport { DurableAgentRepository, type CreateDurableAgentInput } from '../../../durable/DurableAgentRepository.js';\nimport { runDurableAgent, type DurableRunRepository } from '../../../durable/run.js';\n\ninterface RepositoryLike extends DurableRunRepository {\n create(input: CreateDurableAgentInput): Promise<DurableAgent>;\n list(): Promise<DurableAgent[]>;\n recordProviderProcess(id: string, token: string, identity: ProcessIdentity): Promise<void>;\n}\n\ninterface ProbeLike { validate(): Promise<{ executable: string; version: string }> }\ninterface RunnerLike { run(request: Parameters<PiPrintRunner['run']>[0]): Promise<PiPrintRunResult> }\n\nexport interface PiPrintAgentServiceOptions {\n repository?: RepositoryLike;\n probe?: ProbeLike;\n runner?: RunnerLike;\n executable?: string;\n}\n\nexport interface PiPrintSendResult extends PiPrintRunResult {\n agentId: string;\n agentName: string;\n}\n\nexport class PiPrintAgentService {\n readonly repository: RepositoryLike;\n private readonly probe: ProbeLike;\n private readonly runner: RunnerLike;\n private readonly executable?: string;\n\n constructor(options: PiPrintAgentServiceOptions = {}) {\n this.repository = options.repository ?? new DurableAgentRepository();\n this.probe = options.probe ?? new PiCliProbe();\n this.runner = options.runner ?? new PiPrintRunner();\n this.executable = options.executable;\n }\n\n async create(input: Omit<CreateDurableAgentInput, 'provider'>): Promise<DurableAgent> {\n await this.probe.validate();\n return this.repository.create({ ...input, provider: 'pi' });\n }\n\n async send(reference: string, prompt: string): Promise<PiPrintSendResult> {\n const completed = await runDurableAgent({\n reference,\n provider: 'pi',\n repository: this.repository,\n ambiguousError: () => new PiPrintError('Multiple print agents match.', 'PI_UNSUPPORTED'),\n providerError: () => new PiPrintError('Print agent provider is not Pi.', 'PI_UNSUPPORTED'),\n execute: (agent, token) => this.runner.run({\n agent,\n prompt,\n executable: this.executable,\n onSpawn: (identity) => this.repository.recordProviderProcess(agent.id, token, identity),\n }),\n isSessionMismatch: (error) => error instanceof PiPrintError\n && error.code === 'PI_SESSION_MISMATCH',\n });\n return {\n ...completed.result,\n agentId: completed.agent.id,\n agentName: completed.agent.name,\n };\n }\n}\n"],"names":["PiPrintError","PiCliProbe","PiPrintRunner","DurableAgentRepository","runDurableAgent","PiPrintAgentService","repository","probe","runner","executable","options","create","input","validate","provider","send","reference","prompt","completed","ambiguousError","providerError","execute","agent","token","run","onSpawn","identity","recordProviderProcess","id","isSessionMismatch","error","code","result","agentId","agentName","name"],"mappings":"AACA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,aAAa,QAA+B,qBAAqB;AAC1E,SAASC,sBAAsB,QAAsC,6CAA6C;AAClH,SAASC,eAAe,QAAmC,0BAA0B;AAuBrF,OAAO,MAAMC;IACAC,WAA2B;IACnBC,MAAiB;IACjBC,OAAmB;IACnBC,WAAoB;IAErC,YAAYC,UAAsC,CAAC,CAAC,CAAE;QAClD,IAAI,CAACJ,UAAU,GAAGI,QAAQJ,UAAU,IAAI,IAAIH;QAC5C,IAAI,CAACI,KAAK,GAAGG,QAAQH,KAAK,IAAI,IAAIN;QAClC,IAAI,CAACO,MAAM,GAAGE,QAAQF,MAAM,IAAI,IAAIN;QACpC,IAAI,CAACO,UAAU,GAAGC,QAAQD,UAAU;IACxC;IAEA,MAAME,OAAOC,KAAgD,EAAyB;QAClF,MAAM,IAAI,CAACL,KAAK,CAACM,QAAQ;QACzB,OAAO,IAAI,CAACP,UAAU,CAACK,MAAM,CAAC;YAAE,GAAGC,KAAK;YAAEE,UAAU;QAAK;IAC7D;IAEA,MAAMC,KAAKC,SAAiB,EAAEC,MAAc,EAA8B;QACtE,MAAMC,YAAY,MAAMd,gBAAgB;YACpCY;YACAF,UAAU;YACVR,YAAY,IAAI,CAACA,UAAU;YAC3Ba,gBAAgB,IAAM,IAAInB,aAAa,gCAAgC;YACvEoB,eAAe,IAAM,IAAIpB,aAAa,mCAAmC;YACzEqB,SAAS,CAACC,OAAOC,QAAU,IAAI,CAACf,MAAM,CAACgB,GAAG,CAAC;oBACvCF;oBACAL;oBACAR,YAAY,IAAI,CAACA,UAAU;oBAC3BgB,SAAS,CAACC,WAAa,IAAI,CAACpB,UAAU,CAACqB,qBAAqB,CAACL,MAAMM,EAAE,EAAEL,OAAOG;gBAClF;YACAG,mBAAmB,CAACC,QAAUA,iBAAiB9B,gBACxC8B,MAAMC,IAAI,KAAK;QAC1B;QACA,OAAO;YACH,GAAGb,UAAUc,MAAM;YACnBC,SAASf,UAAUI,KAAK,CAACM,EAAE;YAC3BM,WAAWhB,UAAUI,KAAK,CAACa,IAAI;QACnC;IACJ;AACJ"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function buildPiPrintArgs(providerSessionId: string, firstRun: boolean): string[];
|
|
2
|
+
export declare function readPiSessionId(event: Record<string, unknown>, currentSessionId: string | null, expectedSessionId: string): string;
|
|
3
|
+
export declare function readPiAssistantText(event: Record<string, unknown>): string | null;
|
|
4
|
+
//# sourceMappingURL=PiPrintProtocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PiPrintProtocol.d.ts","sourceRoot":"","sources":["../../../../src/providers/pi/durable/PiPrintProtocol.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAIvF;AAED,wBAAgB,eAAe,CAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,EAC/B,iBAAiB,EAAE,MAAM,GAC1B,MAAM,CASR;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAcjF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PiPrintError } from '../../../durable/DurableAgent.js';
|
|
2
|
+
import { isUuid } from '../../../durable/utils.js';
|
|
3
|
+
export function buildPiPrintArgs(providerSessionId, firstRun) {
|
|
4
|
+
return firstRun ? [
|
|
5
|
+
'--mode',
|
|
6
|
+
'json',
|
|
7
|
+
'--session-id',
|
|
8
|
+
providerSessionId
|
|
9
|
+
] : [
|
|
10
|
+
'--mode',
|
|
11
|
+
'json',
|
|
12
|
+
'--session',
|
|
13
|
+
providerSessionId
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
export function readPiSessionId(event, currentSessionId, expectedSessionId) {
|
|
17
|
+
if (currentSessionId !== null || typeof event.id !== 'string' || !isUuid(event.id)) {
|
|
18
|
+
throw new PiPrintError('Pi emitted an invalid session identity.', 'PI_PROTOCOL');
|
|
19
|
+
}
|
|
20
|
+
const sessionId = event.id;
|
|
21
|
+
if (expectedSessionId !== sessionId) {
|
|
22
|
+
throw new PiPrintError('Pi returned a different session identity.', 'PI_SESSION_MISMATCH');
|
|
23
|
+
}
|
|
24
|
+
return sessionId;
|
|
25
|
+
}
|
|
26
|
+
export function readPiAssistantText(event) {
|
|
27
|
+
if (event.type !== 'message_end') return null;
|
|
28
|
+
const message = event.message;
|
|
29
|
+
if (!message || typeof message !== 'object' || Array.isArray(message)) return null;
|
|
30
|
+
const record = message;
|
|
31
|
+
if (record.role !== 'assistant') return null;
|
|
32
|
+
if (typeof record.content === 'string') return record.content.trim() ? record.content : null;
|
|
33
|
+
if (!Array.isArray(record.content)) return null;
|
|
34
|
+
const text = record.content.flatMap((part)=>{
|
|
35
|
+
if (!part || typeof part !== 'object' || Array.isArray(part)) return [];
|
|
36
|
+
const block = part;
|
|
37
|
+
return block.type === 'text' && typeof block.text === 'string' ? [
|
|
38
|
+
block.text
|
|
39
|
+
] : [];
|
|
40
|
+
}).join('');
|
|
41
|
+
return text.trim() ? text : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=PiPrintProtocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/pi/durable/PiPrintProtocol.ts"],"sourcesContent":["import { PiPrintError } from '../../../durable/DurableAgent.js';\nimport { isUuid } from '../../../durable/utils.js';\n\nexport function buildPiPrintArgs(providerSessionId: string, firstRun: boolean): string[] {\n return firstRun\n ? ['--mode', 'json', '--session-id', providerSessionId]\n : ['--mode', 'json', '--session', providerSessionId];\n}\n\nexport function readPiSessionId(\n event: Record<string, unknown>,\n currentSessionId: string | null,\n expectedSessionId: string,\n): string {\n if (currentSessionId !== null || typeof event.id !== 'string' || !isUuid(event.id)) {\n throw new PiPrintError('Pi emitted an invalid session identity.', 'PI_PROTOCOL');\n }\n const sessionId = event.id;\n if (expectedSessionId !== sessionId) {\n throw new PiPrintError('Pi returned a different session identity.', 'PI_SESSION_MISMATCH');\n }\n return sessionId;\n}\n\nexport function readPiAssistantText(event: Record<string, unknown>): string | null {\n if (event.type !== 'message_end') return null;\n const message = event.message;\n if (!message || typeof message !== 'object' || Array.isArray(message)) return null;\n const record = message as Record<string, unknown>;\n if (record.role !== 'assistant') return null;\n if (typeof record.content === 'string') return record.content.trim() ? record.content : null;\n if (!Array.isArray(record.content)) return null;\n const text = record.content.flatMap((part) => {\n if (!part || typeof part !== 'object' || Array.isArray(part)) return [];\n const block = part as Record<string, unknown>;\n return block.type === 'text' && typeof block.text === 'string' ? [block.text] : [];\n }).join('');\n return text.trim() ? text : null;\n}\n"],"names":["PiPrintError","isUuid","buildPiPrintArgs","providerSessionId","firstRun","readPiSessionId","event","currentSessionId","expectedSessionId","id","sessionId","readPiAssistantText","type","message","Array","isArray","record","role","content","trim","text","flatMap","part","block","join"],"mappings":"AAAA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,MAAM,QAAQ,4BAA4B;AAEnD,OAAO,SAASC,iBAAiBC,iBAAyB,EAAEC,QAAiB;IACzE,OAAOA,WACD;QAAC;QAAU;QAAQ;QAAgBD;KAAkB,GACrD;QAAC;QAAU;QAAQ;QAAaA;KAAkB;AAC5D;AAEA,OAAO,SAASE,gBACZC,KAA8B,EAC9BC,gBAA+B,EAC/BC,iBAAyB;IAEzB,IAAID,qBAAqB,QAAQ,OAAOD,MAAMG,EAAE,KAAK,YAAY,CAACR,OAAOK,MAAMG,EAAE,GAAG;QAChF,MAAM,IAAIT,aAAa,2CAA2C;IACtE;IACA,MAAMU,YAAYJ,MAAMG,EAAE;IAC1B,IAAID,sBAAsBE,WAAW;QACjC,MAAM,IAAIV,aAAa,6CAA6C;IACxE;IACA,OAAOU;AACX;AAEA,OAAO,SAASC,oBAAoBL,KAA8B;IAC9D,IAAIA,MAAMM,IAAI,KAAK,eAAe,OAAO;IACzC,MAAMC,UAAUP,MAAMO,OAAO;IAC7B,IAAI,CAACA,WAAW,OAAOA,YAAY,YAAYC,MAAMC,OAAO,CAACF,UAAU,OAAO;IAC9E,MAAMG,SAASH;IACf,IAAIG,OAAOC,IAAI,KAAK,aAAa,OAAO;IACxC,IAAI,OAAOD,OAAOE,OAAO,KAAK,UAAU,OAAOF,OAAOE,OAAO,CAACC,IAAI,KAAKH,OAAOE,OAAO,GAAG;IACxF,IAAI,CAACJ,MAAMC,OAAO,CAACC,OAAOE,OAAO,GAAG,OAAO;IAC3C,MAAME,OAAOJ,OAAOE,OAAO,CAACG,OAAO,CAAC,CAACC;QACjC,IAAI,CAACA,QAAQ,OAAOA,SAAS,YAAYR,MAAMC,OAAO,CAACO,OAAO,OAAO,EAAE;QACvE,MAAMC,QAAQD;QACd,OAAOC,MAAMX,IAAI,KAAK,UAAU,OAAOW,MAAMH,IAAI,KAAK,WAAW;YAACG,MAAMH,IAAI;SAAC,GAAG,EAAE;IACtF,GAAGI,IAAI,CAAC;IACR,OAAOJ,KAAKD,IAAI,KAAKC,OAAO;AAChC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ChildProcessWithoutNullStreams, type SpawnOptionsWithoutStdio } from 'child_process';
|
|
2
|
+
import type { PiDurableAgent, ProcessIdentity } from '../../../durable/DurableAgent.js';
|
|
3
|
+
import { type ProcessInspector } from '../../../durable/process.js';
|
|
4
|
+
type Spawn = (command: string, args: readonly string[], options: SpawnOptionsWithoutStdio & {
|
|
5
|
+
stdio: ['pipe', 'pipe', 'pipe'];
|
|
6
|
+
}) => ChildProcessWithoutNullStreams;
|
|
7
|
+
export interface PiPrintRunRequest {
|
|
8
|
+
agent: PiDurableAgent;
|
|
9
|
+
prompt: string;
|
|
10
|
+
executable?: string;
|
|
11
|
+
onSpawn(identity: ProcessIdentity): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export interface PiPrintRunResult {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
result: string;
|
|
16
|
+
messages: string[];
|
|
17
|
+
exitCode: number;
|
|
18
|
+
}
|
|
19
|
+
export interface PiPrintRunnerOptions {
|
|
20
|
+
spawn?: Spawn;
|
|
21
|
+
processInspector?: ProcessInspector;
|
|
22
|
+
maxLineBytes?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare class PiPrintRunner {
|
|
25
|
+
private readonly spawn;
|
|
26
|
+
private readonly processInspector;
|
|
27
|
+
private readonly maxLineBytes;
|
|
28
|
+
constructor(options?: PiPrintRunnerOptions);
|
|
29
|
+
run(request: PiPrintRunRequest): Promise<PiPrintRunResult>;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=PiPrintRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PiPrintRunner.d.ts","sourceRoot":"","sources":["../../../../src/providers/pi/durable/PiPrintRunner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,8BAA8B,EAAE,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACvH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExF,OAAO,EAAyB,KAAK,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAK3F,KAAK,KAAK,GAAG,CACT,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,wBAAwB,GAAG;IAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KACtE,8BAA8B,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAC9B,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,OAAO,GAAE,oBAAyB;IAMxC,GAAG,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA0CnE"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { spawn as nodeSpawn } from 'child_process';
|
|
2
|
+
import { PiPrintError } from '../../../durable/DurableAgent.js';
|
|
3
|
+
import { LocalProcessInspector } from '../../../durable/process.js';
|
|
4
|
+
import { waitForChildClose } from '../../../durable/utils.js';
|
|
5
|
+
import { buildPiPrintArgs } from './PiPrintProtocol.js';
|
|
6
|
+
import { PiStreamParser } from './PiStreamParser.js';
|
|
7
|
+
export class PiPrintRunner {
|
|
8
|
+
spawn;
|
|
9
|
+
processInspector;
|
|
10
|
+
maxLineBytes;
|
|
11
|
+
constructor(options = {}){
|
|
12
|
+
this.spawn = options.spawn ?? nodeSpawn;
|
|
13
|
+
this.processInspector = options.processInspector ?? new LocalProcessInspector();
|
|
14
|
+
this.maxLineBytes = options.maxLineBytes ?? 1024 * 1024;
|
|
15
|
+
}
|
|
16
|
+
async run(request) {
|
|
17
|
+
const args = buildPiPrintArgs(request.agent.providerSessionId, request.agent.sessionHealth === 'uninitialized');
|
|
18
|
+
const child = this.spawn(request.executable ?? 'pi', args, {
|
|
19
|
+
cwd: request.agent.cwd,
|
|
20
|
+
shell: false,
|
|
21
|
+
stdio: [
|
|
22
|
+
'pipe',
|
|
23
|
+
'pipe',
|
|
24
|
+
'pipe'
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
if (!child.pid) {
|
|
28
|
+
child.kill();
|
|
29
|
+
throw new PiPrintError('Pi process did not provide a PID.', 'PI_PROCESS');
|
|
30
|
+
}
|
|
31
|
+
const identity = this.processInspector.getIdentity(child.pid);
|
|
32
|
+
if (!identity) {
|
|
33
|
+
child.kill();
|
|
34
|
+
throw new PiPrintError('Cannot verify Pi process identity.', 'PI_PROCESS');
|
|
35
|
+
}
|
|
36
|
+
const parser = new PiStreamParser(request.agent.providerSessionId, this.maxLineBytes);
|
|
37
|
+
child.stdout.on('data', (chunk)=>{
|
|
38
|
+
if (parser.hasFailed()) return;
|
|
39
|
+
try {
|
|
40
|
+
parser.accept(chunk);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
parser.fail(error);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
child.stderr.resume();
|
|
46
|
+
const closed = waitForChildClose(child);
|
|
47
|
+
try {
|
|
48
|
+
await request.onSpawn(identity);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
child.kill();
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
child.stdin.end(request.prompt);
|
|
54
|
+
const close = await closed.catch(()=>{
|
|
55
|
+
throw new PiPrintError('Pi process failed to start or communicate.', 'PI_PROCESS');
|
|
56
|
+
});
|
|
57
|
+
return parser.result(close);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=PiPrintRunner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/pi/durable/PiPrintRunner.ts"],"sourcesContent":["import { spawn as nodeSpawn, type ChildProcessWithoutNullStreams, type SpawnOptionsWithoutStdio } from 'child_process';\nimport type { PiDurableAgent, ProcessIdentity } from '../../../durable/DurableAgent.js';\nimport { PiPrintError } from '../../../durable/DurableAgent.js';\nimport { LocalProcessInspector, type ProcessInspector } from '../../../durable/process.js';\nimport { waitForChildClose } from '../../../durable/utils.js';\nimport { buildPiPrintArgs } from './PiPrintProtocol.js';\nimport { PiStreamParser } from './PiStreamParser.js';\n\ntype Spawn = (\n command: string,\n args: readonly string[],\n options: SpawnOptionsWithoutStdio & { stdio: ['pipe', 'pipe', 'pipe'] },\n) => ChildProcessWithoutNullStreams;\n\nexport interface PiPrintRunRequest {\n agent: PiDurableAgent;\n prompt: string;\n executable?: string;\n onSpawn(identity: ProcessIdentity): Promise<void>;\n}\n\nexport interface PiPrintRunResult {\n sessionId: string;\n result: string;\n messages: string[];\n exitCode: number;\n}\n\nexport interface PiPrintRunnerOptions {\n spawn?: Spawn;\n processInspector?: ProcessInspector;\n maxLineBytes?: number;\n}\n\nexport class PiPrintRunner {\n private readonly spawn: Spawn;\n private readonly processInspector: ProcessInspector;\n private readonly maxLineBytes: number;\n\n constructor(options: PiPrintRunnerOptions = {}) {\n this.spawn = options.spawn ?? (nodeSpawn as Spawn);\n this.processInspector = options.processInspector ?? new LocalProcessInspector();\n this.maxLineBytes = options.maxLineBytes ?? 1024 * 1024;\n }\n\n async run(request: PiPrintRunRequest): Promise<PiPrintRunResult> {\n const args = buildPiPrintArgs(request.agent.providerSessionId, request.agent.sessionHealth === 'uninitialized');\n const child = this.spawn(request.executable ?? 'pi', args, {\n cwd: request.agent.cwd,\n shell: false,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n if (!child.pid) {\n child.kill();\n throw new PiPrintError('Pi process did not provide a PID.', 'PI_PROCESS');\n }\n const identity = this.processInspector.getIdentity(child.pid);\n if (!identity) {\n child.kill();\n throw new PiPrintError('Cannot verify Pi process identity.', 'PI_PROCESS');\n }\n\n const parser = new PiStreamParser(request.agent.providerSessionId, this.maxLineBytes);\n child.stdout.on('data', (chunk: Buffer | string) => {\n if (parser.hasFailed()) return;\n try {\n parser.accept(chunk);\n } catch (error) {\n parser.fail(error);\n }\n });\n child.stderr.resume();\n\n const closed = waitForChildClose(child);\n try {\n await request.onSpawn(identity);\n } catch (error) {\n child.kill();\n throw error;\n }\n\n child.stdin.end(request.prompt);\n const close = await closed.catch(() => {\n throw new PiPrintError('Pi process failed to start or communicate.', 'PI_PROCESS');\n });\n return parser.result(close);\n }\n}\n"],"names":["spawn","nodeSpawn","PiPrintError","LocalProcessInspector","waitForChildClose","buildPiPrintArgs","PiStreamParser","PiPrintRunner","processInspector","maxLineBytes","options","run","request","args","agent","providerSessionId","sessionHealth","child","executable","cwd","shell","stdio","pid","kill","identity","getIdentity","parser","stdout","on","chunk","hasFailed","accept","error","fail","stderr","resume","closed","onSpawn","stdin","end","prompt","close","catch","result"],"mappings":"AAAA,SAASA,SAASC,SAAS,QAA4E,gBAAgB;AAEvH,SAASC,YAAY,QAAQ,mCAAmC;AAChE,SAASC,qBAAqB,QAA+B,8BAA8B;AAC3F,SAASC,iBAAiB,QAAQ,4BAA4B;AAC9D,SAASC,gBAAgB,QAAQ,uBAAuB;AACxD,SAASC,cAAc,QAAQ,sBAAsB;AA4BrD,OAAO,MAAMC;IACQP,MAAa;IACbQ,iBAAmC;IACnCC,aAAqB;IAEtC,YAAYC,UAAgC,CAAC,CAAC,CAAE;QAC5C,IAAI,CAACV,KAAK,GAAGU,QAAQV,KAAK,IAAKC;QAC/B,IAAI,CAACO,gBAAgB,GAAGE,QAAQF,gBAAgB,IAAI,IAAIL;QACxD,IAAI,CAACM,YAAY,GAAGC,QAAQD,YAAY,IAAI,OAAO;IACvD;IAEA,MAAME,IAAIC,OAA0B,EAA6B;QAC7D,MAAMC,OAAOR,iBAAiBO,QAAQE,KAAK,CAACC,iBAAiB,EAAEH,QAAQE,KAAK,CAACE,aAAa,KAAK;QAC/F,MAAMC,QAAQ,IAAI,CAACjB,KAAK,CAACY,QAAQM,UAAU,IAAI,MAAML,MAAM;YACvDM,KAAKP,QAAQE,KAAK,CAACK,GAAG;YACtBC,OAAO;YACPC,OAAO;gBAAC;gBAAQ;gBAAQ;aAAO;QACnC;QACA,IAAI,CAACJ,MAAMK,GAAG,EAAE;YACZL,MAAMM,IAAI;YACV,MAAM,IAAIrB,aAAa,qCAAqC;QAChE;QACA,MAAMsB,WAAW,IAAI,CAAChB,gBAAgB,CAACiB,WAAW,CAACR,MAAMK,GAAG;QAC5D,IAAI,CAACE,UAAU;YACXP,MAAMM,IAAI;YACV,MAAM,IAAIrB,aAAa,sCAAsC;QACjE;QAEA,MAAMwB,SAAS,IAAIpB,eAAeM,QAAQE,KAAK,CAACC,iBAAiB,EAAE,IAAI,CAACN,YAAY;QACpFQ,MAAMU,MAAM,CAACC,EAAE,CAAC,QAAQ,CAACC;YACrB,IAAIH,OAAOI,SAAS,IAAI;YACxB,IAAI;gBACAJ,OAAOK,MAAM,CAACF;YAClB,EAAE,OAAOG,OAAO;gBACZN,OAAOO,IAAI,CAACD;YAChB;QACJ;QACAf,MAAMiB,MAAM,CAACC,MAAM;QAEnB,MAAMC,SAAShC,kBAAkBa;QACjC,IAAI;YACA,MAAML,QAAQyB,OAAO,CAACb;QAC1B,EAAE,OAAOQ,OAAO;YACZf,MAAMM,IAAI;YACV,MAAMS;QACV;QAEAf,MAAMqB,KAAK,CAACC,GAAG,CAAC3B,QAAQ4B,MAAM;QAC9B,MAAMC,QAAQ,MAAML,OAAOM,KAAK,CAAC;YAC7B,MAAM,IAAIxC,aAAa,8CAA8C;QACzE;QACA,OAAOwB,OAAOiB,MAAM,CAACF;IACzB;AACJ"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ChildCloseResult } from '../../../durable/utils.js';
|
|
2
|
+
export declare class PiStreamParser {
|
|
3
|
+
private readonly expectedSessionId;
|
|
4
|
+
private readonly lines;
|
|
5
|
+
private sessionId;
|
|
6
|
+
private ended;
|
|
7
|
+
private readonly messages;
|
|
8
|
+
private failure;
|
|
9
|
+
constructor(expectedSessionId: string, maxLineBytes: number);
|
|
10
|
+
hasFailed(): boolean;
|
|
11
|
+
accept(chunk: Buffer | string): void;
|
|
12
|
+
fail(error: unknown): void;
|
|
13
|
+
result(close: ChildCloseResult): {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
result: string;
|
|
16
|
+
messages: string[];
|
|
17
|
+
exitCode: number;
|
|
18
|
+
};
|
|
19
|
+
private acceptLine;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=PiStreamParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PiStreamParser.d.ts","sourceRoot":"","sources":["../../../../src/providers/pi/durable/PiStreamParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAG9E,qBAAa,cAAc;IAQnB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAPtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,OAAO,CAA6B;gBAGvB,iBAAiB,EAAE,MAAM,EAC1C,YAAY,EAAE,MAAM;IAQxB,SAAS,IAAI,OAAO;IAIpB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAOpC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAM1B,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAuB5G,OAAO,CAAC,UAAU;CAsBrB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PiPrintError } from '../../../durable/DurableAgent.js';
|
|
2
|
+
import { LineBuffer } from '../../../durable/utils.js';
|
|
3
|
+
import { readPiAssistantText, readPiSessionId } from './PiPrintProtocol.js';
|
|
4
|
+
export class PiStreamParser {
|
|
5
|
+
expectedSessionId;
|
|
6
|
+
lines;
|
|
7
|
+
sessionId = null;
|
|
8
|
+
ended = false;
|
|
9
|
+
messages = [];
|
|
10
|
+
failure = null;
|
|
11
|
+
constructor(expectedSessionId, maxLineBytes){
|
|
12
|
+
this.expectedSessionId = expectedSessionId;
|
|
13
|
+
this.lines = new LineBuffer(maxLineBytes, ()=>new PiPrintError('Pi stream line exceeded the safety limit.', 'PI_PROTOCOL'));
|
|
14
|
+
}
|
|
15
|
+
hasFailed() {
|
|
16
|
+
return this.failure !== null;
|
|
17
|
+
}
|
|
18
|
+
accept(chunk) {
|
|
19
|
+
for (const line of this.lines.accept(chunk)){
|
|
20
|
+
if (line.length === 0) continue;
|
|
21
|
+
this.acceptLine(line);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
fail(error) {
|
|
25
|
+
this.failure = error instanceof PiPrintError ? error : new PiPrintError('Pi stream processing failed.', 'PI_PROTOCOL');
|
|
26
|
+
}
|
|
27
|
+
result(close) {
|
|
28
|
+
if (this.failure) throw this.failure;
|
|
29
|
+
this.lines.assertComplete(()=>new PiPrintError('Pi stream ended with incomplete JSON.', 'PI_PROTOCOL'));
|
|
30
|
+
if (close.code !== 0) {
|
|
31
|
+
throw new PiPrintError(`Pi print run failed${close.signal ? ` (${close.signal})` : '.'}`, 'PI_PROCESS');
|
|
32
|
+
}
|
|
33
|
+
if (this.sessionId === null) {
|
|
34
|
+
throw new PiPrintError('Pi stream ended without a session identity.', 'PI_PROTOCOL');
|
|
35
|
+
}
|
|
36
|
+
if (!this.ended) throw new PiPrintError('Pi stream ended before agent completion.', 'PI_PROTOCOL');
|
|
37
|
+
if (this.messages.length === 0) {
|
|
38
|
+
throw new PiPrintError('Pi stream ended without an assistant result.', 'PI_RESULT_MISSING');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
sessionId: this.sessionId,
|
|
42
|
+
result: this.messages.at(-1),
|
|
43
|
+
messages: this.messages,
|
|
44
|
+
exitCode: close.code
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
acceptLine(line) {
|
|
48
|
+
let value;
|
|
49
|
+
try {
|
|
50
|
+
value = JSON.parse(line.toString('utf8'));
|
|
51
|
+
} catch {
|
|
52
|
+
throw new PiPrintError('Pi emitted malformed stream JSON.', 'PI_PROTOCOL');
|
|
53
|
+
}
|
|
54
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
55
|
+
throw new PiPrintError('Pi emitted a non-object stream message.', 'PI_PROTOCOL');
|
|
56
|
+
}
|
|
57
|
+
const event = value;
|
|
58
|
+
if (event.type === 'session') {
|
|
59
|
+
this.sessionId = readPiSessionId(event, this.sessionId, this.expectedSessionId);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (event.type === 'agent_end') {
|
|
63
|
+
this.ended = true;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const text = readPiAssistantText(event);
|
|
67
|
+
if (text !== null) this.messages.push(text);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=PiStreamParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/providers/pi/durable/PiStreamParser.ts"],"sourcesContent":["import { PiPrintError } from '../../../durable/DurableAgent.js';\nimport { LineBuffer, type ChildCloseResult } from '../../../durable/utils.js';\nimport { readPiAssistantText, readPiSessionId } from './PiPrintProtocol.js';\n\nexport class PiStreamParser {\n private readonly lines: LineBuffer;\n private sessionId: string | null = null;\n private ended = false;\n private readonly messages: string[] = [];\n private failure: PiPrintError | null = null;\n\n constructor(\n private readonly expectedSessionId: string,\n maxLineBytes: number,\n ) {\n this.lines = new LineBuffer(\n maxLineBytes,\n () => new PiPrintError('Pi stream line exceeded the safety limit.', 'PI_PROTOCOL'),\n );\n }\n\n hasFailed(): boolean {\n return this.failure !== null;\n }\n\n accept(chunk: Buffer | string): void {\n for (const line of this.lines.accept(chunk)) {\n if (line.length === 0) continue;\n this.acceptLine(line);\n }\n }\n\n fail(error: unknown): void {\n this.failure = error instanceof PiPrintError\n ? error\n : new PiPrintError('Pi stream processing failed.', 'PI_PROTOCOL');\n }\n\n result(close: ChildCloseResult): { sessionId: string; result: string; messages: string[]; exitCode: number } {\n if (this.failure) throw this.failure;\n this.lines.assertComplete(\n () => new PiPrintError('Pi stream ended with incomplete JSON.', 'PI_PROTOCOL'),\n );\n if (close.code !== 0) {\n throw new PiPrintError(`Pi print run failed${close.signal ? ` (${close.signal})` : '.'}`, 'PI_PROCESS');\n }\n if (this.sessionId === null) {\n throw new PiPrintError('Pi stream ended without a session identity.', 'PI_PROTOCOL');\n }\n if (!this.ended) throw new PiPrintError('Pi stream ended before agent completion.', 'PI_PROTOCOL');\n if (this.messages.length === 0) {\n throw new PiPrintError('Pi stream ended without an assistant result.', 'PI_RESULT_MISSING');\n }\n return {\n sessionId: this.sessionId,\n result: this.messages.at(-1)!,\n messages: this.messages,\n exitCode: close.code,\n };\n }\n\n private acceptLine(line: Buffer): void {\n let value: unknown;\n try {\n value = JSON.parse(line.toString('utf8'));\n } catch {\n throw new PiPrintError('Pi emitted malformed stream JSON.', 'PI_PROTOCOL');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new PiPrintError('Pi emitted a non-object stream message.', 'PI_PROTOCOL');\n }\n const event = value as Record<string, unknown>;\n if (event.type === 'session') {\n this.sessionId = readPiSessionId(event, this.sessionId, this.expectedSessionId);\n return;\n }\n if (event.type === 'agent_end') {\n this.ended = true;\n return;\n }\n const text = readPiAssistantText(event);\n if (text !== null) this.messages.push(text);\n }\n}\n"],"names":["PiPrintError","LineBuffer","readPiAssistantText","readPiSessionId","PiStreamParser","lines","sessionId","ended","messages","failure","expectedSessionId","maxLineBytes","hasFailed","accept","chunk","line","length","acceptLine","fail","error","result","close","assertComplete","code","signal","at","exitCode","value","JSON","parse","toString","Array","isArray","event","type","text","push"],"mappings":"AAAA,SAASA,YAAY,QAAQ,mCAAmC;AAChE,SAASC,UAAU,QAA+B,4BAA4B;AAC9E,SAASC,mBAAmB,EAAEC,eAAe,QAAQ,uBAAuB;AAE5E,OAAO,MAAMC;;IACQC,MAAkB;IAC3BC,YAA2B,KAAK;IAChCC,QAAQ,MAAM;IACLC,WAAqB,EAAE,CAAC;IACjCC,UAA+B,KAAK;IAE5C,YACI,AAAiBC,iBAAyB,EAC1CC,YAAoB,CACtB;aAFmBD,oBAAAA;QAGjB,IAAI,CAACL,KAAK,GAAG,IAAIJ,WACbU,cACA,IAAM,IAAIX,aAAa,6CAA6C;IAE5E;IAEAY,YAAqB;QACjB,OAAO,IAAI,CAACH,OAAO,KAAK;IAC5B;IAEAI,OAAOC,KAAsB,EAAQ;QACjC,KAAK,MAAMC,QAAQ,IAAI,CAACV,KAAK,CAACQ,MAAM,CAACC,OAAQ;YACzC,IAAIC,KAAKC,MAAM,KAAK,GAAG;YACvB,IAAI,CAACC,UAAU,CAACF;QACpB;IACJ;IAEAG,KAAKC,KAAc,EAAQ;QACvB,IAAI,CAACV,OAAO,GAAGU,iBAAiBnB,eAC1BmB,QACA,IAAInB,aAAa,gCAAgC;IAC3D;IAEAoB,OAAOC,KAAuB,EAA+E;QACzG,IAAI,IAAI,CAACZ,OAAO,EAAE,MAAM,IAAI,CAACA,OAAO;QACpC,IAAI,CAACJ,KAAK,CAACiB,cAAc,CACrB,IAAM,IAAItB,aAAa,yCAAyC;QAEpE,IAAIqB,MAAME,IAAI,KAAK,GAAG;YAClB,MAAM,IAAIvB,aAAa,CAAC,mBAAmB,EAAEqB,MAAMG,MAAM,GAAG,CAAC,EAAE,EAAEH,MAAMG,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE;QAC9F;QACA,IAAI,IAAI,CAAClB,SAAS,KAAK,MAAM;YACzB,MAAM,IAAIN,aAAa,+CAA+C;QAC1E;QACA,IAAI,CAAC,IAAI,CAACO,KAAK,EAAE,MAAM,IAAIP,aAAa,4CAA4C;QACpF,IAAI,IAAI,CAACQ,QAAQ,CAACQ,MAAM,KAAK,GAAG;YAC5B,MAAM,IAAIhB,aAAa,gDAAgD;QAC3E;QACA,OAAO;YACHM,WAAW,IAAI,CAACA,SAAS;YACzBc,QAAQ,IAAI,CAACZ,QAAQ,CAACiB,EAAE,CAAC,CAAC;YAC1BjB,UAAU,IAAI,CAACA,QAAQ;YACvBkB,UAAUL,MAAME,IAAI;QACxB;IACJ;IAEQN,WAAWF,IAAY,EAAQ;QACnC,IAAIY;QACJ,IAAI;YACAA,QAAQC,KAAKC,KAAK,CAACd,KAAKe,QAAQ,CAAC;QACrC,EAAE,OAAM;YACJ,MAAM,IAAI9B,aAAa,qCAAqC;QAChE;QACA,IAAI,CAAC2B,SAAS,OAAOA,UAAU,YAAYI,MAAMC,OAAO,CAACL,QAAQ;YAC7D,MAAM,IAAI3B,aAAa,2CAA2C;QACtE;QACA,MAAMiC,QAAQN;QACd,IAAIM,MAAMC,IAAI,KAAK,WAAW;YAC1B,IAAI,CAAC5B,SAAS,GAAGH,gBAAgB8B,OAAO,IAAI,CAAC3B,SAAS,EAAE,IAAI,CAACI,iBAAiB;YAC9E;QACJ;QACA,IAAIuB,MAAMC,IAAI,KAAK,aAAa;YAC5B,IAAI,CAAC3B,KAAK,GAAG;YACb;QACJ;QACA,MAAM4B,OAAOjC,oBAAoB+B;QACjC,IAAIE,SAAS,MAAM,IAAI,CAAC3B,QAAQ,CAAC4B,IAAI,CAACD;IAC1C;AACJ"}
|