@janole/ai-sdk-provider-codex-asp 0.2.4 → 0.3.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 CHANGED
@@ -147,6 +147,7 @@ See [`src/provider.ts`](src/provider.ts) for full type definitions.
147
147
  See the [`examples/`](examples/) directory:
148
148
 
149
149
  - [`generate-text.ts`](examples/generate-text.ts) — Non-streaming text generation
150
+ - [`generate-object.ts`](examples/generate-object.ts) — Structured output with `generateText` + `Output.object`
150
151
  - [`stream-text.ts`](examples/stream-text.ts) — Streaming text generation
151
152
  - [`cross-call-tools.ts`](examples/cross-call-tools.ts) — Standard AI SDK tools via Codex
152
153
  - [`dynamic-tools.ts`](examples/dynamic-tools.ts) — Provider-level dynamic tools
package/dist/index.cjs CHANGED
@@ -935,7 +935,7 @@ var DynamicToolsDispatcher = class {
935
935
  // package.json
936
936
  var package_default = {
937
937
  name: "@janole/ai-sdk-provider-codex-asp",
938
- version: "0.2.4"};
938
+ version: "0.3.0"};
939
939
 
940
940
  // src/package-info.ts
941
941
  var PACKAGE_NAME = package_default.name;
@@ -943,14 +943,14 @@ var PACKAGE_VERSION = package_default.version;
943
943
 
944
944
  // src/protocol/provider-metadata.ts
945
945
  var CODEX_PROVIDER_ID = "@janole/ai-sdk-provider-codex-asp";
