@janole/ai-sdk-provider-codex-asp 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,1559 @@
1
+ 'use strict';
2
+
3
+ var child_process = require('child_process');
4
+ var provider = require('@ai-sdk/provider');
5
+
6
+ // src/approvals.ts
7
+ var ApprovalsDispatcher = class {
8
+ onCommandApproval;
9
+ onFileChangeApproval;
10
+ constructor(settings = {}) {
11
+ this.onCommandApproval = settings.onCommandApproval ?? (() => "accept");
12
+ this.onFileChangeApproval = settings.onFileChangeApproval ?? (() => "accept");
13
+ }
14
+ attach(client) {
15
+ const unsubCommand = client.onRequest(
16
+ "item/commandExecution/requestApproval",
17
+ async (params, _request) => {
18
+ const p = params;
19
+ const request = {
20
+ threadId: p.threadId,
21
+ turnId: p.turnId,
22
+ itemId: p.itemId,
23
+ ...p.approvalId !== void 0 ? { approvalId: p.approvalId } : {},
24
+ ...p.reason !== void 0 ? { reason: p.reason } : {},
25
+ ...p.command !== void 0 ? { command: p.command } : {},
26
+ ...p.cwd !== void 0 ? { cwd: p.cwd } : {}
27
+ };
28
+ const decision = await this.onCommandApproval(request);
29
+ return { decision };
30
+ }
31
+ );
32
+ const unsubFileChange = client.onRequest(
33
+ "item/fileChange/requestApproval",
34
+ async (params, _request) => {
35
+ const p = params;
36
+ const request = {
37
+ threadId: p.threadId,
38
+ turnId: p.turnId,
39
+ itemId: p.itemId,
40
+ ...p.reason !== void 0 ? { reason: p.reason } : {},
41
+ ...p.grantRoot !== void 0 ? { grantRoot: p.grantRoot } : {}
42
+ };
43
+ const decision = await this.onFileChangeApproval(request);
44
+ return { decision };
45
+ }
46
+ );
47
+ return () => {
48
+ unsubCommand();
49
+ unsubFileChange();
50
+ };
51
+ }
52
+ };
53
+
54
+ // src/errors.ts
55
+ var CodexProviderError = class extends Error {
56
+ constructor(message, options) {
57
+ super(message, options);
58
+ this.name = "CodexProviderError";
59
+ }
60
+ };
61
+ var CodexNotImplementedError = class extends CodexProviderError {
62
+ constructor(method) {
63
+ super(`Codex provider method not implemented yet: ${method}`);
64
+ this.name = "CodexNotImplementedError";
65
+ }
66
+ };
67
+
68
+ // src/client/app-server-client.ts
69
+ var JsonRpcError = class extends CodexProviderError {
70
+ code;
71
+ data;
72
+ constructor(error) {
73
+ super(error.message);
74
+ this.name = "JsonRpcError";
75
+ this.code = error.code;
76
+ this.data = error.data;
77
+ }
78
+ };
79
+ function isResponse(message) {
80
+ return "id" in message && message.id !== void 0 && ("result" in message || "error" in message) && !("method" in message);
81
+ }
82
+ function isRequestOrNotification(message) {
83
+ return "method" in message && typeof message.method === "string";
84
+ }
85
+ var AppServerClient = class {
86
+ transport;
87
+ requestTimeoutMs;
88
+ nextId = 1;
89
+ pendingRequests = /* @__PURE__ */ new Map();
90
+ notificationHandlers = /* @__PURE__ */ new Map();
91
+ anyNotificationHandlers = /* @__PURE__ */ new Set();
92
+ requestHandlers = /* @__PURE__ */ new Map();
93
+ removeMessageListener = null;
94
+ removeErrorListener = null;
95
+ constructor(transport, settings = {}) {
96
+ this.transport = transport;
97
+ this.requestTimeoutMs = settings.requestTimeoutMs ?? 3e4;
98
+ }
99
+ async connect() {
100
+ await this.transport.connect();
101
+ this.removeMessageListener = this.transport.on("message", (message) => {
102
+ void this.handleMessage(message).catch(() => {
103
+ });
104
+ });
105
+ this.removeErrorListener = this.transport.on("error", (error) => {
106
+ for (const pending of this.pendingRequests.values()) {
107
+ clearTimeout(pending.timer);
108
+ pending.reject(error);
109
+ }
110
+ this.pendingRequests.clear();
111
+ });
112
+ }
113
+ async disconnect() {
114
+ if (this.removeMessageListener) {
115
+ this.removeMessageListener();
116
+ this.removeMessageListener = null;
117
+ }
118
+ if (this.removeErrorListener) {
119
+ this.removeErrorListener();
120
+ this.removeErrorListener = null;
121
+ }
122
+ for (const pending of this.pendingRequests.values()) {
123
+ clearTimeout(pending.timer);
124
+ pending.reject(new CodexProviderError("Client disconnected."));
125
+ }
126
+ this.pendingRequests.clear();
127
+ await this.transport.disconnect();
128
+ }
129
+ async request(method, params, timeoutMs = this.requestTimeoutMs) {
130
+ const id = this.nextId++;
131
+ const message = params === void 0 ? { id, method } : { id, method, params };
132
+ const promise = new Promise((resolve, reject) => {
133
+ const timer = setTimeout(() => {
134
+ this.pendingRequests.delete(id);
135
+ reject(new CodexProviderError(`Request timed out: ${method}`));
136
+ }, timeoutMs);
137
+ this.pendingRequests.set(id, {
138
+ resolve: (value) => resolve(value),
139
+ reject,
140
+ timer
141
+ });
142
+ });
143
+ await this.transport.sendMessage(message);
144
+ return promise;
145
+ }
146
+ async notification(method, params) {
147
+ await this.transport.sendNotification(method, params);
148
+ }
149
+ onNotification(method, handler) {
150
+ const handlers = this.notificationHandlers.get(method) ?? /* @__PURE__ */ new Set();
151
+ handlers.add(handler);
152
+ this.notificationHandlers.set(method, handlers);
153
+ return () => {
154
+ handlers.delete(handler);
155
+ if (handlers.size === 0) {
156
+ this.notificationHandlers.delete(method);
157
+ }
158
+ };
159
+ }
160
+ onAnyNotification(handler) {
161
+ this.anyNotificationHandlers.add(handler);
162
+ return () => {
163
+ this.anyNotificationHandlers.delete(handler);
164
+ };
165
+ }
166
+ onRequest(method, handler) {
167
+ this.requestHandlers.set(method, handler);
168
+ return () => {
169
+ this.requestHandlers.delete(method);
170
+ };
171
+ }
172
+ onToolCallRequest(handler) {
173
+ return this.onRequest(
174
+ "item/tool/call",
175
+ async (params, request) => handler(params ?? {}, request)
176
+ );
177
+ }
178
+ async handleMessage(message) {
179
+ if (isResponse(message)) {
180
+ this.handleResponse(message);
181
+ return;
182
+ }
183
+ if (!isRequestOrNotification(message)) {
184
+ return;
185
+ }
186
+ const hasRequestId = "id" in message && message.id !== void 0;
187
+ if (hasRequestId) {
188
+ await this.handleInboundRequest(message);
189
+ return;
190
+ }
191
+ await this.handleNotification(message.method, message.params);
192
+ }
193
+ handleResponse(message) {
194
+ const pending = this.pendingRequests.get(message.id);
195
+ if (!pending) {
196
+ return;
197
+ }
198
+ clearTimeout(pending.timer);
199
+ this.pendingRequests.delete(message.id);
200
+ if ("error" in message) {
201
+ pending.reject(new JsonRpcError(message.error));
202
+ return;
203
+ }
204
+ pending.resolve(message.result);
205
+ }
206
+ async handleNotification(method, params) {
207
+ const handlers = this.notificationHandlers.get(method);
208
+ if (handlers) {
209
+ for (const handler of handlers) {
210
+ await handler(params);
211
+ }
212
+ }
213
+ for (const handler of this.anyNotificationHandlers) {
214
+ await handler(method, params);
215
+ }
216
+ }
217
+ async handleInboundRequest(request) {
218
+ const handler = this.requestHandlers.get(request.method);
219
+ if (!handler) {
220
+ await this.transport.sendMessage({
221
+ id: request.id,
222
+ error: {
223
+ code: -32601,
224
+ message: `Method not found: ${request.method}`
225
+ }
226
+ });
227
+ return;
228
+ }
229
+ try {
230
+ const result = await handler(request.params, request);
231
+ await this.transport.sendMessage({
232
+ id: request.id,
233
+ result
234
+ });
235
+ } catch (error) {
236
+ try {
237
+ await this.transport.sendMessage({
238
+ id: request.id,
239
+ error: {
240
+ code: -32e3,
241
+ message: error instanceof Error ? error.message : "Request handler failed"
242
+ }
243
+ });
244
+ } catch {
245
+ }
246
+ }
247
+ }
248
+ };
249
+
250
+ // src/client/transport-persistent.ts
251
+ var PersistentTransport = class {
252
+ pool;
253
+ worker = null;
254
+ pendingInitializeId = null;
255
+ initializeIntercepted = false;
256
+ messageListeners = /* @__PURE__ */ new Set();
257
+ errorListeners = /* @__PURE__ */ new Set();
258
+ closeListeners = /* @__PURE__ */ new Set();
259
+ constructor(settings) {
260
+ this.pool = settings.pool;
261
+ }
262
+ async connect() {
263
+ this.worker = this.pool.acquire();
264
+ await this.worker.ensureConnected();
265
+ }
266
+ disconnect() {
267
+ if (this.worker) {
268
+ const w = this.worker;
269
+ this.worker = null;
270
+ this.messageListeners.clear();
271
+ this.errorListeners.clear();
272
+ this.closeListeners.clear();
273
+ this.pool.release(w);
274
+ }
275
+ return Promise.resolve();
276
+ }
277
+ async sendMessage(message) {
278
+ if (!this.worker) {
279
+ throw new Error("PersistentTransport is not connected.");
280
+ }
281
+ if (isInitializeRequest(message)) {
282
+ if (this.worker.initialized) {
283
+ this.initializeIntercepted = true;
284
+ const requestId = message.id;
285
+ const cachedResult = this.worker.initializeResult;
286
+ queueMicrotask(() => {
287
+ for (const listener of this.messageListeners) {
288
+ listener({ id: requestId, result: cachedResult });
289
+ }
290
+ });
291
+ return;
292
+ }
293
+ this.initializeIntercepted = false;
294
+ this.pendingInitializeId = message.id;
295
+ }
296
+ await this.worker.sendMessage(message);
297
+ }
298
+ async sendNotification(method, params) {
299
+ if (!this.worker) {
300
+ throw new Error("PersistentTransport is not connected.");
301
+ }
302
+ if (method === "initialized" && this.initializeIntercepted) {
303
+ return;
304
+ }
305
+ await this.worker.sendNotification(method, params);
306
+ }
307
+ on(event, listener) {
308
+ if (!this.worker) {
309
+ throw new Error("PersistentTransport is not connected.");
310
+ }
311
+ if (event === "message") {
312
+ const msgListener = listener;
313
+ const wrappedListener = ((incoming) => {
314
+ if (this.pendingInitializeId !== null && "id" in incoming && incoming.id === this.pendingInitializeId && "result" in incoming) {
315
+ this.worker?.markInitialized(incoming.result);
316
+ this.pendingInitializeId = null;
317
+ }
318
+ msgListener(incoming);
319
+ });
320
+ const workerUnsub = this.worker.onSession(event, wrappedListener);
321
+ this.messageListeners.add(msgListener);
322
+ return () => {
323
+ workerUnsub();
324
+ this.messageListeners.delete(msgListener);
325
+ };
326
+ }
327
+ if (event === "error") {
328
+ const errListener = listener;
329
+ const workerUnsub = this.worker.onSession(event, listener);
330
+ this.errorListeners.add(errListener);
331
+ return () => {
332
+ workerUnsub();
333
+ this.errorListeners.delete(errListener);
334
+ };
335
+ }
336
+ if (event === "close") {
337
+ const closeListener = listener;
338
+ const workerUnsub = this.worker.onSession(event, listener);
339
+ this.closeListeners.add(closeListener);
340
+ return () => {
341
+ workerUnsub();
342
+ this.closeListeners.delete(closeListener);
343
+ };
344
+ }
345
+ return this.worker.onSession(event, listener);
346
+ }
347
+ getPendingToolCall() {
348
+ return this.worker?.pendingToolCall ?? null;
349
+ }
350
+ async respondToToolCall(result) {
351
+ if (!this.worker?.pendingToolCall) {
352
+ throw new Error("No pending tool call to respond to.");
353
+ }
354
+ const { requestId } = this.worker.pendingToolCall;
355
+ this.worker.pendingToolCall = null;
356
+ await this.worker.sendMessage({
357
+ id: requestId,
358
+ result
359
+ });
360
+ }
361
+ parkToolCall(pending) {
362
+ if (!this.worker) {
363
+ throw new Error("PersistentTransport is not connected.");
364
+ }
365
+ this.worker.pendingToolCall = pending;
366
+ }
367
+ };
368
+ function isInitializeRequest(message) {
369
+ return "id" in message && "method" in message && message.method === "initialize";
370
+ }
371
+ var DEFAULT_COMMAND = "codex";
372
+ var DEFAULT_ARGS = ["app-server", "--listen", "stdio://"];
373
+ var StdioTransport = class {
374
+ settings;
375
+ process = null;
376
+ listeners = {
377
+ message: /* @__PURE__ */ new Set(),
378
+ error: /* @__PURE__ */ new Set(),
379
+ close: /* @__PURE__ */ new Set()
380
+ };
381
+ stdoutBuffer = "";
382
+ constructor(settings = {}) {
383
+ this.settings = settings;
384
+ }
385
+ connect() {
386
+ if (this.process !== null) {
387
+ return Promise.resolve();
388
+ }
389
+ const options = {
390
+ cwd: this.settings.cwd,
391
+ env: this.settings.env,
392
+ stdio: "pipe"
393
+ };
394
+ const child = child_process.spawn(
395
+ this.settings.command ?? DEFAULT_COMMAND,
396
+ this.settings.args ?? DEFAULT_ARGS,
397
+ options
398
+ );
399
+ this.process = child;
400
+ child.stdout.setEncoding("utf8");
401
+ child.stdout.on("data", (chunk) => {
402
+ this.handleStdoutChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
403
+ });
404
+ child.stderr.setEncoding("utf8");
405
+ child.stderr.on("data", (chunk) => {
406
+ this.emit("error", new Error(`codex stderr: ${typeof chunk === "string" ? chunk : chunk.toString("utf8")}`));
407
+ });
408
+ child.on("error", (error) => {
409
+ this.emit("error", error);
410
+ });
411
+ child.on("close", (code, signal) => {
412
+ this.process = null;
413
+ this.emit("close", code, signal);
414
+ });
415
+ return Promise.resolve();
416
+ }
417
+ async disconnect() {
418
+ if (this.process === null) {
419
+ return;
420
+ }
421
+ const child = this.process;
422
+ this.process = null;
423
+ await new Promise((resolve) => {
424
+ let finished = false;
425
+ const finish = () => {
426
+ if (!finished) {
427
+ finished = true;
428
+ resolve();
429
+ }
430
+ };
431
+ child.once("close", () => finish());
432
+ child.once("exit", () => finish());
433
+ if (!child.killed) {
434
+ child.kill();
435
+ }
436
+ setTimeout(finish, 250);
437
+ });
438
+ }
439
+ async sendMessage(message) {
440
+ if (this.process === null || this.process.stdin.destroyed) {
441
+ throw new Error("StdioTransport is not connected.");
442
+ }
443
+ const payload = `${JSON.stringify(message)}
444
+ `;
445
+ await new Promise((resolve, reject) => {
446
+ this.process?.stdin.write(payload, (error) => {
447
+ if (error) {
448
+ reject(error);
449
+ return;
450
+ }
451
+ resolve();
452
+ });
453
+ });
454
+ }
455
+ async sendNotification(method, params) {
456
+ await this.sendMessage(
457
+ params === void 0 ? { method } : { method, params }
458
+ );
459
+ }
460
+ on(event, listener) {
461
+ const listeners = this.listeners[event];
462
+ listeners.add(listener);
463
+ return () => {
464
+ listeners.delete(listener);
465
+ };
466
+ }
467
+ handleStdoutChunk(chunk) {
468
+ this.stdoutBuffer += chunk;
469
+ let lineBreakIndex = this.stdoutBuffer.indexOf("\n");
470
+ while (lineBreakIndex >= 0) {
471
+ const line = this.stdoutBuffer.slice(0, lineBreakIndex).trim();
472
+ this.stdoutBuffer = this.stdoutBuffer.slice(lineBreakIndex + 1);
473
+ if (line.length > 0) {
474
+ try {
475
+ const message = JSON.parse(line);
476
+ this.emit("message", message);
477
+ } catch (error) {
478
+ this.emit("error", error);
479
+ }
480
+ }
481
+ lineBreakIndex = this.stdoutBuffer.indexOf("\n");
482
+ }
483
+ }
484
+ emit(event, ...args) {
485
+ const listeners = this.listeners[event];
486
+ for (const listener of listeners) {
487
+ listener(...args);
488
+ }
489
+ }
490
+ };
491
+
492
+ // src/client/transport-websocket.ts
493
+ var DEFAULT_WS_URL = "ws://localhost:3000";
494
+ var WebSocketTransport = class {
495
+ settings;
496
+ socket = null;
497
+ listeners = {
498
+ message: /* @__PURE__ */ new Set(),
499
+ error: /* @__PURE__ */ new Set(),
500
+ close: /* @__PURE__ */ new Set()
501
+ };
502
+ constructor(settings = {}) {
503
+ this.settings = settings;
504
+ }
505
+ async connect() {
506
+ if (this.socket && this.socket.readyState === this.socket.OPEN) {
507
+ return;
508
+ }
509
+ const WebSocketCtor = globalThis.WebSocket;
510
+ if (!WebSocketCtor) {
511
+ throw new Error("WebSocket is not available in this runtime.");
512
+ }
513
+ const socket = new WebSocketCtor(
514
+ this.settings.url ?? DEFAULT_WS_URL,
515
+ void 0,
516
+ this.settings.headers ? { headers: this.settings.headers } : void 0
517
+ );
518
+ this.socket = socket;
519
+ socket.addEventListener("message", (event) => {
520
+ this.handleIncomingMessage(event.data);
521
+ });
522
+ socket.addEventListener("error", (event) => {
523
+ this.emit("error", event);
524
+ });
525
+ socket.addEventListener("close", (event) => {
526
+ this.socket = null;
527
+ this.emit("close", event.code, null);
528
+ });
529
+ await new Promise((resolve, reject) => {
530
+ const onOpen = () => {
531
+ socket.removeEventListener("open", onOpen);
532
+ socket.removeEventListener("error", onError);
533
+ resolve();
534
+ };
535
+ const onError = (event) => {
536
+ socket.removeEventListener("open", onOpen);
537
+ socket.removeEventListener("error", onError);
538
+ reject(new Error(`WebSocket connection failed: ${String(event.type)}`));
539
+ };
540
+ socket.addEventListener("open", onOpen, { once: true });
541
+ socket.addEventListener("error", onError, { once: true });
542
+ });
543
+ }
544
+ async disconnect() {
545
+ if (!this.socket) {
546
+ return;
547
+ }
548
+ const socket = this.socket;
549
+ await new Promise((resolve) => {
550
+ let finished = false;
551
+ const finish = () => {
552
+ if (!finished) {
553
+ finished = true;
554
+ resolve();
555
+ }
556
+ };
557
+ socket.addEventListener("close", () => finish(), { once: true });
558
+ socket.close();
559
+ setTimeout(finish, 250);
560
+ });
561
+ this.socket = null;
562
+ }
563
+ sendMessage(message) {
564
+ if (!this.socket || this.socket.readyState !== this.socket.OPEN) {
565
+ return Promise.reject(new Error("WebSocketTransport is not connected."));
566
+ }
567
+ this.socket.send(JSON.stringify(message));
568
+ return Promise.resolve();
569
+ }
570
+ async sendNotification(method, params) {
571
+ await this.sendMessage(
572
+ params === void 0 ? { method } : { method, params }
573
+ );
574
+ }
575
+ on(event, listener) {
576
+ const listeners = this.listeners[event];
577
+ listeners.add(listener);
578
+ return () => {
579
+ listeners.delete(listener);
580
+ };
581
+ }
582
+ handleIncomingMessage(raw) {
583
+ try {
584
+ if (typeof raw !== "string") {
585
+ return;
586
+ }
587
+ const message = JSON.parse(raw);
588
+ this.emit("message", message);
589
+ } catch (error) {
590
+ this.emit("error", error);
591
+ }
592
+ }
593
+ emit(event, ...args) {
594
+ const listeners = this.listeners[event];
595
+ for (const listener of listeners) {
596
+ listener(...args);
597
+ }
598
+ }
599
+ };
600
+
601
+ // src/client/worker.ts
602
+ var CodexWorker = class {
603
+ state = "disconnected";
604
+ initialized = false;
605
+ initializeResult = void 0;
606
+ pendingToolCall = null;
607
+ inner = null;
608
+ settings;
609
+ idleTimer = null;
610
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
611
+ sessionListeners = [];
612
+ constructor(settings) {
613
+ this.settings = settings;
614
+ }
615
+ async ensureConnected() {
616
+ if (this.inner) {
617
+ return;
618
+ }
619
+ this.inner = this.settings.transportFactory();
620
+ this.inner.on("close", () => {
621
+ this.initialized = false;
622
+ this.initializeResult = void 0;
623
+ this.inner = null;
624
+ this.state = "disconnected";
625
+ });
626
+ this.inner.on("error", () => {
627
+ this.initialized = false;
628
+ this.initializeResult = void 0;
629
+ this.inner = null;
630
+ this.state = "disconnected";
631
+ });
632
+ await this.inner.connect();
633
+ }
634
+ acquire() {
635
+ if (this.idleTimer) {
636
+ clearTimeout(this.idleTimer);
637
+ this.idleTimer = null;
638
+ }
639
+ this.state = "busy";
640
+ }
641
+ release() {
642
+ this.clearSessionListeners();
643
+ this.state = "idle";
644
+ if (this.settings.idleTimeoutMs > 0) {
645
+ this.idleTimer = setTimeout(() => {
646
+ void this.shutdown();
647
+ }, this.settings.idleTimeoutMs);
648
+ }
649
+ }
650
+ markInitialized(result) {
651
+ this.initialized = true;
652
+ this.initializeResult = result;
653
+ }
654
+ onSession(event, listener) {
655
+ if (!this.inner) {
656
+ throw new Error("Worker has no active transport.");
657
+ }
658
+ const unsubscribe = this.inner.on(event, listener);
659
+ this.sessionListeners.push({ event, listener, unsubscribe });
660
+ return unsubscribe;
661
+ }
662
+ clearSessionListeners() {
663
+ for (const entry of this.sessionListeners) {
664
+ entry.unsubscribe();
665
+ }
666
+ this.sessionListeners = [];
667
+ }
668
+ async sendMessage(message) {
669
+ if (!this.inner) {
670
+ throw new Error("Worker has no active transport.");
671
+ }
672
+ await this.inner.sendMessage(message);
673
+ }
674
+ async sendNotification(method, params) {
675
+ if (!this.inner) {
676
+ throw new Error("Worker has no active transport.");
677
+ }
678
+ await this.inner.sendNotification(method, params);
679
+ }
680
+ async shutdown() {
681
+ if (this.idleTimer) {
682
+ clearTimeout(this.idleTimer);
683
+ this.idleTimer = null;
684
+ }
685
+ this.clearSessionListeners();
686
+ if (this.inner) {
687
+ const transport = this.inner;
688
+ this.inner = null;
689
+ this.initialized = false;
690
+ this.initializeResult = void 0;
691
+ this.state = "disconnected";
692
+ await transport.disconnect();
693
+ } else {
694
+ this.state = "disconnected";
695
+ }
696
+ }
697
+ };
698
+
699
+ // src/client/worker-pool.ts
700
+ var CodexWorkerPool = class {
701
+ workers;
702
+ shutdownCalled = false;
703
+ constructor(settings) {
704
+ const size = settings.poolSize ?? 1;
705
+ const idleTimeoutMs = settings.idleTimeoutMs ?? 3e5;
706
+ this.workers = Array.from(
707
+ { length: size },
708
+ () => new CodexWorker({
709
+ transportFactory: settings.transportFactory,
710
+ idleTimeoutMs
711
+ })
712
+ );
713
+ }
714
+ acquire() {
715
+ if (this.shutdownCalled) {
716
+ throw new CodexProviderError("Worker pool has been shut down.");
717
+ }
718
+ const worker = this.workers.find(
719
+ (w) => w.state === "idle" || w.state === "disconnected"
720
+ );
721
+ if (!worker) {
722
+ throw new CodexProviderError(
723
+ "All workers are busy. Try again later or increase poolSize."
724
+ );
725
+ }
726
+ worker.acquire();
727
+ return worker;
728
+ }
729
+ release(worker) {
730
+ worker.release();
731
+ }
732
+ async shutdown() {
733
+ this.shutdownCalled = true;
734
+ await Promise.all(this.workers.map((w) => w.shutdown()));
735
+ }
736
+ };
737
+
738
+ // src/dynamic-tools.ts
739
+ function toTextResult(message, success) {
740
+ const contentItems = [{ type: "inputText", text: message }];
741
+ return { success, contentItems };
742
+ }
743
+ function withTimeout(promise, timeoutMs) {
744
+ return new Promise((resolve, reject) => {
745
+ const timer = setTimeout(() => {
746
+ reject(new CodexProviderError(`Dynamic tool execution timed out after ${timeoutMs}ms.`));
747
+ }, timeoutMs);
748
+ promise.then((value) => {
749
+ clearTimeout(timer);
750
+ resolve(value);
751
+ }).catch((error) => {
752
+ clearTimeout(timer);
753
+ reject(error instanceof Error ? error : new Error(String(error)));
754
+ });
755
+ });
756
+ }
757
+ var DynamicToolsDispatcher = class {
758
+ handlers = /* @__PURE__ */ new Map();
759
+ timeoutMs;
760
+ constructor(settings = {}) {
761
+ this.timeoutMs = settings.timeoutMs ?? 3e4;
762
+ if (settings.tools) {
763
+ for (const [name, def] of Object.entries(settings.tools)) {
764
+ this.register(name, def.execute);
765
+ }
766
+ }
767
+ if (settings.handlers) {
768
+ for (const [name, handler] of Object.entries(settings.handlers)) {
769
+ this.register(name, handler);
770
+ }
771
+ }
772
+ }
773
+ register(name, handler) {
774
+ this.handlers.set(name, handler);
775
+ }
776
+ attach(client) {
777
+ return client.onToolCallRequest(async (params) => this.dispatch(params));
778
+ }
779
+ async dispatch(params) {
780
+ const toolName = params.tool ?? params.toolName;
781
+ if (!toolName) {
782
+ return toTextResult("Dynamic tool call is missing the tool name.", false);
783
+ }
784
+ const handler = this.handlers.get(toolName);
785
+ if (!handler) {
786
+ return toTextResult(`No dynamic tool handler registered for "${toolName}".`, false);
787
+ }
788
+ const context = {
789
+ toolName,
790
+ ...params.threadId ? { threadId: params.threadId } : {},
791
+ ...params.turnId ? { turnId: params.turnId } : {},
792
+ ...params.callId ? { callId: params.callId } : {}
793
+ };
794
+ const args = params.arguments ?? params.input;
795
+ try {
796
+ return await withTimeout(handler(args, context), this.timeoutMs);
797
+ } catch (error) {
798
+ const message = error instanceof Error ? error.message : "Dynamic tool execution failed.";
799
+ return toTextResult(message, false);
800
+ }
801
+ }
802
+ };
803
+
804
+ // package.json
805
+ var package_default = {
806
+ name: "@janole/ai-sdk-provider-codex-asp",
807
+ version: "0.1.0"};
808
+
809
+ // src/package-info.ts
810
+ var PACKAGE_NAME = package_default.name;
811
+ var PACKAGE_VERSION = package_default.version;
812
+
813
+ // src/protocol/provider-metadata.ts
814
+ var CODEX_PROVIDER_ID = "codex-app-server";
815
+ function codexProviderMetadata(threadId) {
816
+ if (!threadId) {
817
+ return void 0;
818
+ }
819
+ return { [CODEX_PROVIDER_ID]: { threadId } };
820
+ }
821
+ function withProviderMetadata(part, threadId) {
822
+ const meta = codexProviderMetadata(threadId);
823
+ return meta ? { ...part, providerMetadata: meta } : part;
824
+ }
825
+
826
+ // src/protocol/event-mapper.ts
827
+ var EMPTY_USAGE = {
828
+ inputTokens: {
829
+ total: void 0,
830
+ noCache: void 0,
831
+ cacheRead: void 0,
832
+ cacheWrite: void 0
833
+ },
834
+ outputTokens: {
835
+ total: void 0,
836
+ text: void 0,
837
+ reasoning: void 0
838
+ }
839
+ };
840
+ function toFinishReason(status) {
841
+ switch (status) {
842
+ case "completed":
843
+ return { unified: "stop", raw: "completed" };
844
+ case "failed":
845
+ return { unified: "error", raw: "failed" };
846
+ case "interrupted":
847
+ return { unified: "other", raw: "interrupted" };
848
+ default:
849
+ return { unified: "other", raw: void 0 };
850
+ }
851
+ }
852
+ var CodexEventMapper = class {
853
+ streamStarted = false;
854
+ openTextParts = /* @__PURE__ */ new Set();
855
+ threadId;
856
+ setThreadId(threadId) {
857
+ this.threadId = threadId;
858
+ }
859
+ map(event) {
860
+ const parts = [];
861
+ const withMeta = (part) => withProviderMetadata(part, this.threadId);
862
+ const pushStreamStart = () => {
863
+ if (!this.streamStarted) {
864
+ parts.push({ type: "stream-start", warnings: [] });
865
+ this.streamStarted = true;
866
+ }
867
+ };
868
+ switch (event.method) {
869
+ case "turn/started": {
870
+ pushStreamStart();
871
+ break;
872
+ }
873
+ case "item/started": {
874
+ const item = event.params ?? {};
875
+ if (item.itemType === "assistantMessage" && item.itemId) {
876
+ pushStreamStart();
877
+ this.openTextParts.add(item.itemId);
878
+ parts.push(withMeta({ type: "text-start", id: item.itemId }));
879
+ }
880
+ break;
881
+ }
882
+ case "item/agentMessage/delta": {
883
+ const delta = event.params ?? {};
884
+ if (!delta.itemId || !delta.delta) {
885
+ break;
886
+ }
887
+ pushStreamStart();
888
+ if (!this.openTextParts.has(delta.itemId)) {
889
+ this.openTextParts.add(delta.itemId);
890
+ parts.push(withMeta({ type: "text-start", id: delta.itemId }));
891
+ }
892
+ parts.push(withMeta({ type: "text-delta", id: delta.itemId, delta: delta.delta }));
893
+ break;
894
+ }
895
+ case "item/completed": {
896
+ const item = event.params ?? {};
897
+ if (item.itemType === "assistantMessage" && item.itemId && this.openTextParts.has(item.itemId)) {
898
+ parts.push(withMeta({ type: "text-end", id: item.itemId }));
899
+ this.openTextParts.delete(item.itemId);
900
+ }
901
+ break;
902
+ }
903
+ case "item/tool/callStarted": {
904
+ const params = event.params ?? {};
905
+ if (params.callId && params.tool) {
906
+ pushStreamStart();
907
+ parts.push(withMeta({ type: "tool-input-start", id: params.callId, toolName: params.tool, dynamic: true }));
908
+ }
909
+ break;
910
+ }
911
+ case "item/tool/callDelta": {
912
+ const params = event.params ?? {};
913
+ if (params.callId && params.delta) {
914
+ parts.push(withMeta({ type: "tool-input-delta", id: params.callId, delta: params.delta }));
915
+ }
916
+ break;
917
+ }
918
+ case "item/tool/callFinished": {
919
+ const params = event.params ?? {};
920
+ if (params.callId) {
921
+ parts.push(withMeta({ type: "tool-input-end", id: params.callId }));
922
+ }
923
+ break;
924
+ }
925
+ case "turn/completed": {
926
+ pushStreamStart();
927
+ for (const itemId of this.openTextParts) {
928
+ parts.push(withMeta({ type: "text-end", id: itemId }));
929
+ }
930
+ this.openTextParts.clear();
931
+ const completed = event.params ?? {};
932
+ parts.push(withMeta({ type: "finish", finishReason: toFinishReason(completed.status), usage: EMPTY_USAGE }));
933
+ break;
934
+ }
935
+ }
936
+ return parts;
937
+ }
938
+ };
939
+
940
+ // src/protocol/prompt-mapper.ts
941
+ function mapSystemPrompt(prompt) {
942
+ const chunks = [];
943
+ for (const message of prompt) {
944
+ if (message.role === "system") {
945
+ const text = message.content.trim();
946
+ if (text.length > 0) {
947
+ chunks.push(text);
948
+ }
949
+ }
950
+ }
951
+ return chunks.length > 0 ? chunks.join("\n\n") : void 0;
952
+ }
953
+ function mapPromptToTurnInput(prompt, isResume = false) {
954
+ if (isResume) {
955
+ for (let i = prompt.length - 1; i >= 0; i--) {
956
+ const message = prompt[i];
957
+ if (message?.role === "user") {
958
+ const items = [];
959
+ for (const part of message.content) {
960
+ if (part.type === "text") {
961
+ const text = part.text.trim();
962
+ if (text.length > 0) {
963
+ items.push({ type: "text", text, text_elements: [] });
964
+ }
965
+ }
966
+ }
967
+ return items;
968
+ }
969
+ }
970
+ return [];
971
+ }
972
+ const chunks = [];
973
+ for (const message of prompt) {
974
+ if (message.role === "user") {
975
+ for (const part of message.content) {
976
+ if (part.type === "text") {
977
+ const text = part.text.trim();
978
+ if (text.length > 0) {
979
+ chunks.push(text);
980
+ }
981
+ }
982
+ }
983
+ }
984
+ }
985
+ return [{ type: "text", text: chunks.join("\n\n"), text_elements: [] }];
986
+ }
987
+
988
+ // src/model.ts
989
+ function createEmptyUsage() {
990
+ return {
991
+ inputTokens: {
992
+ total: void 0,
993
+ noCache: void 0,
994
+ cacheRead: void 0,
995
+ cacheWrite: void 0
996
+ },
997
+ outputTokens: {
998
+ total: void 0,
999
+ text: void 0,
1000
+ reasoning: void 0
1001
+ }
1002
+ };
1003
+ }
1004
+ function extractThreadId(result) {
1005
+ const threadId = result.threadId ?? result.thread?.id;
1006
+ if (!threadId) {
1007
+ throw new CodexProviderError("thread/start response does not include a thread id.");
1008
+ }
1009
+ return threadId;
1010
+ }
1011
+ function extractTurnId(result) {
1012
+ const turnId = result.turnId ?? result.turn?.id;
1013
+ if (!turnId) {
1014
+ throw new CodexProviderError("turn/start response does not include a turn id.");
1015
+ }
1016
+ return turnId;
1017
+ }
1018
+ function extractResumeThreadId(prompt) {
1019
+ for (let i = prompt.length - 1; i >= 0; i--) {
1020
+ const message = prompt[i];
1021
+ if (message?.role === "assistant") {
1022
+ const meta = message.providerOptions?.["codex-app-server"];
1023
+ if (meta && typeof meta["threadId"] === "string") {
1024
+ return meta["threadId"];
1025
+ }
1026
+ }
1027
+ }
1028
+ return void 0;
1029
+ }
1030
+ function extractToolResults(prompt) {
1031
+ for (let i = prompt.length - 1; i >= 0; i--) {
1032
+ const message = prompt[i];
1033
+ if (message?.role === "tool") {
1034
+ const contentItems = [];
1035
+ let success = true;
1036
+ for (const part of message.content) {
1037
+ if (part.type === "tool-result") {
1038
+ if (part.output.type === "text") {
1039
+ contentItems.push({ type: "inputText", text: part.output.value });
1040
+ } else if (part.output.type === "json") {
1041
+ contentItems.push({ type: "inputText", text: JSON.stringify(part.output.value) });
1042
+ } else if (part.output.type === "execution-denied") {
1043
+ success = false;
1044
+ contentItems.push({
1045
+ type: "inputText",
1046
+ text: part.output.reason ?? "Tool execution was denied."
1047
+ });
1048
+ }
1049
+ }
1050
+ }
1051
+ if (contentItems.length > 0) {
1052
+ return { success, contentItems };
1053
+ }
1054
+ }
1055
+ }
1056
+ return void 0;
1057
+ }
1058
+ function sdkToolsToCodexDynamicTools(tools) {
1059
+ return tools.filter((t) => t.type === "function").map((t) => ({
1060
+ name: t.name,
1061
+ ...t.description ? { description: t.description } : {},
1062
+ inputSchema: t.inputSchema
1063
+ }));
1064
+ }
1065
+ function isPassThroughContentPart(part) {
1066
+ switch (part.type) {
1067
+ case "tool-call":
1068
+ case "tool-result":
1069
+ case "file":
1070
+ case "source":
1071
+ case "tool-approval-request":
1072
+ return true;
1073
+ default:
1074
+ return false;
1075
+ }
1076
+ }
1077
+ var CodexLanguageModel = class {
1078
+ specificationVersion = "v3";
1079
+ provider;
1080
+ modelId;
1081
+ supportedUrls = {};
1082
+ settings;
1083
+ config;
1084
+ constructor(modelId, settings, config) {
1085
+ this.modelId = modelId;
1086
+ this.settings = settings;
1087
+ this.config = config;
1088
+ this.provider = config.provider;
1089
+ }
1090
+ async doGenerate(options) {
1091
+ void this.settings;
1092
+ const streamResult = await this.doStream(options);
1093
+ const reader = streamResult.stream.getReader();
1094
+ const textOrder = [];
1095
+ const textById = /* @__PURE__ */ new Map();
1096
+ const passThroughContent = [];
1097
+ let warnings = [];
1098
+ let finishReason = {
1099
+ unified: "other",
1100
+ raw: void 0
1101
+ };
1102
+ let usage = createEmptyUsage();
1103
+ let providerMetadata;
1104
+ while (true) {
1105
+ const { value, done } = await reader.read();
1106
+ if (done) {
1107
+ break;
1108
+ }
1109
+ if (value.type === "stream-start") {
1110
+ warnings = value.warnings;
1111
+ continue;
1112
+ }
1113
+ if (value.type === "text-start") {
1114
+ if (!textById.has(value.id)) {
1115
+ textOrder.push(value.id);
1116
+ textById.set(value.id, "");
1117
+ }
1118
+ continue;
1119
+ }
1120
+ if (value.type === "text-delta") {
1121
+ if (!textById.has(value.id)) {
1122
+ textOrder.push(value.id);
1123
+ textById.set(value.id, value.delta);
1124
+ } else {
1125
+ textById.set(value.id, `${textById.get(value.id) ?? ""}${value.delta}`);
1126
+ }
1127
+ continue;
1128
+ }
1129
+ if (value.type === "finish") {
1130
+ finishReason = value.finishReason;
1131
+ usage = value.usage;
1132
+ providerMetadata = value.providerMetadata;
1133
+ continue;
1134
+ }
1135
+ if (value.type === "error") {
1136
+ if (value.error instanceof Error) {
1137
+ throw value.error;
1138
+ }
1139
+ throw new CodexProviderError("Generation stream emitted an error.", {
1140
+ cause: value.error
1141
+ });
1142
+ }
1143
+ if (isPassThroughContentPart(value)) {
1144
+ passThroughContent.push(value);
1145
+ }
1146
+ }
1147
+ const textContent = textOrder.map((id) => {
1148
+ const text = textById.get(id) ?? "";
1149
+ if (text.length === 0) {
1150
+ return null;
1151
+ }
1152
+ return {
1153
+ type: "text",
1154
+ text
1155
+ };
1156
+ }).filter((part) => part !== null);
1157
+ return {
1158
+ content: [...textContent, ...passThroughContent],
1159
+ finishReason,
1160
+ usage,
1161
+ warnings,
1162
+ ...providerMetadata ? { providerMetadata } : {},
1163
+ ...streamResult.request ? { request: streamResult.request } : {}
1164
+ };
1165
+ }
1166
+ registerCrossCallToolHandler(client, controller, persistentTransport, threadId, closeSuccessfully) {
1167
+ client.onToolCallRequest((params, request) => {
1168
+ const toolName = params.tool ?? params.toolName ?? "unknown";
1169
+ const callId = params.callId ?? `call_${Date.now()}`;
1170
+ const args = params.arguments ?? params.input ?? {};
1171
+ const withMeta = (part) => withProviderMetadata(part, threadId);
1172
+ persistentTransport.parkToolCall({
1173
+ requestId: request.id,
1174
+ callId,
1175
+ toolName,
1176
+ args,
1177
+ threadId
1178
+ });
1179
+ controller.enqueue(withMeta({
1180
+ type: "tool-call",
1181
+ toolCallId: callId,
1182
+ toolName,
1183
+ input: typeof args === "string" ? args : JSON.stringify(args)
1184
+ }));
1185
+ controller.enqueue(withMeta({
1186
+ type: "finish",
1187
+ finishReason: { unified: "tool-calls", raw: "tool-calls" },
1188
+ usage: createEmptyUsage()
1189
+ }));
1190
+ void closeSuccessfully();
1191
+ return new Promise(() => {
1192
+ });
1193
+ });
1194
+ }
1195
+ doStream(options) {
1196
+ 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);
1197
+ const client = new AppServerClient(transport);
1198
+ const mapper = new CodexEventMapper();
1199
+ const stream = new ReadableStream({
1200
+ start: (controller) => {
1201
+ let closed = false;
1202
+ const closeWithError = async (error) => {
1203
+ if (closed) {
1204
+ return;
1205
+ }
1206
+ controller.enqueue({ type: "error", error });
1207
+ closed = true;
1208
+ try {
1209
+ controller.close();
1210
+ } finally {
1211
+ await client.disconnect();
1212
+ }
1213
+ };
1214
+ const closeSuccessfully = async () => {
1215
+ if (closed) {
1216
+ return;
1217
+ }
1218
+ closed = true;
1219
+ try {
1220
+ controller.close();
1221
+ } finally {
1222
+ await client.disconnect();
1223
+ }
1224
+ };
1225
+ const abortHandler = () => {
1226
+ void closeWithError(new DOMException("Aborted", "AbortError"));
1227
+ };
1228
+ if (options.abortSignal) {
1229
+ if (options.abortSignal.aborted) {
1230
+ abortHandler();
1231
+ return;
1232
+ }
1233
+ options.abortSignal.addEventListener("abort", abortHandler, { once: true });
1234
+ }
1235
+ void (async () => {
1236
+ try {
1237
+ await client.connect();
1238
+ const persistentTransport = transport instanceof PersistentTransport ? transport : null;
1239
+ const pendingToolCall = persistentTransport?.getPendingToolCall() ?? null;
1240
+ if (pendingToolCall && persistentTransport) {
1241
+ const toolResult = extractToolResults(options.prompt);
1242
+ mapper.setThreadId(pendingToolCall.threadId);
1243
+ client.onAnyNotification((method, params) => {
1244
+ const parts = mapper.map({ method, params });
1245
+ for (const part of parts) {
1246
+ controller.enqueue(part);
1247
+ if (part.type === "finish") {
1248
+ void closeSuccessfully();
1249
+ }
1250
+ }
1251
+ });
1252
+ this.registerCrossCallToolHandler(
1253
+ client,
1254
+ controller,
1255
+ persistentTransport,
1256
+ pendingToolCall.threadId,
1257
+ closeSuccessfully
1258
+ );
1259
+ const approvalsDispatcher2 = new ApprovalsDispatcher({
1260
+ ...this.config.providerSettings.approvals?.onCommandApproval ? { onCommandApproval: this.config.providerSettings.approvals.onCommandApproval } : {},
1261
+ ...this.config.providerSettings.approvals?.onFileChangeApproval ? { onFileChangeApproval: this.config.providerSettings.approvals.onFileChangeApproval } : {}
1262
+ });
1263
+ approvalsDispatcher2.attach(client);
1264
+ await persistentTransport.respondToToolCall(
1265
+ toolResult ?? { success: true, contentItems: [] }
1266
+ );
1267
+ return;
1268
+ }
1269
+ const dynamicToolsEnabled = this.config.providerSettings.experimentalApi === true;
1270
+ if (dynamicToolsEnabled) {
1271
+ const dispatcher = new DynamicToolsDispatcher({
1272
+ ...this.config.providerSettings.tools ? { tools: this.config.providerSettings.tools } : {},
1273
+ ...this.config.providerSettings.toolHandlers ? { handlers: this.config.providerSettings.toolHandlers } : {},
1274
+ ...this.config.providerSettings.toolTimeoutMs !== void 0 ? { timeoutMs: this.config.providerSettings.toolTimeoutMs } : {}
1275
+ });
1276
+ dispatcher.attach(client);
1277
+ }
1278
+ const approvalsDispatcher = new ApprovalsDispatcher({
1279
+ ...this.config.providerSettings.approvals?.onCommandApproval ? { onCommandApproval: this.config.providerSettings.approvals.onCommandApproval } : {},
1280
+ ...this.config.providerSettings.approvals?.onFileChangeApproval ? { onFileChangeApproval: this.config.providerSettings.approvals.onFileChangeApproval } : {}
1281
+ });
1282
+ approvalsDispatcher.attach(client);
1283
+ client.onAnyNotification((method, params) => {
1284
+ const parts = mapper.map({ method, params });
1285
+ for (const part of parts) {
1286
+ controller.enqueue(part);
1287
+ if (part.type === "finish") {
1288
+ void closeSuccessfully();
1289
+ }
1290
+ }
1291
+ });
1292
+ const providerToolDefs = this.config.providerSettings.tools;
1293
+ const providerDynamicTools = providerToolDefs ? Object.entries(providerToolDefs).map(([name, def]) => ({
1294
+ name,
1295
+ description: def.description,
1296
+ inputSchema: def.inputSchema
1297
+ })) : [];
1298
+ const sdkDynamicTools = options.tools ? sdkToolsToCodexDynamicTools(options.tools) : [];
1299
+ const allDynamicTools = [...providerDynamicTools, ...sdkDynamicTools];
1300
+ const dynamicTools = allDynamicTools.length > 0 ? allDynamicTools : void 0;
1301
+ const hasSdkTools = sdkDynamicTools.length > 0;
1302
+ const needsExperimentalApi = this.config.providerSettings.experimentalApi === true || dynamicTools !== void 0;
1303
+ const initializeParams = {
1304
+ clientInfo: this.config.providerSettings.clientInfo ?? {
1305
+ name: PACKAGE_NAME,
1306
+ version: PACKAGE_VERSION
1307
+ },
1308
+ ...needsExperimentalApi ? { capabilities: { experimentalApi: true } } : {}
1309
+ };
1310
+ await client.request("initialize", initializeParams);
1311
+ await client.notification("initialized");
1312
+ const resumeThreadId = extractResumeThreadId(options.prompt);
1313
+ const developerInstructions = mapSystemPrompt(options.prompt);
1314
+ let threadId;
1315
+ if (resumeThreadId) {
1316
+ const resumeParams = {
1317
+ threadId: resumeThreadId,
1318
+ persistExtendedHistory: false,
1319
+ ...developerInstructions ? { developerInstructions } : {}
1320
+ };
1321
+ const resumeResult = await client.request(
1322
+ "thread/resume",
1323
+ resumeParams
1324
+ );
1325
+ threadId = resumeResult.threadId ?? resumeResult.thread?.id ?? resumeThreadId;
1326
+ } else {
1327
+ const threadStartParams = {
1328
+ model: this.config.providerSettings.defaultModel ?? this.modelId,
1329
+ ...dynamicTools ? { dynamicTools } : {},
1330
+ ...developerInstructions ? { developerInstructions } : {},
1331
+ ...this.config.providerSettings.defaultThreadSettings?.cwd ? { cwd: this.config.providerSettings.defaultThreadSettings.cwd } : {},
1332
+ ...this.config.providerSettings.defaultThreadSettings?.approvalPolicy ? {
1333
+ approvalPolicy: this.config.providerSettings.defaultThreadSettings.approvalPolicy
1334
+ } : {},
1335
+ ...this.config.providerSettings.defaultThreadSettings?.sandbox ? {
1336
+ sandbox: this.config.providerSettings.defaultThreadSettings.sandbox
1337
+ } : {}
1338
+ };
1339
+ const threadStartResult = await client.request(
1340
+ "thread/start",
1341
+ threadStartParams
1342
+ );
1343
+ threadId = extractThreadId(threadStartResult);
1344
+ }
1345
+ mapper.setThreadId(threadId);
1346
+ if (hasSdkTools && persistentTransport) {
1347
+ this.registerCrossCallToolHandler(
1348
+ client,
1349
+ controller,
1350
+ persistentTransport,
1351
+ threadId,
1352
+ closeSuccessfully
1353
+ );
1354
+ }
1355
+ const turnStartResult = await client.request("turn/start", {
1356
+ threadId,
1357
+ input: mapPromptToTurnInput(options.prompt, !!resumeThreadId)
1358
+ });
1359
+ extractTurnId(turnStartResult);
1360
+ } catch (error) {
1361
+ await closeWithError(error);
1362
+ }
1363
+ })();
1364
+ },
1365
+ cancel: async () => {
1366
+ await client.disconnect();
1367
+ }
1368
+ });
1369
+ return Promise.resolve({ stream });
1370
+ }
1371
+ };
1372
+
1373
+ // src/client/persistent-pool-registry.ts
1374
+ var GLOBAL_PERSISTENT_POOL_DEFAULT_KEY = "default";
1375
+ var globalPersistentPools = /* @__PURE__ */ new Map();
1376
+ function acquirePersistentPool(settings) {
1377
+ if (settings.scope === "provider") {
1378
+ const pool2 = new CodexWorkerPool({
1379
+ poolSize: settings.poolSize,
1380
+ transportFactory: settings.transportFactory,
1381
+ idleTimeoutMs: settings.idleTimeoutMs
1382
+ });
1383
+ let released2 = false;
1384
+ return {
1385
+ pool: pool2,
1386
+ async release() {
1387
+ if (released2) {
1388
+ return;
1389
+ }
1390
+ released2 = true;
1391
+ await pool2.shutdown();
1392
+ }
1393
+ };
1394
+ }
1395
+ const key = settings.key ?? GLOBAL_PERSISTENT_POOL_DEFAULT_KEY;
1396
+ const existing = globalPersistentPools.get(key);
1397
+ if (existing) {
1398
+ if (existing.poolSize !== settings.poolSize || existing.idleTimeoutMs !== settings.idleTimeoutMs) {
1399
+ throw new Error(
1400
+ `Global persistent pool "${key}" already exists with different settings.`
1401
+ );
1402
+ }
1403
+ existing.refCount++;
1404
+ let released2 = false;
1405
+ return {
1406
+ pool: existing.pool,
1407
+ async release() {
1408
+ if (released2) {
1409
+ return;
1410
+ }
1411
+ released2 = true;
1412
+ const entry = globalPersistentPools.get(key);
1413
+ if (!entry) {
1414
+ return;
1415
+ }
1416
+ entry.refCount--;
1417
+ if (entry.refCount <= 0) {
1418
+ globalPersistentPools.delete(key);
1419
+ await entry.pool.shutdown();
1420
+ }
1421
+ }
1422
+ };
1423
+ }
1424
+ const pool = new CodexWorkerPool({
1425
+ poolSize: settings.poolSize,
1426
+ transportFactory: settings.transportFactory,
1427
+ idleTimeoutMs: settings.idleTimeoutMs
1428
+ });
1429
+ globalPersistentPools.set(key, {
1430
+ pool,
1431
+ refCount: 1,
1432
+ poolSize: settings.poolSize,
1433
+ idleTimeoutMs: settings.idleTimeoutMs
1434
+ });
1435
+ let released = false;
1436
+ return {
1437
+ pool,
1438
+ async release() {
1439
+ if (released) {
1440
+ return;
1441
+ }
1442
+ released = true;
1443
+ const entry = globalPersistentPools.get(key);
1444
+ if (!entry) {
1445
+ return;
1446
+ }
1447
+ entry.refCount--;
1448
+ if (entry.refCount <= 0) {
1449
+ globalPersistentPools.delete(key);
1450
+ await entry.pool.shutdown();
1451
+ }
1452
+ }
1453
+ };
1454
+ }
1455
+
1456
+ // src/provider.ts
1457
+ var PROVIDER_ID = "codex-app-server";
1458
+ function createNoSuchModelError(modelId, modelType) {
1459
+ return new provider.NoSuchModelError({ modelId, modelType });
1460
+ }
1461
+ function createCodexAppServer(settings = {}) {
1462
+ let persistentPoolHandle = null;
1463
+ const baseTransportFactory = settings.transportFactory;
1464
+ if (settings.persistent) {
1465
+ const scope = settings.persistent.scope ?? "provider";
1466
+ const poolSize = settings.persistent.poolSize ?? 1;
1467
+ const idleTimeoutMs = settings.persistent.idleTimeoutMs ?? 3e5;
1468
+ const poolTransportFactory = baseTransportFactory ?? (settings.transport?.type === "websocket" ? () => new WebSocketTransport(settings.transport?.websocket) : () => new StdioTransport(settings.transport?.stdio));
1469
+ persistentPoolHandle = acquirePersistentPool({
1470
+ scope,
1471
+ ...settings.persistent.key !== void 0 ? { key: settings.persistent.key } : {},
1472
+ poolSize,
1473
+ idleTimeoutMs,
1474
+ transportFactory: poolTransportFactory
1475
+ });
1476
+ }
1477
+ const persistentPool = persistentPoolHandle?.pool ?? null;
1478
+ const effectiveTransportFactory = persistentPool ? () => new PersistentTransport({ pool: persistentPool }) : baseTransportFactory;
1479
+ const resolvedSettings = Object.freeze({
1480
+ ...settings.defaultModel ? { defaultModel: settings.defaultModel } : {},
1481
+ ...settings.experimentalApi !== void 0 ? { experimentalApi: settings.experimentalApi } : {},
1482
+ ...settings.clientInfo ? {
1483
+ clientInfo: {
1484
+ ...settings.clientInfo
1485
+ }
1486
+ } : {},
1487
+ ...settings.transport ? {
1488
+ transport: {
1489
+ ...settings.transport.type ? { type: settings.transport.type } : {},
1490
+ ...settings.transport.stdio ? { stdio: { ...settings.transport.stdio } } : {},
1491
+ ...settings.transport.websocket ? { websocket: { ...settings.transport.websocket } } : {}
1492
+ }
1493
+ } : {},
1494
+ ...settings.defaultThreadSettings ? { defaultThreadSettings: { ...settings.defaultThreadSettings } } : {},
1495
+ ...effectiveTransportFactory ? { transportFactory: effectiveTransportFactory } : {},
1496
+ ...settings.tools ? { tools: { ...settings.tools } } : {},
1497
+ ...settings.toolHandlers ? { toolHandlers: { ...settings.toolHandlers } } : {},
1498
+ ...settings.toolTimeoutMs !== void 0 ? { toolTimeoutMs: settings.toolTimeoutMs } : {},
1499
+ ...settings.approvals ? { approvals: { ...settings.approvals } } : {}
1500
+ });
1501
+ const createLanguageModel = (modelId, modelSettings = {}) => new CodexLanguageModel(modelId, modelSettings, {
1502
+ provider: PROVIDER_ID,
1503
+ providerSettings: resolvedSettings
1504
+ });
1505
+ const providerFn = ((modelId, modelSettings = {}) => createLanguageModel(modelId, modelSettings));
1506
+ const provider = Object.assign(providerFn, {
1507
+ specificationVersion: "v3",
1508
+ settings: resolvedSettings,
1509
+ languageModel(modelId) {
1510
+ return createLanguageModel(modelId);
1511
+ },
1512
+ chat(modelId, modelSettings = {}) {
1513
+ return createLanguageModel(modelId, modelSettings);
1514
+ },
1515
+ embeddingModel(modelId) {
1516
+ throw createNoSuchModelError(modelId, "embeddingModel");
1517
+ },
1518
+ imageModel(modelId) {
1519
+ throw createNoSuchModelError(modelId, "imageModel");
1520
+ },
1521
+ async shutdown() {
1522
+ if (!persistentPoolHandle) {
1523
+ return;
1524
+ }
1525
+ const handle = persistentPoolHandle;
1526
+ persistentPoolHandle = null;
1527
+ await handle.release();
1528
+ }
1529
+ });
1530
+ return provider;
1531
+ }
1532
+ var codexAppServer = createCodexAppServer();
1533
+ var createCodexProvider = createCodexAppServer;
1534
+
1535
+ exports.AppServerClient = AppServerClient;
1536
+ exports.ApprovalsDispatcher = ApprovalsDispatcher;
1537
+ exports.CODEX_PROVIDER_ID = CODEX_PROVIDER_ID;
1538
+ exports.CodexEventMapper = CodexEventMapper;
1539
+ exports.CodexLanguageModel = CodexLanguageModel;
1540
+ exports.CodexNotImplementedError = CodexNotImplementedError;
1541
+ exports.CodexProviderError = CodexProviderError;
1542
+ exports.CodexWorker = CodexWorker;
1543
+ exports.CodexWorkerPool = CodexWorkerPool;
1544
+ exports.DynamicToolsDispatcher = DynamicToolsDispatcher;
1545
+ exports.JsonRpcError = JsonRpcError;
1546
+ exports.PACKAGE_NAME = PACKAGE_NAME;
1547
+ exports.PACKAGE_VERSION = PACKAGE_VERSION;
1548
+ exports.PersistentTransport = PersistentTransport;
1549
+ exports.StdioTransport = StdioTransport;
1550
+ exports.WebSocketTransport = WebSocketTransport;
1551
+ exports.codexAppServer = codexAppServer;
1552
+ exports.codexProviderMetadata = codexProviderMetadata;
1553
+ exports.createCodexAppServer = createCodexAppServer;
1554
+ exports.createCodexProvider = createCodexProvider;
1555
+ exports.mapPromptToTurnInput = mapPromptToTurnInput;
1556
+ exports.mapSystemPrompt = mapSystemPrompt;
1557
+ exports.withProviderMetadata = withProviderMetadata;
1558
+ //# sourceMappingURL=index.cjs.map
1559
+ //# sourceMappingURL=index.cjs.map