@openclaw/codex 2026.8.1-beta.2 → 2026.9.1-beta.1

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 (60) hide show
  1. package/dist/api.js +147 -0
  2. package/dist/{attempt-client-cleanup-DMLXUfa8.js → attempt-client-cleanup-bfsmcQ6m.js} +21 -2
  3. package/dist/{binding-connection-I5Bo-AsX.js → binding-connection-BMvPX73o.js} +15 -3
  4. package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-B7iBUcuP.js} +22 -16
  5. package/dist/{capabilities-CybGI1oz.js → capabilities-BRMh0aIq.js} +1 -1
  6. package/dist/cli-metadata.js +1 -1
  7. package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-DEsIufkt.js} +2 -2
  8. package/dist/{command-handlers-Db8pu_ds.js → command-handlers-D_-1_qRp.js} +65 -37
  9. package/dist/command-rpc-CCeCkf_v.js +90 -0
  10. package/dist/{compact-LspQaGfl.js → compact-BglNFZrQ.js} +35 -29
  11. package/dist/{session-binding-DPxIvMgE.js → config-giW8X0QA.js} +108 -914
  12. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  13. package/dist/doctor-contract-api.js +23 -21
  14. package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-Dnlfa--w.js} +1345 -1424
  15. package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-CTeGrnfO.js} +2 -2
  16. package/dist/elicitation-input-DMkeki8d.js +71 -0
  17. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  18. package/dist/{event-projector-usage-e5huIQWu.js → event-projector-usage-Bk1I90Bg.js} +18 -18
  19. package/dist/harness-Csz0F-DK.js +258 -0
  20. package/dist/harness.js +2 -226
  21. package/dist/index.js +262 -181
  22. package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cv6FqygM.js} +4 -4
  23. package/dist/managed-binary-DFYK4DWq.js +248 -0
  24. package/dist/media-understanding-provider.js +2 -2
  25. package/dist/model-catalog-i9rNBthX.js +48 -0
  26. package/dist/{models-BFlpn1Ex.js → models-TS3HBU-q.js} +4 -3
  27. package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-4Mfq2HDs.js} +354 -83
  28. package/dist/node-exec-server.runtime-BpWqJO1V.js +192 -0
  29. package/dist/{plugin-app-cache-key-C3H2CVp6.js → plugin-app-cache-key-C1CAdfcP.js} +19 -4
  30. package/dist/plugin-approval-roundtrip-bUm777tR.js +95 -0
  31. package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-B9DvaAG-.js} +59 -54
  32. package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CTCT3w5L.js} +164 -134
  33. package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-VeJxxJ0U.js} +80 -5
  34. package/dist/{rate-limits-DZXmOL8-.js → rate-limits-C5_D8Gmb.js} +1 -1
  35. package/dist/{request-BRl5_UfX.js → request-DXXGHko0.js} +2 -2
  36. package/dist/{run-attempt-P8BdxC1I.js → run-attempt-DYc0QCBF.js} +1276 -765
  37. package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-BvyT1uyd.js} +4 -7
  38. package/dist/{sandbox-guard-Cmwc9eIk.js → sandbox-guard-kuWTn9C5.js} +25 -19
  39. package/dist/session-binding-Bcynfd-_.js +874 -0
  40. package/dist/{session-catalog-xwNi_SDM.js → session-catalog-DaLKVtpH.js} +1534 -1288
  41. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  42. package/dist/{session-cli-7hgXZDV7.js → session-cli-DMc4oS2w.js} +20 -7
  43. package/dist/session-permission-policy-BrNH1bjy.js +160 -0
  44. package/dist/{session-retirement-DoMMJFKm.js → session-retirement-CcNC3YSY.js} +3 -3
  45. package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-BIkusb95.js} +1 -1
  46. package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-Dc3ApjU4.js} +24 -20
  47. package/dist/{shared-client-kIBbGjk4.js → shared-client-DKz23hHY.js} +1632 -372
  48. package/dist/{side-question-9HAL26l9.js → side-question-DjA_jsNe.js} +105 -54
  49. package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-L7oEkTlq.js} +1147 -114
  50. package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-DZeuKH1j.js} +2 -2
  51. package/dist/{thread-resume-CPrJNQVM.js → thread-resume-BE9qNEW0.js} +3 -3
  52. package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-DsCMWBca.js} +137 -38
  53. package/dist/{transport-stdio-DIImwDVS.js → transport-stdio-DhoGy33Z.js} +2 -2
  54. package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
  55. package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-DlaHxSLC.js} +12 -6
  56. package/dist/{usage-CHlV0e-o.js → usage-ROIaW3wo.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-ClaNPV7N.js} +3 -3
  58. package/openclaw.plugin.json +49 -2
  59. package/package.json +9 -8
  60. package/dist/app-server-policy-zcBDc1JU.js +0 -49
@@ -1,5 +1,5 @@
1
- import { K as releaseCodexAppServerLiveThread, W as isCodexAppServerLiveThreadClaimed, d as retainSharedCodexAppServerClientByInstanceId, q as retainCodexAppServerLiveThread } from "./shared-client-kIBbGjk4.js";
2
- import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DMLXUfa8.js";
1
+ import { $ as releaseCodexAppServerLiveThread, Z as isCodexAppServerLiveThreadClaimed, et as retainCodexAppServerLiveThread, h as retainSharedCodexAppServerClientByInstanceId } from "./shared-client-DKz23hHY.js";
2
+ import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-bfsmcQ6m.js";
3
3
  import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
