@openclaw/codex 2026.7.2-beta.7 → 2026.7.34

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.
Files changed (64) hide show
  1. package/README.md +3 -27
  2. package/dist/{command-formatters-C336eRVS.js → .setup/app-server-policy-C_qTMEMy.mjs} +51 -9
  3. package/dist/{attempt-notifications-AP-a-Q5k.js → .setup/attempt-notifications-F8krwWL4.mjs} +6 -3
  4. package/dist/{command-handlers-DAHUSry9.js → .setup/command-handlers-DSRFfor4.mjs} +1156 -1319
  5. package/dist/.setup/command-rpc-BvYsfQ7G.mjs +786 -0
  6. package/dist/{compact-D_uvHurS.js → .setup/compact-BNgh7I4t.mjs} +10 -40
  7. package/dist/.setup/computer-use-C3QkmSO3.mjs +377 -0
  8. package/dist/.setup/config-CYEDnLJ2.mjs +1138 -0
  9. package/dist/{conversation-binding-data-BHRpYbX3.js → .setup/conversation-binding-data-CrRxtDBu.mjs} +1 -1
  10. package/dist/{bounded-turn-D2ZAgZVz.js → .setup/media-understanding-provider-EbJCyDqe.mjs} +203 -109
  11. package/dist/{models-BBMKU4jA.js → .setup/models-C_aZk03A.mjs} +11 -6
  12. package/dist/.setup/notification-correlation-iYs4WieS.mjs +35 -0
  13. package/dist/.setup/plugin-app-cache-key-DR8jV9oS.mjs +99 -0
  14. package/dist/.setup/protocol-2POPqAY4.mjs +13 -0
  15. package/dist/{transcript-mirror-DzsdNCf5.js → .setup/protocol-validators-dZQ-UTOa.mjs} +112 -922
  16. package/dist/{rate-limits-CU-gVCCS.js → .setup/provider-DGxDs6g8.mjs} +269 -13
  17. package/dist/{dynamic-tools-D2gYkSBO.js → .setup/provider-capabilities-DS2N_zc1.mjs} +5632 -3953
  18. package/dist/.setup/request-DFR0JyoV.mjs +36 -0
  19. package/dist/.setup/run-attempt-C7xEKFVB.mjs +8180 -0
  20. package/dist/{sandbox-guard-NuhpXmPB.js → .setup/sandbox-guard-DA2TQfZW.mjs} +1 -14
  21. package/dist/.setup/session-binding-DuihlMJc.mjs +628 -0
  22. package/dist/.setup/shared-client-B2KmLPRw.mjs +1854 -0
  23. package/dist/{side-question-_ulBk1AL.js → .setup/side-question-Cv6JXWCS.mjs} +84 -159
  24. package/dist/.setup/thread-lifecycle-u6CZdOOH.mjs +2593 -0
  25. package/dist/{web-search-provider.runtime-CCFhg2z5.js → .setup/web-search-provider.runtime-Ce2zOHxW.mjs} +3 -3
  26. package/dist/doctor-contract-api.js +122 -88
  27. package/dist/harness.js +20 -89
  28. package/dist/index.js +436 -1615
  29. package/dist/media-understanding-provider.js +1 -173
  30. package/dist/prompt-overlay.js +15 -0
  31. package/dist/provider-catalog.js +79 -0
  32. package/dist/provider-discovery.js +34 -0
  33. package/dist/provider.js +2 -0
  34. package/dist/web-search-contract-api.js +1 -1
  35. package/openclaw.plugin.json +178 -221
  36. package/package.json +8 -9
  37. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  38. package/dist/auth-binding-B4FfbcCg.js +0 -62
  39. package/dist/capabilities-BFDTVYr4.js +0 -36
  40. package/dist/cli-metadata.js +0 -20
  41. package/dist/computer-use-CYEc8U3w.js +0 -693
  42. package/dist/conversation-control-xsIeXbo4.js +0 -287
  43. package/dist/effective-mcp-catalog-Bbd98Inw.js +0 -114
  44. package/dist/event-projector-assistant-message-DTgnPPVF.js +0 -101
  45. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  46. package/dist/incognito-session-ET_ufDH-.js +0 -2
  47. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  48. package/dist/plugin-app-cache-key-DztPafOA.js +0 -408
  49. package/dist/request-qKh331yu.js +0 -157
  50. package/dist/run-attempt-CY9WlDLc.js +0 -12413
  51. package/dist/runtime-artifact-CmtG_t1L.js +0 -554
  52. package/dist/session-binding-BXpo9ymA.js +0 -2214
  53. package/dist/session-catalog-DyOgR4WH.js +0 -2668
  54. package/dist/session-cli-2PZaFLRh.js +0 -175
  55. package/dist/session-upstream-marker-B6U7tLw5.js +0 -82
  56. package/dist/settled-turn-finalizer-CXY2Z9dT.js +0 -316
  57. package/dist/shared-client-DTbvH-XV.js +0 -3069
  58. package/dist/thread-lifecycle-DF53ogiA.js +0 -3987
  59. package/dist/transport-stdio-DXgGZ7Ib.js +0 -88
  60. package/dist/upstream-session-fork-Dy4Xvuoj.js +0 -320
  61. package/dist/usage-CQ6GhD5-.js +0 -25
  62. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  63. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  64. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import process from "node:process";
