@openclaw/codex 2026.7.2-beta.5 → 2026.7.33

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 (66) hide show
  1. package/README.md +3 -27
  2. package/dist/{command-formatters-ico4ZFnk.js → .setup/app-server-policy-C_qTMEMy.mjs} +51 -9
  3. package/dist/{attempt-notifications-CMR2_fmR.js → .setup/attempt-notifications-F8krwWL4.mjs} +6 -3
  4. package/dist/{command-handlers-CRmnwI2N.js → .setup/command-handlers-DSRFfor4.mjs} +1156 -1319
  5. package/dist/.setup/command-rpc-BvYsfQ7G.mjs +786 -0
  6. package/dist/{compact-dEN49UH6.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-FEbUXoYT.js → .setup/media-understanding-provider-EbJCyDqe.mjs} +193 -92
  11. package/dist/{models-BA01NEez.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/{protocol-validators-Dm4eXZmt.js → .setup/protocol-validators-dZQ-UTOa.mjs} +111 -334
  16. package/dist/{rate-limits-S_PXs0ul.js → .setup/provider-DGxDs6g8.mjs} +269 -13
  17. package/dist/{dynamic-tools-LIt9ojep.js → .setup/provider-capabilities-DS2N_zc1.mjs} +5465 -3399
  18. package/dist/.setup/request-DFR0JyoV.mjs +36 -0
  19. package/dist/.setup/run-attempt-C7xEKFVB.mjs +8180 -0
  20. package/dist/{sandbox-guard-D1Wky__S.js → .setup/sandbox-guard-DA2TQfZW.mjs} +1 -10
  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-CO12sHxo.js → .setup/side-question-Cv6JXWCS.mjs} +84 -159
  24. package/dist/{thread-lifecycle-DRg_FdzC.js → .setup/thread-lifecycle-u6CZdOOH.mjs} +1159 -1799
  25. package/dist/{web-search-provider.runtime-CaQMYDbp.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 -85
  28. package/dist/index.js +381 -1537
  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 -10
  37. package/dist/app-server-policy-BmDgseo_.js +0 -49
  38. package/dist/attempt-client-cleanup-Ia52yRWc.js +0 -127
  39. package/dist/auth-binding-B4FfbcCg.js +0 -62
  40. package/dist/capabilities-BHRSI6Cn.js +0 -36
  41. package/dist/cli-metadata.js +0 -20
  42. package/dist/computer-use-BjGylO-E.js +0 -695
  43. package/dist/conversation-control-DE7d9DOj.js +0 -287
  44. package/dist/event-projector-assistant-message-DTgnPPVF.js +0 -101
  45. package/dist/event-projector-usage-tvgb1NCX.js +0 -69
  46. package/dist/incognito-session-ET_ufDH-.js +0 -2
  47. package/dist/notification-correlation-Bj_Ak_jI.js +0 -67
  48. package/dist/plugin-app-cache-key-DSXX-rXO.js +0 -315
  49. package/dist/realtime-voice-api-BPcA1uN9.js +0 -494
  50. package/dist/realtime-voice-api.js +0 -2
  51. package/dist/request-CXpPennK.js +0 -157
  52. package/dist/run-attempt-C5GTPJOE.js +0 -11935
  53. package/dist/runtime-artifact-C2ITXdhM.js +0 -488
  54. package/dist/session-binding-DlVQ-Pxs.js +0 -2161
  55. package/dist/session-catalog-CP2oCcEb.js +0 -2444
  56. package/dist/session-cli-CqZ0Fp2a.js +0 -175
  57. package/dist/session-upstream-marker-QE-m5QFG.js +0 -82
  58. package/dist/settled-turn-finalizer-CA_2QXIE.js +0 -303
  59. package/dist/shared-client-BVKE40c-.js +0 -2952
  60. package/dist/transcript-mirror-uKA-A4tB.js +0 -550
  61. package/dist/transport-stdio-DXgGZ7Ib.js +0 -88
  62. package/dist/upstream-session-fork-_Vrz4WJr.js +0 -320
  63. package/dist/usage-UpVbdX5G.js +0 -25
  64. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  65. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  66. /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,11 +1,11 @@
1
- import { V as isJsonObject, s as isCodexAppServerStartSelectionChangedError } from "./shared-client-BVKE40c-.js";
2
- import { p as resolveCodexAppServerRuntimeOptions } from "./session-binding-DlVQ-Pxs.js";
3
- import { o as interruptCodexTurnAndWaitBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS } from "./attempt-client-cleanup-Ia52yRWc.js";
4
- import { _ as readCodexNotificationItem, h as isRetryableErrorNotification } from "./attempt-notifications-CMR2_fmR.js";
5
- import { G as mergeCodexThreadConfigs, d as buildCodexRingZeroThreadConfigPatch, f as buildCodexRuntimeThreadConfig, l as assertCodexRingZeroHasNoManagedHooks, p as readCodexInheritedMcpServerNames, u as attestCodexRingZeroThreadHasNoMcpServers } from "./thread-lifecycle-DRg_FdzC.js";
6
- import { t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-tvgb1NCX.js";
7
- import { a as assertCodexTurnStartResponse, i as assertCodexThreadStartResponse, s as readCodexErrorNotification, u as readCodexTurnCompletedNotification } from "./protocol-validators-Dm4eXZmt.js";
8
- import { r as readModelListResult } from "./models-BA01NEez.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";
9
9
  import fs from "node:fs/promises";
10
10
  import path from "node:path";
11
11
  import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
@@ -16,7 +16,7 @@ const CODEX_PRIVATE_STDIO_ARGS = [
16
16
  "--listen",
17
17
  "stdio://"
18
18
  ];
19
- 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";
20
20
  const CODEX_BOUNDED_THREAD_CONFIG = {
21
21
  "features.multi_agent": false,
22
22
  "features.apps": false,
@@ -29,15 +29,8 @@ const CODEX_PRIVATE_BOUNDED_THREAD_CONFIG = {
29
29
  "features.hooks": false,
30
30
  notify: []
31
31
  };
32
- const CODEX_SETTLED_FINALIZER_THREAD_CONFIG = {
33
- "skills.include_instructions": false,
34
- include_environment_context: false
35
- };
36
32
  async function runBoundedCodexAppServerTurn(params) {
37
- const appServer = resolveCodexAppServerRuntimeOptions({
38
- pluginConfig: params.options.pluginConfig,
39
- managedCommandOrder: params.isolation === "private-stdio" ? "package-first" : void 0
40
- });
33
+ const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.options.pluginConfig });
41
34
  if (params.isolation === "configured-transport") return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, { cwd: params.agentDir?.trim() || process.cwd() });
42
35
  if (appServer.start.transport !== "stdio") throw new Error("Bounded Codex turns require stdio transport so native tools can be isolated.");
43
36
  return await withTempWorkspace({
@@ -53,11 +46,8 @@ async function runBoundedCodexAppServerTurn(params) {
53
46
  });
54
47
  });
