coding-agents-sdk 0.0.1 → 0.2.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/README.md +242 -0
- package/dist/Agent-D8WkUilj.mjs +262 -0
- package/dist/SdkAgent-B47mJiIE.mjs +38 -0
- package/dist/adapters/claude-code-cli/index.d.mts +2 -0
- package/dist/adapters/claude-code-cli/index.mjs +490 -0
- package/dist/adapters/claude-code-sdk/index.d.mts +2 -0
- package/dist/adapters/claude-code-sdk/index.mjs +483 -0
- package/dist/adapters/codex-cli/index.d.mts +2 -0
- package/dist/adapters/codex-cli/index.mjs +626 -0
- package/dist/adapters/codex-sdk/index.d.mts +2 -0
- package/dist/adapters/codex-sdk/index.mjs +286 -0
- package/dist/adapters/gemini-cli/index.d.mts +2 -0
- package/dist/adapters/gemini-cli/index.mjs +292 -0
- package/dist/classify-error-pL6jeu4T.mjs +456 -0
- package/dist/container/index.d.mts +2 -0
- package/dist/container/index.mjs +24 -0
- package/dist/container-2UmPZ0CI.mjs +22 -0
- package/dist/container-CHxKIonn.mjs +440 -0
- package/dist/container-D2Z0ITDJ.mjs +22 -0
- package/dist/diff-De8d3MVb.mjs +333 -0
- package/dist/errors-BAmHDQu8.mjs +45 -0
- package/dist/events-nxuRbYIu.d.mts +239 -0
- package/dist/index-B3YqrgIp.d.mts +45 -0
- package/dist/index-ByAOGMUM.d.mts +224 -0
- package/dist/index-C3ZxLAd0.d.mts +315 -0
- package/dist/index-CFpNOmdA.d.mts +145 -0
- package/dist/index-dRVpEAr8.d.mts +39 -0
- package/dist/index-nzo1sBiK.d.mts +110 -0
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs +61 -0
- package/dist/oci-DMZZQZ47.mjs +438 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +2 -0
- package/dist/schemas-DwD4pwJB.mjs +96 -0
- package/dist/spawner-Bw9UBEGX.mjs +54 -0
- package/dist/structured-output-BHtr_zpz.mjs +19 -0
- package/dist/types-Cb_EXIEe.d.mts +177 -0
- package/dist/types-aNMD8h3x.mjs +19 -0
- package/dist/util-B4RQZkKr.mjs +77 -0
- package/package.json +86 -9
- package/index.js +0 -7
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import { n as AgentValidationError } from "../../types-aNMD8h3x.mjs";
|
|
2
|
+
import { a as toArray, i as sumTokens, n as isRecord, r as parseJsonResponseText } from "../../util-B4RQZkKr.mjs";
|
|
3
|
+
import { c as getInputText, l as toTextPart, o as createAgentEvent, s as createEventParser } from "../../classify-error-pL6jeu4T.mjs";
|
|
4
|
+
import { t as Agent } from "../../Agent-D8WkUilj.mjs";
|
|
5
|
+
import { z } from "zod/v4";
|
|
6
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
//#region src/adapters/codex-cli/events/schemas.ts
|
|
10
|
+
const codexEventSchema = z.object({ type: z.string() }).passthrough();
|
|
11
|
+
const codexUsageSchema = z.object({
|
|
12
|
+
input_tokens: z.number().optional(),
|
|
13
|
+
cached_input_tokens: z.number().optional(),
|
|
14
|
+
output_tokens: z.number().optional(),
|
|
15
|
+
reasoning_output_tokens: z.number().optional(),
|
|
16
|
+
total_tokens: z.number().optional()
|
|
17
|
+
}).passthrough();
|
|
18
|
+
const codexThreadStartedEventSchema = z.object({
|
|
19
|
+
type: z.literal("thread.started"),
|
|
20
|
+
thread_id: z.string()
|
|
21
|
+
}).passthrough();
|
|
22
|
+
const codexTurnCompletedEventSchema = z.object({
|
|
23
|
+
type: z.literal("turn.completed"),
|
|
24
|
+
usage: codexUsageSchema.optional(),
|
|
25
|
+
last_agent_message: z.string().optional(),
|
|
26
|
+
duration_ms: z.number().optional(),
|
|
27
|
+
num_turns: z.number().optional()
|
|
28
|
+
}).passthrough();
|
|
29
|
+
const codexTurnFailedEventSchema = z.object({
|
|
30
|
+
type: z.literal("turn.failed"),
|
|
31
|
+
usage: codexUsageSchema.optional(),
|
|
32
|
+
last_agent_message: z.string().optional(),
|
|
33
|
+
duration_ms: z.number().optional(),
|
|
34
|
+
num_turns: z.number().optional(),
|
|
35
|
+
message: z.string().optional(),
|
|
36
|
+
error: z.unknown().optional()
|
|
37
|
+
}).passthrough();
|
|
38
|
+
const codexItemSchema = z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
type: z.string()
|
|
41
|
+
}).passthrough();
|
|
42
|
+
const codexItemStartedEventSchema = z.object({
|
|
43
|
+
type: z.literal("item.started"),
|
|
44
|
+
item: codexItemSchema
|
|
45
|
+
}).passthrough();
|
|
46
|
+
const codexItemUpdatedEventSchema = z.object({
|
|
47
|
+
type: z.literal("item.updated"),
|
|
48
|
+
item: codexItemSchema
|
|
49
|
+
}).passthrough();
|
|
50
|
+
const codexItemCompletedEventSchema = z.object({
|
|
51
|
+
type: z.literal("item.completed"),
|
|
52
|
+
item: codexItemSchema
|
|
53
|
+
}).passthrough();
|
|
54
|
+
const codexErrorEventSchema = z.object({
|
|
55
|
+
type: z.literal("error"),
|
|
56
|
+
message: z.string().optional(),
|
|
57
|
+
error: z.unknown().optional()
|
|
58
|
+
}).passthrough();
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/adapters/codex-cli/events/mappers.ts
|
|
61
|
+
const asRecord = (value) => {
|
|
62
|
+
return isRecord(value) ? value : void 0;
|
|
63
|
+
};
|
|
64
|
+
const getValue = (record, keys) => {
|
|
65
|
+
if (!record) return void 0;
|
|
66
|
+
for (const key of keys) if (key in record) return record[key];
|
|
67
|
+
};
|
|
68
|
+
const getString = (record, keys) => {
|
|
69
|
+
const value = getValue(record, keys);
|
|
70
|
+
return typeof value === "string" ? value : void 0;
|
|
71
|
+
};
|
|
72
|
+
const getNumber = (record, keys) => {
|
|
73
|
+
const value = getValue(record, keys);
|
|
74
|
+
return typeof value === "number" ? value : void 0;
|
|
75
|
+
};
|
|
76
|
+
const getCompactObject = (value) => {
|
|
77
|
+
const entries = Object.entries(value).filter(([, entry]) => entry !== void 0);
|
|
78
|
+
if (entries.length === 0) return;
|
|
79
|
+
return Object.fromEntries(entries);
|
|
80
|
+
};
|
|
81
|
+
const normalizeItemType = (value) => {
|
|
82
|
+
return value.replace(/([\da-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
83
|
+
};
|
|
84
|
+
const getErrorMessage = (value, fallback) => {
|
|
85
|
+
if (typeof value === "string" && value.trim() !== "") return value;
|
|
86
|
+
const record = asRecord(value);
|
|
87
|
+
if (!record) return fallback;
|
|
88
|
+
return getString(record, [
|
|
89
|
+
"message",
|
|
90
|
+
"error",
|
|
91
|
+
"status_message"
|
|
92
|
+
]) ?? getString(asRecord(record.additional_details), ["message"]) ?? fallback;
|
|
93
|
+
};
|
|
94
|
+
const toStats = (event) => {
|
|
95
|
+
const usage = asRecord(event.usage);
|
|
96
|
+
const inputTokens = getNumber(usage, ["input_tokens"]);
|
|
97
|
+
const cacheReadInputTokens = getNumber(usage, ["cached_input_tokens"]);
|
|
98
|
+
const outputTokens = getNumber(usage, ["output_tokens"]);
|
|
99
|
+
const reasoningOutputTokens = getNumber(usage, ["reasoning_output_tokens"]);
|
|
100
|
+
const totalTokens = getNumber(usage, ["total_tokens"]) ?? sumTokens(inputTokens, cacheReadInputTokens, outputTokens, reasoningOutputTokens);
|
|
101
|
+
return {
|
|
102
|
+
durationMs: getNumber(event, ["duration_ms", "durationMs"]) ?? 0,
|
|
103
|
+
apiDurationMs: getNumber(event, ["duration_ms", "durationMs"]) ?? 0,
|
|
104
|
+
turns: getNumber(event, ["num_turns", "numTurns"]) ?? 1,
|
|
105
|
+
costUsd: 0,
|
|
106
|
+
inputTokens,
|
|
107
|
+
cacheReadInputTokens,
|
|
108
|
+
outputTokens,
|
|
109
|
+
totalTokens
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
const getCommandToolRecord = (item) => ({
|
|
113
|
+
toolName: "Bash",
|
|
114
|
+
input: getCompactObject({
|
|
115
|
+
command: getString(item, ["command"]),
|
|
116
|
+
cwd: getString(item, ["cwd", "working_directory"]),
|
|
117
|
+
parsedCommand: getValue(item, ["parsed_cmd", "parsedCommand"])
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
const getMcpToolRecord = (item) => {
|
|
121
|
+
const toolName = getString(item, ["tool", "tool_name"]) ?? "mcp_tool_call";
|
|
122
|
+
const server = getString(item, ["server"]);
|
|
123
|
+
const argumentsValue = getValue(item, [
|
|
124
|
+
"arguments",
|
|
125
|
+
"invocation",
|
|
126
|
+
"input"
|
|
127
|
+
]);
|
|
128
|
+
return {
|
|
129
|
+
toolName,
|
|
130
|
+
input: server === void 0 ? argumentsValue : getCompactObject({
|
|
131
|
+
server,
|
|
132
|
+
arguments: argumentsValue
|
|
133
|
+
})
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
const getWebSearchToolRecord = (item) => ({
|
|
137
|
+
toolName: "WebSearch",
|
|
138
|
+
input: getCompactObject({
|
|
139
|
+
query: getString(item, ["query"]),
|
|
140
|
+
action: getValue(item, ["action"])
|
|
141
|
+
})
|
|
142
|
+
});
|
|
143
|
+
const getToolErrorState = (item) => {
|
|
144
|
+
const status = getString(item, ["status"]);
|
|
145
|
+
const exitCode = getNumber(item, ["exit_code", "exitCode"]);
|
|
146
|
+
const error = getString(item, ["error"]) ?? getString(asRecord(item.result), ["error"]);
|
|
147
|
+
return {
|
|
148
|
+
isError: status === "error" || status === "failed" || status === "errored" || status === "interrupted" || exitCode !== void 0 && exitCode !== 0 || error !== void 0,
|
|
149
|
+
error
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
const mapThreadStartedEvent = (event) => ({
|
|
153
|
+
events: [],
|
|
154
|
+
sessionId: event.thread_id
|
|
155
|
+
});
|
|
156
|
+
const mapTurnCompletedEvent = (event, context) => {
|
|
157
|
+
const state = {
|
|
158
|
+
stats: toStats(event),
|
|
159
|
+
status: "completed"
|
|
160
|
+
};
|
|
161
|
+
if (event.last_agent_message !== void 0) state.output = { text: event.last_agent_message };
|
|
162
|
+
if (context.schemaRequested && event.last_agent_message) try {
|
|
163
|
+
state.output = {
|
|
164
|
+
...state.output,
|
|
165
|
+
value: parseJsonResponseText(event.last_agent_message)
|
|
166
|
+
};
|
|
167
|
+
} catch {}
|
|
168
|
+
return {
|
|
169
|
+
events: [],
|
|
170
|
+
state
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
const mapTurnFailedEvent = (event) => ({
|
|
174
|
+
events: [],
|
|
175
|
+
state: {
|
|
176
|
+
stats: toStats(event),
|
|
177
|
+
status: "failed",
|
|
178
|
+
output: event.last_agent_message === void 0 ? void 0 : { text: event.last_agent_message },
|
|
179
|
+
error: {
|
|
180
|
+
kind: "provider",
|
|
181
|
+
message: getErrorMessage(event.error ?? event.message, "Codex turn failed.")
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const mapErrorEvent = (event) => ({
|
|
186
|
+
events: [],
|
|
187
|
+
state: {
|
|
188
|
+
status: "failed",
|
|
189
|
+
error: {
|
|
190
|
+
kind: "provider",
|
|
191
|
+
message: getErrorMessage(event.error ?? event.message, "Codex emitted an error event.")
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const mapToolCallStart = (item, context, toolRecord, options) => {
|
|
196
|
+
const toolCallId = getString(item, ["id"]);
|
|
197
|
+
if (!toolCallId) return { events: [] };
|
|
198
|
+
return {
|
|
199
|
+
events: [createAgentEvent(context.runId, "tool-call", {
|
|
200
|
+
sessionId: context.sessionId,
|
|
201
|
+
model: options.model ?? null,
|
|
202
|
+
toolCallId,
|
|
203
|
+
toolName: toolRecord.toolName,
|
|
204
|
+
input: toolRecord.input
|
|
205
|
+
})],
|
|
206
|
+
toolCalls: [{
|
|
207
|
+
toolCallId,
|
|
208
|
+
toolName: toolRecord.toolName,
|
|
209
|
+
input: toolRecord.input
|
|
210
|
+
}]
|
|
211
|
+
};
|
|
212
|
+
};
|
|
213
|
+
const getCommandOutput = (item) => getValue(item, [
|
|
214
|
+
"aggregated_output",
|
|
215
|
+
"aggregatedOutput",
|
|
216
|
+
"output",
|
|
217
|
+
"result",
|
|
218
|
+
"text"
|
|
219
|
+
]) ?? "";
|
|
220
|
+
const getMcpOutput = (item) => getValue(item, ["result", "output"]) ?? getString(item, ["error"]) ?? "";
|
|
221
|
+
const getWebSearchOutput = (item) => getValue(item, [
|
|
222
|
+
"results",
|
|
223
|
+
"result",
|
|
224
|
+
"action"
|
|
225
|
+
]) ?? "";
|
|
226
|
+
const mapToolResultCompletion = (item, context, toolRecord, output, options) => {
|
|
227
|
+
const toolCallId = getString(item, ["id"]);
|
|
228
|
+
if (!toolCallId) return { events: [] };
|
|
229
|
+
const priorToolCall = context.toolCalls.get(toolCallId);
|
|
230
|
+
const resolvedTool = priorToolCall ?? toolRecord;
|
|
231
|
+
const errorState = getToolErrorState(item);
|
|
232
|
+
const events = [];
|
|
233
|
+
const toolCalls = [];
|
|
234
|
+
if (!priorToolCall) {
|
|
235
|
+
events.push(createAgentEvent(context.runId, "tool-call", {
|
|
236
|
+
sessionId: context.sessionId,
|
|
237
|
+
model: options.model ?? null,
|
|
238
|
+
toolCallId,
|
|
239
|
+
toolName: toolRecord.toolName,
|
|
240
|
+
input: toolRecord.input
|
|
241
|
+
}));
|
|
242
|
+
toolCalls.push({
|
|
243
|
+
toolCallId,
|
|
244
|
+
toolName: toolRecord.toolName,
|
|
245
|
+
input: toolRecord.input
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
events.push(createAgentEvent(context.runId, "tool-result", {
|
|
249
|
+
sessionId: context.sessionId,
|
|
250
|
+
toolCallId,
|
|
251
|
+
toolName: resolvedTool.toolName,
|
|
252
|
+
input: resolvedTool.input,
|
|
253
|
+
output,
|
|
254
|
+
isError: errorState.isError || void 0,
|
|
255
|
+
error: errorState.error
|
|
256
|
+
}));
|
|
257
|
+
return {
|
|
258
|
+
events,
|
|
259
|
+
toolCalls
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
const getReasoningText = (item) => {
|
|
263
|
+
const directText = getString(item, [
|
|
264
|
+
"summary_text",
|
|
265
|
+
"reasoning_text",
|
|
266
|
+
"text",
|
|
267
|
+
"summary",
|
|
268
|
+
"raw_content"
|
|
269
|
+
]);
|
|
270
|
+
if (directText) return directText;
|
|
271
|
+
const summaryParts = getValue(item, ["summary"]);
|
|
272
|
+
if (Array.isArray(summaryParts)) {
|
|
273
|
+
const joined = summaryParts.flatMap((part) => {
|
|
274
|
+
if (typeof part === "string") return [part];
|
|
275
|
+
const text = getString(asRecord(part), ["text", "summary_text"]);
|
|
276
|
+
return text ? [text] : [];
|
|
277
|
+
}).join("\n");
|
|
278
|
+
if (joined) return joined;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
const cacheItem = (item, options) => {
|
|
282
|
+
const id = getString(item, ["id"]);
|
|
283
|
+
if (!id || !options.itemCache) return;
|
|
284
|
+
const existing = options.itemCache.get(id);
|
|
285
|
+
options.itemCache.set(id, existing ? {
|
|
286
|
+
...existing,
|
|
287
|
+
...item
|
|
288
|
+
} : { ...item });
|
|
289
|
+
};
|
|
290
|
+
const mergeWithCached = (item, options) => {
|
|
291
|
+
const id = getString(item, ["id"]);
|
|
292
|
+
if (!id || !options.itemCache) return item;
|
|
293
|
+
const cached = options.itemCache.get(id);
|
|
294
|
+
options.itemCache.delete(id);
|
|
295
|
+
if (!cached) return item;
|
|
296
|
+
return {
|
|
297
|
+
...cached,
|
|
298
|
+
...item
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
const mapItemStartedEvent = (event, context, options) => {
|
|
302
|
+
const item = asRecord(event.item);
|
|
303
|
+
if (!item) return { events: [] };
|
|
304
|
+
cacheItem(item, options);
|
|
305
|
+
switch (normalizeItemType(getString(item, ["type"]) ?? "")) {
|
|
306
|
+
case "command_execution": return mapToolCallStart(item, context, getCommandToolRecord(item), options);
|
|
307
|
+
case "mcp_tool_call": return mapToolCallStart(item, context, getMcpToolRecord(item), options);
|
|
308
|
+
case "web_search": return mapToolCallStart(item, context, getWebSearchToolRecord(item), options);
|
|
309
|
+
default: return { events: [] };
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
const mapItemUpdatedEvent = (event, options) => {
|
|
313
|
+
const item = asRecord(event.item);
|
|
314
|
+
if (item) cacheItem(item, options);
|
|
315
|
+
return { events: [] };
|
|
316
|
+
};
|
|
317
|
+
const mapItemCompletedEvent = (event, context, options) => {
|
|
318
|
+
const rawItem = asRecord(event.item);
|
|
319
|
+
if (!rawItem) return { events: [] };
|
|
320
|
+
const item = mergeWithCached(rawItem, options);
|
|
321
|
+
switch (normalizeItemType(getString(item, ["type"]) ?? "")) {
|
|
322
|
+
case "agent_message": {
|
|
323
|
+
const text = getString(item, ["text"]);
|
|
324
|
+
if (!text) return { events: [] };
|
|
325
|
+
const isFinalAnswer = context.schemaRequested && (getString(item, ["phase"]) === void 0 || getString(item, ["phase"]) === "final_answer");
|
|
326
|
+
let parsedOutput;
|
|
327
|
+
if (isFinalAnswer) try {
|
|
328
|
+
parsedOutput = parseJsonResponseText(text);
|
|
329
|
+
} catch {}
|
|
330
|
+
return {
|
|
331
|
+
events: [createAgentEvent(context.runId, "message", {
|
|
332
|
+
sessionId: context.sessionId,
|
|
333
|
+
model: options.model ?? null,
|
|
334
|
+
role: "assistant",
|
|
335
|
+
content: [toTextPart(text)],
|
|
336
|
+
text
|
|
337
|
+
})],
|
|
338
|
+
state: { output: {
|
|
339
|
+
text,
|
|
340
|
+
...parsedOutput === void 0 ? {} : { value: parsedOutput }
|
|
341
|
+
} }
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
case "reasoning": {
|
|
345
|
+
const text = getReasoningText(item);
|
|
346
|
+
if (!text) return { events: [] };
|
|
347
|
+
return { events: [createAgentEvent(context.runId, "reasoning", {
|
|
348
|
+
sessionId: context.sessionId,
|
|
349
|
+
model: options.model ?? null,
|
|
350
|
+
content: [toTextPart(text)],
|
|
351
|
+
text
|
|
352
|
+
})] };
|
|
353
|
+
}
|
|
354
|
+
case "command_execution": return mapToolResultCompletion(item, context, getCommandToolRecord(item), getCommandOutput(item), options);
|
|
355
|
+
case "mcp_tool_call": return mapToolResultCompletion(item, context, getMcpToolRecord(item), getMcpOutput(item), options);
|
|
356
|
+
case "web_search": return mapToolResultCompletion(item, context, getWebSearchToolRecord(item), getWebSearchOutput(item), options);
|
|
357
|
+
default: return { events: [] };
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
function mapCodexEventDetailed(event, context, options = {}) {
|
|
361
|
+
const threadStarted = codexThreadStartedEventSchema.safeParse(event);
|
|
362
|
+
if (threadStarted.success) return {
|
|
363
|
+
batch: mapThreadStartedEvent(threadStarted.data),
|
|
364
|
+
disposition: "mapped"
|
|
365
|
+
};
|
|
366
|
+
if (event.type === "turn.started") return {
|
|
367
|
+
batch: { events: [] },
|
|
368
|
+
disposition: "known-ignored"
|
|
369
|
+
};
|
|
370
|
+
const turnCompleted = codexTurnCompletedEventSchema.safeParse(event);
|
|
371
|
+
if (turnCompleted.success) return {
|
|
372
|
+
batch: mapTurnCompletedEvent(turnCompleted.data, context),
|
|
373
|
+
disposition: "mapped"
|
|
374
|
+
};
|
|
375
|
+
const turnFailed = codexTurnFailedEventSchema.safeParse(event);
|
|
376
|
+
if (turnFailed.success) return {
|
|
377
|
+
batch: mapTurnFailedEvent(turnFailed.data),
|
|
378
|
+
disposition: "mapped"
|
|
379
|
+
};
|
|
380
|
+
const errorEvent = codexErrorEventSchema.safeParse(event);
|
|
381
|
+
if (errorEvent.success) return {
|
|
382
|
+
batch: mapErrorEvent(errorEvent.data),
|
|
383
|
+
disposition: "mapped"
|
|
384
|
+
};
|
|
385
|
+
const itemStarted = codexItemStartedEventSchema.safeParse(event);
|
|
386
|
+
if (itemStarted.success) {
|
|
387
|
+
const batch = mapItemStartedEvent(itemStarted.data, context, options);
|
|
388
|
+
return {
|
|
389
|
+
batch,
|
|
390
|
+
disposition: batch.events.length > 0 || (batch.toolCalls?.length ?? 0) > 0 ? "mapped" : "known-ignored"
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
const itemUpdated = codexItemUpdatedEventSchema.safeParse(event);
|
|
394
|
+
if (itemUpdated.success) return {
|
|
395
|
+
batch: mapItemUpdatedEvent(itemUpdated.data, options),
|
|
396
|
+
disposition: "known-ignored"
|
|
397
|
+
};
|
|
398
|
+
const itemCompleted = codexItemCompletedEventSchema.safeParse(event);
|
|
399
|
+
if (itemCompleted.success) {
|
|
400
|
+
const batch = mapItemCompletedEvent(itemCompleted.data, context, options);
|
|
401
|
+
return {
|
|
402
|
+
batch,
|
|
403
|
+
disposition: batch.events.length > 0 || batch.state !== void 0 || (batch.toolCalls?.length ?? 0) > 0 || batch.sessionId !== void 0 ? "mapped" : "known-ignored"
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
switch (event.type) {
|
|
407
|
+
case "thread.started":
|
|
408
|
+
case "turn.started":
|
|
409
|
+
case "turn.completed":
|
|
410
|
+
case "turn.failed":
|
|
411
|
+
case "item.started":
|
|
412
|
+
case "item.updated":
|
|
413
|
+
case "item.completed":
|
|
414
|
+
case "error": return {
|
|
415
|
+
batch: { events: [] },
|
|
416
|
+
disposition: "known-malformed"
|
|
417
|
+
};
|
|
418
|
+
default: return {
|
|
419
|
+
batch: { events: [] },
|
|
420
|
+
disposition: "unknown"
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/adapters/codex-cli/events/parser.ts
|
|
426
|
+
const parseCodexEvent = createEventParser(codexEventSchema);
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/adapters/codex-cli/adapter.ts
|
|
429
|
+
const CODEX_CLI_CAPABILITIES = {
|
|
430
|
+
structuredOutput: true,
|
|
431
|
+
sessionResume: true,
|
|
432
|
+
imageInput: false,
|
|
433
|
+
mcp: true,
|
|
434
|
+
eventStreaming: true
|
|
435
|
+
};
|
|
436
|
+
const isSafeKey = (value) => /^\w+$/.test(value);
|
|
437
|
+
const formatConfigKey = (value) => isSafeKey(value) ? value : JSON.stringify(value);
|
|
438
|
+
const joinConfigPath = (...parts) => parts.map(formatConfigKey).join(".");
|
|
439
|
+
const fmtValue = (value) => JSON.stringify(value);
|
|
440
|
+
const fmtArray = (values) => `[${values.map((v) => JSON.stringify(v)).join(",")}]`;
|
|
441
|
+
const mcpServersToConfigArgs = (servers) => {
|
|
442
|
+
const args = [];
|
|
443
|
+
for (const [name, server] of Object.entries(servers)) {
|
|
444
|
+
const base = joinConfigPath("mcp_servers", name);
|
|
445
|
+
if (server.url) args.push("--config", `${base}.url=${fmtValue(server.url)}`);
|
|
446
|
+
if (server.command) args.push("--config", `${base}.command=${fmtValue(server.command)}`);
|
|
447
|
+
if (server.args && server.args.length > 0) args.push("--config", `${base}.args=${fmtArray(server.args)}`);
|
|
448
|
+
if (server.cwd) args.push("--config", `${base}.cwd=${fmtValue(server.cwd)}`);
|
|
449
|
+
if (server.headers) for (const [key, value] of Object.entries(server.headers)) args.push("--config", `${joinConfigPath("mcp_servers", name, "http_headers", key)}=${fmtValue(value)}`);
|
|
450
|
+
if (server.env) for (const [key, value] of Object.entries(server.env)) args.push("--config", `${joinConfigPath("mcp_servers", name, "env", key)}=${fmtValue(value)}`);
|
|
451
|
+
}
|
|
452
|
+
return args;
|
|
453
|
+
};
|
|
454
|
+
const readStringArray = (value, label) => {
|
|
455
|
+
if (value === void 0) return;
|
|
456
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new AgentValidationError(`${label} must be an array of strings.`);
|
|
457
|
+
return [...value];
|
|
458
|
+
};
|
|
459
|
+
const readStringRecord = (value, label) => {
|
|
460
|
+
if (value === void 0) return;
|
|
461
|
+
if (!isRecord(value) || Array.isArray(value)) throw new AgentValidationError(`${label} must be an object.`);
|
|
462
|
+
const result = {};
|
|
463
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
464
|
+
if (typeof entry !== "string") throw new AgentValidationError(`${label}.${key} must be a string.`);
|
|
465
|
+
result[key] = entry;
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
};
|
|
469
|
+
const readMcpServerConfig = (value, label) => {
|
|
470
|
+
if (!isRecord(value) || Array.isArray(value)) throw new AgentValidationError(`${label} must be an object.`);
|
|
471
|
+
const command = value.command;
|
|
472
|
+
const url = value.url;
|
|
473
|
+
const cwd = value.cwd;
|
|
474
|
+
if (command !== void 0 && typeof command !== "string") throw new AgentValidationError(`${label}.command must be a string.`);
|
|
475
|
+
if (url !== void 0 && typeof url !== "string") throw new AgentValidationError(`${label}.url must be a string.`);
|
|
476
|
+
if (cwd !== void 0 && typeof cwd !== "string") throw new AgentValidationError(`${label}.cwd must be a string.`);
|
|
477
|
+
return {
|
|
478
|
+
command,
|
|
479
|
+
url,
|
|
480
|
+
cwd,
|
|
481
|
+
args: readStringArray(value.args, `${label}.args`),
|
|
482
|
+
env: readStringRecord(value.env, `${label}.env`),
|
|
483
|
+
headers: readStringRecord(value.headers, `${label}.headers`)
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
const readMcpConfig = (configPath) => {
|
|
487
|
+
let parsed;
|
|
488
|
+
try {
|
|
489
|
+
parsed = JSON.parse(readFileSync(configPath, "utf8"));
|
|
490
|
+
} catch (error) {
|
|
491
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") throw new AgentValidationError(`mcpConfig file not found: ${configPath}`);
|
|
492
|
+
throw new AgentValidationError(`mcpConfig must be valid JSON: ${configPath}`);
|
|
493
|
+
}
|
|
494
|
+
if (!isRecord(parsed) || Array.isArray(parsed)) throw new AgentValidationError(`mcpConfig must contain a JSON object: ${configPath}`);
|
|
495
|
+
const mcpServers = parsed.mcpServers;
|
|
496
|
+
if (mcpServers === void 0) return;
|
|
497
|
+
if (!isRecord(mcpServers) || Array.isArray(mcpServers)) throw new AgentValidationError(`mcpConfig.mcpServers must be an object: ${configPath}`);
|
|
498
|
+
const parsedServers = {};
|
|
499
|
+
for (const [name, server] of Object.entries(mcpServers)) parsedServers[name] = readMcpServerConfig(server, `mcpConfig.mcpServers.${name}`);
|
|
500
|
+
return parsedServers;
|
|
501
|
+
};
|
|
502
|
+
const buildMcpConfigArgs = (configPath) => {
|
|
503
|
+
const servers = readMcpConfig(configPath);
|
|
504
|
+
return servers ? mcpServersToConfigArgs(servers) : [];
|
|
505
|
+
};
|
|
506
|
+
var CodexCliAgentImpl = class extends Agent {
|
|
507
|
+
type = "codex-cli";
|
|
508
|
+
creationOptions;
|
|
509
|
+
runDefaults;
|
|
510
|
+
schemaDirs = /* @__PURE__ */ new Map();
|
|
511
|
+
runModels = /* @__PURE__ */ new Map();
|
|
512
|
+
itemCaches = /* @__PURE__ */ new Map();
|
|
513
|
+
constructor(options = {}) {
|
|
514
|
+
super({
|
|
515
|
+
type: "codex-cli",
|
|
516
|
+
capabilities: CODEX_CLI_CAPABILITIES,
|
|
517
|
+
defaults: {
|
|
518
|
+
cwd: options.cwd,
|
|
519
|
+
env: options.env,
|
|
520
|
+
command: toArray(options.command ?? "codex"),
|
|
521
|
+
sessionId: options.sessionId,
|
|
522
|
+
model: options.model
|
|
523
|
+
},
|
|
524
|
+
spawner: options.spawner,
|
|
525
|
+
container: options.container,
|
|
526
|
+
logPath: options.logPath,
|
|
527
|
+
onEvent: options.onEvent
|
|
528
|
+
});
|
|
529
|
+
this.creationOptions = options;
|
|
530
|
+
this.runDefaults = {
|
|
531
|
+
sandbox: options.sandbox,
|
|
532
|
+
additionalDirectories: options.additionalDirectories ? [...options.additionalDirectories] : void 0,
|
|
533
|
+
skipGitRepoCheck: options.skipGitRepoCheck,
|
|
534
|
+
permissionMode: options.permissionMode,
|
|
535
|
+
ephemeral: options.ephemeral,
|
|
536
|
+
mcpConfig: options.mcpConfig,
|
|
537
|
+
mcpServers: options.mcpServers ? { ...options.mcpServers } : void 0,
|
|
538
|
+
extraArgs: options.extraArgs ? [...options.extraArgs] : void 0
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
onValidateRun(request, _normalizedRequest) {
|
|
542
|
+
const mcpConfig = request.mcpConfig ?? this.runDefaults.mcpConfig;
|
|
543
|
+
if (mcpConfig) readMcpConfig(mcpConfig);
|
|
544
|
+
}
|
|
545
|
+
buildArgs(request, run) {
|
|
546
|
+
const args = ["exec", "--json"];
|
|
547
|
+
const sandbox = request.sandbox ?? this.runDefaults.sandbox;
|
|
548
|
+
const additionalDirectories = request.additionalDirectories ?? this.runDefaults.additionalDirectories;
|
|
549
|
+
const skipGitRepoCheck = request.skipGitRepoCheck ?? this.runDefaults.skipGitRepoCheck;
|
|
550
|
+
const permissionMode = request.permissionMode ?? this.runDefaults.permissionMode;
|
|
551
|
+
const ephemeral = request.ephemeral ?? this.runDefaults.ephemeral;
|
|
552
|
+
const extraArgs = request.extraArgs ?? this.runDefaults.extraArgs;
|
|
553
|
+
this.runModels.set(run.runId, request.model);
|
|
554
|
+
if (request.model) args.push("--model", request.model);
|
|
555
|
+
if (sandbox) args.push("--sandbox", sandbox);
|
|
556
|
+
if (permissionMode === "full-auto") args.push("--full-auto");
|
|
557
|
+
else if (permissionMode === "full-access") args.push("--dangerously-bypass-approvals-and-sandbox");
|
|
558
|
+
if (skipGitRepoCheck) args.push("--skip-git-repo-check");
|
|
559
|
+
if (ephemeral) args.push("--ephemeral");
|
|
560
|
+
for (const dir of additionalDirectories ?? []) args.push("--add-dir", dir);
|
|
561
|
+
if (request.schema.kind !== "none") args.push("--output-schema", this.createSchemaFile(run.runId, request.schema.jsonSchema));
|
|
562
|
+
const mcpConfig = request.mcpConfig ?? this.runDefaults.mcpConfig;
|
|
563
|
+
if (mcpConfig) args.push(...buildMcpConfigArgs(mcpConfig));
|
|
564
|
+
const mcpServers = request.mcpServers ?? this.runDefaults.mcpServers;
|
|
565
|
+
if (mcpServers) args.push(...mcpServersToConfigArgs(mcpServers));
|
|
566
|
+
if (extraArgs && extraArgs.length > 0) args.push(...extraArgs);
|
|
567
|
+
if (run.requestedSessionId) args.push("resume", run.requestedSessionId);
|
|
568
|
+
const inputText = getInputText(request.input);
|
|
569
|
+
if (inputText.trim().startsWith("-")) args.push("--", inputText);
|
|
570
|
+
else args.push(inputText);
|
|
571
|
+
return args;
|
|
572
|
+
}
|
|
573
|
+
buildEnv(_request, _run) {
|
|
574
|
+
return this.buildDefaultEnv(this.creationOptions.propagateEnv);
|
|
575
|
+
}
|
|
576
|
+
mapRawEvent(raw, context) {
|
|
577
|
+
this.appendRawLog(raw);
|
|
578
|
+
const parsed = parseCodexEvent(raw);
|
|
579
|
+
if (!parsed) {
|
|
580
|
+
this.onParseError(JSON.stringify(raw).slice(0, 200), /* @__PURE__ */ new Error("schema validation failed"));
|
|
581
|
+
return { events: [] };
|
|
582
|
+
}
|
|
583
|
+
let itemCache = this.itemCaches.get(context.runId);
|
|
584
|
+
if (!itemCache) {
|
|
585
|
+
itemCache = /* @__PURE__ */ new Map();
|
|
586
|
+
this.itemCaches.set(context.runId, itemCache);
|
|
587
|
+
}
|
|
588
|
+
const result = mapCodexEventDetailed(parsed, context, {
|
|
589
|
+
model: this.runModels.get(context.runId),
|
|
590
|
+
itemCache
|
|
591
|
+
});
|
|
592
|
+
if (result.disposition === "known-malformed") this.onParseError(JSON.stringify(raw).slice(0, 200), /* @__PURE__ */ new Error(`known Codex event "${parsed.type}" did not match the expected payload shape`));
|
|
593
|
+
return result.batch;
|
|
594
|
+
}
|
|
595
|
+
async onRunFinished(run) {
|
|
596
|
+
await super.onRunFinished(run);
|
|
597
|
+
this.runModels.delete(run.runId);
|
|
598
|
+
this.itemCaches.delete(run.runId);
|
|
599
|
+
const schemaDir = this.schemaDirs.get(run.runId);
|
|
600
|
+
if (!schemaDir) return;
|
|
601
|
+
this.schemaDirs.delete(run.runId);
|
|
602
|
+
rmSync(schemaDir, {
|
|
603
|
+
recursive: true,
|
|
604
|
+
force: true
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
createSchemaFile(runId, schema) {
|
|
608
|
+
const schemaDir = mkdtempSync(join(tmpdir(), "coding-agents-sdk-codex-cli-"));
|
|
609
|
+
const schemaPath = join(schemaDir, "output-schema.json");
|
|
610
|
+
writeFileSync(schemaPath, JSON.stringify(schema, null, 2), {
|
|
611
|
+
encoding: "utf8",
|
|
612
|
+
mode: 384
|
|
613
|
+
});
|
|
614
|
+
this.schemaDirs.set(runId, schemaDir);
|
|
615
|
+
return schemaPath;
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
const createCodexCliAgent = (options) => {
|
|
619
|
+
if (!options?.container) return new CodexCliAgentImpl(options);
|
|
620
|
+
return new CodexCliAgentImpl({
|
|
621
|
+
...options,
|
|
622
|
+
spawner: options.container.spawner
|
|
623
|
+
});
|
|
624
|
+
};
|
|
625
|
+
//#endregion
|
|
626
|
+
export { createCodexCliAgent };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as CodexSdkItem, i as CodexSdkEvent, n as CodexSdkAgent, o as CodexSdkPermissionMode, r as CodexSdkAgentOptions, s as CodexSdkRunOptions, t as createCodexSdkAgent } from "../../index-CFpNOmdA.mjs";
|
|
2
|
+
export { CodexSdkAgent, CodexSdkAgentOptions, CodexSdkEvent, CodexSdkItem, CodexSdkPermissionMode, CodexSdkRunOptions, createCodexSdkAgent };
|