axexec 1.0.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 +196 -0
- package/bin/axexec +17 -0
- package/dist/agents/claude-code/adapter.d.ts +6 -0
- package/dist/agents/claude-code/adapter.js +71 -0
- package/dist/agents/claude-code/parse-event.d.ts +16 -0
- package/dist/agents/claude-code/parse-event.js +185 -0
- package/dist/agents/claude-code/types.d.ts +180 -0
- package/dist/agents/claude-code/types.js +112 -0
- package/dist/agents/codex/adapter.d.ts +6 -0
- package/dist/agents/codex/adapter.js +62 -0
- package/dist/agents/codex/item-parsers.d.ts +17 -0
- package/dist/agents/codex/item-parsers.js +126 -0
- package/dist/agents/codex/parse-event.d.ts +38 -0
- package/dist/agents/codex/parse-event.js +141 -0
- package/dist/agents/codex/types.d.ts +407 -0
- package/dist/agents/codex/types.js +188 -0
- package/dist/agents/copilot/adapter.d.ts +11 -0
- package/dist/agents/copilot/adapter.js +81 -0
- package/dist/agents/copilot/parse-event.d.ts +20 -0
- package/dist/agents/copilot/parse-event.js +137 -0
- package/dist/agents/copilot/stream-session.d.ts +10 -0
- package/dist/agents/copilot/stream-session.js +120 -0
- package/dist/agents/copilot/tail-file.d.ts +11 -0
- package/dist/agents/copilot/tail-file.js +52 -0
- package/dist/agents/copilot/transform-event.d.ts +19 -0
- package/dist/agents/copilot/transform-event.js +100 -0
- package/dist/agents/copilot/types.d.ts +320 -0
- package/dist/agents/copilot/types.js +220 -0
- package/dist/agents/copilot/watch-session.d.ts +26 -0
- package/dist/agents/copilot/watch-session.js +186 -0
- package/dist/agents/gemini/adapter.d.ts +6 -0
- package/dist/agents/gemini/adapter.js +78 -0
- package/dist/agents/gemini/parse-event.d.ts +18 -0
- package/dist/agents/gemini/parse-event.js +144 -0
- package/dist/agents/gemini/types.d.ts +162 -0
- package/dist/agents/gemini/types.js +103 -0
- package/dist/agents/opencode/adapter.d.ts +16 -0
- package/dist/agents/opencode/adapter.js +142 -0
- package/dist/agents/opencode/cleanup-session.d.ts +17 -0
- package/dist/agents/opencode/cleanup-session.js +41 -0
- package/dist/agents/opencode/create-session-start-event.d.ts +18 -0
- package/dist/agents/opencode/create-session-start-event.js +24 -0
- package/dist/agents/opencode/detect-empty-session.d.ts +25 -0
- package/dist/agents/opencode/detect-empty-session.js +42 -0
- package/dist/agents/opencode/map-error-to-event.d.ts +10 -0
- package/dist/agents/opencode/map-error-to-event.js +55 -0
- package/dist/agents/opencode/parse-message-part.d.ts +24 -0
- package/dist/agents/opencode/parse-message-part.js +112 -0
- package/dist/agents/opencode/parse-sse-event.d.ts +23 -0
- package/dist/agents/opencode/parse-sse-event.js +125 -0
- package/dist/agents/opencode/process-sse-events.d.ts +24 -0
- package/dist/agents/opencode/process-sse-events.js +66 -0
- package/dist/agents/opencode/server-types.d.ts +509 -0
- package/dist/agents/opencode/server-types.js +293 -0
- package/dist/agents/opencode/session-api.d.ts +56 -0
- package/dist/agents/opencode/session-api.js +151 -0
- package/dist/agents/opencode/spawn-server.d.ts +29 -0
- package/dist/agents/opencode/spawn-server.js +95 -0
- package/dist/agents/opencode/sse-client.d.ts +33 -0
- package/dist/agents/opencode/sse-client.js +145 -0
- package/dist/agents/registry.d.ts +15 -0
- package/dist/agents/registry.js +24 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +119 -0
- package/dist/credentials/get-credential-environment.d.ts +13 -0
- package/dist/credentials/get-credential-environment.js +46 -0
- package/dist/credentials/install-credentials.d.ts +27 -0
- package/dist/credentials/install-credentials.js +102 -0
- package/dist/credentials/save-json-file.d.ts +11 -0
- package/dist/credentials/save-json-file.js +21 -0
- package/dist/credentials/types.d.ts +24 -0
- package/dist/credentials/types.js +4 -0
- package/dist/credentials/write-agent-credentials.d.ts +36 -0
- package/dist/credentials/write-agent-credentials.js +91 -0
- package/dist/determine-session-success.d.ts +15 -0
- package/dist/determine-session-success.js +25 -0
- package/dist/format-event-tsv.d.ts +23 -0
- package/dist/format-event-tsv.js +136 -0
- package/dist/parse-credentials.d.ts +13 -0
- package/dist/parse-credentials.js +63 -0
- package/dist/parse-iso-timestamp.d.ts +21 -0
- package/dist/parse-iso-timestamp.js +37 -0
- package/dist/resolve-binary.d.ts +29 -0
- package/dist/resolve-binary.js +46 -0
- package/dist/resolve-output-mode.d.ts +39 -0
- package/dist/resolve-output-mode.js +39 -0
- package/dist/run-agent.d.ts +32 -0
- package/dist/run-agent.js +146 -0
- package/dist/stream-agent.d.ts +20 -0
- package/dist/stream-agent.js +207 -0
- package/dist/types/adapter.d.ts +101 -0
- package/dist/types/adapter.js +14 -0
- package/dist/types/events.d.ts +82 -0
- package/dist/types/events.js +13 -0
- package/dist/types/options.d.ts +41 -0
- package/dist/types/options.js +4 -0
- package/dist/validate-agent.d.ts +20 -0
- package/dist/validate-agent.js +50 -0
- package/dist/write-event.d.ts +23 -0
- package/dist/write-event.js +43 -0
- package/package.json +79 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw event types from Claude Code's JSONL stream.
|
|
3
|
+
*
|
|
4
|
+
* These types represent the raw output from:
|
|
5
|
+
* `claude -p "..." --output-format stream-json --verbose`
|
|
6
|
+
*
|
|
7
|
+
* The parser transforms these into normalized {@link AxexecEvent} types.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
/** System event - emitted at startup with session info */
|
|
11
|
+
declare const ClaudeSystemEvent: z.ZodObject<{
|
|
12
|
+
type: z.ZodLiteral<"system">;
|
|
13
|
+
subtype: z.ZodOptional<z.ZodString>;
|
|
14
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
15
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
16
|
+
model: z.ZodOptional<z.ZodString>;
|
|
17
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
type ClaudeSystemEvent = z.infer<typeof ClaudeSystemEvent>;
|
|
20
|
+
/** Assistant event - model responses and tool calls */
|
|
21
|
+
declare const ClaudeAssistantEvent: z.ZodObject<{
|
|
22
|
+
type: z.ZodLiteral<"assistant">;
|
|
23
|
+
subtype: z.ZodOptional<z.ZodEnum<{
|
|
24
|
+
content: "content";
|
|
25
|
+
tool_use: "tool_use";
|
|
26
|
+
thinking: "thinking";
|
|
27
|
+
}>>;
|
|
28
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
29
|
+
message: z.ZodOptional<z.ZodObject<{
|
|
30
|
+
id: z.ZodOptional<z.ZodString>;
|
|
31
|
+
role: z.ZodOptional<z.ZodString>;
|
|
32
|
+
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
33
|
+
type: z.ZodString;
|
|
34
|
+
text: z.ZodOptional<z.ZodString>;
|
|
35
|
+
id: z.ZodOptional<z.ZodString>;
|
|
36
|
+
name: z.ZodOptional<z.ZodString>;
|
|
37
|
+
input: z.ZodOptional<z.ZodUnknown>;
|
|
38
|
+
}, z.core.$strip>>>;
|
|
39
|
+
model: z.ZodOptional<z.ZodString>;
|
|
40
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
41
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
44
|
+
}, z.core.$strip>>;
|
|
45
|
+
content_block: z.ZodOptional<z.ZodObject<{
|
|
46
|
+
type: z.ZodString;
|
|
47
|
+
text: z.ZodOptional<z.ZodString>;
|
|
48
|
+
id: z.ZodOptional<z.ZodString>;
|
|
49
|
+
name: z.ZodOptional<z.ZodString>;
|
|
50
|
+
input: z.ZodOptional<z.ZodUnknown>;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
type ClaudeAssistantEvent = z.infer<typeof ClaudeAssistantEvent>;
|
|
54
|
+
/** User event - typically tool results */
|
|
55
|
+
declare const ClaudeUserEvent: z.ZodObject<{
|
|
56
|
+
type: z.ZodLiteral<"user">;
|
|
57
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
58
|
+
message: z.ZodOptional<z.ZodObject<{
|
|
59
|
+
role: z.ZodOptional<z.ZodString>;
|
|
60
|
+
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
61
|
+
type: z.ZodEnum<{
|
|
62
|
+
text: "text";
|
|
63
|
+
tool_result: "tool_result";
|
|
64
|
+
}>;
|
|
65
|
+
tool_use_id: z.ZodOptional<z.ZodString>;
|
|
66
|
+
content: z.ZodOptional<z.ZodUnknown>;
|
|
67
|
+
text: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>>>;
|
|
69
|
+
}, z.core.$strip>>;
|
|
70
|
+
tool_use_result: z.ZodOptional<z.ZodObject<{
|
|
71
|
+
type: z.ZodOptional<z.ZodString>;
|
|
72
|
+
status: z.ZodOptional<z.ZodString>;
|
|
73
|
+
}, z.core.$loose>>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
type ClaudeUserEvent = z.infer<typeof ClaudeUserEvent>;
|
|
76
|
+
/** Result event - emitted when task completes */
|
|
77
|
+
declare const ClaudeResultEvent: z.ZodObject<{
|
|
78
|
+
type: z.ZodLiteral<"result">;
|
|
79
|
+
subtype: z.ZodEnum<{
|
|
80
|
+
success: "success";
|
|
81
|
+
error: "error";
|
|
82
|
+
cancelled: "cancelled";
|
|
83
|
+
}>;
|
|
84
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
85
|
+
message: z.ZodOptional<z.ZodString>;
|
|
86
|
+
error: z.ZodOptional<z.ZodString>;
|
|
87
|
+
duration_ms: z.ZodOptional<z.ZodNumber>;
|
|
88
|
+
total_cost_usd: z.ZodOptional<z.ZodNumber>;
|
|
89
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
90
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
91
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
92
|
+
}, z.core.$strip>>;
|
|
93
|
+
}, z.core.$strip>;
|
|
94
|
+
type ClaudeResultEvent = z.infer<typeof ClaudeResultEvent>;
|
|
95
|
+
/** Union of all Claude Code event types */
|
|
96
|
+
declare const ClaudeEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
97
|
+
type: z.ZodLiteral<"system">;
|
|
98
|
+
subtype: z.ZodOptional<z.ZodString>;
|
|
99
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
100
|
+
session_id: z.ZodOptional<z.ZodString>;
|
|
101
|
+
model: z.ZodOptional<z.ZodString>;
|
|
102
|
+
tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
103
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
104
|
+
type: z.ZodLiteral<"assistant">;
|
|
105
|
+
subtype: z.ZodOptional<z.ZodEnum<{
|
|
106
|
+
content: "content";
|
|
107
|
+
tool_use: "tool_use";
|
|
108
|
+
thinking: "thinking";
|
|
109
|
+
}>>;
|
|
110
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
111
|
+
message: z.ZodOptional<z.ZodObject<{
|
|
112
|
+
id: z.ZodOptional<z.ZodString>;
|
|
113
|
+
role: z.ZodOptional<z.ZodString>;
|
|
114
|
+
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
115
|
+
type: z.ZodString;
|
|
116
|
+
text: z.ZodOptional<z.ZodString>;
|
|
117
|
+
id: z.ZodOptional<z.ZodString>;
|
|
118
|
+
name: z.ZodOptional<z.ZodString>;
|
|
119
|
+
input: z.ZodOptional<z.ZodUnknown>;
|
|
120
|
+
}, z.core.$strip>>>;
|
|
121
|
+
model: z.ZodOptional<z.ZodString>;
|
|
122
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
123
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
125
|
+
}, z.core.$strip>>;
|
|
126
|
+
}, z.core.$strip>>;
|
|
127
|
+
content_block: z.ZodOptional<z.ZodObject<{
|
|
128
|
+
type: z.ZodString;
|
|
129
|
+
text: z.ZodOptional<z.ZodString>;
|
|
130
|
+
id: z.ZodOptional<z.ZodString>;
|
|
131
|
+
name: z.ZodOptional<z.ZodString>;
|
|
132
|
+
input: z.ZodOptional<z.ZodUnknown>;
|
|
133
|
+
}, z.core.$strip>>;
|
|
134
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
135
|
+
type: z.ZodLiteral<"user">;
|
|
136
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
137
|
+
message: z.ZodOptional<z.ZodObject<{
|
|
138
|
+
role: z.ZodOptional<z.ZodString>;
|
|
139
|
+
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
140
|
+
type: z.ZodEnum<{
|
|
141
|
+
text: "text";
|
|
142
|
+
tool_result: "tool_result";
|
|
143
|
+
}>;
|
|
144
|
+
tool_use_id: z.ZodOptional<z.ZodString>;
|
|
145
|
+
content: z.ZodOptional<z.ZodUnknown>;
|
|
146
|
+
text: z.ZodOptional<z.ZodString>;
|
|
147
|
+
}, z.core.$strip>>>;
|
|
148
|
+
}, z.core.$strip>>;
|
|
149
|
+
tool_use_result: z.ZodOptional<z.ZodObject<{
|
|
150
|
+
type: z.ZodOptional<z.ZodString>;
|
|
151
|
+
status: z.ZodOptional<z.ZodString>;
|
|
152
|
+
}, z.core.$loose>>;
|
|
153
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
154
|
+
type: z.ZodLiteral<"result">;
|
|
155
|
+
subtype: z.ZodEnum<{
|
|
156
|
+
success: "success";
|
|
157
|
+
error: "error";
|
|
158
|
+
cancelled: "cancelled";
|
|
159
|
+
}>;
|
|
160
|
+
timestamp: z.ZodOptional<z.ZodString>;
|
|
161
|
+
message: z.ZodOptional<z.ZodString>;
|
|
162
|
+
error: z.ZodOptional<z.ZodString>;
|
|
163
|
+
duration_ms: z.ZodOptional<z.ZodNumber>;
|
|
164
|
+
total_cost_usd: z.ZodOptional<z.ZodNumber>;
|
|
165
|
+
usage: z.ZodOptional<z.ZodObject<{
|
|
166
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
167
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
169
|
+
}, z.core.$strip>], "type">;
|
|
170
|
+
type ClaudeEvent = z.infer<typeof ClaudeEvent>;
|
|
171
|
+
/** Type guard for system events */
|
|
172
|
+
declare function isSystemEvent(event: ClaudeEvent): event is ClaudeSystemEvent;
|
|
173
|
+
/** Type guard for assistant events */
|
|
174
|
+
declare function isAssistantEvent(event: ClaudeEvent): event is ClaudeAssistantEvent;
|
|
175
|
+
/** Type guard for user events */
|
|
176
|
+
declare function isUserEvent(event: ClaudeEvent): event is ClaudeUserEvent;
|
|
177
|
+
/** Type guard for result events */
|
|
178
|
+
declare function isResultEvent(event: ClaudeEvent): event is ClaudeResultEvent;
|
|
179
|
+
export { ClaudeEvent, isAssistantEvent, isResultEvent, isSystemEvent, isUserEvent, };
|
|
180
|
+
export type { ClaudeAssistantEvent, ClaudeResultEvent, ClaudeSystemEvent, ClaudeUserEvent, };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw event types from Claude Code's JSONL stream.
|
|
3
|
+
*
|
|
4
|
+
* These types represent the raw output from:
|
|
5
|
+
* `claude -p "..." --output-format stream-json --verbose`
|
|
6
|
+
*
|
|
7
|
+
* The parser transforms these into normalized {@link AxexecEvent} types.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
/** Content block schema - used in assistant events */
|
|
11
|
+
const ClaudeContentBlock = z.object({
|
|
12
|
+
type: z.string(),
|
|
13
|
+
text: z.string().optional(),
|
|
14
|
+
id: z.string().optional(),
|
|
15
|
+
name: z.string().optional(),
|
|
16
|
+
input: z.unknown().optional(),
|
|
17
|
+
});
|
|
18
|
+
/** System event - emitted at startup with session info */
|
|
19
|
+
const ClaudeSystemEvent = z.object({
|
|
20
|
+
type: z.literal("system"),
|
|
21
|
+
subtype: z.string().optional(),
|
|
22
|
+
timestamp: z.string().optional(),
|
|
23
|
+
session_id: z.string().optional(),
|
|
24
|
+
model: z.string().optional(),
|
|
25
|
+
tools: z.array(z.string()).optional(),
|
|
26
|
+
});
|
|
27
|
+
/** Assistant event - model responses and tool calls */
|
|
28
|
+
const ClaudeAssistantEvent = z.object({
|
|
29
|
+
type: z.literal("assistant"),
|
|
30
|
+
subtype: z.enum(["content", "tool_use", "thinking"]).optional(),
|
|
31
|
+
timestamp: z.string().optional(),
|
|
32
|
+
message: z
|
|
33
|
+
.object({
|
|
34
|
+
id: z.string().optional(),
|
|
35
|
+
role: z.string().optional(),
|
|
36
|
+
content: z.array(ClaudeContentBlock).optional(),
|
|
37
|
+
model: z.string().optional(),
|
|
38
|
+
usage: z
|
|
39
|
+
.object({
|
|
40
|
+
input_tokens: z.number().optional(),
|
|
41
|
+
output_tokens: z.number().optional(),
|
|
42
|
+
})
|
|
43
|
+
.optional(),
|
|
44
|
+
})
|
|
45
|
+
.optional(),
|
|
46
|
+
content_block: ClaudeContentBlock.optional(),
|
|
47
|
+
});
|
|
48
|
+
/** Content block in user messages (tool results) */
|
|
49
|
+
const ClaudeUserContentBlock = z.object({
|
|
50
|
+
type: z.enum(["tool_result", "text"]),
|
|
51
|
+
tool_use_id: z.string().optional(),
|
|
52
|
+
content: z.unknown().optional(),
|
|
53
|
+
text: z.string().optional(),
|
|
54
|
+
});
|
|
55
|
+
/** User event - typically tool results */
|
|
56
|
+
const ClaudeUserEvent = z.object({
|
|
57
|
+
type: z.literal("user"),
|
|
58
|
+
timestamp: z.string().optional(),
|
|
59
|
+
message: z
|
|
60
|
+
.object({
|
|
61
|
+
role: z.string().optional(),
|
|
62
|
+
content: z.array(ClaudeUserContentBlock).optional(),
|
|
63
|
+
})
|
|
64
|
+
.optional(),
|
|
65
|
+
// Tool use result metadata (when present)
|
|
66
|
+
tool_use_result: z
|
|
67
|
+
.looseObject({
|
|
68
|
+
type: z.string().optional(),
|
|
69
|
+
status: z.string().optional(),
|
|
70
|
+
})
|
|
71
|
+
.optional(),
|
|
72
|
+
});
|
|
73
|
+
/** Result event - emitted when task completes */
|
|
74
|
+
const ClaudeResultEvent = z.object({
|
|
75
|
+
type: z.literal("result"),
|
|
76
|
+
subtype: z.enum(["success", "error", "cancelled"]),
|
|
77
|
+
timestamp: z.string().optional(),
|
|
78
|
+
message: z.string().optional(),
|
|
79
|
+
error: z.string().optional(),
|
|
80
|
+
duration_ms: z.number().optional(),
|
|
81
|
+
total_cost_usd: z.number().optional(),
|
|
82
|
+
usage: z
|
|
83
|
+
.object({
|
|
84
|
+
input_tokens: z.number().optional(),
|
|
85
|
+
output_tokens: z.number().optional(),
|
|
86
|
+
})
|
|
87
|
+
.optional(),
|
|
88
|
+
});
|
|
89
|
+
/** Union of all Claude Code event types */
|
|
90
|
+
const ClaudeEvent = z.discriminatedUnion("type", [
|
|
91
|
+
ClaudeSystemEvent,
|
|
92
|
+
ClaudeAssistantEvent,
|
|
93
|
+
ClaudeUserEvent,
|
|
94
|
+
ClaudeResultEvent,
|
|
95
|
+
]);
|
|
96
|
+
/** Type guard for system events */
|
|
97
|
+
function isSystemEvent(event) {
|
|
98
|
+
return event.type === "system";
|
|
99
|
+
}
|
|
100
|
+
/** Type guard for assistant events */
|
|
101
|
+
function isAssistantEvent(event) {
|
|
102
|
+
return event.type === "assistant";
|
|
103
|
+
}
|
|
104
|
+
/** Type guard for user events */
|
|
105
|
+
function isUserEvent(event) {
|
|
106
|
+
return event.type === "user";
|
|
107
|
+
}
|
|
108
|
+
/** Type guard for result events */
|
|
109
|
+
function isResultEvent(event) {
|
|
110
|
+
return event.type === "result";
|
|
111
|
+
}
|
|
112
|
+
export { ClaudeEvent, isAssistantEvent, isResultEvent, isSystemEvent, isUserEvent, };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex adapter implementation.
|
|
3
|
+
*
|
|
4
|
+
* Implements the {@link AgentAdapter} interface for Codex CLI.
|
|
5
|
+
*/
|
|
6
|
+
import { determineSessionSuccess } from "../../determine-session-success.js";
|
|
7
|
+
import { resolveBinary } from "../../resolve-binary.js";
|
|
8
|
+
import { registerAdapter } from "../registry.js";
|
|
9
|
+
import { createCodexParser } from "./parse-event.js";
|
|
10
|
+
const CODEX_INFO = {
|
|
11
|
+
id: "codex",
|
|
12
|
+
name: "Codex",
|
|
13
|
+
package: "@openai/codex",
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Prepares the command to spawn Codex CLI.
|
|
17
|
+
*/
|
|
18
|
+
function prepareCommand(options) {
|
|
19
|
+
// Build CLI arguments.
|
|
20
|
+
// Enable network access in sandbox: Codex blocks network by default in
|
|
21
|
+
// workspace-write mode, but other agents (Gemini, OpenCode) allow it by
|
|
22
|
+
// default. For unified behavior, enable it. This keeps file-level sandbox
|
|
23
|
+
// protections while allowing gh, curl, etc.
|
|
24
|
+
const cliArguments = [
|
|
25
|
+
"exec",
|
|
26
|
+
"--json",
|
|
27
|
+
"--full-auto",
|
|
28
|
+
"-c",
|
|
29
|
+
"sandbox_workspace_write.network_access=true",
|
|
30
|
+
// Add model flag if specified (o4-mini, gpt-5.1-codex, gpt-5.2, etc.)
|
|
31
|
+
...(options.model ? ["--model", options.model] : []),
|
|
32
|
+
// Use "--" to prevent prompt from being misinterpreted as a flag
|
|
33
|
+
"--",
|
|
34
|
+
options.prompt,
|
|
35
|
+
];
|
|
36
|
+
const environment = {};
|
|
37
|
+
// Pass through authentication environment variable.
|
|
38
|
+
// If not set, Codex CLI will handle auth errors on its own.
|
|
39
|
+
if (process.env["OPENAI_API_KEY"]) {
|
|
40
|
+
environment["OPENAI_API_KEY"] = process.env["OPENAI_API_KEY"];
|
|
41
|
+
}
|
|
42
|
+
const bin = resolveBinary({
|
|
43
|
+
name: "codex",
|
|
44
|
+
command: "codex",
|
|
45
|
+
environmentVariable: "AXEXEC_CODEX_PATH",
|
|
46
|
+
installHint: "npm install -g @openai/codex",
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
bin,
|
|
50
|
+
args: cliArguments,
|
|
51
|
+
env: environment,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Codex adapter */
|
|
55
|
+
const codexAdapter = {
|
|
56
|
+
info: () => CODEX_INFO,
|
|
57
|
+
prepareCommand,
|
|
58
|
+
createParser: (options) => createCodexParser(options?.model),
|
|
59
|
+
isSuccess: determineSessionSuccess,
|
|
60
|
+
};
|
|
61
|
+
// Self-register on import
|
|
62
|
+
registerAdapter(codexAdapter);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AxexecEvent } from "../../types/events.js";
|
|
2
|
+
import type { CodexItemCompletedEvent, CodexItemStartedEvent } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses item.started events.
|
|
5
|
+
*
|
|
6
|
+
* Only handles tool calls (command_execution, mcp_tool_call, file_change).
|
|
7
|
+
* Codex emits reasoning and agent_message only as item.completed, not item.started.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseItemStartedEvent(event: CodexItemStartedEvent, toolContext: Map<string, {
|
|
10
|
+
tool: string;
|
|
11
|
+
input: unknown;
|
|
12
|
+
}>, timestamp: number): AxexecEvent | undefined;
|
|
13
|
+
/** Parses item.completed events */
|
|
14
|
+
export declare function parseItemCompletedEvent(event: CodexItemCompletedEvent, toolContext: Map<string, {
|
|
15
|
+
tool: string;
|
|
16
|
+
input: unknown;
|
|
17
|
+
}>, timestamp: number): AxexecEvent | undefined;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses item.started events.
|
|
3
|
+
*
|
|
4
|
+
* Only handles tool calls (command_execution, mcp_tool_call, file_change).
|
|
5
|
+
* Codex emits reasoning and agent_message only as item.completed, not item.started.
|
|
6
|
+
*/
|
|
7
|
+
export function parseItemStartedEvent(event, toolContext, timestamp) {
|
|
8
|
+
const item = event.item;
|
|
9
|
+
if (item.type === "command_execution") {
|
|
10
|
+
const tool = "shell";
|
|
11
|
+
const input = { command: item.command };
|
|
12
|
+
toolContext.set(item.id, { tool, input });
|
|
13
|
+
return {
|
|
14
|
+
type: "tool.call",
|
|
15
|
+
callId: item.id,
|
|
16
|
+
tool,
|
|
17
|
+
input,
|
|
18
|
+
timestamp,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (item.type === "mcp_tool_call") {
|
|
22
|
+
const tool = `${item.server}:${item.tool}`;
|
|
23
|
+
const input = item.arguments;
|
|
24
|
+
toolContext.set(item.id, { tool, input });
|
|
25
|
+
return {
|
|
26
|
+
type: "tool.call",
|
|
27
|
+
callId: item.id,
|
|
28
|
+
tool,
|
|
29
|
+
input,
|
|
30
|
+
timestamp,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (item.type === "file_change") {
|
|
34
|
+
const tool = "file_change";
|
|
35
|
+
const input = item.changes;
|
|
36
|
+
toolContext.set(item.id, { tool, input });
|
|
37
|
+
return {
|
|
38
|
+
type: "tool.call",
|
|
39
|
+
callId: item.id,
|
|
40
|
+
tool,
|
|
41
|
+
input,
|
|
42
|
+
timestamp,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Ignore other item types like web_search, todo_list, error (handled elsewhere or ignored)
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
/** Parses item.completed events */
|
|
49
|
+
export function parseItemCompletedEvent(event, toolContext, timestamp) {
|
|
50
|
+
const item = event.item;
|
|
51
|
+
// Handle reasoning and agent_message items as progress events.
|
|
52
|
+
// Codex emits these as item.completed, not item.started.
|
|
53
|
+
if (item.type === "reasoning") {
|
|
54
|
+
return {
|
|
55
|
+
type: "agent.reasoning",
|
|
56
|
+
content: item.text,
|
|
57
|
+
timestamp,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (item.type === "agent_message") {
|
|
61
|
+
return {
|
|
62
|
+
type: "agent.message",
|
|
63
|
+
content: item.text,
|
|
64
|
+
timestamp,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// Only handle tool completions below
|
|
68
|
+
if (item.type !== "command_execution" &&
|
|
69
|
+
item.type !== "mcp_tool_call" &&
|
|
70
|
+
item.type !== "file_change") {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const context = toolContext.get(item.id);
|
|
74
|
+
// If an item.completed event arrives without a corresponding item.started event,
|
|
75
|
+
// we won't have context, so deriveToolName reconstructs the tool name from the item type.
|
|
76
|
+
const toolName = context?.tool ?? deriveToolName(item.type, item);
|
|
77
|
+
// Clean up map
|
|
78
|
+
toolContext.delete(item.id);
|
|
79
|
+
let output;
|
|
80
|
+
switch (item.type) {
|
|
81
|
+
case "command_execution": {
|
|
82
|
+
output = item.aggregated_output;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "mcp_tool_call": {
|
|
86
|
+
output = item.result ?? item.error;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case "file_change": {
|
|
90
|
+
// File change doesn't usually have an output other than success/fail status
|
|
91
|
+
// We can use the changes as output or just "File changes applied"
|
|
92
|
+
output = item.changes;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
type: "tool.result",
|
|
98
|
+
callId: item.id,
|
|
99
|
+
tool: toolName,
|
|
100
|
+
output,
|
|
101
|
+
success: item.status === "completed",
|
|
102
|
+
timestamp,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Helper to derive tool name if context is missing */
|
|
106
|
+
function deriveToolName(type, item) {
|
|
107
|
+
switch (type) {
|
|
108
|
+
case "command_execution": {
|
|
109
|
+
return "shell";
|
|
110
|
+
}
|
|
111
|
+
case "mcp_tool_call": {
|
|
112
|
+
// Validate mcp_tool_call has expected shape before accessing properties
|
|
113
|
+
if (typeof item === "object" &&
|
|
114
|
+
item !== null &&
|
|
115
|
+
"server" in item &&
|
|
116
|
+
"tool" in item) {
|
|
117
|
+
const mcp = item;
|
|
118
|
+
return `${mcp.server}:${mcp.tool}`;
|
|
119
|
+
}
|
|
120
|
+
return "unknown_mcp";
|
|
121
|
+
}
|
|
122
|
+
case "file_change": {
|
|
123
|
+
return "file_change";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event parser for Codex CLI.
|
|
3
|
+
*
|
|
4
|
+
* Transforms raw Codex CLI JSONL events into normalized {@link AxexecEvent} types.
|
|
5
|
+
* Uses stateful correlation to resolve tool names in tool.result events.
|
|
6
|
+
*
|
|
7
|
+
* ## Turn Completion Semantics
|
|
8
|
+
*
|
|
9
|
+
* In `codex exec` mode (the mode used by this adapter), each process invocation
|
|
10
|
+
* handles exactly **one turn** before exiting. The event sequence is:
|
|
11
|
+
*
|
|
12
|
+
* 1. `thread.started` - session initialized
|
|
13
|
+
* 2. `turn.started` - single turn begins
|
|
14
|
+
* 3. `item.*` events - tool calls, messages, reasoning
|
|
15
|
+
* 4. `turn.completed` or `turn.failed` - turn ends
|
|
16
|
+
* 5. Process exits
|
|
17
|
+
*
|
|
18
|
+
* This means a single `codex exec` invocation will emit exactly one
|
|
19
|
+
* `turn.completed` (or `turn.failed`) event. The "resume" functionality
|
|
20
|
+
* (`codex exec resume <id>`) spawns a **new process** for each resumed turn.
|
|
21
|
+
*
|
|
22
|
+
* Therefore, mapping `turn.completed` to `task.complete` is correct; there is
|
|
23
|
+
* no risk of multiple `task.complete` events per session.
|
|
24
|
+
*
|
|
25
|
+
* @see https://github.com/openai/codex/blob/main/codex-rs/exec/src/lib.rs
|
|
26
|
+
* Search for `TaskComplete` handling which triggers `InitiateShutdown`.
|
|
27
|
+
*/
|
|
28
|
+
import type { EventParser } from "../../types/adapter.js";
|
|
29
|
+
/**
|
|
30
|
+
* Creates a parser for Codex CLI events.
|
|
31
|
+
*
|
|
32
|
+
* Maintains a mapping from item ID to tool info to support
|
|
33
|
+
* correlating start/complete events for tools.
|
|
34
|
+
*
|
|
35
|
+
* @param requestedModel - Model passed via --model flag (if any)
|
|
36
|
+
*/
|
|
37
|
+
declare function createCodexParser(requestedModel?: string): EventParser;
|
|
38
|
+
export { createCodexParser };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event parser for Codex CLI.
|
|
3
|
+
*
|
|
4
|
+
* Transforms raw Codex CLI JSONL events into normalized {@link AxexecEvent} types.
|
|
5
|
+
* Uses stateful correlation to resolve tool names in tool.result events.
|
|
6
|
+
*
|
|
7
|
+
* ## Turn Completion Semantics
|
|
8
|
+
*
|
|
9
|
+
* In `codex exec` mode (the mode used by this adapter), each process invocation
|
|
10
|
+
* handles exactly **one turn** before exiting. The event sequence is:
|
|
11
|
+
*
|
|
12
|
+
* 1. `thread.started` - session initialized
|
|
13
|
+
* 2. `turn.started` - single turn begins
|
|
14
|
+
* 3. `item.*` events - tool calls, messages, reasoning
|
|
15
|
+
* 4. `turn.completed` or `turn.failed` - turn ends
|
|
16
|
+
* 5. Process exits
|
|
17
|
+
*
|
|
18
|
+
* This means a single `codex exec` invocation will emit exactly one
|
|
19
|
+
* `turn.completed` (or `turn.failed`) event. The "resume" functionality
|
|
20
|
+
* (`codex exec resume <id>`) spawns a **new process** for each resumed turn.
|
|
21
|
+
*
|
|
22
|
+
* Therefore, mapping `turn.completed` to `task.complete` is correct; there is
|
|
23
|
+
* no risk of multiple `task.complete` events per session.
|
|
24
|
+
*
|
|
25
|
+
* @see https://github.com/openai/codex/blob/main/codex-rs/exec/src/lib.rs
|
|
26
|
+
* Search for `TaskComplete` handling which triggers `InitiateShutdown`.
|
|
27
|
+
*/
|
|
28
|
+
import { createTimestampParser } from "../../parse-iso-timestamp.js";
|
|
29
|
+
import { CodexEvent, isErrorEvent, isItemCompletedEvent, isItemStartedEvent, isThreadStartedEvent, isTurnCompletedEvent, isTurnFailedEvent, } from "./types.js";
|
|
30
|
+
import { parseItemCompletedEvent, parseItemStartedEvent, } from "./item-parsers.js";
|
|
31
|
+
/**
|
|
32
|
+
* Creates a parser for Codex CLI events.
|
|
33
|
+
*
|
|
34
|
+
* Maintains a mapping from item ID to tool info to support
|
|
35
|
+
* correlating start/complete events for tools.
|
|
36
|
+
*
|
|
37
|
+
* @param requestedModel - Model passed via --model flag (if any)
|
|
38
|
+
*/
|
|
39
|
+
function createCodexParser(requestedModel) {
|
|
40
|
+
// Map from item ID to tool info for correlation
|
|
41
|
+
// This is needed because item.completed events might need context from item.started
|
|
42
|
+
// (specifically tool name, although AxexecEvent.tool.result needs it)
|
|
43
|
+
const toolContext = new Map();
|
|
44
|
+
// Stateful timestamp parser - falls back to previous timestamp when missing
|
|
45
|
+
const parseTimestamp = createTimestampParser();
|
|
46
|
+
// Track session start time to calculate duration (Codex doesn't provide it)
|
|
47
|
+
let sessionStartMs;
|
|
48
|
+
return (line) => {
|
|
49
|
+
const trimmed = line.trim();
|
|
50
|
+
if (trimmed === "") {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
let json;
|
|
54
|
+
try {
|
|
55
|
+
json = JSON.parse(trimmed);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
// Extract timestamp from RolloutLine envelope before schema validation.
|
|
61
|
+
// Codex wraps events in RolloutLine which adds a timestamp field at the top level.
|
|
62
|
+
const rawTimestamp = typeof json === "object" &&
|
|
63
|
+
json !== null &&
|
|
64
|
+
"timestamp" in json &&
|
|
65
|
+
typeof json["timestamp"] === "string"
|
|
66
|
+
? json["timestamp"]
|
|
67
|
+
: undefined;
|
|
68
|
+
const timestamp = parseTimestamp(rawTimestamp);
|
|
69
|
+
const result = CodexEvent.safeParse(json);
|
|
70
|
+
if (!result.success) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
const raw = result.data;
|
|
74
|
+
if (isThreadStartedEvent(raw)) {
|
|
75
|
+
sessionStartMs = Date.now();
|
|
76
|
+
return parseThreadStartedEvent(raw, timestamp, requestedModel);
|
|
77
|
+
}
|
|
78
|
+
if (isItemStartedEvent(raw)) {
|
|
79
|
+
return parseItemStartedEvent(raw, toolContext, timestamp);
|
|
80
|
+
}
|
|
81
|
+
if (isItemCompletedEvent(raw)) {
|
|
82
|
+
return parseItemCompletedEvent(raw, toolContext, timestamp);
|
|
83
|
+
}
|
|
84
|
+
if (isTurnCompletedEvent(raw)) {
|
|
85
|
+
const durationMs = sessionStartMs === undefined ? 0 : Date.now() - sessionStartMs;
|
|
86
|
+
return parseTurnCompletedEvent(raw, durationMs, timestamp);
|
|
87
|
+
}
|
|
88
|
+
if (isTurnFailedEvent(raw)) {
|
|
89
|
+
return parseTurnFailedEvent(raw, timestamp);
|
|
90
|
+
}
|
|
91
|
+
if (isErrorEvent(raw)) {
|
|
92
|
+
return parseErrorEvent(raw, timestamp);
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/** Parses a thread.started event (session start) */
|
|
98
|
+
function parseThreadStartedEvent(event, timestamp, requestedModel) {
|
|
99
|
+
// Codex JSONL output doesn't include model info - it's stripped during
|
|
100
|
+
// conversion from SessionConfiguredEvent to ThreadStartedEvent.
|
|
101
|
+
// Use the model passed via CLI if available, otherwise report "unknown".
|
|
102
|
+
return {
|
|
103
|
+
type: "session.start",
|
|
104
|
+
sessionId: event.thread_id,
|
|
105
|
+
agent: "codex",
|
|
106
|
+
model: requestedModel ?? "unknown",
|
|
107
|
+
provider: "openai",
|
|
108
|
+
timestamp,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Parses turn.completed event (session complete) */
|
|
112
|
+
function parseTurnCompletedEvent(event, durationMs, timestamp) {
|
|
113
|
+
return {
|
|
114
|
+
type: "session.complete",
|
|
115
|
+
stats: {
|
|
116
|
+
durationMs,
|
|
117
|
+
inputTokens: event.usage.input_tokens,
|
|
118
|
+
outputTokens: event.usage.output_tokens,
|
|
119
|
+
},
|
|
120
|
+
timestamp,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Parses turn.failed event (session error) */
|
|
124
|
+
function parseTurnFailedEvent(event, timestamp) {
|
|
125
|
+
return {
|
|
126
|
+
type: "session.error",
|
|
127
|
+
code: "AGENT_ERROR",
|
|
128
|
+
message: event.error.message,
|
|
129
|
+
timestamp,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/** Parses error event (session error) */
|
|
133
|
+
function parseErrorEvent(event, timestamp) {
|
|
134
|
+
return {
|
|
135
|
+
type: "session.error",
|
|
136
|
+
code: "AGENT_ERROR",
|
|
137
|
+
message: event.message,
|
|
138
|
+
timestamp,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
export { createCodexParser };
|