@@ -1,10 +1,11 @@
1
- import { W as isJsonObject, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-DTbvH-XV.js";
2
- import { g as resolveCodexAppServerRuntimeOptions } from "./session-binding-BXpo9ymA.js";
3
- import { G as mergeCodexThreadConfigs, d as attestCodexRingZeroThreadHasNoMcpServers, f as buildCodexRingZeroThreadConfigPatch, m as readCodexInheritedMcpServerNames, mt as interruptCodexTurnAndWaitBestEffort, p as buildCodexRuntimeThreadConfig, u as assertCodexRingZeroHasNoManagedHooks, ut as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./thread-lifecycle-DF53ogiA.js";
4
- import { _ as readCodexNotificationItem, h as isRetryableErrorNotification } from "./attempt-notifications-AP-a-Q5k.js";
5
- import { n as normalizeCodexResponseTokenUsage } from "./event-projector-usage-Xp4AlR2k.js";
6
- import { C as readCodexTurnCompletedNotification, _ as assertCodexThreadStartResponse, b as readCodexErrorNotification, v as assertCodexTurnStartResponse } from "./transcript-mirror-DzsdNCf5.js";
7
- import { r as readModelListResult } from "./models-BBMKU4jA.js";
1
+ import { CODEX_PROVIDER_ID, FALLBACK_CODEX_MODELS } from "../provider-catalog.js";
2
+ import { r as isJsonObject } from "./protocol-2POPqAY4.mjs";
3
+ import { _ as readCodexNotificationItem } from "./attempt-notifications-F8krwWL4.mjs";
4
+ import { d as resolveCodexAppServerRuntimeOptions } from "./config-CYEDnLJ2.mjs";
5
+ import { i as assertCodexTurnStartResponse, l as readCodexTurnCompletedNotification, o as readCodexErrorNotification, r as assertCodexThreadStartResponse } from "./protocol-validators-dZQ-UTOa.mjs";
6
+ import { i as readModelListResult } from "./models-C_aZk03A.mjs";
7
+ import { H as mergeCodexThreadConfigs, r as buildCodexRuntimeThreadConfig } from "./thread-lifecycle-u6CZdOOH.mjs";
8
+ import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
10
11
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
@@ -15,7 +16,7 @@ const CODEX_PRIVATE_STDIO_ARGS = [
15
16
  "--listen",
16
17
  "stdio://"
17
18
  ];
18
- const CODEX_APP_SERVER_ARGS_ENV_KEY = "OPENCLAW_CODEX_APP_SERVER_ARGS";
19
+ const OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR = "OPENCLAW_CODEX_APP_SERVER_ARGS";
19
20
  const CODEX_BOUNDED_THREAD_CONFIG = {
20
21
  "features.multi_agent": false,
21
22
  "features.apps": false,
@@ -28,22 +29,8 @@ const CODEX_PRIVATE_BOUNDED_THREAD_CONFIG = {
28
29
  "features.hooks": false,
29
30
  notify: []
30
31
  };
31
- const CODEX_SETTLED_FINALIZER_THREAD_CONFIG = {
32
- "skills.include_instructions": false,
33
- include_environment_context: false
34
- };
35
- var CodexBoundedTurnTimeoutError = class extends Error {
36
- constructor(taskLabel, timeoutMs) {
37
- const bound = timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3}s` : `${timeoutMs}ms`;
38
- super(`codex app-server ${taskLabel} turn timed out after ${bound}`);
39
- this.name = "TimeoutError";
40
- }
41
- };
42
32
  async function runBoundedCodexAppServerTurn(params) {
43
- const appServer = resolveCodexAppServerRuntimeOptions({
44
- pluginConfig: params.options.pluginConfig,
45
- managedCommandOrder: params.isolation === "private-stdio" ? "package-first" : void 0
46
- });
33
+ const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
47
34
  if (params.isolation === "configured-transport") return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, { cwd: params.agentDir?.trim() || process.cwd() });
48
35
  if (appServer.start.transport !== "stdio") throw new Error("Bounded Codex turns require stdio transport so native tools can be isolated.");
49
36
  return await withTempWorkspace({
@@ -59,12 +46,8 @@ async function runBoundedCodexAppServerTurn(params) {
59
46
  });
60
47
  });
61
48
  }
62
- async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt = 0, timing) {
63
- const totalTimeoutMs = timing?.timeoutMs ?? resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
64
- const timeoutError = new CodexBoundedTurnTimeoutError(params.taskLabel, totalTimeoutMs);
65
- const deadline = timing?.deadline ?? Date.now() + totalTimeoutMs;
66
- const timeoutMs = deadline - Date.now();
67
- if (timeoutMs <= 0) throw timeoutError;
49
+ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace) {
50
+ const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
68
51
  const agentDir = params.agentDir?.trim() || void 0;
69
52
  const startOptions = workspace.codexHome ? buildPrivateCodexAppServerStartOptions(appServer.start, workspace.codexHome) : appServer.start;
70
53
  const ownsClient = !params.options.clientFactory;
@@ -73,41 +56,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
73
56
  authProfileId: params.profile,
74
57
  agentDir,
75
58
  config: params.config,
76
- timeoutMs,
77
- ...params.signal ? { abandonSignal: params.signal } : {}
78
- }) : await import("./shared-client-DTbvH-XV.js").then((n) => n.m).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
59
+ timeoutMs
60
+ }) : await import("./shared-client-B2KmLPRw.mjs").then((n) => n.c).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
79
61
  startOptions,
80
62
  timeoutMs,
81
63
  authProfileId: params.profile,
82
64
  agentDir,
83
65
  authProfileStore: params.authProfileStore,
84
- config: params.config,
85
- ...params.signal ? { abandonSignal: params.signal } : {}
66
+ config: params.config
86
67
  }));
87
68
  const abortController = new AbortController();
88
- let activeThreadId;
89
- let activeTurnId = "";
90
- let interruptPromise;
91
- const requestInterrupt = () => {
92
- if (!activeThreadId || interruptPromise) return;
93
- interruptPromise = interruptCodexTurnAndWaitBestEffort(client, {
94
- threadId: activeThreadId,
95
- turnId: activeTurnId,
96
- timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
97
- });
98
- };
99
- const abortRun = (reason) => {
100
- abortController.abort(reason);
101
- requestInterrupt();
102
- };
103
- const abortFromCaller = () => abortRun(params.signal?.reason ?? "aborted");
69
+ const abortFromCaller = () => abortController.abort(params.signal?.reason ?? "aborted");
104
70
  if (params.signal?.aborted) abortFromCaller();
105
71
  else params.signal?.addEventListener("abort", abortFromCaller, { once: true });
106
- const remainingRunMs = deadline - Date.now();
107
- if (remainingRunMs <= 0) abortRun(timeoutError);
108
- const timeout = setTimeout(() => abortRun(timeoutError), Math.max(1, remainingRunMs));
72
+ const timeout = setTimeout(() => abortController.abort("timeout"), timeoutMs);
109
73
  timeout.unref?.();
110
- let retrySelection = false;
111
74
  try {
112
75
  const model = await resolveCodexBoundedTurnModel({
113
76
  client,
@@ -116,8 +79,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
116
79
  timeoutMs,
117
80
  signal: abortController.signal
118
81
  });
119
- const inheritedMcpServerNames = params.requireNoExternalCapabilities ? await readCodexInheritedMcpServerNames(client, workspace.cwd, abortController.signal) : [];
120
- if (params.requireNoExternalCapabilities) await assertCodexRingZeroHasNoManagedHooks(client, abortController.signal);
121
82
  const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
122
83
  model,
123
84
  modelProvider: "openai",
@@ -125,9 +86,8 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
125
86
  approvalPolicy: "on-request",
126
87
  sandbox: "read-only",
127
88
  serviceName: "OpenClaw",
128
- ...params.requireNoExternalCapabilities ? { baseInstructions: "" } : {},
129
89
  developerInstructions: params.developerInstructions,
130
- config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false }),
90
+ config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace), { nativeCodeModeEnabled: false }),
131
91
  environments: [],
132
92
  dynamicTools: [],
133
93
  experimentalRawEvents: true,
@@ -136,16 +96,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
136
96
  timeoutMs,
137
97
  signal: abortController.signal
138
98
  }));
139
- activeThreadId = thread.thread.id;
140
- if (abortController.signal.aborted) requestInterrupt();
141
- if (params.requireNoExternalCapabilities) await attestCodexRingZeroThreadHasNoMcpServers(client, thread.thread.id, abortController.signal);
142
- if (params.historyItems?.length) await client.request("thread/inject_items", {
143
- threadId: thread.thread.id,
144
- items: params.historyItems
145
- }, {
146
- timeoutMs,
147
- signal: abortController.signal
148
- });
149
99
  const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel);
150
100
  const cleanup = client.addNotificationHandler(collector.handleNotification);
151
101
  const requestCleanup = client.addRequestHandler(createCodexBoundedApprovalHandler(params.taskLabel));
@@ -161,12 +111,10 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
161
111
  timeoutMs,
162
112
  signal: abortController.signal
163
113
  }));
164
- activeTurnId = turn.turn.id;
165
- if (abortController.signal.aborted) requestInterrupt();
166
114
  return {
167
115
  ...await collector.collect(turn.turn, {
168
- signal: abortController.signal,
169
- timeoutError
116
+ timeoutMs,
117
+ signal: abortController.signal
170
118
  }),
171
119
  model
172
120
  };
@@ -174,33 +122,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
174
122
  requestCleanup();
175
123
  cleanup();
176
124
  }
177
- } catch (error) {
178
- if (abortController.signal.aborted) throw resolveCodexBoundedTurnAbortError(abortController.signal, params.taskLabel, timeoutError);
179
- if (ownsClient && isCodexAppServerStartSelectionChangedError(error) && selectionAttempt === 0) retrySelection = true;
180
- else throw error;
181
125
  } finally {
182
126
  clearTimeout(timeout);
183
127
  params.signal?.removeEventListener("abort", abortFromCaller);
184
- await interruptPromise;
185
128
  if (ownsClient) client.close();
186
129
  }
187
- if (retrySelection) return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt + 1, {
188
- deadline,
189
- timeoutMs: totalTimeoutMs
190
- });
191
- throw new Error("Codex bounded turn selection retry exited unexpectedly");
192
130
  }
193
- function resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames) {
131
+ function resolveBoundedThreadConfig(params, workspace) {
194
132
  const boundedConfig = mergeCodexThreadConfigs(CODEX_BOUNDED_THREAD_CONFIG, params.threadConfig) ?? CODEX_BOUNDED_THREAD_CONFIG;
195
- const privateConfig = workspace.codexHome ? mergeCodexThreadConfigs(boundedConfig, CODEX_PRIVATE_BOUNDED_THREAD_CONFIG) ?? boundedConfig : boundedConfig;
196
- if (!params.requireNoExternalCapabilities) return privateConfig;
197
- return mergeCodexThreadConfigs(privateConfig, CODEX_SETTLED_FINALIZER_THREAD_CONFIG, buildCodexRingZeroThreadConfigPatch({ toolsAllow: ["openclaw"] }, true, inheritedMcpServerNames)) ?? privateConfig;
133
+ return workspace.codexHome ? mergeCodexThreadConfigs(boundedConfig, CODEX_PRIVATE_BOUNDED_THREAD_CONFIG) ?? boundedConfig : boundedConfig;
198
134
  }
199
135
  function buildPrivateCodexAppServerStartOptions(start, codexHome) {
200
- const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !== CODEX_APP_SERVER_ARGS_ENV_KEY));
136
+ const privateEnv = Object.fromEntries(Object.entries(start.env ?? {}).filter(([name]) => name.trim().toUpperCase() !== OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR));
201
137
  const clearEnv = (start.clearEnv ?? []).filter((name) => {
202
138
  const normalized = name.trim().toUpperCase();
203
- return normalized !== "CODEX_HOME" && normalized !== CODEX_APP_SERVER_ARGS_ENV_KEY;
139
+ return normalized !== "CODEX_HOME" && normalized !== OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR;
204
140
  });
205
141
  return {
206
142
  ...start,
@@ -209,7 +145,7 @@ function buildPrivateCodexAppServerStartOptions(start, codexHome) {
209
145
  ...privateEnv,
210
146
  CODEX_HOME: codexHome
211
147
  },
212
- clearEnv: [...clearEnv, CODEX_APP_SERVER_ARGS_ENV_KEY]
148
+ clearEnv: [...clearEnv, OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR]
213
149
  };
214
150
  }
215
151
  function createCodexBoundedApprovalHandler(taskLabel) {
@@ -230,14 +166,15 @@ function createCodexBoundedApprovalHandler(taskLabel) {
230
166
  };
231
167
  }
232
168
  async function resolveCodexBoundedTurnModel(params) {
233
- const listed = readModelListResult(await params.client.request("model/list", {
169
+ const result = await params.client.request("model/list", {
234
170
  limit: null,
235
171
  cursor: null,
236
172
  includeHidden: false
237
173
  }, {
238
174
  timeoutMs: Math.min(params.timeoutMs, 5e3),
239
175
  signal: params.signal
240
- })).models;
176
+ });
177
+ const listed = readModelListResult(result).models;
241
178
  if (params.selection.mode === "live-default") {
242
179
  const supported = listed.filter((entry) => params.requiredModalities.every((modality) => entry.inputModalities.includes(modality)));
243
180
  const selected = supported.find((entry) => entry.isDefault) ?? supported[0];
@@ -255,7 +192,6 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
255
192
  let turnId;
256
193
  let completedTurn;
257
194
  let promptError;
258
- let responseUsage;
259
195
  const pending = [];
260
196
  const completedItems = /* @__PURE__ */ new Map();
261
197
  const assistantTextByItem = /* @__PURE__ */ new Map();
@@ -291,18 +227,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
291
227
  rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
292
228
  return;
293
229
  }
294
- if (notification.method === "rawResponse/completed") {
295
- const usage = isJsonObject(params.usage) ? params.usage : void 0;
296
- responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
297
- return;
298
- }
299
230
  if (notification.method === "turn/completed") {
300
231
  completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
301
232
  resolveCompletion?.();
302
233
  return;
303
234
  }
304
235
  if (notification.method === "error") {
305
- if (isRetryableErrorNotification(notification.params)) return;
306
236
  promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
307
237
  resolveCompletion?.();
308
238
  }
@@ -315,13 +245,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
315
245
  for (const notification of pending.splice(0)) handleNotification(notification);
316
246
  if (!completedTurn && !promptError) await waitForTurnCompletion({
317
247
  completion,
248
+ timeoutMs: options.timeoutMs,
318
249
  signal: options.signal,
319
- taskLabel,
320
- timeoutError: options.timeoutError
250
+ taskLabel
321
251
  });
322
252
  if (promptError) throw new Error(promptError);
323
253
  if (completedTurn?.status === "failed") throw new Error(completedTurn.error?.message ?? `codex app-server ${taskLabel} turn failed`);
324
- if (completedTurn?.status !== "completed") throw new Error(`codex app-server ${taskLabel} turn ended with status ${completedTurn?.status ?? "unknown"}`);
325
254
  const items = collectCompletedItems(completedTurn?.items, completedItems);
326
255
  const itemText = collectAssistantTextFromItems(items);
327
256
  const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
@@ -329,8 +258,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
329
258
  if (!text) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
330
259
  return {
331
260
  text,
332
- items,
333
- ...responseUsage ? { usage: responseUsage } : {}
261
+ items
334
262
  };
335
263
  }
336
264
  };
@@ -341,21 +269,22 @@ function collectCompletedItems(turnItems, notificationItems) {
341
269
  return [...items.values()];
342
270
  }
343
271
  async function waitForTurnCompletion(params) {
344
- if (params.signal.aborted) throw resolveCodexBoundedTurnAbortError(params.signal, params.taskLabel, params.timeoutError);
272
+ if (params.signal.aborted) throw new Error(`codex app-server ${params.taskLabel} turn aborted`);
273
+ let timeout;
345
274
  let cleanupAbort;
346
275
  try {
347
276
  await Promise.race([params.completion, new Promise((_, reject) => {
348
- const abortListener = () => reject(resolveCodexBoundedTurnAbortError(params.signal, params.taskLabel, params.timeoutError));
277
+ timeout = setTimeout(() => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn timed out`)), params.timeoutMs);
278
+ timeout.unref?.();
279
+ const abortListener = () => reject(/* @__PURE__ */ new Error(`codex app-server ${params.taskLabel} turn aborted`));
349
280
  params.signal.addEventListener("abort", abortListener, { once: true });
350
281
  cleanupAbort = () => params.signal.removeEventListener("abort", abortListener);
351
282
  })]);