55
48
  }
56
- async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt = 0, timing) {
57
- const totalTimeoutMs = timing?.timeoutMs ?? resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
58
- const deadline = timing?.deadline ?? Date.now() + totalTimeoutMs;
59
- const timeoutMs = deadline - Date.now();
60
- if (timeoutMs <= 0) throw new Error(`${params.taskLabel} timed out`);
49
+ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace) {
50
+ const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
61
51
  const agentDir = params.agentDir?.trim() || void 0;
62
52
  const startOptions = workspace.codexHome ? buildPrivateCodexAppServerStartOptions(appServer.start, workspace.codexHome) : appServer.start;
63
53
  const ownsClient = !params.options.clientFactory;
@@ -66,41 +56,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
66
56
  authProfileId: params.profile,
67
57
  agentDir,
68
58
  config: params.config,
69
- timeoutMs,
70
- ...params.signal ? { abandonSignal: params.signal } : {}
71
- }) : await import("./shared-client-BVKE40c-.js").then((n) => n.p).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
59
+ timeoutMs
60
+ }) : await import("./shared-client-B2KmLPRw.mjs").then((n) => n.c).then(({ createIsolatedCodexAppServerClient }) => createIsolatedCodexAppServerClient({
72
61
  startOptions,
73
62
  timeoutMs,
74
63
  authProfileId: params.profile,
75
64
  agentDir,
76
65
  authProfileStore: params.authProfileStore,
77
- config: params.config,
78
- ...params.signal ? { abandonSignal: params.signal } : {}
66
+ config: params.config
79
67
  }));