946
- function codexProviderMetadata(threadId) {
946
+ function codexProviderMetadata(threadId, turnId) {
947
947
  if (!threadId) {
948
948
  return void 0;
949
949
  }
950
- return { [CODEX_PROVIDER_ID]: { threadId } };
950
+ return { [CODEX_PROVIDER_ID]: stripUndefined({ threadId, turnId }) };
951
951
  }
952
- function withProviderMetadata(part, threadId) {
953
- const meta = codexProviderMetadata(threadId);
952
+ function withProviderMetadata(part, threadId, turnId) {
953
+ const meta = codexProviderMetadata(threadId, turnId);
954
954
  return meta ? { ...part, providerMetadata: meta } : part;
955
955
  }
956
956
 
@@ -989,6 +989,7 @@ var CodexEventMapper = class {
989
989
  openToolCalls = /* @__PURE__ */ new Map();
990
990
  planSequenceByTurnId = /* @__PURE__ */ new Map();
991
991
  threadId;
992
+ turnId;
992
993
  latestUsage;
993
994
  constructor(options) {
994
995
  this.options = {
@@ -998,6 +999,12 @@ var CodexEventMapper = class {
998
999
  setThreadId(threadId) {
999
1000
  this.threadId = threadId;
1000
1001
  }
1002
+ setTurnId(turnId) {
1003
+ this.turnId = turnId;
1004
+ }
1005
+ getTurnId() {
1006
+ return this.turnId;
1007
+ }
1001
1008
  nextPlanSequence(turnId) {
1002
1009
  const next = (this.planSequenceByTurnId.get(turnId) ?? 0) + 1;
1003
1010
  this.planSequenceByTurnId.set(turnId, next);
@@ -1005,7 +1012,7 @@ var CodexEventMapper = class {
1005
1012
  }
1006
1013
  map(event) {
1007
1014
  const parts = [];
1008
- const withMeta = (part) => withProviderMetadata(part, this.threadId);
1015
+ const withMeta = (part) => withProviderMetadata(part, this.threadId, this.turnId);
1009
1016
  const pushStreamStart = () => {
1010
1017
  if (!this.streamStarted) {
1011
1018
  parts.push({ type: "stream-start", warnings: [] });
@@ -1025,6 +1032,10 @@ var CodexEventMapper = class {
1025
1032
  };
1026
1033
  switch (event.method) {
1027
1034
  case "turn/started": {
1035
+ const turnStartedParams = event.params;
1036
+ if (turnStartedParams?.turn?.id) {
1037
+ this.turnId = turnStartedParams.turn.id;
1038
+ }
1028
1039
  pushStreamStart();
1029
1040
  break;
1030
1041
  }
@@ -1322,6 +1333,75 @@ var CodexEventMapper = class {
1322
1333
  return parts;
1323
1334
  }
1324
1335
  };
1336
+
1337
+ // src/session.ts
1338
+ var CodexSessionImpl = class {
1339
+ _threadId;
1340
+ _turnId;
1341
+ _active = true;
1342
+ client;
1343
+ interruptTimeoutMs;
1344
+ constructor(opts) {
1345
+ this.client = opts.client;
1346
+ this._threadId = opts.threadId;
1347
+ this._turnId = opts.turnId;
1348
+ this.interruptTimeoutMs = opts.interruptTimeoutMs;
1349
+ }
1350
+ get threadId() {
1351
+ return this._threadId;
1352
+ }
1353
+ get turnId() {
1354
+ return this._turnId;
1355
+ }
1356
+ /** @internal Called by the model when turn/started arrives with a turnId. */
1357
+ setTurnId(turnId) {
1358
+ this._turnId = turnId;
1359
+ }
1360
+ /** @internal Called by the model when the turn completes or the stream closes. */
1361
+ markInactive() {
1362
+ this._active = false;
1363
+ }
1364
+ isActive() {
1365
+ return this._active;
1366
+ }
1367
+ /**
1368
+ * Inject follow-up input into the current thread.
1369
+ *
1370
+ * Uses turn/start which the app-server routes through steer_input when a
1371
+ * turn is already active, or starts a new turn otherwise. This avoids the
1372
+ * strict timing requirements of turn/steer (which needs codex/event/task_started
1373
+ * before it accepts input). We may revisit turn/steer in the future.
1374
+ */
1375
+ async injectMessage(input) {
1376
+ if (!this._active) {
1377
+ throw new Error("Session is no longer active.");
1378
+ }
1379
+ const userInput = typeof input === "string" ? [{ type: "text", text: input, text_elements: [] }] : input;
1380
+ const turnStartParams = {
1381
+ threadId: this._threadId,
1382
+ input: userInput
1383
+ };
1384
+ const result = await this.client.request("turn/start", turnStartParams);
1385
+ const newTurnId = result.turnId ?? result.turn?.id;
1386
+ if (newTurnId) {
1387
+ this._turnId = newTurnId;
1388
+ }
1389
+ }
1390
+ async interrupt() {
1391
+ if (!this._active || !this._turnId) {
1392
+ return;
1393
+ }
1394
+ const interruptParams = {
1395
+ threadId: this._threadId,
1396
+ turnId: this._turnId
1397
+ };
1398
+ await this.client.request(
1399
+ "turn/interrupt",
1400
+ interruptParams,
1401
+ this.interruptTimeoutMs
1402
+ );
1403
+ }
1404
+ };
1325
1405
  function mapSystemPrompt(prompt) {
1326
1406
  const chunks = [];
1327
1407
  for (const message of prompt) {
@@ -1754,6 +1834,7 @@ var CodexLanguageModel = class {
1754
1834
  }));
1755
1835
  let activeThreadId;
1756
1836
  let activeTurnId;
1837
+ let session;
1757
1838
  const interruptTimeoutMs = this.config.providerSettings.interruptTimeoutMs ?? 1e4;
1758
1839
  const interruptTurnIfPossible = async () => {
1759
1840
  if (!activeThreadId || !activeTurnId) {
@@ -1774,6 +1855,7 @@ var CodexLanguageModel = class {
1774
1855
  if (closed) {
1775
1856
  return;
1776
1857
  }
1858
+ session?.markInactive();
1777
1859
  controller.enqueue({ type: "error", error });
1778
1860
  closed = true;
1779
1861
  try {
@@ -1787,6 +1869,7 @@ var CodexLanguageModel = class {
1787
1869
  if (closed) {
1788
1870
  return;
1789
1871
  }
1872
+ session?.markInactive();
1790
1873
  closed = true;
1791
1874
  try {
1792
1875
  controller.close();
@@ -1893,6 +1976,11 @@ var CodexLanguageModel = class {
1893
1976
  approvalsDispatcher.attach(client);
1894
1977
  client.onAnyNotification((method, params) => {
1895
1978
  const parts = mapper.map({ method, params });
1979
+ const mappedTurnId = mapper.getTurnId();
1980
+ if (mappedTurnId && mappedTurnId !== activeTurnId) {
1981
+ activeTurnId = mappedTurnId;
1982
+ session?.setTurnId(mappedTurnId);
1983
+ }
1896
1984
  for (const part of parts) {
1897
1985
  controller.enqueue(part);
1898
1986
  if (part.type === "finish") {
@@ -1990,10 +2078,13 @@ var CodexLanguageModel = class {
1990
2078
  }
1991
2079
  }
1992
2080
  } else {
2081
+ const mcpServers = this.config.providerSettings.mcpServers;
2082
+ const config = mcpServers ? { mcp_servers: mcpServers } : void 0;
1993
2083
  const threadStartParams = stripUndefined({
1994
2084
  model: this.config.providerSettings.defaultModel ?? this.modelId,
1995
2085
  dynamicTools,
1996
2086
  developerInstructions,
2087
+ config,
1997
2088
  cwd: this.config.providerSettings.defaultThreadSettings?.cwd,
1998
2089
  approvalPolicy: this.config.providerSettings.defaultThreadSettings?.approvalPolicy,
1999
2090
  sandbox: this.config.providerSettings.defaultThreadSettings?.sandbox
@@ -2025,17 +2116,26 @@ var CodexLanguageModel = class {
2025
2116
  sandboxPolicy: this.config.providerSettings.defaultTurnSettings?.sandboxPolicy,
2026
2117
  model: this.config.providerSettings.defaultTurnSettings?.model,
2027
2118
  effort: this.config.providerSettings.defaultTurnSettings?.effort,
2028
- summary: this.config.providerSettings.defaultTurnSettings?.summary
2119
+ summary: this.config.providerSettings.defaultTurnSettings?.summary,
2120
+ outputSchema: options.responseFormat?.type === "json" ? options.responseFormat.schema : void 0
2029
2121
  });
2030
2122
  debugLog?.("outbound", "turn/start", turnStartParams);
2031
2123
  const turnStartResult = await client.request("turn/start", turnStartParams);
2032
2124
  activeTurnId = extractTurnId(turnStartResult);
2125
+ session = new CodexSessionImpl({
2126
+ client,
2127
+ threadId: activeThreadId,
2128
+ turnId: activeTurnId,
2129
+ interruptTimeoutMs
2130
+ });
2131
+ this.config.providerSettings.onSessionCreated?.(session);
2033
2132
  } catch (error) {
2034
2133
  await closeWithError(error);
2035
2134
  }
2036
2135
  })();
2037
2136
  },
2038
2137
  cancel: async () => {
2138
+ session?.markInactive();
2039
2139
  try {
2040
2140
  await interruptTurnIfPossible();
2041
2141
  } catch {
@@ -2170,12 +2270,15 @@ function createCodexAppServer(settings = {}) {
2170
2270
  defaultTurnSettings: settings.defaultTurnSettings ? { ...settings.defaultTurnSettings } : void 0,
2171
2271
  compaction: settings.compaction ? { ...settings.compaction } : void 0,
2172
2272
  transportFactory: effectiveTransportFactory,
2273
+ mcpServers: settings.mcpServers ? { ...settings.mcpServers } : void 0,
2173
2274
  tools: settings.tools ? { ...settings.tools } : void 0,
2174
2275
  toolHandlers: settings.toolHandlers ? { ...settings.toolHandlers } : void 0,
2175
2276
  toolTimeoutMs: settings.toolTimeoutMs,
2176
2277
  interruptTimeoutMs: settings.interruptTimeoutMs,
2177
2278
  approvals: settings.approvals ? { ...settings.approvals } : void 0,
2178
- debug: settings.debug ? { ...settings.debug } : void 0
2279
+ debug: settings.debug ? { ...settings.debug } : void 0,
2280
+ emitPlanUpdates: settings.emitPlanUpdates,
2281
+ onSessionCreated: settings.onSessionCreated
2179
2282
  }));
2180
2283
  const createLanguageModel = (modelId, modelSettings = {}) => new CodexLanguageModel(modelId, modelSettings, {
2181
2284
  provider: CODEX_PROVIDER_ID,
@@ -2197,6 +2300,31 @@ function createCodexAppServer(settings = {}) {
2197
2300
  imageModel(modelId) {
2198
2301
  throw createNoSuchModelError(modelId, "imageModel");
2199
2302
  },
2303
+ async listModels(params) {
2304
+ const transport = effectiveTransportFactory ? effectiveTransportFactory() : resolvedSettings.transport?.type === "websocket" ? new WebSocketTransport(resolvedSettings.transport.websocket) : new StdioTransport(resolvedSettings.transport?.stdio);
2305
+ const client = new AppServerClient(transport);
2306
+ try {
2307
+ await client.connect();
2308
+ const initializeParams = stripUndefined({
2309
+ clientInfo: resolvedSettings.clientInfo ?? {
2310
+ name: PACKAGE_NAME,
2311
+ version: PACKAGE_VERSION
2312
+ }
2313
+ });
2314
+ await client.request("initialize", initializeParams);
2315
+ await client.notification("initialized");
2316
+ const models = [];
2317
+ let cursor;
2318
+ do {
2319
+ const response = await client.request("model/list", stripUndefined({ ...params, cursor }));
2320
+ models.push(...response.data);
2321
+ cursor = response.nextCursor ?? void 0;
2322
+ } while (cursor);
2323
+ return models;
2324
+ } finally {
2325
+ await client.disconnect();
2326
+ }
2327
+ },
2200
2328
  async shutdown() {
2201
2329
  if (!persistentPoolHandle) {
2202
2330
  return;