4
4
  //#region extensions/codex/src/app-server/thread-ownership.ts
5
5
  const nativeThreadOwners = new KeyedAsyncQueue();
@@ -1,6 +1,6 @@
1
- import { F as isCodexAppServerPrewriteRequestCancellationError, s as isCodexAppServerStartSelectionChangedError, z as CodexAppServerRpcError } from "./shared-client-kIBbGjk4.js";
2
- import { i as assertCodexThreadResumeSubscription, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DMLXUfa8.js";
3
- import { i as assertCodexThreadResumeResponse } from "./protocol-validators-B4F7L8Rf.js";
1
+ import { B as isCodexAppServerPrewriteRequestCancellationError, G as CodexAppServerRpcError, c as isCodexAppServerStartSelectionChangedError } from "./shared-client-DKz23hHY.js";
2
+ import { i as assertCodexThreadResumeSubscription, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-bfsmcQ6m.js";
3
+ import { i as assertCodexThreadResumeResponse } from "./protocol-validators-VeJxxJ0U.js";
4
4
  //#region extensions/codex/src/app-server/thread-resume.ts
5
5
  /** Owns Codex thread/resume subscription safety. */
6
6
  /** Resumes one thread and retires the physical client when acceptance is indeterminate. */
@@ -1,7 +1,8 @@
1
- import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-ClRBije0.js";
2
- import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
- import { embeddedAgentLog, formatErrorMessage, projectAgentHarnessTranscriptMessageForDisplay, runAgentHarnessBeforeMessageWriteHook } from "openclaw/plugin-sdk/agent-harness-runtime";
1
+ import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
2
+ import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { deliverAgentHarnessUserInputPrompt, embeddedAgentLog, formatErrorMessage, projectAgentHarnessTranscriptMessageForDisplay, runAgentHarnessBeforeMessageWriteHook } from "openclaw/plugin-sdk/agent-harness-runtime";
4
4
  import { createHash } from "node:crypto";
5
+ import { truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
5
6
  import { withCodexSessionTranscriptMirrorWriteLock } from "openclaw/plugin-sdk/codex-session-transcript-runtime";
6
7
  import { publishSessionTranscriptUpdateByIdentity } from "openclaw/plugin-sdk/session-transcript-runtime";
7
8
  import { Buffer } from "node:buffer";
@@ -27,16 +28,6 @@ const CODEX_HISTORY_ZERO_USAGE = {
27
28
  total: 0
28
29
  }
29
30
  };
30
- function isUtf8ContinuationByte(byte) {
31
- return byte !== void 0 && (byte & 192) === 128;
32
- }
33
- function truncateUtf8Prefix(value, maxBytes) {
34
- const bytes = Buffer.from(value);
35
- if (bytes.byteLength <= maxBytes) return value;
36
- let end = Math.max(0, maxBytes);
37
- while (end > 0 && isUtf8ContinuationByte(bytes[end])) end -= 1;
38
- return bytes.subarray(0, end).toString("utf8");
39
- }
40
31
  function normalizeImportedHistoryText(value) {
41
32
  if (typeof value !== "string") return;
42
33
  const text = value.trim();
@@ -91,6 +82,8 @@ function projectCodexThreadHistory(params) {
91
82
  const role = item.type === "userMessage" ? "user" : item.type === "agentMessage" ? "assistant" : void 0;
92
83
  itemOffset += 1;
93
84
  if (!text || !role) continue;
85
+ const phase = item.phase === "commentary" || item.phase === "final_answer" ? item.phase : void 0;
86
+ const asyncDelivery = item.delivery === "async";
94
87
  const message = role === "assistant" ? attachCodexMirrorIdentity({
95
88
  role,
96
89
  content: [{
@@ -103,13 +96,14 @@ function projectCodexThreadHistory(params) {
103
96
  usage: CODEX_HISTORY_ZERO_USAGE,
104
97
  stopReason: turn.status === "interrupted" ? "aborted" : turn.status === "failed" ? "error" : "stop",
105
98
  ...turn.status === "failed" && turn.error?.message ? { errorMessage: turn.error.message } : {},
99
+ ...phase ? { phase } : {},
100
+ ...asyncDelivery && itemId ? { openclawAsyncDelivery: { itemId } } : {},
106
101
  timestamp
107
102
  }, identity) : attachCodexMirrorIdentity({
108
103
  role,
109
104
  content: text,
110
105
  timestamp
111
106
  }, identity);
112
- const phase = item.phase === "commentary" || item.phase === "final_answer" ? item.phase : void 0;
113
107
  projected.push({
114
108
  message,
115
109
  responseItem: {
@@ -150,7 +144,7 @@ function projectBoundedCodexThreadHistory(params) {
150
144
  return {
151
145
  importedMessages: selected.length,
152
146
  omittedMessages: projected.length - selected.length,
153
- responseItems: selected.filter(({ message }) => message.role !== "assistant" || message.stopReason !== "aborted" && message.stopReason !== "error").map(({ responseItem }) => responseItem),
147
+ responseItems: selected.filter(({ message }) => message.role !== "assistant" || message.stopReason !== "aborted" && message.stopReason !== "error" && !("openclawAsyncDelivery" in message)).map(({ responseItem }) => responseItem),
154
148
  transcriptMessages: selected.map(({ message }) => message)
155
149
  };
156
150
  }
@@ -159,7 +153,7 @@ function projectBoundedCodexVisibleSessionHistory(entries) {
159
153
  const projected = [];
160
154
  for (const entry of entries) {
161
155
  if (entry.role !== "user" && entry.role !== "assistant" || !("content" in entry.message)) continue;
162
- if (entry.role === "assistant" && "stopReason" in entry.message && (entry.message.stopReason === "aborted" || entry.message.stopReason === "error")) continue;
156
+ if (entry.role === "assistant" && ("stopReason" in entry.message && (entry.message.stopReason === "aborted" || entry.message.stopReason === "error") || "openclawAsyncDelivery" in entry.message)) continue;
163
157
  const content = entry.message.content;
164
158
  const text = normalizeImportedHistoryText(typeof content === "string" ? content : Array.isArray(content) ? content.flatMap((part) => part && typeof part === "object" && "text" in part && typeof part.text === "string" ? [part.text] : []).join("\n") : void 0);
165
159
  if (!text) continue;
@@ -183,35 +177,46 @@ function projectBoundedCodexVisibleSessionHistory(entries) {
183
177
  const MIRROR_ORIGIN_META_KEY = "mirrorOrigin";
184
178
  const MIRROR_SOURCE_FINGERPRINT_META_KEY = "mirrorSourceFingerprint";
185
179
  const CODEX_APP_SERVER_MIRROR_ORIGIN = "codex-app-server";
180
+ const CODEX_META_KEY = "__openclaw";
186
181
  function attachCodexMirrorAttestation(message, sourceFingerprint) {
187
- const record = message;
188
- const existing = record["__openclaw"];
182
+ const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
189
183
  const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
190
184
  return {
191
- ...record,
192
- __openclaw: {
185
+ ...message,
186
+ [CODEX_META_KEY]: {
193
187
  ...baseMeta,
194
188
  [MIRROR_ORIGIN_META_KEY]: CODEX_APP_SERVER_MIRROR_ORIGIN,
195
189
  ...sourceFingerprint ? { [MIRROR_SOURCE_FINGERPRINT_META_KEY]: sourceFingerprint } : {}
196
190
  }
197
191
  };
198
192
  }
193
+ function attachCodexMirrorRunId(message, runId, terminal = false) {
194
+ const { runTerminal: _staleTerminal, ...current } = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0) ?? {};
195
+ return {
196
+ ...message,
197
+ [CODEX_META_KEY]: {
198
+ ...current,
199
+ runId,
200
+ ...terminal ? { runTerminal: true } : {}
201
+ }
202
+ };
203
+ }
199
204
  function readCodexMirrorSourceFingerprint(message) {
200
- const meta = message["__openclaw"];
205
+ const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
201
206
  if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
202
207
  const value = meta[MIRROR_SOURCE_FINGERPRINT_META_KEY];
203
208
  return typeof value === "string" && value ? value : void 0;
204
209
  }
205
210
  function serializeCodexMirrorSourceEvidence(message) {
206
- const record = message;
211
+ const content = "content" in message ? message.content : void 0;
207
212
  return JSON.stringify({
208
213
  role: message.role,
209
- content: record.content,
214
+ content,
210
215
  ...message.role === "user" ? { upstreamUserText: readUpstreamUserText(message) } : {},
211
216
  ...message.role === "toolResult" ? {
212
- toolCallId: record.toolCallId,
213
- toolName: record.toolName,
214
- isError: record.isError === true
217
+ toolCallId: message.toolCallId,
218
+ toolName: message.toolName,
219
+ isError: message.isError
215
220
  } : {}
216
221
  });
217
222
  }
@@ -247,7 +252,7 @@ function buildFromPrepared(params, preparedUserMessage) {
247
252
  ...senderUsername ? { senderUsername } : {},
248
253
  ...senderE164 ? { senderE164 } : {},
249
254
  ...senderLabel ? { senderLabel } : {},
250
- ...preparedUserMessage ? preparedUserMessage : { content: params.prompt }
255
+ ...preparedUserMessage ?? { content: params.transcriptPrompt ?? params.prompt }
251
256
  };
252
257
  }
253
258
  function buildCodexUserPromptMessage(params) {
@@ -268,6 +273,10 @@ async function buildResolvedCodexUserPromptMessage(params) {
268
273
  function isMirroredAgentMessage(message) {
269
274
  return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
270
275
  }
276
+ function readMirroredAssistantText(message) {
277
+ if (message?.role !== "assistant") return;
278
+ return message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n") || void 0;
279
+ }
271
280
  /** Imports a bounded, user-visible Codex history tail into a new OpenClaw transcript. */
272
281
  async function importCodexThreadHistoryToTranscript(params) {
273
282
  const projection = projectBoundedCodexThreadHistory({
@@ -310,6 +319,12 @@ async function mirrorBestEffort(params) {
310
319
  cwd: params.cwd,
311
320
  messages,
312
321
  idempotencyScope: `codex-app-server:${params.threadId}`,
322
+ runId: params.params.runId,
323
+ runMirrorIdentityPrefix: `${params.turnId}:`,
324
+ terminalAssistantOwner: {
325
+ mirrorIdentity: `${params.turnId}:assistant`,
326
+ runId: params.params.runId
327
+ },
313
328
  config: params.params.config
314
329
  });
315
330
  for (const receipt of mirrorResult.userMessageReceipts) try {
@@ -327,8 +342,9 @@ async function mirrorBestEffort(params) {
327
342
  return identity !== void 0 && readCodexMirrorSourceFingerprint(message) === expectedFingerprints.get(identity);
328
343
  });
329
344
  const assistantMirrorIdentity = `${params.turnId}:assistant`;
330
- const assistantTranscriptOwned = mirrorResult.assistantMirrorIdentitiesOwned.includes(assistantMirrorIdentity);
331
- const assistantTranscriptIdempotencyKey = normalizeOptionalString((assistantTranscriptOwned ? mirroredMessages.find((message) => readMirrorIdentity(message) === assistantMirrorIdentity) : void 0)?.idempotencyKey);
345
+ const assistantTranscriptMessage = mirroredMessages.find((message) => readMirrorIdentity(message) === assistantMirrorIdentity);
346
+ const assistantTranscriptOwned = Boolean(assistantTranscriptMessage && mirrorResult.assistantMirrorIdentitiesOwned.includes(assistantMirrorIdentity));
347
+ const assistantTranscriptIdempotencyKey = normalizeOptionalString(assistantTranscriptMessage?.idempotencyKey);
332
348
  const terminalMessage = mirroredMessages.at(-1);
333
349
  const terminalMirrorIdentity = terminalMessage ? readMirrorIdentity(terminalMessage) : void 0;
334
350
  const terminalAnchor = (terminalMirrorIdentity ? mirrorResult.anchorsByMirrorIdentity.get(terminalMirrorIdentity) : void 0) ?? params.params.userTurnTranscriptRecorder?.getAdmissionReceipt();
@@ -391,6 +407,8 @@ async function mirrorPromptAtTurnStartBestEffort(params) {
391
407
  cwd: params.cwd,
392
408
  messages: [userPromptMessage],
393
409
  idempotencyScope: `codex-app-server:${params.threadId}`,
410
+ runId: params.params.runId,
411
+ runMirrorIdentityPrefix: `${params.turnId}:`,
394
412
  config: params.params.config
395
413
  });
396
414
  for (const receipt of mirrorResult.userMessageReceipts) params.notifyUserMessagePersisted(receipt.message, receipt.anchor);
@@ -420,6 +438,7 @@ function buildMirrorDedupeIdentity(message) {
420
438
  async function mirror(params) {
421
439
  const messages = params.messages.filter(isMirroredAgentMessage);
422
440
  if (messages.length === 0) return {
441
+ assistantMirrorIdentitiesAppended: [],
423
442
  assistantMirrorIdentitiesOwned: [],
424
443
  anchorsByMirrorIdentity: /* @__PURE__ */ new Map(),
425
444
  messagesPresent: [],
@@ -431,18 +450,19 @@ async function mirror(params) {
431
450
  const sourceFingerprint = fingerprintCodexMirrorSourceMessage(message);
432
451
  return {
433
452
  dedupeIdentity,
434
- idempotencyKey: (message.role === "user" ? normalizeOptionalString(message.idempotencyKey) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0),
453
+ idempotencyKey: (message.role === "user" ? normalizeOptionalString("idempotencyKey" in message ? message.idempotencyKey : void 0) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0),
435
454
  message,
436
455
  sourceFingerprint
437
456
  };
438
457
  });
439
458
  const candidateIdempotencyKeys = candidates.flatMap(({ idempotencyKey }) => idempotencyKey ? [idempotencyKey] : []);
440
459
  const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
441
- const { appendedUpdates, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
460
+ const { appendedUpdates, assistantMirrorIdentitiesAppended, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
442
461
  ...transcriptTarget,
443
462
  config: params.config
444
463
  }, async (transcript) => {
445
464
  const nextAppendedUpdates = [];
465
+ const nextAssistantMirrorIdentitiesAppended = /* @__PURE__ */ new Set();
446
466
  const nextAssistantMirrorIdentitiesOwned = /* @__PURE__ */ new Set();
447
467
  const nextAnchorsByMirrorIdentity = /* @__PURE__ */ new Map();
448
468
  const nextMessagesPresent = [];
@@ -450,8 +470,12 @@ async function mirror(params) {
450
470
  const nextUserMessagesPresent = [];
451
471
  const mirrorFacts = await transcript.readMessageFacts({ idempotencyKeys: candidateIdempotencyKeys });
452
472
  for (const { dedupeIdentity, idempotencyKey, message, sourceFingerprint } of candidates) {
473
+ const mirrorIdentity = readMirrorIdentity(message);
474
+ const ownsRun = Boolean(params.runId && (!params.runMirrorIdentityPrefix || mirrorIdentity?.startsWith(params.runMirrorIdentityPrefix)));
475
+ const terminalOwner = params.terminalAssistantOwner;
476
+ const ownsTerminal = Boolean(ownsRun && terminalOwner && mirrorIdentity === terminalOwner.mirrorIdentity);
453
477
  const transcriptMessage = {
454
- ...attachCodexMirrorAttestation(message, sourceFingerprint),
478
+ ...attachCodexMirrorAttestation(ownsRun && params.runId ? attachCodexMirrorRunId(message, params.runId, ownsTerminal) : message, sourceFingerprint),
455
479
  ...idempotencyKey ? { idempotencyKey } : {}
456
480
  };
457
481
  if (idempotencyKey && mirrorFacts.existingIdempotencyKeys.has(idempotencyKey)) {
@@ -484,8 +508,9 @@ async function mirror(params) {
484
508
  ...attachCodexMirrorAttestation(nextMessage, sourceFingerprint),
485
509
  idempotencyKey
486
510
  } : attachCodexMirrorAttestation(nextMessage, sourceFingerprint);
487
- const mirrorIdentity = readMirrorIdentity(message);
488
511
  if (mirrorIdentity) messageToAppend = attachCodexMirrorIdentity(messageToAppend, mirrorIdentity);
512
+ if (ownsRun && params.runId) messageToAppend = attachCodexMirrorRunId(messageToAppend, params.runId, ownsTerminal);
513
+ if (message.role === "assistant" && message.openclawAsyncDelivery) messageToAppend = Object.assign(messageToAppend, { openclawAsyncDelivery: { itemId: message.openclawAsyncDelivery.itemId } });
489
514
  messageToAppend = projectAgentHarnessTranscriptMessageForDisplay({
490
515
  hidden: message.display === false,
491
516
  message: messageToAppend
@@ -510,11 +535,14 @@ async function mirror(params) {
510
535
  message: appendedMessage
511
536
  });
512
537
  }
513
- if (appended.appended) nextAppendedUpdates.push({
514
- messageId,
515
- message: appendedMessage,
516
- ...messageSeq !== void 0 ? { messageSeq } : {}
517
- });
538
+ if (appended.appended) {
539
+ if (message.role === "assistant") nextAssistantMirrorIdentitiesAppended.add(dedupeIdentity);
540
+ nextAppendedUpdates.push({
541
+ messageId,
542
+ message: appendedMessage,
543
+ ...messageSeq !== void 0 ? { messageSeq } : {}
544
+ });
545
+ }
518
546
  if (idempotencyKey) {
519
547
  mirrorFacts.existingIdempotencyKeys.add(idempotencyKey);
520
548
  if (appended.anchor) mirrorFacts.anchorsByIdempotencyKey.set(idempotencyKey, appended.anchor);
@@ -522,6 +550,7 @@ async function mirror(params) {
522
550
  }
523
551
  return {
524
552
  appendedUpdates: nextAppendedUpdates,
553
+ assistantMirrorIdentitiesAppended: [...nextAssistantMirrorIdentitiesAppended],
525
554
  assistantMirrorIdentitiesOwned: [...nextAssistantMirrorIdentitiesOwned],
526
555
  anchorsByMirrorIdentity: nextAnchorsByMirrorIdentity,
527
556
  messagesPresent: nextMessagesPresent,
@@ -530,6 +559,8 @@ async function mirror(params) {
530
559
  };
531
560
  });
532
561
  for (const update of appendedUpdates) try {
562
+ const terminalOwner = params.terminalAssistantOwner;
563
+ const terminalRunId = update.message.role === "assistant" && terminalOwner && readMirrorIdentity(update.message) === terminalOwner.mirrorIdentity ? terminalOwner.runId : void 0;
533
564
  await publishSessionTranscriptUpdateByIdentity({
534
565
  ...transcriptTarget,
535
566
  update: {
@@ -537,6 +568,7 @@ async function mirror(params) {
537
568
  message: update.message,
538
569
  messageId: update.messageId,
539
570
  ...update.messageSeq !== void 0 ? { messageSeq: update.messageSeq } : {},
571
+ ...terminalRunId ? { runId: terminalRunId } : {},
540
572
  sessionKey: transcriptTarget.sessionKey
541
573
  }
542
574
  });
@@ -544,6 +576,7 @@ async function mirror(params) {
544
576
  embeddedAgentLog.warn("failed to publish codex app-server transcript update", { error: formatErrorMessage(error) });
545
577
  }
546
578
  return {
579
+ assistantMirrorIdentitiesAppended,
547
580
  assistantMirrorIdentitiesOwned,
548
581
  anchorsByMirrorIdentity,
549
582
  messagesPresent,
@@ -551,10 +584,76 @@ async function mirror(params) {
551
584
  userMessagesPresent
552
585
  };
553
586
  }
587
+ async function deliverAsyncMessageBestEffort(params) {
588
+ const mirrorIdentity = `${params.turnId}:async:${params.itemId}`;
589
+ const deliveryIntentId = `block-reply:v1:codex-app-server:${[
590
+ params.threadId,
591
+ params.turnId,
592
+ params.itemId
593
+ ].map(encodeURIComponent).join(":")}`;
594
+ const target = params.params.sessionTarget;
595
+ if (!target) {
596
+ if (!params.params.onBlockReply) return "retry";
597
+ try {
598
+ await deliverAsyncBlockReply(params.params.onBlockReply, params.text, deliveryIntentId);
599
+ return "settled";
600
+ } catch (error) {
601
+ embeddedAgentLog.warn("failed to deliver codex async agent message", {
602
+ error: formatErrorMessage(error),
603
+ itemId: params.itemId,
604
+ runId: params.params.runId,
605
+ threadId: params.threadId,
606
+ turnId: params.turnId
607
+ });
608
+ return "retry";
609
+ }
610
+ }
611
+ let result;
612
+ try {
613
+ result = await mirror({
614
+ agentId: target.agentId ?? params.params.agentId,
615
+ sessionId: target.sessionId ?? params.params.sessionId,
616
+ sessionKey: target.sessionKey ?? params.params.sessionKey,
617
+ storePath: target.storePath,
618
+ cwd: params.cwd,
619
+ config: params.params.config,
620
+ messages: [attachCodexMirrorIdentity(params.message, mirrorIdentity)],
621
+ idempotencyScope: `codex-app-server:${params.threadId}`
622
+ });
623
+ } catch (error) {
624
+ embeddedAgentLog.warn("failed to persist codex async agent message", {
625
+ error: formatErrorMessage(error),
626
+ itemId: params.itemId,
627
+ runId: params.params.runId,
628
+ threadId: params.threadId,
629
+ turnId: params.turnId
630
+ });
631
+ return "retry";
632
+ }
633
+ if (!result.assistantMirrorIdentitiesOwned.includes(mirrorIdentity)) return "retry";
634
+ const persistedText = readMirroredAssistantText(result.messagesPresent.find((message) => readMirrorIdentity(message) === mirrorIdentity));
635
+ if (params.params.onBlockReply && persistedText !== void 0) try {
636
+ await deliverAsyncBlockReply(params.params.onBlockReply, persistedText, deliveryIntentId);
637
+ } catch (error) {
638
+ embeddedAgentLog.warn("failed to deliver persisted codex async agent message", {
639
+ error: formatErrorMessage(error),
640
+ itemId: params.itemId,
641
+ runId: params.params.runId,
642
+ threadId: params.threadId,
643
+ turnId: params.turnId
644
+ });
645
+ return "retry";
646
+ }
647
+ return "settled";
648
+ }
554
649
  const codexTranscriptMirrorRuntime = {
650
+ deliverAsyncMessageBestEffort,
555
651
  mirror,
556
652
  mirrorBestEffort
557
653
  };
654
+ async function deliverAsyncBlockReply(onBlockReply, text, deliveryIntentId) {
655
+ await deliverAgentHarnessUserInputPrompt({ onBlockReply: (payload) => onBlockReply(payload, { deliveryIntentId }) }, [], { intro: text });
656
+ }
558
657
  function resolveCodexMirrorTranscriptTarget(params) {
559
658
  const sessionKey = params.sessionKey?.trim();
560
659
  const storePath = params.storePath?.trim();
@@ -75,8 +75,8 @@ function copySafeEnvironmentEntries(target, source) {
75
75
  }
76
76
  }
77
77
  /** Spawns the Codex app-server process and returns the shared transport interface. */
78
- function createStdioTransport(options) {
79
- const env = resolveCodexAppServerSpawnEnv(options);
78
+ function createStdioTransport(options, baseEnv = process.env) {
79
+ const env = resolveCodexAppServerSpawnEnv(options, baseEnv);
80
80
  const invocation = resolveCodexAppServerSpawnInvocation(options, {
81
81
  platform: process.platform,
82
82
  env,
@@ -1,12 +1,12 @@
1
+ import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
1
2
  //#region extensions/codex/src/app-server/upstream-prompt-provenance.ts
2
3
  const UPSTREAM_USER_TEXT_META_KEY = "upstreamUserText";
3
4
  const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
5
+ const CODEX_META_KEY = "__openclaw";
4
6
  function attachCodexMirrorIdentity(message, identity) {
5
- const record = message;
6
- const existing = record["__openclaw"];
7
- const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
7
+ const baseMeta = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0) ?? {};
8
8
  return {
9
- ...record,
9
+ ...message,
10
10
  __openclaw: {
11
11
  ...baseMeta,
12
12
  [MIRROR_IDENTITY_META_KEY]: identity
@@ -14,17 +14,15 @@ function attachCodexMirrorIdentity(message, identity) {
14
14
  };
15
15
  }
16
16
  function readMirrorIdentity(message) {
17
- const meta = message["__openclaw"];
18
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
19
- const id = meta[MIRROR_IDENTITY_META_KEY];
17
+ const record = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0);
18
+ if (!record) return;
19
+ const id = record[MIRROR_IDENTITY_META_KEY];
20
20
  return typeof id === "string" && id ? id : void 0;
21
21
  }
22
22
  function attachUpstreamUserText(message, text) {
23
- const record = message;
24
- const existing = record["__openclaw"];
25
- const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
23
+ const baseMeta = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0) ?? {};
26
24
  return {
27
- ...record,
25
+ ...message,
28
26
  __openclaw: {
29
27
  ...baseMeta,
30
28
  [UPSTREAM_USER_TEXT_META_KEY]: text
@@ -32,9 +30,9 @@ function attachUpstreamUserText(message, text) {
32
30
  };
33
31
  }
34
32
  function readUpstreamUserText(message) {
35
- const meta = message?.["__openclaw"];
36
- if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
37
- const text = meta[UPSTREAM_USER_TEXT_META_KEY];
33
+ const record = asOptionalRecord(message && CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0);
34
+ if (!record) return;
35
+ const text = record[UPSTREAM_USER_TEXT_META_KEY];
38
36
  return typeof text === "string" && text ? text : void 0;
39
37
  }
40
38
  //#endregion
@@ -1,7 +1,7 @@
1
- import { d as sessionBindingIdentity } from "./session-binding-DPxIvMgE.js";
2
- import { r as assertCodexThreadForkResponse } from "./protocol-validators-B4F7L8Rf.js";
1
+ import { d as sessionBindingIdentity } from "./session-binding-Bcynfd-_.js";
2
+ import { r as assertCodexThreadForkResponse } from "./protocol-validators-VeJxxJ0U.js";
3
3
  import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
4
- import { i as createImportedCodexSession, n as codexUpstreamBaseline, t as codexLastTerminalTurnId } from "./session-upstream-marker-CrIFX06J.js";
4
+ import { i as createImportedCodexSession, n as codexUpstreamBaseline, t as codexLastTerminalTurnId } from "./session-upstream-marker-BIkusb95.js";
5
5
  import { isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
6
6
  import { readVisibleSessionTranscriptMessageEntries } from "openclaw/plugin-sdk/session-transcript-runtime";
7
7
  import { deleteSessionUpstreamLink, upsertSessionUpstreamLink } from "openclaw/plugin-sdk/session-catalog";
@@ -171,7 +171,14 @@ function normalizeTurnId(value) {
171
171
  }
172
172
  async function forkCodexUpstreamSession(params, options) {
173
173
  try {
174
- return await options.control.withPinnedConnection(async (control) => {
174
+ const sourceFingerprint = params.upstream.kind === "codex-app-server" ? readConnectionFingerprint(params.upstream.ref) : void 0;
175
+ const requestControl = sourceFingerprint ? options.controlFactory.forUpstream(params.source.agentId, sourceFingerprint) : void 0;
176
+ if (!sourceFingerprint || !requestControl) return {
177
+ status: "failed",
178
+ code: "upstream-unavailable",
179
+ message: "This Codex thread is not available on the current connection. Reconnect to its host and try again."
180
+ };
181
+ return await requestControl.withPinnedConnection(async (control) => {
175
182
  const incognito = isIncognitoSessionKey(params.targetKey);
176
183
  const clientId = control.clientId?.trim();
177
184
  if (incognito && !clientId) throw new Error("Incognito Codex forks require the live pinned app-server client");
@@ -185,8 +192,7 @@ async function forkCodexUpstreamSession(params, options) {
185
192
  if (linked) deleteSessionUpstreamLink(params.targetKey, params.source.agentId);
186
193
  await control.archiveThread(forkedThreadId).catch(() => void 0);
187
194
  };
188
- const sourceFingerprint = readConnectionFingerprint(params.upstream.ref);
189
- if (params.upstream.kind !== "codex-app-server" || !sourceFingerprint || sourceFingerprint !== control.connectionFingerprint) return {
195
+ if (sourceFingerprint !== control.connectionFingerprint) return {
190
196
  status: "failed",
191
197
  code: "upstream-unavailable",
192
198
  message: "This Codex thread is not available on the current connection. Reconnect to its host and try again."
@@ -1,6 +1,6 @@
1
- import { g as resolveCodexAppServerRuntimeOptions } from "./session-binding-DPxIvMgE.js";
2
- import { t as buildCodexAppServerUsageSnapshot } from "./rate-limits-DZXmOL8-.js";
3
- import { t as readCodexAppServerUsage } from "./request-BRl5_UfX.js";
1
+ import { i as resolveCodexAppServerRuntimeOptions } from "./config-giW8X0QA.js";
2
+ import { t as buildCodexAppServerUsageSnapshot } from "./rate-limits-C5_D8Gmb.js";
3
+ import { t as readCodexAppServerUsage } from "./request-DXXGHko0.js";
4
4
  import { CODEX_APP_SERVER_AUTH_MARKER } from "openclaw/plugin-sdk/agent-runtime";
5
5
  //#region extensions/codex/src/app-server/usage.ts
6
6
  /** Handles the synthetic usage credential for a Codex-backed OpenAI route. */
@@ -1,6 +1,6 @@
1
- import { ct as isJsonObject } from "./shared-client-kIBbGjk4.js";
2
- import { d as buildCodexNativeWebSearchThreadConfig } from "./thread-lifecycle-Bu1BTDXr.js";
3
- import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-qgZmzy_4.js";
1
+ import { vt as isJsonObject } from "./shared-client-DKz23hHY.js";
2
+ import { P as buildCodexNativeWebSearchThreadConfig } from "./thread-lifecycle-L7oEkTlq.js";
3
+ import { t as runBoundedCodexAppServerTurn } from "./bounded-turn-B7iBUcuP.js";
4
4
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { readStringParam, resolveSearchTimeoutSeconds, wrapWebContent } from "openclaw/plugin-sdk/provider-web-search";
6
6
  //#region extensions/codex/src/web-search-provider.runtime.ts
@@ -1,5 +1,22 @@
1
1
  {
2
2
  "id": "codex",
3
+ "backupResources": [
4
+ {
5
+ "disposition": "regenerable",
6
+ "scope": "agent",
7
+ "relativePath": "codex-home/tmp/arg0"
8
+ },
9
+ {
10
+ "disposition": "regenerable",
11
+ "scope": "agent",
12
+ "relativePath": "codex-home/.tmp/plugins"
13
+ },
14
+ {
15
+ "disposition": "regenerable",
16
+ "scope": "agent",
17
+ "relativePath": "codex-home/.tmp/bundled-marketplaces"
18
+ }
19
+ ],
3
20
  "doctorContract": {
4
21
  "configRepair": true,
5
22
  "stateMigrations": true
@@ -16,6 +33,13 @@
16
33
  ],
17
34
  "name": "Codex",
18
35
  "description": "Codex app-server harness and native session catalog.",
36
+ "cliCommands": [
37
+ {
38
+ "name": "codex",
39
+ "description": "Inspect and branch from Codex sessions through the Gateway",
40
+ "hasSubcommands": true
41
+ }
42
+ ],
19
43
  "contracts": {
20
44
  "mediaUnderstandingProviders": ["codex"],
21
45
  "migrationProviders": ["codex"],
@@ -45,6 +69,7 @@
45
69
  "onConfigPaths": [
46
70
  "plugins.entries.codex.config.appServer.transport",
47
71
  "plugins.entries.codex.config.sessionCatalog.enabled",
72
+ "plugins.entries.codex.config.sessionCatalog.homes",
48
73
  "plugins.entries.codex.config.supervision.enabled"
49
74
  ]
50
75
  },
@@ -73,7 +98,24 @@
73
98
  "type": "object",
74
99
  "additionalProperties": false,
75
100
  "properties": {
76
- "enabled": { "type": "boolean", "default": true }
101
+ "enabled": { "type": "boolean", "default": true },
102
+ "homes": {
103
+ "type": "array",
104
+ "items": {
105
+ "anyOf": [
106
+ { "type": "string", "minLength": 1, "pattern": "\\S" },
107
+ {
108
+ "type": "object",
109
+ "additionalProperties": false,
110
+ "required": ["path"],
111
+ "properties": {
112
+ "path": { "type": "string", "minLength": 1, "pattern": "\\S" },
113
+ "label": { "type": "string", "minLength": 1, "pattern": "\\S" }
114
+ }
115
+ }
116
+ ]
117
+ }
118
+ }
77
119
  }
78
120
  },
79
121
  "discovery": {
@@ -392,6 +434,11 @@
392
434
  "label": "Discover Codex Sessions",
393
435
  "help": "List native Codex sessions in the sidebar from this Gateway and eligible paired nodes."
394
436
  },
437
+ "sessionCatalog.homes": {
438
+ "label": "Additional Codex Homes",
439
+ "help": "Existing local Codex home directories to include in native session discovery. String paths use the canonical directory basename as their label; object entries can override it with label. Paths are canonicalized and deduplicated. Requires appServer.transport=stdio and a Gateway restart.",
440
+ "advanced": true
441
+ },
395
442
  "codexDynamicToolsLoading": {
396
443
  "label": "Dynamic Tools Loading",
397
444
  "help": "Use searchable to defer OpenClaw dynamic tools behind Codex tool search, or direct to expose them in the initial context.",
@@ -467,7 +514,7 @@
467
514
  },
468
515
  "computerUse.autoRepair": {
469
516
  "label": "Auto Repair",
470
- "help": "When true, failed Computer Use live tests repair stale scoped Computer Use MCP children before retrying once.",
517
+ "help": "When true, failed Computer Use live tests reload the Codex-owned MCP runtime before retrying once.",
471
518
  "advanced": true
472
519
  },
473
520
  "computerUse.marketplaceSource": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.8.1-beta.2",
3
+ "version": "2026.9.1-beta.1",
4
4
  "description": "OpenClaw Codex app-server harness and native session supervision plugin.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,10 +8,11 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@openai/codex": "0.147.0",
12
- "smol-toml": "1.7.1",
13
- "typebox": "1.3.6",
14
- "ws": "8.21.1",
11
+ "@openai/codex": "0.150.1",
12
+ "semver": "7.8.5",
13
+ "smol-toml": "1.8.0",
14
+ "typebox": "1.3.16",
15
+ "ws": "8.21.3",
15
16
  "zod": "4.4.3"
16
17
  },
17
18
  "devDependencies": {
@@ -35,10 +36,10 @@
35
36
  ]
36
37
  },
37
38
  "compat": {
38
- "pluginApi": ">=2026.8.1-beta.2"
39
+ "pluginApi": ">=2026.9.1-beta.1"
39
40
  },
40
41
  "build": {
41
- "openclawVersion": "2026.8.1-beta.2"
42
+ "openclawVersion": "2026.9.1-beta.1"
42
43
  },
43
44
  "release": {
44
45
  "publishToClawHub": true,
@@ -58,7 +59,7 @@
58
59
  "README.md"
59
60
  ],
60
61
  "peerDependencies": {
61
- "openclaw": ">=2026.8.1-beta.2"
62
+ "openclaw": ">=2026.9.1-beta.1"
62
63
  },
63
64
  "peerDependenciesMeta": {
64
65
  "openclaw": {