@codex-native/sdk 0.0.1
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 +379 -0
- package/codex_native.darwin-arm64.node +0 -0
- package/dist/index.d.mts +562 -0
- package/dist/index.mjs +638 -0
- package/dist/index.mjs.map +1 -0
- package/npm/darwin-arm64/README.md +3 -0
- package/npm/darwin-arm64/package.json +21 -0
- package/npm/darwin-x64/README.md +3 -0
- package/npm/darwin-x64/package.json +21 -0
- package/npm/linux-arm64-gnu/README.md +3 -0
- package/npm/linux-arm64-gnu/package.json +24 -0
- package/npm/linux-arm64-musl/README.md +3 -0
- package/npm/linux-arm64-musl/package.json +24 -0
- package/npm/linux-x64-gnu/README.md +3 -0
- package/npm/linux-x64-gnu/package.json +24 -0
- package/npm/linux-x64-musl/README.md +3 -0
- package/npm/linux-x64-musl/package.json +24 -0
- package/npm/win32-arm64-msvc/README.md +3 -0
- package/npm/win32-arm64-msvc/package.json +21 -0
- package/npm/win32-x64-msvc/README.md +3 -0
- package/npm/win32-x64-msvc/package.json +21 -0
- package/package.json +70 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/outputSchemaFile.ts
|
|
23
|
+
import { promises as fs } from "fs";
|
|
24
|
+
import os from "os";
|
|
25
|
+
import path from "path";
|
|
26
|
+
async function createOutputSchemaFile(schema) {
|
|
27
|
+
if (schema === void 0) {
|
|
28
|
+
return { cleanup: async () => {
|
|
29
|
+
} };
|
|
30
|
+
}
|
|
31
|
+
if (!isJsonObject(schema)) {
|
|
32
|
+
throw new Error("outputSchema must be a plain JSON object");
|
|
33
|
+
}
|
|
34
|
+
const schemaDir = await fs.mkdtemp(path.join(os.tmpdir(), "codex-output-schema-"));
|
|
35
|
+
const schemaPath = path.join(schemaDir, "schema.json");
|
|
36
|
+
const cleanup = async () => {
|
|
37
|
+
try {
|
|
38
|
+
await fs.rm(schemaDir, { recursive: true, force: true });
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
await fs.writeFile(schemaPath, JSON.stringify(schema), "utf8");
|
|
44
|
+
return { schemaPath, cleanup };
|
|
45
|
+
} catch (error) {
|
|
46
|
+
await cleanup();
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isJsonObject(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
var init_outputSchemaFile = __esm({
|
|
54
|
+
"src/outputSchemaFile.ts"() {
|
|
55
|
+
"use strict";
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/thread.ts
|
|
60
|
+
function normalizeInput(input) {
|
|
61
|
+
if (typeof input === "string") {
|
|
62
|
+
return { prompt: input, images: [] };
|
|
63
|
+
}
|
|
64
|
+
const promptParts = [];
|
|
65
|
+
const images = [];
|
|
66
|
+
for (const item of input) {
|
|
67
|
+
if (item.type === "text") {
|
|
68
|
+
promptParts.push(item.text);
|
|
69
|
+
} else if (item.type === "local_image") {
|
|
70
|
+
images.push(item.path);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { prompt: promptParts.join("\n\n"), images };
|
|
74
|
+
}
|
|
75
|
+
var Thread;
|
|
76
|
+
var init_thread = __esm({
|
|
77
|
+
"src/thread.ts"() {
|
|
78
|
+
"use strict";
|
|
79
|
+
init_outputSchemaFile();
|
|
80
|
+
Thread = class {
|
|
81
|
+
_exec;
|
|
82
|
+
_options;
|
|
83
|
+
_id;
|
|
84
|
+
_threadOptions;
|
|
85
|
+
/** Returns the ID of the thread. Populated after the first turn starts. */
|
|
86
|
+
get id() {
|
|
87
|
+
return this._id;
|
|
88
|
+
}
|
|
89
|
+
/* @internal */
|
|
90
|
+
constructor(exec, options, threadOptions, id = null) {
|
|
91
|
+
this._exec = exec;
|
|
92
|
+
this._options = options;
|
|
93
|
+
this._id = id;
|
|
94
|
+
this._threadOptions = threadOptions;
|
|
95
|
+
}
|
|
96
|
+
/** Provides the input to the agent and streams events as they are produced during the turn. */
|
|
97
|
+
async runStreamed(input, turnOptions = {}) {
|
|
98
|
+
return { events: this.runStreamedInternal(input, turnOptions) };
|
|
99
|
+
}
|
|
100
|
+
async *runStreamedInternal(input, turnOptions = {}) {
|
|
101
|
+
const { schemaPath, cleanup } = await createOutputSchemaFile(turnOptions.outputSchema);
|
|
102
|
+
const options = this._threadOptions;
|
|
103
|
+
const { prompt, images } = normalizeInput(input);
|
|
104
|
+
const generator = this._exec.run({
|
|
105
|
+
input: prompt,
|
|
106
|
+
baseUrl: this._options.baseUrl,
|
|
107
|
+
apiKey: this._options.apiKey,
|
|
108
|
+
threadId: this._id,
|
|
109
|
+
images,
|
|
110
|
+
model: options?.model,
|
|
111
|
+
sandboxMode: options?.sandboxMode,
|
|
112
|
+
workingDirectory: options?.workingDirectory,
|
|
113
|
+
skipGitRepoCheck: options?.skipGitRepoCheck,
|
|
114
|
+
outputSchemaFile: schemaPath,
|
|
115
|
+
outputSchema: turnOptions.outputSchema
|
|
116
|
+
});
|
|
117
|
+
try {
|
|
118
|
+
for await (const item of generator) {
|
|
119
|
+
let parsed;
|
|
120
|
+
try {
|
|
121
|
+
parsed = JSON.parse(item);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
throw new Error(`Failed to parse item: ${item}`, { cause: error });
|
|
124
|
+
}
|
|
125
|
+
if (parsed.type === "thread.started") {
|
|
126
|
+
this._id = parsed.thread_id;
|
|
127
|
+
}
|
|
128
|
+
yield parsed;
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
await cleanup();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** Provides the input to the agent and returns the completed turn. */
|
|
135
|
+
async run(input, turnOptions = {}) {
|
|
136
|
+
const generator = this.runStreamedInternal(input, turnOptions);
|
|
137
|
+
const items = [];
|
|
138
|
+
let finalResponse = "";
|
|
139
|
+
let usage = null;
|
|
140
|
+
let turnFailure = null;
|
|
141
|
+
for await (const event of generator) {
|
|
142
|
+
if (event.type === "item.completed") {
|
|
143
|
+
if (event.item.type === "agent_message") {
|
|
144
|
+
finalResponse = event.item.text;
|
|
145
|
+
}
|
|
146
|
+
items.push(event.item);
|
|
147
|
+
} else if (event.type === "turn.completed") {
|
|
148
|
+
usage = event.usage;
|
|
149
|
+
} else if (event.type === "turn.failed") {
|
|
150
|
+
turnFailure = event.error;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (turnFailure) {
|
|
155
|
+
throw new Error(turnFailure.message);
|
|
156
|
+
}
|
|
157
|
+
return { items, finalResponse, usage };
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// src/nativeBinding.ts
|
|
164
|
+
import { createRequire } from "module";
|
|
165
|
+
function getNativeBinding() {
|
|
166
|
+
if (cachedBinding !== void 0) {
|
|
167
|
+
return cachedBinding;
|
|
168
|
+
}
|
|
169
|
+
const require2 = createRequire(import.meta.url);
|
|
170
|
+
try {
|
|
171
|
+
const binding = require2("../index.js");
|
|
172
|
+
cachedBinding = binding;
|
|
173
|
+
return cachedBinding;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.warn("Failed to load native NAPI binding:", error);
|
|
176
|
+
cachedBinding = null;
|
|
177
|
+
return cachedBinding;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
var cachedBinding;
|
|
181
|
+
var init_nativeBinding = __esm({
|
|
182
|
+
"src/nativeBinding.ts"() {
|
|
183
|
+
"use strict";
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// src/exec.ts
|
|
188
|
+
var CodexExec, AsyncQueue;
|
|
189
|
+
var init_exec = __esm({
|
|
190
|
+
"src/exec.ts"() {
|
|
191
|
+
"use strict";
|
|
192
|
+
init_nativeBinding();
|
|
193
|
+
CodexExec = class {
|
|
194
|
+
native;
|
|
195
|
+
constructor() {
|
|
196
|
+
const nativeBinding = getNativeBinding();
|
|
197
|
+
if (!nativeBinding) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
"Native NAPI binding not available. Make sure @openai/codex-native is properly installed and built."
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
this.native = nativeBinding;
|
|
203
|
+
}
|
|
204
|
+
async *run(args) {
|
|
205
|
+
const binding = this.native;
|
|
206
|
+
const queue = new AsyncQueue();
|
|
207
|
+
const request = {
|
|
208
|
+
prompt: args.input,
|
|
209
|
+
threadId: args.threadId ?? void 0,
|
|
210
|
+
images: args.images && args.images.length > 0 ? args.images : void 0,
|
|
211
|
+
model: args.model,
|
|
212
|
+
sandboxMode: args.sandboxMode,
|
|
213
|
+
workingDirectory: args.workingDirectory,
|
|
214
|
+
skipGitRepoCheck: args.skipGitRepoCheck,
|
|
215
|
+
outputSchema: args.outputSchema,
|
|
216
|
+
baseUrl: args.baseUrl,
|
|
217
|
+
apiKey: args.apiKey
|
|
218
|
+
};
|
|
219
|
+
let runPromise;
|
|
220
|
+
try {
|
|
221
|
+
runPromise = binding.runThreadStream(request, (err, eventJson) => {
|
|
222
|
+
if (err) {
|
|
223
|
+
queue.fail(err);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
queue.push(eventJson ?? "null");
|
|
228
|
+
} catch (error) {
|
|
229
|
+
queue.fail(error);
|
|
230
|
+
}
|
|
231
|
+
}).then(
|
|
232
|
+
() => {
|
|
233
|
+
queue.end();
|
|
234
|
+
},
|
|
235
|
+
(error) => {
|
|
236
|
+
queue.fail(error);
|
|
237
|
+
}
|
|
238
|
+
);
|
|
239
|
+
} catch (error) {
|
|
240
|
+
queue.fail(error);
|
|
241
|
+
throw error;
|
|
242
|
+
}
|
|
243
|
+
let loopError;
|
|
244
|
+
try {
|
|
245
|
+
for await (const value of queue) {
|
|
246
|
+
yield value;
|
|
247
|
+
}
|
|
248
|
+
await runPromise;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
loopError = error;
|
|
251
|
+
throw error;
|
|
252
|
+
} finally {
|
|
253
|
+
queue.end();
|
|
254
|
+
if (loopError) {
|
|
255
|
+
await runPromise.catch(() => {
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
AsyncQueue = class {
|
|
262
|
+
buffer = [];
|
|
263
|
+
waiters = [];
|
|
264
|
+
ended = false;
|
|
265
|
+
error;
|
|
266
|
+
push(value) {
|
|
267
|
+
if (this.ended) return;
|
|
268
|
+
if (this.waiters.length > 0) {
|
|
269
|
+
const waiter = this.waiters.shift();
|
|
270
|
+
waiter.resolve({ value, done: false });
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
this.buffer.push(value);
|
|
274
|
+
}
|
|
275
|
+
end() {
|
|
276
|
+
if (this.ended) return;
|
|
277
|
+
this.ended = true;
|
|
278
|
+
const waiters = this.waiters;
|
|
279
|
+
this.waiters = [];
|
|
280
|
+
for (const waiter of waiters) {
|
|
281
|
+
waiter.resolve({ value: void 0, done: true });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
fail(error) {
|
|
285
|
+
if (this.ended) return;
|
|
286
|
+
this.error = error;
|
|
287
|
+
this.ended = true;
|
|
288
|
+
const waiters = this.waiters;
|
|
289
|
+
this.waiters = [];
|
|
290
|
+
for (const waiter of waiters) {
|
|
291
|
+
waiter.reject(error);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
async next() {
|
|
295
|
+
if (this.buffer.length > 0) {
|
|
296
|
+
const value = this.buffer.shift();
|
|
297
|
+
return { value, done: false };
|
|
298
|
+
}
|
|
299
|
+
if (this.error) {
|
|
300
|
+
return Promise.reject(this.error);
|
|
301
|
+
}
|
|
302
|
+
if (this.ended) {
|
|
303
|
+
return { value: void 0, done: true };
|
|
304
|
+
}
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
this.waiters.push({ resolve, reject });
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
[Symbol.asyncIterator]() {
|
|
310
|
+
return this;
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// src/codex.ts
|
|
317
|
+
var codex_exports = {};
|
|
318
|
+
__export(codex_exports, {
|
|
319
|
+
Codex: () => Codex
|
|
320
|
+
});
|
|
321
|
+
var Codex;
|
|
322
|
+
var init_codex = __esm({
|
|
323
|
+
"src/codex.ts"() {
|
|
324
|
+
"use strict";
|
|
325
|
+
init_exec();
|
|
326
|
+
init_nativeBinding();
|
|
327
|
+
init_thread();
|
|
328
|
+
Codex = class {
|
|
329
|
+
exec;
|
|
330
|
+
options;
|
|
331
|
+
nativeBinding;
|
|
332
|
+
constructor(options = {}) {
|
|
333
|
+
const predefinedTools = options.tools ? [...options.tools] : [];
|
|
334
|
+
this.nativeBinding = getNativeBinding();
|
|
335
|
+
this.options = { ...options, tools: [] };
|
|
336
|
+
if (this.nativeBinding) {
|
|
337
|
+
if (typeof this.nativeBinding.clearRegisteredTools === "function") {
|
|
338
|
+
this.nativeBinding.clearRegisteredTools();
|
|
339
|
+
}
|
|
340
|
+
for (const tool of predefinedTools) {
|
|
341
|
+
this.registerTool(tool);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
this.exec = new CodexExec();
|
|
345
|
+
}
|
|
346
|
+
registerTool(tool) {
|
|
347
|
+
if (!this.nativeBinding) {
|
|
348
|
+
throw new Error("Native tool registration requires the NAPI binding");
|
|
349
|
+
}
|
|
350
|
+
if (typeof this.nativeBinding.registerTool !== "function") {
|
|
351
|
+
console.warn("registerTool is not available in this build - tools feature may be incomplete");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const { handler, ...info } = tool;
|
|
355
|
+
this.nativeBinding.registerTool(info, handler);
|
|
356
|
+
if (!this.options.tools) {
|
|
357
|
+
this.options.tools = [];
|
|
358
|
+
}
|
|
359
|
+
this.options.tools.push(tool);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Starts a new conversation with an agent.
|
|
363
|
+
* @returns A new thread instance.
|
|
364
|
+
*/
|
|
365
|
+
startThread(options = {}) {
|
|
366
|
+
return new Thread(this.exec, this.options, options);
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Resumes a conversation with an agent based on the thread id.
|
|
370
|
+
* Threads are persisted in ~/.codex/sessions.
|
|
371
|
+
*
|
|
372
|
+
* @param id The id of the thread to resume.
|
|
373
|
+
* @returns A new thread instance.
|
|
374
|
+
*/
|
|
375
|
+
resumeThread(id, options = {}) {
|
|
376
|
+
return new Thread(this.exec, this.options, options, id);
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// src/index.ts
|
|
383
|
+
init_thread();
|
|
384
|
+
init_codex();
|
|
385
|
+
|
|
386
|
+
// src/agents/CodexProvider.ts
|
|
387
|
+
var CodexProvider = class {
|
|
388
|
+
codex = null;
|
|
389
|
+
options;
|
|
390
|
+
constructor(options = {}) {
|
|
391
|
+
this.options = {
|
|
392
|
+
workingDirectory: options.workingDirectory || process.cwd(),
|
|
393
|
+
skipGitRepoCheck: options.skipGitRepoCheck ?? false,
|
|
394
|
+
...options
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Lazy initialization of Codex instance
|
|
399
|
+
*/
|
|
400
|
+
getCodex() {
|
|
401
|
+
if (!this.codex) {
|
|
402
|
+
const { Codex: CodexClass } = (init_codex(), __toCommonJS(codex_exports));
|
|
403
|
+
this.codex = new CodexClass({
|
|
404
|
+
apiKey: this.options.apiKey,
|
|
405
|
+
baseUrl: this.options.baseUrl
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
return this.codex;
|
|
409
|
+
}
|
|
410
|
+
getModel(modelName) {
|
|
411
|
+
const model = modelName || this.options.defaultModel;
|
|
412
|
+
return new CodexModel(this.getCodex(), model, this.options);
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var CodexModel = class {
|
|
416
|
+
codex;
|
|
417
|
+
modelName;
|
|
418
|
+
thread = null;
|
|
419
|
+
options;
|
|
420
|
+
constructor(codex, modelName, options) {
|
|
421
|
+
this.codex = codex;
|
|
422
|
+
this.modelName = modelName;
|
|
423
|
+
this.options = options;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get or create the thread for this model instance
|
|
427
|
+
*/
|
|
428
|
+
getThread(conversationId) {
|
|
429
|
+
if (conversationId && !this.thread) {
|
|
430
|
+
this.thread = this.codex.resumeThread(conversationId, this.getThreadOptions());
|
|
431
|
+
} else if (!this.thread) {
|
|
432
|
+
this.thread = this.codex.startThread(this.getThreadOptions());
|
|
433
|
+
}
|
|
434
|
+
return this.thread;
|
|
435
|
+
}
|
|
436
|
+
getThreadOptions() {
|
|
437
|
+
return {
|
|
438
|
+
model: this.modelName,
|
|
439
|
+
workingDirectory: this.options.workingDirectory,
|
|
440
|
+
skipGitRepoCheck: this.options.skipGitRepoCheck
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
async getResponse(request) {
|
|
444
|
+
const thread = this.getThread(request.conversationId || request.previousResponseId);
|
|
445
|
+
const input = this.convertRequestToInput(request);
|
|
446
|
+
const turn = await thread.run(input, {
|
|
447
|
+
outputSchema: request.outputType?.schema
|
|
448
|
+
});
|
|
449
|
+
return {
|
|
450
|
+
usage: this.convertUsage(turn.usage),
|
|
451
|
+
output: this.convertItemsToOutput(turn.items, turn.finalResponse),
|
|
452
|
+
responseId: thread.id || void 0
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
async *getStreamedResponse(request) {
|
|
456
|
+
const thread = this.getThread(request.conversationId || request.previousResponseId);
|
|
457
|
+
const input = this.convertRequestToInput(request);
|
|
458
|
+
const { events } = await thread.runStreamed(input, {
|
|
459
|
+
outputSchema: request.outputType?.schema
|
|
460
|
+
});
|
|
461
|
+
let accumulatedText = "";
|
|
462
|
+
for await (const event of events) {
|
|
463
|
+
const streamEvents = this.convertCodexEventToStreamEvent(event, accumulatedText);
|
|
464
|
+
if (event.type === "item.completed" && event.item.type === "agent_message") {
|
|
465
|
+
accumulatedText = event.item.text;
|
|
466
|
+
}
|
|
467
|
+
for (const streamEvent of streamEvents) {
|
|
468
|
+
yield streamEvent;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Convert ModelRequest to Codex Input format
|
|
474
|
+
*/
|
|
475
|
+
convertRequestToInput(request) {
|
|
476
|
+
const parts = [];
|
|
477
|
+
if (request.systemInstructions) {
|
|
478
|
+
parts.push({
|
|
479
|
+
type: "text",
|
|
480
|
+
text: `<system>
|
|
481
|
+
${request.systemInstructions}
|
|
482
|
+
</system>
|
|
483
|
+
|
|
484
|
+
`
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (typeof request.input === "string") {
|
|
488
|
+
parts.push({ type: "text", text: request.input });
|
|
489
|
+
} else {
|
|
490
|
+
for (const item of request.input) {
|
|
491
|
+
if (item.type === "input_text") {
|
|
492
|
+
parts.push({ type: "text", text: item.text });
|
|
493
|
+
} else if (item.type === "input_image") {
|
|
494
|
+
if (typeof item.image === "string") {
|
|
495
|
+
continue;
|
|
496
|
+
} else if ("url" in item.image) {
|
|
497
|
+
continue;
|
|
498
|
+
} else if ("fileId" in item.image) {
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (parts.length === 1 && parts[0].type === "text") {
|
|
505
|
+
return parts[0].text;
|
|
506
|
+
}
|
|
507
|
+
return parts;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Convert Codex Usage to ModelResponse Usage
|
|
511
|
+
*/
|
|
512
|
+
convertUsage(usage) {
|
|
513
|
+
if (!usage) {
|
|
514
|
+
return {
|
|
515
|
+
inputTokens: 0,
|
|
516
|
+
outputTokens: 0,
|
|
517
|
+
totalTokens: 0
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
const inputTokensDetails = usage.cached_input_tokens ? [{ cachedTokens: usage.cached_input_tokens }] : void 0;
|
|
521
|
+
return {
|
|
522
|
+
inputTokens: usage.input_tokens,
|
|
523
|
+
outputTokens: usage.output_tokens,
|
|
524
|
+
totalTokens: usage.input_tokens + usage.output_tokens,
|
|
525
|
+
inputTokensDetails
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Convert Codex ThreadItems to AgentOutputItems
|
|
530
|
+
*/
|
|
531
|
+
convertItemsToOutput(items, finalResponse) {
|
|
532
|
+
const output = [];
|
|
533
|
+
for (const item of items) {
|
|
534
|
+
switch (item.type) {
|
|
535
|
+
case "agent_message": {
|
|
536
|
+
const content = [
|
|
537
|
+
{
|
|
538
|
+
type: "output_text",
|
|
539
|
+
text: item.text
|
|
540
|
+
}
|
|
541
|
+
];
|
|
542
|
+
output.push({
|
|
543
|
+
type: "message",
|
|
544
|
+
role: "assistant",
|
|
545
|
+
status: "completed",
|
|
546
|
+
content
|
|
547
|
+
});
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case "reasoning": {
|
|
551
|
+
output.push({
|
|
552
|
+
type: "reasoning",
|
|
553
|
+
reasoning: item.text
|
|
554
|
+
});
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
// Codex handles tools internally, so we don't expose them as function calls
|
|
558
|
+
// The results are already incorporated into the agent_message
|
|
559
|
+
case "command_execution":
|
|
560
|
+
case "file_change":
|
|
561
|
+
case "mcp_tool_call":
|
|
562
|
+
break;
|
|
563
|
+
default:
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (output.length === 0 && finalResponse) {
|
|
568
|
+
output.push({
|
|
569
|
+
type: "message",
|
|
570
|
+
role: "assistant",
|
|
571
|
+
status: "completed",
|
|
572
|
+
content: [
|
|
573
|
+
{
|
|
574
|
+
type: "output_text",
|
|
575
|
+
text: finalResponse
|
|
576
|
+
}
|
|
577
|
+
]
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
return output;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Convert Codex ThreadEvent to OpenAI Agents StreamEvent
|
|
584
|
+
*/
|
|
585
|
+
convertCodexEventToStreamEvent(event, previousText) {
|
|
586
|
+
const events = [];
|
|
587
|
+
switch (event.type) {
|
|
588
|
+
case "thread.started":
|
|
589
|
+
events.push({ type: "response_started" });
|
|
590
|
+
break;
|
|
591
|
+
case "turn.started":
|
|
592
|
+
break;
|
|
593
|
+
case "item.started":
|
|
594
|
+
break;
|
|
595
|
+
case "item.completed":
|
|
596
|
+
if (event.item.type === "agent_message") {
|
|
597
|
+
events.push({
|
|
598
|
+
type: "output_text_done",
|
|
599
|
+
text: event.item.text
|
|
600
|
+
});
|
|
601
|
+
} else if (event.item.type === "reasoning") {
|
|
602
|
+
events.push({
|
|
603
|
+
type: "reasoning_done",
|
|
604
|
+
reasoning: event.item.text
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
break;
|
|
608
|
+
case "turn.completed":
|
|
609
|
+
events.push({
|
|
610
|
+
type: "response_done",
|
|
611
|
+
response: {
|
|
612
|
+
usage: this.convertUsage(event.usage),
|
|
613
|
+
output: [],
|
|
614
|
+
// Items were already emitted
|
|
615
|
+
responseId: this.thread?.id || void 0
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
break;
|
|
619
|
+
case "turn.failed":
|
|
620
|
+
events.push({
|
|
621
|
+
type: "error",
|
|
622
|
+
error: {
|
|
623
|
+
message: event.error.message
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
break;
|
|
627
|
+
default:
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
return events;
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
export {
|
|
634
|
+
Codex,
|
|
635
|
+
CodexProvider,
|
|
636
|
+
Thread
|
|
637
|
+
};
|
|
638
|
+
//# sourceMappingURL=index.mjs.map
|