@janole/ai-sdk-provider-codex-asp 0.2.2 → 0.2.4
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 +1 -1
- package/dist/index.cjs +210 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +130 -22
- package/dist/index.d.ts +130 -22
- package/dist/index.js +209 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { randomUUID } from 'crypto';
|
|
3
|
+
import { writeFile, unlink } from 'fs/promises';
|
|
4
|
+
import { tmpdir } from 'os';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
2
7
|
import { NoSuchModelError } from '@ai-sdk/provider';
|
|
3
8
|
|
|
4
9
|
// src/utils/object.ts
|
|
@@ -272,6 +277,7 @@ var AppServerClient = class {
|
|
|
272
277
|
// src/client/transport-persistent.ts
|
|
273
278
|
var PersistentTransport = class {
|
|
274
279
|
pool;
|
|
280
|
+
signal;
|
|
275
281
|
worker = null;
|
|
276
282
|
pendingInitializeId = null;
|
|
277
283
|
initializeIntercepted = false;
|
|
@@ -280,9 +286,10 @@ var PersistentTransport = class {
|
|
|
280
286
|
closeListeners = /* @__PURE__ */ new Set();
|
|
281
287
|
constructor(settings) {
|
|
282
288
|
this.pool = settings.pool;
|
|
289
|
+
this.signal = settings.signal;
|
|
283
290
|
}
|
|
284
291
|
async connect() {
|
|
285
|
-
this.worker = this.pool.acquire();
|
|
292
|
+
this.worker = await this.pool.acquire(stripUndefined({ signal: this.signal }));
|
|
286
293
|
await this.worker.ensureConnected();
|
|
287
294
|
}
|
|
288
295
|
disconnect() {
|
|
@@ -722,6 +729,7 @@ var CodexWorker = class {
|
|
|
722
729
|
var CodexWorkerPool = class {
|
|
723
730
|
workers;
|
|
724
731
|
shutdownCalled = false;
|
|
732
|
+
waiters = [];
|
|
725
733
|
constructor(settings) {
|
|
726
734
|
const size = settings.poolSize ?? 1;
|
|
727
735
|
const idleTimeoutMs = settings.idleTimeoutMs ?? 3e5;
|
|
@@ -733,7 +741,7 @@ var CodexWorkerPool = class {
|
|
|
733
741
|
})
|
|
734
742
|
);
|
|
735
743
|
}
|
|
736
|
-
acquire() {
|
|
744
|
+
async acquire(options) {
|
|
737
745
|
if (this.shutdownCalled) {
|
|
738
746
|
throw new CodexProviderError("Worker pool has been shut down.");
|
|
739
747
|
}
|
|
@@ -741,20 +749,61 @@ var CodexWorkerPool = class {
|
|
|
741
749
|
(w) => w.state === "idle" || w.state === "disconnected"
|
|
742
750
|
);
|
|
743
751
|
if (!worker) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
752
|
+
if (options?.signal?.aborted) {
|
|
753
|
+
throw new CodexProviderError("Worker acquisition aborted while waiting.");
|
|
754
|
+
}
|
|
755
|
+
return new Promise((resolve, reject) => {
|
|
756
|
+
const waiter = {
|
|
757
|
+
resolve,
|
|
758
|
+
reject,
|
|
759
|
+
signal: options?.signal,
|
|
760
|
+
abortHandler: void 0
|
|
761
|
+
};
|
|
762
|
+
if (waiter.signal) {
|
|
763
|
+
waiter.abortHandler = () => {
|
|
764
|
+
this.removeWaiter(waiter);
|
|
765
|
+
waiter.reject(new CodexProviderError("Worker acquisition aborted while waiting."));
|
|
766
|
+
};
|
|
767
|
+
waiter.signal.addEventListener("abort", waiter.abortHandler, { once: true });
|
|
768
|
+
}
|
|
769
|
+
this.waiters.push(waiter);
|
|
770
|
+
});
|
|
747
771
|
}
|
|
748
772
|
worker.acquire();
|
|
749
773
|
return worker;
|
|
750
774
|
}
|
|
751
775
|
release(worker) {
|
|
752
|
-
|
|
776
|
+
const waiter = this.waiters.shift();
|
|
777
|
+
if (waiter) {
|
|
778
|
+
this.clearWaiterAbortHandler(waiter);
|
|
779
|
+
waiter.resolve(worker);
|
|
780
|
+
} else {
|
|
781
|
+
worker.release();
|
|
782
|
+
}
|
|
753
783
|
}
|
|
754
784
|
async shutdown() {
|
|
755
785
|
this.shutdownCalled = true;
|
|
786
|
+
while (this.waiters.length > 0) {
|
|
787
|
+
const waiter = this.waiters.shift();
|
|
788
|
+
this.clearWaiterAbortHandler(waiter);
|
|
789
|
+
waiter.reject(new CodexProviderError("Worker pool has been shut down."));
|
|
790
|
+
}
|
|
756
791
|
await Promise.all(this.workers.map((w) => w.shutdown()));
|
|
757
792
|
}
|
|
793
|
+
removeWaiter(target) {
|
|
794
|
+
const index = this.waiters.indexOf(target);
|
|
795
|
+
if (index >= 0) {
|
|
796
|
+
this.waiters.splice(index, 1);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
/** Remove the abort listener so it doesn't fire after the waiter is already served. */
|
|
800
|
+
clearWaiterAbortHandler(waiter) {
|
|
801
|
+
if (!waiter.signal || !waiter.abortHandler) {
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
waiter.signal.removeEventListener("abort", waiter.abortHandler);
|
|
805
|
+
waiter.abortHandler = void 0;
|
|
806
|
+
}
|
|
758
807
|
};
|
|
759
808
|
|
|
760
809
|
// src/dynamic-tools.ts
|
|
@@ -884,7 +933,7 @@ var DynamicToolsDispatcher = class {
|
|
|
884
933
|
// package.json
|
|
885
934
|
var package_default = {
|
|
886
935
|
name: "@janole/ai-sdk-provider-codex-asp",
|
|
887
|
-
version: "0.2.
|
|
936
|
+
version: "0.2.4"};
|
|
888
937
|
|
|
889
938
|
// src/package-info.ts
|
|
890
939
|
var PACKAGE_NAME = package_default.name;
|
|
@@ -1271,8 +1320,6 @@ var CodexEventMapper = class {
|
|
|
1271
1320
|
return parts;
|
|
1272
1321
|
}
|
|
1273
1322
|
};
|
|
1274
|
-
|
|
1275
|
-
// src/protocol/prompt-mapper.ts
|
|
1276
1323
|
function mapSystemPrompt(prompt) {
|
|
1277
1324
|
const chunks = [];
|
|
1278
1325
|
for (const message of prompt) {
|
|
@@ -1285,8 +1332,111 @@ function mapSystemPrompt(prompt) {
|
|
|
1285
1332
|
}
|
|
1286
1333
|
return chunks.length > 0 ? chunks.join("\n\n") : void 0;
|
|
1287
1334
|
}
|
|
1288
|
-
function
|
|
1289
|
-
|
|
1335
|
+
function textItem(text) {
|
|
1336
|
+
return { type: "text", text, text_elements: [] };
|
|
1337
|
+
}
|
|
1338
|
+
var MEDIA_TYPE_TO_EXT = {
|
|
1339
|
+
"image/png": ".png",
|
|
1340
|
+
"image/jpeg": ".jpg",
|
|
1341
|
+
"image/gif": ".gif",
|
|
1342
|
+
"image/webp": ".webp",
|
|
1343
|
+
"image/svg+xml": ".svg",
|
|
1344
|
+
"image/bmp": ".bmp",
|
|
1345
|
+
"image/tiff": ".tiff"
|
|
1346
|
+
};
|
|
1347
|
+
function extensionForMediaType(mediaType) {
|
|
1348
|
+
return MEDIA_TYPE_TO_EXT[mediaType] ?? ".bin";
|
|
1349
|
+
}
|
|
1350
|
+
var LocalFileWriter = class {
|
|
1351
|
+
async write(data, mediaType) {
|
|
1352
|
+
const ext = extensionForMediaType(mediaType);
|
|
1353
|
+
const filename = `codex-ai-sdk-${randomUUID()}${ext}`;
|
|
1354
|
+
const filepath = join(tmpdir(), filename);
|
|
1355
|
+
const buffer = typeof data === "string" ? Buffer.from(data, "base64") : data;
|
|
1356
|
+
await writeFile(filepath, buffer);
|
|
1357
|
+
return pathToFileURL(filepath);
|
|
1358
|
+
}
|
|
1359
|
+
async cleanup(urls) {
|
|
1360
|
+
await Promise.allSettled(
|
|
1361
|
+
urls.filter((u) => u.protocol === "file:").map((u) => unlink(u))
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
var PromptFileResolver = class {
|
|
1366
|
+
writer;
|
|
1367
|
+
written = [];
|
|
1368
|
+
constructor(writer) {
|
|
1369
|
+
this.writer = writer ?? new LocalFileWriter();
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Resolve inline file data and map user content to Codex input items.
|
|
1373
|
+
*
|
|
1374
|
+
* - Inline image data (base64 / Uint8Array) is written via the
|
|
1375
|
+
* {@link FileWriter} and converted to `localImage` or `image` items.
|
|
1376
|
+
* - URL-based image file parts are converted directly.
|
|
1377
|
+
* - Inline text file data is decoded and inlined as text.
|
|
1378
|
+
* - Unsupported media types are silently skipped.
|
|
1379
|
+
*
|
|
1380
|
+
* @param isResume - When true only the last user message is extracted.
|
|
1381
|
+
* When false (fresh thread) all user text is accumulated with images
|
|
1382
|
+
* flushing the text buffer to preserve ordering.
|
|
1383
|
+
*/
|
|
1384
|
+
async resolve(prompt, isResume = false) {
|
|
1385
|
+
if (isResume) {
|
|
1386
|
+
return this.resolveResumed(prompt);
|
|
1387
|
+
}
|
|
1388
|
+
return this.resolveFresh(prompt);
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Remove all files created by previous {@link resolve} calls.
|
|
1392
|
+
* Best-effort — never throws.
|
|
1393
|
+
*/
|
|
1394
|
+
async cleanup() {
|
|
1395
|
+
const urls = this.written.splice(0);
|
|
1396
|
+
if (urls.length > 0) {
|
|
1397
|
+
await this.writer.cleanup(urls);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Convert a resolved image URL to a Codex input item.
|
|
1402
|
+
*/
|
|
1403
|
+
mapImageUrl(mediaType, data) {
|
|
1404
|
+
if (!mediaType.startsWith("image/")) {
|
|
1405
|
+
return null;
|
|
1406
|
+
}
|
|
1407
|
+
if (data.protocol === "file:") {
|
|
1408
|
+
return { type: "localImage", path: fileURLToPath(data) };
|
|
1409
|
+
}
|
|
1410
|
+
return { type: "image", url: data.href };
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Resolve a single file part: write inline data via the writer, then
|
|
1414
|
+
* convert to a Codex input item. Text files are decoded and returned
|
|
1415
|
+
* as text items. Returns `null` for unsupported media types.
|
|
1416
|
+
*/
|
|
1417
|
+
async resolveFilePart(part) {
|
|
1418
|
+
const { mediaType, data } = part;
|
|
1419
|
+
if (mediaType.startsWith("text/")) {
|
|
1420
|
+
if (data instanceof URL) {
|
|
1421
|
+
return textItem(data.href);
|
|
1422
|
+
}
|
|
1423
|
+
const text = typeof data === "string" ? Buffer.from(data, "base64").toString("utf-8") : new TextDecoder().decode(data);
|
|
1424
|
+
return textItem(text);
|
|
1425
|
+
}
|
|
1426
|
+
if (mediaType.startsWith("image/") && !(data instanceof URL)) {
|
|
1427
|
+
const url = await this.writer.write(data, mediaType);
|
|
1428
|
+
this.written.push(url);
|
|
1429
|
+
return this.mapImageUrl(mediaType, url);
|
|
1430
|
+
}
|
|
1431
|
+
if (data instanceof URL) {
|
|
1432
|
+
return this.mapImageUrl(mediaType, data);
|
|
1433
|
+
}
|
|
1434
|
+
return null;
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* Resume path: extract parts from the last user message individually.
|
|
1438
|
+
*/
|
|
1439
|
+
async resolveResumed(prompt) {
|
|
1290
1440
|
for (let i = prompt.length - 1; i >= 0; i--) {
|
|
1291
1441
|
const message = prompt[i];
|
|
1292
1442
|
if (message?.role === "user") {
|
|
@@ -1295,7 +1445,12 @@ function mapPromptToTurnInput(prompt, isResume = false) {
|
|
|
1295
1445
|
if (part.type === "text") {
|
|
1296
1446
|
const text = part.text.trim();
|
|
1297
1447
|
if (text.length > 0) {
|
|
1298
|
-
items.push(
|
|
1448
|
+
items.push(textItem(text));
|
|
1449
|
+
}
|
|
1450
|
+
} else if (part.type === "file") {
|
|
1451
|
+
const mapped = await this.resolveFilePart(part);
|
|
1452
|
+
if (mapped) {
|
|
1453
|
+
items.push(mapped);
|
|
1299
1454
|
}
|
|
1300
1455
|
}
|
|
1301
1456
|
}
|
|
@@ -1304,21 +1459,45 @@ function mapPromptToTurnInput(prompt, isResume = false) {
|
|
|
1304
1459
|
}
|
|
1305
1460
|
return [];
|
|
1306
1461
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1462
|
+
/**
|
|
1463
|
+
* Fresh thread path: accumulate text chunks across all user messages,
|
|
1464
|
+
* flushing before each image to preserve ordering.
|
|
1465
|
+
*/
|
|
1466
|
+
async resolveFresh(prompt) {
|
|
1467
|
+
const items = [];
|
|
1468
|
+
const textChunks = [];
|
|
1469
|
+
const flushText = () => {
|
|
1470
|
+
if (textChunks.length > 0) {
|
|
1471
|
+
items.push(textItem(textChunks.join("\n\n")));
|
|
1472
|
+
textChunks.length = 0;
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
for (const message of prompt) {
|
|
1476
|
+
if (message.role === "user") {
|
|
1477
|
+
for (const part of message.content) {
|
|
1478
|
+
if (part.type === "text") {
|
|
1479
|
+
const text = part.text.trim();
|
|
1480
|
+
if (text.length > 0) {
|
|
1481
|
+
textChunks.push(text);
|
|
1482
|
+
}
|
|
1483
|
+
} else if (part.type === "file") {
|
|
1484
|
+
const mapped = await this.resolveFilePart(part);
|
|
1485
|
+
if (mapped) {
|
|
1486
|
+
if (mapped.type === "text") {
|
|
1487
|
+
textChunks.push(mapped.text);
|
|
1488
|
+
} else {
|
|
1489
|
+
flushText();
|
|
1490
|
+
items.push(mapped);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1315
1493
|
}
|
|
1316
1494
|
}
|
|
1317
1495
|
}
|
|
1318
1496
|
}
|
|
1497
|
+
flushText();
|
|
1498
|
+
return items;
|
|
1319
1499
|
}
|
|
1320
|
-
|
|
1321
|
-
}
|
|
1500
|
+
};
|
|
1322
1501
|
|
|
1323
1502
|
// src/model.ts
|
|
1324
1503
|
function createEmptyUsage() {
|
|
@@ -1553,7 +1732,7 @@ var CodexLanguageModel = class {
|
|
|
1553
1732
|
});
|
|
1554
1733
|
}
|
|
1555
1734
|
doStream(options) {
|
|
1556
|
-
const transport = this.config.providerSettings.transportFactory ? this.config.providerSettings.transportFactory() : this.config.providerSettings.transport?.type === "websocket" ? new WebSocketTransport(this.config.providerSettings.transport.websocket) : new StdioTransport(this.config.providerSettings.transport?.stdio);
|
|
1735
|
+
const transport = this.config.providerSettings.transportFactory ? this.config.providerSettings.transportFactory(options.abortSignal) : this.config.providerSettings.transport?.type === "websocket" ? new WebSocketTransport(this.config.providerSettings.transport.websocket) : new StdioTransport(this.config.providerSettings.transport?.stdio);
|
|
1557
1736
|
const packetLogger = this.config.providerSettings.debug?.logPackets === true ? this.config.providerSettings.debug.logger ?? ((packet) => {
|
|
1558
1737
|
if (packet.direction === "inbound") {
|
|
1559
1738
|
console.debug("[codex packet]", packet.message);
|
|
@@ -1585,6 +1764,7 @@ var CodexLanguageModel = class {
|
|
|
1585
1764
|
debugLog?.("outbound", "turn/interrupt", interruptParams);
|
|
1586
1765
|
await client.request("turn/interrupt", interruptParams, interruptTimeoutMs);
|
|
1587
1766
|
};
|
|
1767
|
+
const fileResolver = new PromptFileResolver();
|
|
1588
1768
|
const stream = new ReadableStream({
|
|
1589
1769
|
start: (controller) => {
|
|
1590
1770
|
let closed = false;
|
|
@@ -1597,6 +1777,7 @@ var CodexLanguageModel = class {
|
|
|
1597
1777
|
try {
|
|
1598
1778
|
controller.close();
|
|
1599
1779
|
} finally {
|
|
1780
|
+
await fileResolver.cleanup();
|
|
1600
1781
|
await client.disconnect();
|
|
1601
1782
|
}
|
|
1602
1783
|
};
|
|
@@ -1608,6 +1789,7 @@ var CodexLanguageModel = class {
|
|
|
1608
1789
|
try {
|
|
1609
1790
|
controller.close();
|
|
1610
1791
|
} finally {
|
|
1792
|
+
await fileResolver.cleanup();
|
|
1611
1793
|
await client.disconnect();
|
|
1612
1794
|
}
|
|
1613
1795
|
};
|
|
@@ -1832,7 +2014,7 @@ var CodexLanguageModel = class {
|
|
|
1832
2014
|
closeSuccessfully
|
|
1833
2015
|
);
|
|
1834
2016
|
}
|
|
1835
|
-
const turnInput =
|
|
2017
|
+
const turnInput = await fileResolver.resolve(options.prompt, !!resumeThreadId);
|
|
1836
2018
|
const turnStartParams = stripUndefined({
|
|
1837
2019
|
threadId,
|
|
1838
2020
|
input: turnInput,
|
|
@@ -1856,6 +2038,7 @@ var CodexLanguageModel = class {
|
|
|
1856
2038
|
await interruptTurnIfPossible();
|
|
1857
2039
|
} catch {
|
|
1858
2040
|
}
|
|
2041
|
+
await fileResolver.cleanup();
|
|
1859
2042
|
await client.disconnect();
|
|
1860
2043
|
}
|
|
1861
2044
|
});
|
|
@@ -1967,7 +2150,7 @@ function createCodexAppServer(settings = {}) {
|
|
|
1967
2150
|
});
|
|
1968
2151
|
}
|
|
1969
2152
|
const persistentPool = persistentPoolHandle?.pool ?? null;
|
|
1970
|
-
const effectiveTransportFactory = persistentPool ? () => new PersistentTransport({ pool: persistentPool }) : baseTransportFactory;
|
|
2153
|
+
const effectiveTransportFactory = persistentPool ? (signal) => new PersistentTransport(stripUndefined({ pool: persistentPool, signal })) : baseTransportFactory;
|
|
1971
2154
|
const resolvedSettings = Object.freeze(stripUndefined({
|
|
1972
2155
|
defaultModel: settings.defaultModel,
|
|
1973
2156
|
experimentalApi: settings.experimentalApi,
|
|
@@ -2026,6 +2209,6 @@ function createCodexAppServer(settings = {}) {
|
|
|
2026
2209
|
var codexAppServer = createCodexAppServer();
|
|
2027
2210
|
var createCodexProvider = createCodexAppServer;
|
|
2028
2211
|
|
|
2029
|
-
export { AppServerClient, ApprovalsDispatcher, CODEX_PROVIDER_ID, CodexEventMapper, CodexLanguageModel, CodexNotImplementedError, CodexProviderError, CodexWorker, CodexWorkerPool, DynamicToolsDispatcher, JsonRpcError, PACKAGE_NAME, PACKAGE_VERSION, PersistentTransport, StdioTransport, WebSocketTransport, codexAppServer, codexProviderMetadata, createCodexAppServer, createCodexProvider,
|
|
2212
|
+
export { AppServerClient, ApprovalsDispatcher, CODEX_PROVIDER_ID, CodexEventMapper, CodexLanguageModel, CodexNotImplementedError, CodexProviderError, CodexWorker, CodexWorkerPool, DynamicToolsDispatcher, JsonRpcError, LocalFileWriter, PACKAGE_NAME, PACKAGE_VERSION, PersistentTransport, PromptFileResolver, StdioTransport, WebSocketTransport, codexAppServer, codexProviderMetadata, createCodexAppServer, createCodexProvider, mapSystemPrompt, withProviderMetadata };
|
|
2030
2213
|
//# sourceMappingURL=index.js.map
|
|
2031
2214
|
//# sourceMappingURL=index.js.map
|