@renseiai/agentfactory 0.8.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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/src/config/index.d.ts +3 -0
- package/dist/src/config/index.d.ts.map +1 -0
- package/dist/src/config/index.js +1 -0
- package/dist/src/config/repository-config.d.ts +44 -0
- package/dist/src/config/repository-config.d.ts.map +1 -0
- package/dist/src/config/repository-config.js +88 -0
- package/dist/src/config/repository-config.test.d.ts +2 -0
- package/dist/src/config/repository-config.test.d.ts.map +1 -0
- package/dist/src/config/repository-config.test.js +249 -0
- package/dist/src/deployment/deployment-checker.d.ts +110 -0
- package/dist/src/deployment/deployment-checker.d.ts.map +1 -0
- package/dist/src/deployment/deployment-checker.js +242 -0
- package/dist/src/deployment/index.d.ts +3 -0
- package/dist/src/deployment/index.d.ts.map +1 -0
- package/dist/src/deployment/index.js +2 -0
- package/dist/src/frontend/index.d.ts +2 -0
- package/dist/src/frontend/index.d.ts.map +1 -0
- package/dist/src/frontend/index.js +1 -0
- package/dist/src/frontend/types.d.ts +106 -0
- package/dist/src/frontend/types.d.ts.map +1 -0
- package/dist/src/frontend/types.js +11 -0
- package/dist/src/governor/decision-engine.d.ts +52 -0
- package/dist/src/governor/decision-engine.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.js +220 -0
- package/dist/src/governor/decision-engine.test.d.ts +2 -0
- package/dist/src/governor/decision-engine.test.d.ts.map +1 -0
- package/dist/src/governor/decision-engine.test.js +629 -0
- package/dist/src/governor/event-bus.d.ts +43 -0
- package/dist/src/governor/event-bus.d.ts.map +1 -0
- package/dist/src/governor/event-bus.js +8 -0
- package/dist/src/governor/event-deduplicator.d.ts +43 -0
- package/dist/src/governor/event-deduplicator.d.ts.map +1 -0
- package/dist/src/governor/event-deduplicator.js +53 -0
- package/dist/src/governor/event-driven-governor.d.ts +131 -0
- package/dist/src/governor/event-driven-governor.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.js +379 -0
- package/dist/src/governor/event-driven-governor.test.d.ts +2 -0
- package/dist/src/governor/event-driven-governor.test.d.ts.map +1 -0
- package/dist/src/governor/event-driven-governor.test.js +673 -0
- package/dist/src/governor/event-types.d.ts +78 -0
- package/dist/src/governor/event-types.d.ts.map +1 -0
- package/dist/src/governor/event-types.js +32 -0
- package/dist/src/governor/governor-types.d.ts +82 -0
- package/dist/src/governor/governor-types.d.ts.map +1 -0
- package/dist/src/governor/governor-types.js +21 -0
- package/dist/src/governor/governor.d.ts +100 -0
- package/dist/src/governor/governor.d.ts.map +1 -0
- package/dist/src/governor/governor.js +262 -0
- package/dist/src/governor/governor.test.d.ts +2 -0
- package/dist/src/governor/governor.test.d.ts.map +1 -0
- package/dist/src/governor/governor.test.js +514 -0
- package/dist/src/governor/human-touchpoints.d.ts +131 -0
- package/dist/src/governor/human-touchpoints.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.js +251 -0
- package/dist/src/governor/human-touchpoints.test.d.ts +2 -0
- package/dist/src/governor/human-touchpoints.test.d.ts.map +1 -0
- package/dist/src/governor/human-touchpoints.test.js +366 -0
- package/dist/src/governor/in-memory-event-bus.d.ts +29 -0
- package/dist/src/governor/in-memory-event-bus.d.ts.map +1 -0
- package/dist/src/governor/in-memory-event-bus.js +79 -0
- package/dist/src/governor/index.d.ts +14 -0
- package/dist/src/governor/index.d.ts.map +1 -0
- package/dist/src/governor/index.js +13 -0
- package/dist/src/governor/override-parser.d.ts +60 -0
- package/dist/src/governor/override-parser.d.ts.map +1 -0
- package/dist/src/governor/override-parser.js +98 -0
- package/dist/src/governor/override-parser.test.d.ts +2 -0
- package/dist/src/governor/override-parser.test.d.ts.map +1 -0
- package/dist/src/governor/override-parser.test.js +312 -0
- package/dist/src/governor/platform-adapter.d.ts +69 -0
- package/dist/src/governor/platform-adapter.d.ts.map +1 -0
- package/dist/src/governor/platform-adapter.js +11 -0
- package/dist/src/governor/processing-state.d.ts +66 -0
- package/dist/src/governor/processing-state.d.ts.map +1 -0
- package/dist/src/governor/processing-state.js +43 -0
- package/dist/src/governor/processing-state.test.d.ts +2 -0
- package/dist/src/governor/processing-state.test.d.ts.map +1 -0
- package/dist/src/governor/processing-state.test.js +96 -0
- package/dist/src/governor/top-of-funnel.d.ts +118 -0
- package/dist/src/governor/top-of-funnel.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.js +168 -0
- package/dist/src/governor/top-of-funnel.test.d.ts +2 -0
- package/dist/src/governor/top-of-funnel.test.d.ts.map +1 -0
- package/dist/src/governor/top-of-funnel.test.js +331 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/linear-cli.d.ts +38 -0
- package/dist/src/linear-cli.d.ts.map +1 -0
- package/dist/src/linear-cli.js +674 -0
- package/dist/src/logger.d.ts +117 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +430 -0
- package/dist/src/manifest/generate.d.ts +20 -0
- package/dist/src/manifest/generate.d.ts.map +1 -0
- package/dist/src/manifest/generate.js +65 -0
- package/dist/src/manifest/index.d.ts +4 -0
- package/dist/src/manifest/index.d.ts.map +1 -0
- package/dist/src/manifest/index.js +2 -0
- package/dist/src/manifest/route-manifest.d.ts +34 -0
- package/dist/src/manifest/route-manifest.d.ts.map +1 -0
- package/dist/src/manifest/route-manifest.js +148 -0
- package/dist/src/orchestrator/activity-emitter.d.ts +119 -0
- package/dist/src/orchestrator/activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/activity-emitter.js +306 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts +167 -0
- package/dist/src/orchestrator/api-activity-emitter.d.ts.map +1 -0
- package/dist/src/orchestrator/api-activity-emitter.js +417 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts +57 -0
- package/dist/src/orchestrator/heartbeat-writer.d.ts.map +1 -0
- package/dist/src/orchestrator/heartbeat-writer.js +137 -0
- package/dist/src/orchestrator/index.d.ts +20 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -0
- package/dist/src/orchestrator/index.js +22 -0
- package/dist/src/orchestrator/log-analyzer.d.ts +160 -0
- package/dist/src/orchestrator/log-analyzer.d.ts.map +1 -0
- package/dist/src/orchestrator/log-analyzer.js +572 -0
- package/dist/src/orchestrator/log-config.d.ts +39 -0
- package/dist/src/orchestrator/log-config.d.ts.map +1 -0
- package/dist/src/orchestrator/log-config.js +45 -0
- package/dist/src/orchestrator/orchestrator.d.ts +316 -0
- package/dist/src/orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/src/orchestrator/orchestrator.js +3290 -0
- package/dist/src/orchestrator/parse-work-result.d.ts +16 -0
- package/dist/src/orchestrator/parse-work-result.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.js +135 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts +2 -0
- package/dist/src/orchestrator/parse-work-result.test.d.ts.map +1 -0
- package/dist/src/orchestrator/parse-work-result.test.js +234 -0
- package/dist/src/orchestrator/progress-logger.d.ts +72 -0
- package/dist/src/orchestrator/progress-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/progress-logger.js +135 -0
- package/dist/src/orchestrator/session-logger.d.ts +159 -0
- package/dist/src/orchestrator/session-logger.d.ts.map +1 -0
- package/dist/src/orchestrator/session-logger.js +275 -0
- package/dist/src/orchestrator/state-recovery.d.ts +96 -0
- package/dist/src/orchestrator/state-recovery.d.ts.map +1 -0
- package/dist/src/orchestrator/state-recovery.js +302 -0
- package/dist/src/orchestrator/state-types.d.ts +165 -0
- package/dist/src/orchestrator/state-types.d.ts.map +1 -0
- package/dist/src/orchestrator/state-types.js +7 -0
- package/dist/src/orchestrator/stream-parser.d.ts +151 -0
- package/dist/src/orchestrator/stream-parser.d.ts.map +1 -0
- package/dist/src/orchestrator/stream-parser.js +137 -0
- package/dist/src/orchestrator/types.d.ts +232 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +4 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts +2 -0
- package/dist/src/orchestrator/validate-git-remote.test.d.ts.map +1 -0
- package/dist/src/orchestrator/validate-git-remote.test.js +61 -0
- package/dist/src/providers/a2a-auth.d.ts +81 -0
- package/dist/src/providers/a2a-auth.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.js +188 -0
- package/dist/src/providers/a2a-auth.test.d.ts +2 -0
- package/dist/src/providers/a2a-auth.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-auth.test.js +232 -0
- package/dist/src/providers/a2a-provider.d.ts +254 -0
- package/dist/src/providers/a2a-provider.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts +9 -0
- package/dist/src/providers/a2a-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.integration.test.js +665 -0
- package/dist/src/providers/a2a-provider.js +811 -0
- package/dist/src/providers/a2a-provider.test.d.ts +2 -0
- package/dist/src/providers/a2a-provider.test.d.ts.map +1 -0
- package/dist/src/providers/a2a-provider.test.js +681 -0
- package/dist/src/providers/amp-provider.d.ts +20 -0
- package/dist/src/providers/amp-provider.d.ts.map +1 -0
- package/dist/src/providers/amp-provider.js +24 -0
- package/dist/src/providers/claude-provider.d.ts +18 -0
- package/dist/src/providers/claude-provider.d.ts.map +1 -0
- package/dist/src/providers/claude-provider.js +437 -0
- package/dist/src/providers/codex-provider.d.ts +133 -0
- package/dist/src/providers/codex-provider.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.js +381 -0
- package/dist/src/providers/codex-provider.test.d.ts +2 -0
- package/dist/src/providers/codex-provider.test.d.ts.map +1 -0
- package/dist/src/providers/codex-provider.test.js +387 -0
- package/dist/src/providers/index.d.ts +44 -0
- package/dist/src/providers/index.d.ts.map +1 -0
- package/dist/src/providers/index.js +85 -0
- package/dist/src/providers/spring-ai-provider.d.ts +90 -0
- package/dist/src/providers/spring-ai-provider.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts +13 -0
- package/dist/src/providers/spring-ai-provider.integration.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.integration.test.js +351 -0
- package/dist/src/providers/spring-ai-provider.js +317 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts +2 -0
- package/dist/src/providers/spring-ai-provider.test.d.ts.map +1 -0
- package/dist/src/providers/spring-ai-provider.test.js +200 -0
- package/dist/src/providers/types.d.ts +165 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +13 -0
- package/dist/src/templates/adapters.d.ts +51 -0
- package/dist/src/templates/adapters.d.ts.map +1 -0
- package/dist/src/templates/adapters.js +104 -0
- package/dist/src/templates/adapters.test.d.ts +2 -0
- package/dist/src/templates/adapters.test.d.ts.map +1 -0
- package/dist/src/templates/adapters.test.js +165 -0
- package/dist/src/templates/agent-definition.d.ts +85 -0
- package/dist/src/templates/agent-definition.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.js +97 -0
- package/dist/src/templates/agent-definition.test.d.ts +2 -0
- package/dist/src/templates/agent-definition.test.d.ts.map +1 -0
- package/dist/src/templates/agent-definition.test.js +209 -0
- package/dist/src/templates/index.d.ts +14 -0
- package/dist/src/templates/index.d.ts.map +1 -0
- package/dist/src/templates/index.js +11 -0
- package/dist/src/templates/loader.d.ts +41 -0
- package/dist/src/templates/loader.d.ts.map +1 -0
- package/dist/src/templates/loader.js +114 -0
- package/dist/src/templates/registry.d.ts +80 -0
- package/dist/src/templates/registry.d.ts.map +1 -0
- package/dist/src/templates/registry.js +177 -0
- package/dist/src/templates/registry.test.d.ts +2 -0
- package/dist/src/templates/registry.test.d.ts.map +1 -0
- package/dist/src/templates/registry.test.js +198 -0
- package/dist/src/templates/renderer.d.ts +29 -0
- package/dist/src/templates/renderer.d.ts.map +1 -0
- package/dist/src/templates/renderer.js +35 -0
- package/dist/src/templates/strategy-templates.test.d.ts +2 -0
- package/dist/src/templates/strategy-templates.test.d.ts.map +1 -0
- package/dist/src/templates/strategy-templates.test.js +619 -0
- package/dist/src/templates/types.d.ts +233 -0
- package/dist/src/templates/types.d.ts.map +1 -0
- package/dist/src/templates/types.js +127 -0
- package/dist/src/templates/types.test.d.ts +2 -0
- package/dist/src/templates/types.test.d.ts.map +1 -0
- package/dist/src/templates/types.test.js +232 -0
- package/dist/src/tools/index.d.ts +6 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/linear-runner.d.ts +34 -0
- package/dist/src/tools/linear-runner.d.ts.map +1 -0
- package/dist/src/tools/linear-runner.js +700 -0
- package/dist/src/tools/plugins/linear.d.ts +9 -0
- package/dist/src/tools/plugins/linear.d.ts.map +1 -0
- package/dist/src/tools/plugins/linear.js +138 -0
- package/dist/src/tools/registry.d.ts +9 -0
- package/dist/src/tools/registry.d.ts.map +1 -0
- package/dist/src/tools/registry.js +18 -0
- package/dist/src/tools/types.d.ts +18 -0
- package/dist/src/tools/types.d.ts.map +1 -0
- package/dist/src/tools/types.js +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI Codex Agent Provider
|
|
3
|
+
*
|
|
4
|
+
* Spawns the `codex` CLI (from @openai/codex) as a child process and parses
|
|
5
|
+
* its JSONL event stream into normalized AgentEvents.
|
|
6
|
+
*
|
|
7
|
+
* CLI invocation patterns:
|
|
8
|
+
* New session: codex exec --json --full-auto -C <cwd> "<prompt>"
|
|
9
|
+
* Resume: codex exec resume --json --full-auto <session_id> "<prompt>"
|
|
10
|
+
*
|
|
11
|
+
* JSONL event types:
|
|
12
|
+
* thread.started → init (sessionId)
|
|
13
|
+
* turn.started → system (turn_started)
|
|
14
|
+
* turn.completed → result (success, usage)
|
|
15
|
+
* turn.failed → result (failure)
|
|
16
|
+
* item.* → tool_use / tool_result / assistant_text / system
|
|
17
|
+
* error → error
|
|
18
|
+
*/
|
|
19
|
+
import { spawn } from 'child_process';
|
|
20
|
+
import { createInterface } from 'readline';
|
|
21
|
+
/**
|
|
22
|
+
* Map a single Codex JSONL event to one or more normalized AgentEvents.
|
|
23
|
+
* Exported for unit testing — the AgentHandle uses this internally.
|
|
24
|
+
*/
|
|
25
|
+
export function mapCodexEvent(event, state) {
|
|
26
|
+
switch (event.type) {
|
|
27
|
+
case 'thread.started':
|
|
28
|
+
state.sessionId = event.thread_id;
|
|
29
|
+
return [{
|
|
30
|
+
type: 'init',
|
|
31
|
+
sessionId: event.thread_id,
|
|
32
|
+
raw: event,
|
|
33
|
+
}];
|
|
34
|
+
case 'turn.started':
|
|
35
|
+
state.turnCount++;
|
|
36
|
+
return [{
|
|
37
|
+
type: 'system',
|
|
38
|
+
subtype: 'turn_started',
|
|
39
|
+
message: `Turn ${state.turnCount} started`,
|
|
40
|
+
raw: event,
|
|
41
|
+
}];
|
|
42
|
+
case 'turn.completed':
|
|
43
|
+
if (event.usage) {
|
|
44
|
+
state.totalInputTokens += event.usage.input_tokens ?? 0;
|
|
45
|
+
state.totalOutputTokens += event.usage.output_tokens ?? 0;
|
|
46
|
+
}
|
|
47
|
+
return [{
|
|
48
|
+
type: 'result',
|
|
49
|
+
success: true,
|
|
50
|
+
cost: {
|
|
51
|
+
inputTokens: state.totalInputTokens || undefined,
|
|
52
|
+
outputTokens: state.totalOutputTokens || undefined,
|
|
53
|
+
numTurns: state.turnCount || undefined,
|
|
54
|
+
},
|
|
55
|
+
raw: event,
|
|
56
|
+
}];
|
|
57
|
+
case 'turn.failed':
|
|
58
|
+
return [{
|
|
59
|
+
type: 'result',
|
|
60
|
+
success: false,
|
|
61
|
+
errors: [event.error?.message ?? 'Turn failed'],
|
|
62
|
+
errorSubtype: 'turn_failed',
|
|
63
|
+
raw: event,
|
|
64
|
+
}];
|
|
65
|
+
case 'item.started':
|
|
66
|
+
case 'item.updated':
|
|
67
|
+
case 'item.completed':
|
|
68
|
+
return mapCodexItemEvent(event);
|
|
69
|
+
case 'error':
|
|
70
|
+
return [{
|
|
71
|
+
type: 'error',
|
|
72
|
+
message: event.message ?? 'Unknown error',
|
|
73
|
+
raw: event,
|
|
74
|
+
}];
|
|
75
|
+
default:
|
|
76
|
+
return [{
|
|
77
|
+
type: 'system',
|
|
78
|
+
subtype: 'unknown',
|
|
79
|
+
message: `Unhandled Codex event type: ${event.type}`,
|
|
80
|
+
raw: event,
|
|
81
|
+
}];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Map a Codex item event to AgentEvents.
|
|
86
|
+
* Exported for unit testing.
|
|
87
|
+
*/
|
|
88
|
+
export function mapCodexItemEvent(event) {
|
|
89
|
+
const item = event.item;
|
|
90
|
+
const eventType = event.type;
|
|
91
|
+
switch (item.type) {
|
|
92
|
+
case 'agent_message':
|
|
93
|
+
return [{
|
|
94
|
+
type: 'assistant_text',
|
|
95
|
+
text: item.text,
|
|
96
|
+
raw: event,
|
|
97
|
+
}];
|
|
98
|
+
case 'reasoning':
|
|
99
|
+
return [{
|
|
100
|
+
type: 'system',
|
|
101
|
+
subtype: 'reasoning',
|
|
102
|
+
message: item.text,
|
|
103
|
+
raw: event,
|
|
104
|
+
}];
|
|
105
|
+
case 'command_execution':
|
|
106
|
+
if (eventType === 'item.started') {
|
|
107
|
+
return [{
|
|
108
|
+
type: 'tool_use',
|
|
109
|
+
toolName: 'shell',
|
|
110
|
+
toolUseId: item.id,
|
|
111
|
+
input: { command: item.command },
|
|
112
|
+
raw: event,
|
|
113
|
+
}];
|
|
114
|
+
}
|
|
115
|
+
if (eventType === 'item.completed') {
|
|
116
|
+
return [{
|
|
117
|
+
type: 'tool_result',
|
|
118
|
+
toolName: 'shell',
|
|
119
|
+
toolUseId: item.id,
|
|
120
|
+
content: item.aggregated_output || '',
|
|
121
|
+
isError: item.status === 'failed' || (item.exit_code !== undefined && item.exit_code !== 0),
|
|
122
|
+
raw: event,
|
|
123
|
+
}];
|
|
124
|
+
}
|
|
125
|
+
return [{
|
|
126
|
+
type: 'system',
|
|
127
|
+
subtype: 'command_progress',
|
|
128
|
+
message: `Command: ${item.command} (${item.status})`,
|
|
129
|
+
raw: event,
|
|
130
|
+
}];
|
|
131
|
+
case 'file_change':
|
|
132
|
+
return [{
|
|
133
|
+
type: 'tool_result',
|
|
134
|
+
toolName: 'file_change',
|
|
135
|
+
toolUseId: item.id,
|
|
136
|
+
content: item.changes.map((c) => `${c.kind}: ${c.path}`).join('\n'),
|
|
137
|
+
isError: item.status === 'failed',
|
|
138
|
+
raw: event,
|
|
139
|
+
}];
|
|
140
|
+
case 'mcp_tool_call':
|
|
141
|
+
if (eventType === 'item.started') {
|
|
142
|
+
return [{
|
|
143
|
+
type: 'tool_use',
|
|
144
|
+
toolName: `mcp:${item.server}/${item.tool}`,
|
|
145
|
+
toolUseId: item.id,
|
|
146
|
+
input: (item.arguments ?? {}),
|
|
147
|
+
raw: event,
|
|
148
|
+
}];
|
|
149
|
+
}
|
|
150
|
+
if (eventType === 'item.completed') {
|
|
151
|
+
const isError = item.status === 'failed' || !!item.error;
|
|
152
|
+
const content = item.error?.message
|
|
153
|
+
?? (item.result?.content ? JSON.stringify(item.result.content) : '');
|
|
154
|
+
return [{
|
|
155
|
+
type: 'tool_result',
|
|
156
|
+
toolName: `mcp:${item.server}/${item.tool}`,
|
|
157
|
+
toolUseId: item.id,
|
|
158
|
+
content,
|
|
159
|
+
isError,
|
|
160
|
+
raw: event,
|
|
161
|
+
}];
|
|
162
|
+
}
|
|
163
|
+
return [];
|
|
164
|
+
case 'todo_list':
|
|
165
|
+
return [{
|
|
166
|
+
type: 'system',
|
|
167
|
+
subtype: 'todo_list',
|
|
168
|
+
message: item.items.map((t) => `${t.completed ? '[x]' : '[ ]'} ${t.text}`).join('\n'),
|
|
169
|
+
raw: event,
|
|
170
|
+
}];
|
|
171
|
+
case 'error':
|
|
172
|
+
return [{
|
|
173
|
+
type: 'error',
|
|
174
|
+
message: item.message,
|
|
175
|
+
raw: event,
|
|
176
|
+
}];
|
|
177
|
+
default:
|
|
178
|
+
return [{
|
|
179
|
+
type: 'system',
|
|
180
|
+
subtype: 'unknown_item',
|
|
181
|
+
message: `Unhandled Codex item type: ${item.type}`,
|
|
182
|
+
raw: event,
|
|
183
|
+
}];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Provider
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
export class CodexProvider {
|
|
190
|
+
name = 'codex';
|
|
191
|
+
spawn(config) {
|
|
192
|
+
return this.createHandle(config);
|
|
193
|
+
}
|
|
194
|
+
resume(sessionId, config) {
|
|
195
|
+
return this.createHandle(config, sessionId);
|
|
196
|
+
}
|
|
197
|
+
createHandle(config, resumeSessionId) {
|
|
198
|
+
const abortController = config.abortController;
|
|
199
|
+
// Resolve the codex binary — prefer CODEX_BIN env var, then fall back to 'codex'
|
|
200
|
+
const codexBin = config.env.CODEX_BIN || process.env.CODEX_BIN || 'codex';
|
|
201
|
+
// Build args
|
|
202
|
+
const args = ['exec'];
|
|
203
|
+
if (resumeSessionId) {
|
|
204
|
+
args.push('resume', '--json');
|
|
205
|
+
// Sandbox and approval mode
|
|
206
|
+
if (config.autonomous) {
|
|
207
|
+
args.push('--full-auto');
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
// Non-autonomous: use suggest-equivalent approval mode
|
|
211
|
+
args.push('--approval-mode', 'untrusted');
|
|
212
|
+
if (config.sandboxEnabled) {
|
|
213
|
+
args.push('--sandbox', 'workspace-write');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
args.push(resumeSessionId);
|
|
217
|
+
// Prompt is the final positional arg
|
|
218
|
+
if (config.prompt) {
|
|
219
|
+
args.push(config.prompt);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
args.push('--json');
|
|
224
|
+
// Sandbox and approval mode
|
|
225
|
+
if (config.autonomous) {
|
|
226
|
+
// --full-auto sets sandbox=workspace-write + approval=on-request
|
|
227
|
+
args.push('--full-auto');
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
args.push('--approval-mode', 'untrusted');
|
|
231
|
+
if (config.sandboxEnabled) {
|
|
232
|
+
args.push('--sandbox', 'workspace-write');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Working directory
|
|
236
|
+
args.push('-C', config.cwd);
|
|
237
|
+
// Prompt is the final positional arg
|
|
238
|
+
args.push(config.prompt);
|
|
239
|
+
}
|
|
240
|
+
// Spawn the codex process
|
|
241
|
+
const child = spawn(codexBin, args, {
|
|
242
|
+
cwd: config.cwd,
|
|
243
|
+
env: {
|
|
244
|
+
...process.env,
|
|
245
|
+
...config.env,
|
|
246
|
+
},
|
|
247
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
248
|
+
});
|
|
249
|
+
config.onProcessSpawned?.(child.pid);
|
|
250
|
+
// Wire up abort
|
|
251
|
+
const abortHandler = () => {
|
|
252
|
+
child.kill('SIGTERM');
|
|
253
|
+
};
|
|
254
|
+
abortController.signal.addEventListener('abort', abortHandler);
|
|
255
|
+
child.once('exit', () => {
|
|
256
|
+
abortController.signal.removeEventListener('abort', abortHandler);
|
|
257
|
+
});
|
|
258
|
+
child.on('error', (err) => {
|
|
259
|
+
console.error('[CodexProvider] Child process error:', err.message);
|
|
260
|
+
});
|
|
261
|
+
return new CodexAgentHandle(child, abortController);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// ---------------------------------------------------------------------------
|
|
265
|
+
// AgentHandle implementation
|
|
266
|
+
// ---------------------------------------------------------------------------
|
|
267
|
+
class CodexAgentHandle {
|
|
268
|
+
sessionId = null;
|
|
269
|
+
child;
|
|
270
|
+
abortController;
|
|
271
|
+
mapperState = {
|
|
272
|
+
sessionId: null,
|
|
273
|
+
totalInputTokens: 0,
|
|
274
|
+
totalOutputTokens: 0,
|
|
275
|
+
turnCount: 0,
|
|
276
|
+
};
|
|
277
|
+
constructor(child, abortController) {
|
|
278
|
+
this.child = child;
|
|
279
|
+
this.abortController = abortController;
|
|
280
|
+
}
|
|
281
|
+
get stream() {
|
|
282
|
+
return this.createEventStream();
|
|
283
|
+
}
|
|
284
|
+
async injectMessage(_text) {
|
|
285
|
+
// Codex exec mode doesn't support mid-session message injection.
|
|
286
|
+
// The prompt is provided at spawn time. Injection would require
|
|
287
|
+
// stopping and resuming with a new prompt.
|
|
288
|
+
throw new Error('Codex provider does not support mid-session message injection. ' +
|
|
289
|
+
'Stop and resume with a new prompt instead.');
|
|
290
|
+
}
|
|
291
|
+
async stop() {
|
|
292
|
+
this.abortController.abort();
|
|
293
|
+
}
|
|
294
|
+
async *createEventStream() {
|
|
295
|
+
const stdout = this.child.stdout;
|
|
296
|
+
if (!stdout) {
|
|
297
|
+
yield {
|
|
298
|
+
type: 'error',
|
|
299
|
+
message: 'Codex process has no stdout',
|
|
300
|
+
raw: null,
|
|
301
|
+
};
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
// Collect stderr for error reporting
|
|
305
|
+
let stderr = '';
|
|
306
|
+
this.child.stderr?.on('data', (chunk) => {
|
|
307
|
+
stderr += chunk.toString();
|
|
308
|
+
});
|
|
309
|
+
// Parse JSONL lines from stdout
|
|
310
|
+
const rl = createInterface({ input: stdout });
|
|
311
|
+
let hasResult = false;
|
|
312
|
+
for await (const line of rl) {
|
|
313
|
+
const trimmed = line.trim();
|
|
314
|
+
if (!trimmed)
|
|
315
|
+
continue;
|
|
316
|
+
let event;
|
|
317
|
+
try {
|
|
318
|
+
event = JSON.parse(trimmed);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// Non-JSON output — emit as system event
|
|
322
|
+
yield {
|
|
323
|
+
type: 'system',
|
|
324
|
+
subtype: 'raw_output',
|
|
325
|
+
message: trimmed,
|
|
326
|
+
raw: trimmed,
|
|
327
|
+
};
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const mapped = mapCodexEvent(event, this.mapperState);
|
|
331
|
+
for (const agentEvent of mapped) {
|
|
332
|
+
if (agentEvent.type === 'init') {
|
|
333
|
+
this.sessionId = this.mapperState.sessionId;
|
|
334
|
+
}
|
|
335
|
+
if (agentEvent.type === 'result') {
|
|
336
|
+
hasResult = true;
|
|
337
|
+
}
|
|
338
|
+
yield agentEvent;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// Wait for process exit
|
|
342
|
+
const exitCode = await new Promise((resolve) => {
|
|
343
|
+
if (this.child.exitCode !== null) {
|
|
344
|
+
resolve(this.child.exitCode);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
this.child.once('exit', (code) => resolve(code));
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
// If we never got a result event, synthesize one from exit code
|
|
351
|
+
if (!hasResult) {
|
|
352
|
+
if (exitCode === 0) {
|
|
353
|
+
yield {
|
|
354
|
+
type: 'result',
|
|
355
|
+
success: true,
|
|
356
|
+
cost: {
|
|
357
|
+
inputTokens: this.mapperState.totalInputTokens || undefined,
|
|
358
|
+
outputTokens: this.mapperState.totalOutputTokens || undefined,
|
|
359
|
+
numTurns: this.mapperState.turnCount || undefined,
|
|
360
|
+
},
|
|
361
|
+
raw: { exitCode },
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
yield {
|
|
366
|
+
type: 'result',
|
|
367
|
+
success: false,
|
|
368
|
+
errors: [stderr.trim() || `Codex process exited with code ${exitCode}`],
|
|
369
|
+
errorSubtype: 'process_exit',
|
|
370
|
+
raw: { exitCode, stderr },
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Create a new Codex provider instance
|
|
378
|
+
*/
|
|
379
|
+
export function createCodexProvider() {
|
|
380
|
+
return new CodexProvider();
|
|
381
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-provider.test.d.ts","sourceRoot":"","sources":["../../../src/providers/codex-provider.test.ts"],"names":[],"mappings":""}
|