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