80
68
  const abortController = new AbortController();
81
- let activeThreadId;
82
- let activeTurnId = "";
83
- let interruptPromise;
84
- const requestInterrupt = () => {
85
- if (!activeThreadId || interruptPromise) return;
86
- interruptPromise = interruptCodexTurnAndWaitBestEffort(client, {
87
- threadId: activeThreadId,
88
- turnId: activeTurnId,
89
- timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
90
- });
91
- };
92
- const abortRun = (reason) => {
93
- abortController.abort(reason);
94
- requestInterrupt();
95
- };
96
- const abortFromCaller = () => abortRun(params.signal?.reason ?? "aborted");
69
+ const abortFromCaller = () => abortController.abort(params.signal?.reason ?? "aborted");
97
70
  if (params.signal?.aborted) abortFromCaller();
98
71
  else params.signal?.addEventListener("abort", abortFromCaller, { once: true });
99
- const remainingRunMs = deadline - Date.now();
100
- if (remainingRunMs <= 0) abortRun("timeout");
101
- const timeout = setTimeout(() => abortRun("timeout"), Math.max(1, remainingRunMs));
72
+ const timeout = setTimeout(() => abortController.abort("timeout"), timeoutMs);
102
73
  timeout.unref?.();
103
- let retrySelection = false;
104
74
  try {
105
75
  const model = await resolveCodexBoundedTurnModel({
106
76
  client,
@@ -109,8 +79,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
109
79
  timeoutMs,
110
80
  signal: abortController.signal
111
81
  });
112
- const inheritedMcpServerNames = params.requireNoExternalCapabilities ? await readCodexInheritedMcpServerNames(client, workspace.cwd, abortController.signal) : [];
113
- if (params.requireNoExternalCapabilities) await assertCodexRingZeroHasNoManagedHooks(client, abortController.signal);
114
82
  const thread = assertCodexThreadStartResponse(await client.request("thread/start", {
115
83
  model,
116
84
  modelProvider: "openai",
@@ -118,9 +86,8 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
118
86
  approvalPolicy: "on-request",
119
87
  sandbox: "read-only",
120
88
  serviceName: "OpenClaw",
121
- ...params.requireNoExternalCapabilities ? { baseInstructions: "" } : {},
122
89
  developerInstructions: params.developerInstructions,
123
- config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames), { nativeCodeModeEnabled: false }),
90
+ config: buildCodexRuntimeThreadConfig(resolveBoundedThreadConfig(params, workspace), { nativeCodeModeEnabled: false }),
124
91
  environments: [],
125
92
  dynamicTools: [],
126
93
  experimentalRawEvents: true,
@@ -129,16 +96,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
129
96
  timeoutMs,
130
97
  signal: abortController.signal
131
98
  }));
132
- activeThreadId = thread.thread.id;
133
- if (abortController.signal.aborted) requestInterrupt();
134
- if (params.requireNoExternalCapabilities) await attestCodexRingZeroThreadHasNoMcpServers(client, thread.thread.id, abortController.signal);
135
- if (params.historyItems?.length) await client.request("thread/inject_items", {
136
- threadId: thread.thread.id,
137
- items: params.historyItems
138
- }, {
139
- timeoutMs,
140
- signal: abortController.signal
141
- });
142
99
  const collector = createCodexBoundedTurnCollector(thread.thread.id, params.taskLabel);
143
100
  const cleanup = client.addNotificationHandler(collector.handleNotification);
144
101
  const requestCleanup = client.addRequestHandler(createCodexBoundedApprovalHandler(params.taskLabel));
@@ -154,8 +111,6 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
154
111
  timeoutMs,
155
112
  signal: abortController.signal
156
113
  }));