352
283
  } finally {
284
+ if (timeout) clearTimeout(timeout);
353
285
  cleanupAbort?.();
354
286
  }
355
287
  }
356
- function resolveCodexBoundedTurnAbortError(signal, taskLabel, timeoutError) {
357
- return signal.reason === timeoutError ? timeoutError : /* @__PURE__ */ new Error(`codex app-server ${taskLabel} turn aborted`);
358
- }
359
288
  function collectAssistantTextFromItems(items) {
360
289
  return (items ?? []).filter((item) => item.type === "agentMessage").map((item) => item.text.trim()).filter(Boolean).join("\n\n").trim();
361
290
  }
@@ -372,4 +301,169 @@ function isTerminalTurn(turn) {
372
301
  return turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed";
373
302
  }
374
303
  //#endregion
375
- export { runBoundedCodexAppServerTurn as t };
304
+ //#region extensions/codex/media-understanding-provider.ts
305
+ /**
306
+ * Codex-backed media understanding provider for bounded image description and
307
+ * structured extraction turns.
308
+ */
309
+ const DEFAULT_CODEX_IMAGE_MODEL = FALLBACK_CODEX_MODELS.find((model) => model.inputModalities.includes("image"))?.id ?? FALLBACK_CODEX_MODELS[0]?.id;
310
+ const DEFAULT_CODEX_IMAGE_PROMPT = "Describe the image.";
311
+ /**
312
+ * Builds the media-understanding provider that delegates image tasks to an
313
+ * isolated Codex app-server session.
314
+ */
315
+ function buildCodexMediaUnderstandingProvider(options = {}) {
316
+ return {
317
+ id: CODEX_PROVIDER_ID,
318
+ capabilities: ["image"],
319
+ ...DEFAULT_CODEX_IMAGE_MODEL ? { defaultModels: { image: DEFAULT_CODEX_IMAGE_MODEL } } : {},
320
+ describeImage: async (req) => describeCodexImages({
321
+ images: [{
322
+ buffer: req.buffer,
323
+ fileName: req.fileName,
324
+ mime: req.mime
325
+ }],
326
+ provider: req.provider,
327
+ model: req.model,
328
+ prompt: req.prompt,
329
+ maxTokens: req.maxTokens,
330
+ timeoutMs: req.timeoutMs,
331
+ profile: req.profile,
332
+ preferredProfile: req.preferredProfile,
333
+ authStore: req.authStore,
334
+ agentDir: req.agentDir,
335
+ cfg: req.cfg
336
+ }, options),
337
+ describeImages: async (req) => describeCodexImages(req, options),
338
+ extractStructured: async (req) => extractCodexStructured(req, options)
339
+ };
340
+ }
341
+ async function describeCodexImages(req, options) {
342
+ const model = req.model.trim();
343
+ if (!model) throw new Error("Codex image understanding requires model id.");
344
+ const { text } = await runBoundedCodexAppServerTurn({
345
+ config: req.cfg,
346
+ model: {
347
+ mode: "required",
348
+ id: model
349
+ },
350
+ profile: req.profile,
351
+ timeoutMs: req.timeoutMs,
352
+ agentDir: req.agentDir,
353
+ authProfileStore: req.authStore,
354
+ options,
355
+ taskLabel: "image understanding",
356
+ developerInstructions: "You are OpenClaw's bounded image-understanding worker. Describe only the provided image content. Do not call tools, edit files, or ask follow-up questions.",
357
+ input: [{
358
+ type: "text",
359
+ text: buildCodexImagePrompt(req),
360
+ text_elements: []
361
+ }, ...req.images.map((image) => ({
362
+ type: "image",
363
+ url: `data:${image.mime ?? "image/png"};base64,${image.buffer.toString("base64")}`
364
+ }))],
365
+ requiredModalities: ["text", "image"],
366
+ isolation: "configured-transport"
367
+ });
368
+ return {
369
+ text,
370
+ model
371
+ };
372
+ }
373
+ async function extractCodexStructured(req, options) {
374
+ const model = req.model.trim();
375
+ if (!model) throw new Error("Codex structured extraction requires model id.");
376
+ if (!req.instructions.trim()) throw new Error("Codex structured extraction requires instructions.");
377
+ if (req.input.length === 0) throw new Error("Codex structured extraction requires at least one input.");
378
+ if (!req.input.some((entry) => entry.type === "image")) throw new Error("Codex structured extraction requires at least one image input.");
379
+ const { text } = await runBoundedCodexAppServerTurn({
380
+ config: req.cfg,
381
+ model: {
382
+ mode: "required",
383
+ id: model
384
+ },
385
+ profile: req.profile,
386
+ timeoutMs: req.timeoutMs,
387
+ agentDir: req.agentDir,
388
+ authProfileStore: req.authStore,
389
+ options,
390
+ taskLabel: "structured extraction",
391
+ developerInstructions: "You are OpenClaw's bounded structured-extraction worker. Return only the requested extraction. Do not call tools, edit files, ask follow-up questions, or include secrets.",
392
+ input: buildCodexStructuredInput(req),
393
+ requiredModalities: requiredStructuredModalities(),
394
+ isolation: "configured-transport"
395
+ });
396
+ return normalizeStructuredExtractionResult({
397
+ text,
398
+ model,
399
+ provider: req.provider,
400
+ req
401
+ });
402
+ }
403
+ function buildCodexImagePrompt(req) {
404
+ const prompt = req.prompt?.trim() || DEFAULT_CODEX_IMAGE_PROMPT;
405
+ if (req.images.length <= 1) return prompt;
406
+ return `${prompt}\n\nAnalyze all ${req.images.length} images together.`;
407
+ }
408
+ function requiredStructuredModalities() {
409
+ return ["text", "image"];
410
+ }
411
+ function buildCodexStructuredInput(req) {
412
+ return [{
413
+ type: "text",
414
+ text: buildStructuredExtractionPrompt(req),
415
+ text_elements: []
416
+ }, ...req.input.map((entry) => {
417
+ if (entry.type === "text") return {
418
+ type: "text",
419
+ text: entry.text,
420
+ text_elements: []
421
+ };
422
+ return {
423
+ type: "image",
424
+ url: `data:${entry.mime ?? "image/png"};base64,${entry.buffer.toString("base64")}`
425
+ };
426
+ })];
427
+ }
428
+ function buildStructuredExtractionPrompt(req) {
429
+ return [
430
+ req.instructions.trim(),
431
+ req.schemaName ? `Schema name: ${req.schemaName}` : void 0,
432
+ req.jsonSchema ? `JSON schema:\n${JSON.stringify(req.jsonSchema)}` : void 0,
433
+ req.jsonMode === false ? "Return the extraction as concise text." : "Return valid JSON only. Do not wrap the JSON in Markdown fences."
434
+ ].filter((part) => Boolean(part)).join("\n\n");
435
+ }
436
+ function isJsonSchemaObject(value) {
437
+ return typeof value === "object" && value !== null && !Array.isArray(value);
438
+ }
439
+ function normalizeStructuredExtractionResult(params) {
440
+ const result = {
441
+ text: params.text,
442
+ model: params.model,
443
+ provider: params.provider,
444
+ contentType: params.req.jsonMode === false ? "text" : "json"
445
+ };
446
+ if (params.req.jsonMode !== false) {
447
+ try {
448
+ result.parsed = JSON.parse(params.text);
449
+ } catch {
450
+ throw new Error("Codex structured extraction returned invalid JSON.");
451
+ }
452
+ if (isJsonSchemaObject(params.req.jsonSchema)) {
453
+ const validation = validateJsonSchemaValue({
454
+ schema: params.req.jsonSchema,
455
+ cacheKey: "codex.media-understanding.extractStructured",
456
+ value: result.parsed,
457
+ cache: false
458
+ });
459
+ if (!validation.ok) {
460
+ const message = validation.errors.map((error) => error.text).join("; ") || "invalid";
461
+ throw new Error(`Codex structured extraction JSON did not match schema: ${message}`);
462
+ }
463
+ result.parsed = validation.value;
464
+ }
465
+ }
466
+ return result;
467
+ }
468
+ //#endregion
469
+ export { runBoundedCodexAppServerTurn as n, buildCodexMediaUnderstandingProvider as t };
@@ -1,10 +1,16 @@
1
- import { x as readCodexModelListResponse } from "./transcript-mirror-DzsdNCf5.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
2
+ import { s as readCodexModelListResponse } from "./protocol-validators-dZQ-UTOa.mjs";
2
3
  import { uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
3
4
  //#region extensions/codex/src/app-server/models.ts
4
5
  /**
5
6
  * Lists and normalizes models exposed by the Codex app-server `model/list`
6
7
  * endpoint, including pagination and shared-client lease handling.
7
8
  */
9
+ var models_exports = /* @__PURE__ */ __exportAll({
10
+ listAllCodexAppServerModels: () => listAllCodexAppServerModels,
11
+ listCodexAppServerModels: () => listCodexAppServerModels,
12
+ readModelListResult: () => readModelListResult
13
+ });
8
14
  /** Lists one Codex app-server model page using the configured auth/client options. */
9
15
  async function listCodexAppServerModels(options = {}) {
10
16
  return await withCodexAppServerModelClient(options, async ({ client, timeoutMs }) => requestModelListPage(client, {
@@ -40,19 +46,17 @@ async function listAllCodexAppServerModels(options = {}) {
40
46
  async function withCodexAppServerModelClient(options, run) {
41
47
  const timeoutMs = options.timeoutMs ?? 2500;
42
48
  const useSharedClient = options.sharedClient !== false;
43
- const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-DTbvH-XV.js").then((n) => n.m);
49
+ const { createIsolatedCodexAppServerClient, getLeasedSharedCodexAppServerClient, releaseLeasedSharedCodexAppServerClient } = await import("./shared-client-B2KmLPRw.mjs").then((n) => n.c);
44
50
  const client = useSharedClient ? await getLeasedSharedCodexAppServerClient({
45
51
  startOptions: options.startOptions,
46
52
  timeoutMs,
47
53
  authProfileId: options.authProfileId,
48
- authRequirement: options.authRequirement,
49
54
  agentDir: options.agentDir,
50
55
  config: options.config
51
56
  }) : await createIsolatedCodexAppServerClient({
52
57
  startOptions: options.startOptions,
53
58
  timeoutMs,
54
59
  authProfileId: options.authProfileId,
55
- authRequirement: options.authRequirement,
56
60
  agentDir: options.agentDir,
57
61
  config: options.config
58
62
  });
@@ -101,7 +105,8 @@ function readCodexModel(value) {
101
105
  };
102
106
  }
103
107
  function readReasoningEfforts(value) {
104
- return uniqueStrings(value.map((entry) => readNonEmptyString(entry.reasoningEffort)).filter((entry) => entry !== void 0));
108
+ const efforts = value.map((entry) => readNonEmptyString(entry.reasoningEffort)).filter((entry) => entry !== void 0);
109
+ return uniqueStrings(efforts);
105
110
  }
106
111
  function readNonEmptyString(value) {
107
112
  if (typeof value !== "string") return;
@@ -111,4 +116,4 @@ function normalizeMaxPages(value) {
111
116
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : 20;
112
117
  }
113
118
  //#endregion
114
- export { listCodexAppServerModels as n, readModelListResult as r, listAllCodexAppServerModels as t };
119
+ export { readModelListResult as i, listCodexAppServerModels as n, models_exports as r, listAllCodexAppServerModels as t };
@@ -0,0 +1,35 @@
1
+ import { r as isJsonObject } from "./protocol-2POPqAY4.mjs";
2
+ //#region extensions/codex/src/app-server/notification-correlation.ts
3
+ /**
4
+ * Correlates Codex app-server notifications with the active thread/turn so
5
+ * projectors can ignore global or stale events without losing diagnostics.
6
+ */
7
+ /** Returns true when a notification payload belongs to the exact active thread and turn. */
8
+ function isCodexNotificationForTurn(value, threadId, turnId) {
9
+ if (!isJsonObject(value)) return false;
10
+ return readCodexNotificationThreadId(value) === threadId && readCodexNotificationTurnId(value) === turnId;
11
+ }
12
+ /**
13
+ * Reads a thread id from canonical top-level or nested thread payloads.
14
+ * The generated v2 schemas require top-level `threadId` on turn/item-scoped
15
+ * notifications and define `Turn` without one, so `turn.threadId` is not a
16
+ * wire shape and is deliberately not read here.
17
+ */
18
+ function readCodexNotificationThreadId(record) {
19
+ const thread = isJsonObject(record.thread) ? record.thread : void 0;
20
+ return readString(record, "threadId") ?? (thread ? readString(thread, "id") : void 0);
21
+ }
22
+ /** Reads a turn id from either top-level notification params or nested turn payloads. */
23
+ function readCodexNotificationTurnId(record) {
24
+ return readNestedTurnId(record) ?? readString(record, "turnId");
25
+ }
26
+ function readNestedTurnId(record) {
27
+ const turn = record.turn;
28
+ return isJsonObject(turn) ? readString(turn, "id") : void 0;
29
+ }
30
+ function readString(record, key) {
31
+ const value = record[key];
32
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
33
+ }
34
+ //#endregion
35
+ export { readCodexNotificationThreadId as n, readCodexNotificationTurnId as r, isCodexNotificationForTurn as t };