157
- activeTurnId = turn.turn.id;
158
- if (abortController.signal.aborted) requestInterrupt();
159
114
  return {
160
115
  ...await collector.collect(turn.turn, {
161
116
  timeoutMs,
@@ -167,32 +122,21 @@ async function runBoundedCodexAppServerTurnInWorkspace(params, appServer, worksp
167
122
  requestCleanup();
168
123
  cleanup();
169
124
  }
170
- } catch (error) {
171
- if (ownsClient && isCodexAppServerStartSelectionChangedError(error) && selectionAttempt === 0) retrySelection = true;
172
- else throw error;
173
125
  } finally {
174
126
  clearTimeout(timeout);
175
127
  params.signal?.removeEventListener("abort", abortFromCaller);
176
- await interruptPromise;
177
128
  if (ownsClient) client.close();
178
129
  }
179
- if (retrySelection) return await runBoundedCodexAppServerTurnInWorkspace(params, appServer, workspace, selectionAttempt + 1, {
180
- deadline,
181
- timeoutMs: totalTimeoutMs
182
- });
183
- throw new Error("Codex bounded turn selection retry exited unexpectedly");
184
130
  }
185
- function resolveBoundedThreadConfig(params, workspace, inheritedMcpServerNames) {
131
+ function resolveBoundedThreadConfig(params, workspace) {
186
132
  const boundedConfig = mergeCodexThreadConfigs(CODEX_BOUNDED_THREAD_CONFIG, params.threadConfig) ?? CODEX_BOUNDED_THREAD_CONFIG;
187
- const privateConfig = workspace.codexHome ? mergeCodexThreadConfigs(boundedConfig, CODEX_PRIVATE_BOUNDED_THREAD_CONFIG) ?? boundedConfig : boundedConfig;
188
- if (!params.requireNoExternalCapabilities) return privateConfig;
189
- 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;
190
134
  }
191
135
  function buildPrivateCodexAppServerStartOptions(start, codexHome) {
192
- 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));
193
137
  const clearEnv = (start.clearEnv ?? []).filter((name) => {
194
138
  const normalized = name.trim().toUpperCase();
195
- return normalized !== "CODEX_HOME" && normalized !== CODEX_APP_SERVER_ARGS_ENV_KEY;
139
+ return normalized !== "CODEX_HOME" && normalized !== OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR;
196
140
  });
197
141
  return {
198
142
  ...start,
@@ -201,7 +145,7 @@ function buildPrivateCodexAppServerStartOptions(start, codexHome) {
201
145
  ...privateEnv,
202
146
  CODEX_HOME: codexHome
203
147
  },
204
- clearEnv: [...clearEnv, CODEX_APP_SERVER_ARGS_ENV_KEY]
148
+ clearEnv: [...clearEnv, OPENCLAW_CODEX_APP_SERVER_ARGS_ENV_VAR]
205
149
  };
206
150
  }
207
151
  function createCodexBoundedApprovalHandler(taskLabel) {
@@ -222,14 +166,15 @@ function createCodexBoundedApprovalHandler(taskLabel) {
222
166
  };
223
167
  }
224
168
  async function resolveCodexBoundedTurnModel(params) {
225
- const listed = readModelListResult(await params.client.request("model/list", {
169
+ const result = await params.client.request("model/list", {
226
170
  limit: null,
227
171
  cursor: null,
228
172
  includeHidden: false
229
173
  }, {
230
174
  timeoutMs: Math.min(params.timeoutMs, 5e3),
231
175
  signal: params.signal
232
- })).models;
176
+ });
177
+ const listed = readModelListResult(result).models;
233
178
  if (params.selection.mode === "live-default") {
234
179
  const supported = listed.filter((entry) => params.requiredModalities.every((modality) => entry.inputModalities.includes(modality)));
235
180
  const selected = supported.find((entry) => entry.isDefault) ?? supported[0];
@@ -247,7 +192,6 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
247
192
  let turnId;
248
193
  let completedTurn;
249
194
  let promptError;
250
- let responseUsage;
251
195
  const pending = [];
252
196
  const completedItems = /* @__PURE__ */ new Map();
253
197
  const assistantTextByItem = /* @__PURE__ */ new Map();
@@ -283,18 +227,12 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
283
227
  rememberAssistantText(itemId, `${assistantTextByItem.get(itemId) ?? ""}${delta}`);
284
228
  return;
285
229
  }
286
- if (notification.method === "rawResponse/completed") {
287
- const usage = isJsonObject(params.usage) ? params.usage : void 0;
288
- responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
289
- return;
290
- }
291
230
  if (notification.method === "turn/completed") {
292
231
  completedTurn = readCodexTurnCompletedNotification(notification.params)?.turn ?? completedTurn;
293
232
  resolveCompletion?.();
294
233
  return;
295
234
  }
296
235
  if (notification.method === "error") {
297
- if (isRetryableErrorNotification(notification.params)) return;
298
236
  promptError = readCodexErrorNotification(notification.params)?.error.message ?? `codex app-server ${taskLabel} turn failed`;
299
237
  resolveCompletion?.();
300
238
  }
@@ -313,7 +251,6 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
313
251
  });
314
252
  if (promptError) throw new Error(promptError);
315
253
  if (completedTurn?.status === "failed") throw new Error(completedTurn.error?.message ?? `codex app-server ${taskLabel} turn failed`);
316
- if (completedTurn?.status !== "completed") throw new Error(`codex app-server ${taskLabel} turn ended with status ${completedTurn?.status ?? "unknown"}`);
317
254
  const items = collectCompletedItems(completedTurn?.items, completedItems);
318
255
  const itemText = collectAssistantTextFromItems(items);
319
256
  const deltaText = assistantItemOrder.map((itemId) => assistantTextByItem.get(itemId)?.trim()).filter((text) => Boolean(text)).join("\n\n").trim();
@@ -321,8 +258,7 @@ function createCodexBoundedTurnCollector(threadId, taskLabel) {
321
258
  if (!text) throw new Error(`Codex app-server ${taskLabel} turn returned no text.`);
322
259
  return {
323
260
  text,
324
- items,
325
- ...responseUsage ? { usage: responseUsage } : {}
261
+ items
326
262
  };
327
263
  }
328
264
  };
@@ -365,4 +301,169 @@ function isTerminalTurn(turn) {
365
301
  return turn.status === "completed" || turn.status === "interrupted" || turn.status === "failed";
366
302
  }
367
303
  //#endregion
368
- 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 { c as readCodexModelListResponse } from "./protocol-validators-Dm4eXZmt.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-BVKE40c-.js").then((n) => n.p);
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 };
@@ -0,0 +1,99 @@
1
+ import { K as buildCodexAppInventoryCacheKey } from "./thread-lifecycle-u6CZdOOH.mjs";
2
+ import { u as CodexAppServerRpcError, x as resolveCodexAppServerHomeDir } from "./shared-client-B2KmLPRw.mjs";
3
+ import { createRequire } from "node:module";
4
+ import { createHash } from "node:crypto";
5
+ import { OPENCLAW_VERSION } from "openclaw/plugin-sdk/agent-harness-runtime";
6
+ import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
7
+ //#region extensions/codex/src/app-server/capabilities.ts
8
+ /**
9
+ * Capability helpers for optional Codex app-server control-plane methods.
10
+ */
11
+ /** Known app-server methods used by OpenClaw control surfaces. */
12
+ const CODEX_CONTROL_METHODS = {
13
+ account: "account/read",
14
+ compact: "thread/compact/start",
15
+ feedback: "feedback/upload",
16
+ forkThread: "thread/fork",
17
+ listMcpServers: "mcpServerStatus/list",
18
+ listSkills: "skills/list",
19
+ listThreads: "thread/list",
20
+ readThread: "thread/read",
21
+ rateLimits: "account/rateLimits/read",
22
+ archiveThread: "thread/archive",
23
+ renameThread: "thread/name/set",
24
+ resumeThread: "thread/resume",
25
+ review: "review/start",
26
+ unarchiveThread: "thread/unarchive"
27
+ };
28
+ /** Formats unsupported control calls differently from ordinary RPC failures. */
29
+ function describeControlFailure(error) {
30
+ if (isUnsupportedControlError(error)) return "unsupported by this Codex app-server";
31
+ return error instanceof Error ? error.message : String(error);
32
+ }
33
+ function isUnsupportedControlError(error) {
34
+ return error instanceof CodexAppServerRpcError && error.code === -32601;
35
+ }
36
+ //#endregion
37
+ //#region extensions/codex/src/app-server/plugin-app-cache-key.ts
38
+ /**
39
+ * Builds stable Codex plugin/app inventory cache keys from app-server startup,
40
+ * auth, account, and version inputs without storing secret material.
41
+ */
42
+ const require = createRequire(import.meta.url);
43
+ const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require });
44
+ /** Builds the full app inventory cache key for Codex plugin/app discovery. */
45
+ function buildCodexPluginAppCacheKey(params) {
46
+ return buildCodexAppInventoryCacheKey({
47
+ codexHome: params.runtimeIdentity?.codexHome ?? resolveCodexPluginAppCacheCodexHome(params.appServer, params.agentDir),
48
+ endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
49
+ authProfileId: params.authProfileId,
50
+ accountId: params.accountId,
51
+ envApiKeyFingerprint: params.envApiKeyFingerprint,
52
+ appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
53
+ runtimeIdentity: params.runtimeIdentity
54
+ }, OPENCLAW_VERSION, CODEX_PLUGIN_VERSION);
55
+ }
56
+ /** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
57
+ function buildCodexAppServerRuntimeFingerprint(params) {
58
+ return JSON.stringify({
59
+ endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
60
+ connectionClass: params.appServer.connectionClass,
61
+ remoteWorkspaceRoot: params.appServer.remoteWorkspaceRoot ?? null,
62
+ appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion ?? null,
63
+ runtimeIdentity: params.runtimeIdentity ?? null
64
+ });
65
+ }
66
+ /** Serializes app-server endpoint identity, including credential fingerprints. */
67
+ function resolveCodexPluginAppCacheEndpoint(appServer) {
68
+ return JSON.stringify({
69
+ transport: appServer.start.transport,
70
+ command: appServer.start.command,
71
+ args: appServer.start.args,
72
+ url: appServer.start.url ?? null,
73
+ credentialFingerprint: fingerprintCodexPluginAppCacheCredentials(appServer.start)
74
+ });
75
+ }
76
+ /** Resolves the CODEX_HOME value that scopes local app-server inventory. */
77
+ function resolveCodexPluginAppCacheCodexHome(appServer, agentDir) {
78
+ const configuredCodexHome = appServer.start.env?.CODEX_HOME?.trim();
79
+ if (configuredCodexHome) return configuredCodexHome;
80
+ return appServer.start.transport === "stdio" && agentDir ? resolveCodexAppServerHomeDir(agentDir) : void 0;
81
+ }
82
+ function fingerprintCodexPluginAppCacheCredentials(startOptions) {
83
+ const authToken = startOptions.authToken ?? "";
84
+ const headers = Object.entries(startOptions.headers).map(([key, value]) => [key.toLowerCase(), value]).toSorted(([left], [right]) => left.localeCompare(right));
85
+ if (!authToken && headers.length === 0) return null;
86
+ const hash = createHash("sha256");
87
+ hash.update("openclaw:codex:plugin-app-cache-credentials:v1");
88
+ hash.update("\0");
89
+ hash.update(authToken);
90
+ for (const [key, value] of headers) {
91
+ hash.update("\0");
92
+ hash.update(key);
93
+ hash.update("\0");
94
+ hash.update(value);
95
+ }
96
+ return `sha256:${hash.digest("hex")}`;
97
+ }
98
+ //#endregion
99
+ export { describeControlFailure as i, buildCodexPluginAppCacheKey as n, CODEX_CONTROL_METHODS as r, buildCodexAppServerRuntimeFingerprint as t };
@@ -0,0 +1,13 @@
1
+ //#region extensions/codex/src/app-server/protocol.ts
2
+ function flattenCodexDynamicToolFunctions(tools) {
3
+ return (tools ?? []).flatMap((tool) => tool.type === "namespace" ? tool.tools : [tool]);
4
+ }
5
+ const CODEX_INTERACTIVE_THREAD_SOURCE_KINDS = ["cli", "vscode"];
6
+ function isJsonObject(value) {
7
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
8
+ }
9
+ function isRpcResponse(message) {
10
+ return "id" in message && !("method" in message);
11
+ }
12
+ //#endregion
13
+ export { isRpcResponse as i, flattenCodexDynamicToolFunctions as n, isJsonObject as r, CODEX_INTERACTIVE_THREAD_SOURCE_KINDS as t };