@openclaw/codex 2026.8.1-beta.3 → 2026.8.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 (64) hide show
  1. package/dist/api.js +4 -5
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CVPvp9dL.js} +47 -5
  3. package/dist/{auth-binding-B4FfbcCg.js → auth-binding-Ds_QVm-X.js} +18 -3
  4. package/dist/{binding-connection-DAvZwp96.js → binding-connection-CCQFs8lf.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-rq5tiSXk.js} +13 -18
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-CGm_94eL.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-C54Yg3eA.js} +2 -2
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-BvOAHTrA.js} +89 -62
  10. package/dist/{compact-COqgBRny.js → compact-Hd7SAc0N.js} +8 -9
  11. package/dist/{config-CpNeo5AE.js → config-Cxw3Cl3k.js} +346 -286
  12. package/dist/doctor-contract-api.js +115 -14
  13. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BFoUcRdx.js} +147 -903
  14. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-BTJHnDSx.js} +2 -2
  15. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  16. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-D3PHFFXh.js} +3 -3
  17. package/dist/{harness-DoKQcF8n.js → harness-DVfUQBlQ.js} +42 -52
  18. package/dist/harness.js +1 -1
  19. package/dist/index.js +278 -295
  20. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cbbx_5Ed.js} +4 -4
  21. package/dist/launch-args-sXOAg0SX.js +84 -0
  22. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  23. package/dist/media-understanding-provider.js +1 -1
  24. package/dist/model-catalog-o6Cgjoss.js +101 -0
  25. package/dist/{models-CZw1wClT.js → models-DgFWSuxA.js} +25 -28
  26. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-CwFyoylz.js} +207 -30
  27. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DXrqpw1c.js} +8 -5
  28. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-D80UZiJ_.js} +1 -1
  29. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-mdmScYOj.js} +30 -39
  30. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CulOABwu.js} +162 -135
  31. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  32. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-hFtzt2Up.js} +1 -1
  33. package/dist/{sandbox-guard-C1qEeZ5C.js → request-CCm4LaED.js} +183 -2
  34. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BwNQDH2u.js} +599 -361
  35. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-DeBvleJw.js} +1 -1
  36. package/dist/{session-binding-BTrLf9Qm.js → session-binding-q2WSTVmC.js} +195 -122
  37. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-C2Tae4rI.js} +229 -122
  38. package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
  39. package/dist/{session-cli-B1hKvfkI.js → session-cli-BuDjm5Ou.js} +1 -1
  40. package/dist/session-permission-policy-gLm40Vtq.js +160 -0
  41. package/dist/session-retirement-CdkI0bvb.js +90 -0
  42. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-Bcy33kam.js} +2 -3
  43. package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-B8JJcxCi.js} +7 -6
  44. package/dist/{shared-client-Dw-rzii0.js → shared-client-kNkljY-R.js} +1720 -786
  45. package/dist/{side-question-DbXkJZzg.js → side-question-GwD73tX6.js} +69 -39
  46. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-Ss-uwnC4.js} +852 -359
  47. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-CeYBqg_4.js} +18 -8
  48. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-DF54hagX.js} +52 -6
  49. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-CkEQIna-.js} +112 -13
  50. package/dist/transport-stdio-C7-s9TLG.js +708 -0
  51. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-BACGlOFa.js} +78 -86
  52. package/dist/{usage-9dKJCgcy.js → usage-C2l8Mils.js} +3 -3
  53. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
  54. package/openclaw.plugin.json +19 -1
  55. package/package.json +8 -8
  56. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  57. package/dist/command-rpc-xUIIonsO.js +0 -90
  58. package/dist/incognito-session-ET_ufDH-.js +0 -2
  59. package/dist/model-catalog-CmGoqVKB.js +0 -48
  60. package/dist/request-DSK0W6YI.js +0 -157
  61. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  62. package/dist/session-retirement-CE4iMiLh.js +0 -36
  63. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  64. package/dist/transport-stdio-DhoGy33Z.js +0 -99
@@ -1,15 +1,20 @@
1
- import { J as releaseCodexAppServerLiveThread, K as isCodexAppServerLiveThreadClaimed, Y as retainCodexAppServerLiveThread, d as retainSharedCodexAppServerClientByInstanceId } from "./shared-client-Dw-rzii0.js";
2
- import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-URjUlCHg.js";
1
+ import { Ct as retainCodexAppServerLiveThread, St as releaseCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientByInstanceId, bt as isCodexAppServerLiveThreadClaimed } from "./shared-client-kNkljY-R.js";
2
+ import { a as closeCodexStartupClientBestEffort, f as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-CVPvp9dL.js";
3
+ import { isIncognitoSessionKey } from "openclaw/plugin-sdk/routing";
3
4
  import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
4
5
  //#region extensions/codex/src/app-server/thread-ownership.ts
5
6
  const nativeThreadOwners = new KeyedAsyncQueue();
7
+ /** Serialize connection-scoped unsubscribe with attach/resume of the same native thread. */
8
+ async function withCodexAppServerThreadMutation(threadId, run) {
9
+ return await nativeThreadOwners.enqueue(`thread:${threadId}`, run);
10
+ }
6
11
  /** Codex subscriptions belong to a physical connection, not the native thread ID alone. */
7
12
  function isSameCodexAppServerThreadOwner(current, expected) {
8
13
  return current !== void 0 && expected !== void 0 && current.threadId === expected.threadId && current.clientId === expected.clientId;
9
14
  }
10
15
  /** Fences native subscription and commit together; Codex subscriptions are not reference-counted. */
11
16
  async function withExclusiveCodexAppServerThread(params) {
12
- return await nativeThreadOwners.enqueue(`thread:${params.threadId}`, async () => {
17
+ return await withCodexAppServerThreadMutation(params.threadId, async () => {
13
18
  if (await params.bindingStore.hasOtherThreadOwner(params.threadId, params.identity)) throw new Error(`Codex thread ${params.threadId} is owned by another OpenClaw session or conversation.`);
14
19
  return await params.run();
15
20
  });
@@ -20,11 +25,13 @@ async function withCodexConversationThreadActivity(bindingId, run) {
20
25
  }
21
26
  /** Publishes one owned persistent subscription into the shared bounded idle registry. */
22
27
  async function retainCodexAppServerBindingSubscription(client, threadId, ownership) {
23
- return await retainCodexAppServerLiveThread(client, threadId, ownership?.release ?? (async (releasedThreadId) => {
28
+ return await retainCodexAppServerLiveThread(client, threadId, ownership?.release ?? (async (releasedThreadId, assertCurrent) => {
24
29
  if (!await unsubscribeCodexThreadBestEffort(client, {
25
30
  threadId: releasedThreadId,
26
- timeoutMs: 5e3
31
+ timeoutMs: 5e3,
32
+ assertCurrent
27
33
  })) {
34
+ assertCurrent?.();
28
35
  await closeCodexStartupClientBestEffort(client);
29
36
  throw new CodexAppServerUnsafeSubscriptionError(`Codex thread subscription could not be released: ${releasedThreadId}`);
30
37
  }
@@ -41,15 +48,18 @@ async function rollbackCodexAppServerBindingSubscription(client, threadId, retai
41
48
  }
42
49
  /** Releases only the physical client and native thread recorded by the displaced binding owner. */
43
50
  async function releaseCodexAppServerBindingSubscription(binding, options = {}) {
51
+ options.assertCurrent?.();
44
52
  const clientLease = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
45
53
  if (!clientLease) return;
46
54
  try {
47
- if (await releaseCodexAppServerLiveThread(clientLease.client, binding.threadId)) return;
55
+ if (await releaseCodexAppServerLiveThread(clientLease.client, binding.threadId, options.assertCurrent)) return;
56
+ options.assertCurrent?.();
48
57
  if (isCodexAppServerLiveThreadClaimed(clientLease.client, binding.threadId)) throw new Error(`Codex thread ${binding.threadId} has an active run; stop it before changing its owner.`);
49
58
  if (!options.allowUntracked) return;
50
59
  if (!await unsubscribeCodexThreadBestEffort(clientLease.client, {
51
60
  threadId: binding.threadId,
52
- timeoutMs: 5e3
61
+ timeoutMs: 5e3,
62
+ assertCurrent: options.assertCurrent
53
63
  })) {
54
64
  await closeCodexStartupClientBestEffort(clientLease.client);
55
65
  throw new CodexAppServerUnsafeSubscriptionError(`Codex retired thread subscription could not be released: ${binding.threadId}`);
@@ -89,4 +99,4 @@ async function retireCodexConversationThreadBinding(params) {
89
99
  });
90
100
  }
91
101
  //#endregion
92
- export { rollbackCodexAppServerBindingSubscription as a, retireCodexConversationThreadBinding as i, releaseCodexAppServerBindingSubscription as n, withCodexConversationThreadActivity as o, retainCodexAppServerBindingSubscription as r, withExclusiveCodexAppServerThread as s, isSameCodexAppServerThreadOwner as t };
102
+ export { rollbackCodexAppServerBindingSubscription as a, withExclusiveCodexAppServerThread as c, retireCodexConversationThreadBinding as i, isIncognitoSessionKey as l, releaseCodexAppServerBindingSubscription as n, withCodexAppServerThreadMutation as o, retainCodexAppServerBindingSubscription as r, withCodexConversationThreadActivity as s, isSameCodexAppServerThreadOwner as t };
@@ -1,5 +1,8 @@
1
- import { x as resolveCodexAppServerUserHomeDir } from "./config-CpNeo5AE.js";
2
- import { ft as resolveCodexAppServerHomeDir, pt as resolveCodexAppServerLocalHomeDir } from "./shared-client-Dw-rzii0.js";
1
+ import { F as resolveCodexAppServerLocalHomeDir, I as resolveCodexAppServerUserHomeDir, P as resolveCodexAppServerHomeDir } from "./config-Cxw3Cl3k.js";
2
+ import { $ as CodexAppServerRpcError, J as isCodexAppServerOverloadError, P as isCodexAppServerStartupError, Y as isCodexAppServerPrewriteRequestCancellationError, u as isCodexAppServerStartSelectionChangedError } from "./shared-client-kNkljY-R.js";
3
+ import { o as assertCodexThreadResumeResponse } from "./protocol-validators-Bg5rpNxk.js";
4
+ import { f as unsubscribeCodexThreadBestEffort, i as assertCodexThreadResumeSubscription, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-CVPvp9dL.js";
5
+ import { t as CodexAppServerScopedRequestRejectedError } from "./request-CCm4LaED.js";
3
6
  import { createRequire } from "node:module";
4
7
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
5
8
  import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
@@ -264,7 +267,10 @@ async function readInstalledApps(request, options) {
264
267
  apps: [],
265
268
  installedApps: []
266
269
  };
267
- const metadataResponses = await Promise.all(Array.from({ length: Math.ceil(apps.length / CODEX_APP_READ_BATCH_LIMIT) }, (_, index) => request("app/read", { appIds: apps.slice(index * CODEX_APP_READ_BATCH_LIMIT, (index + 1) * CODEX_APP_READ_BATCH_LIMIT).map((app) => app.id) })));
270
+ const metadataResponses = await Promise.all(Array.from({ length: Math.ceil(apps.length / CODEX_APP_READ_BATCH_LIMIT) }, (_, index) => request("app/read", {
271
+ appIds: apps.slice(index * CODEX_APP_READ_BATCH_LIMIT, (index + 1) * CODEX_APP_READ_BATCH_LIMIT).map((app) => app.id),
272
+ includeTools: true
273
+ })));
268
274
  const metadataById = new Map(metadataResponses.flatMap((response) => response.apps).map((metadata) => [metadata.id, metadata]));
269
275
  return {
270
276
  apps: apps.flatMap((installedApp) => {
@@ -283,7 +289,8 @@ async function readInstalledApps(request, options) {
283
289
  installUrl: metadata.installUrl ?? null,
284
290
  isAccessible: true,
285
291
  isEnabled: installedApp.enabled,
286
- pluginDisplayNames: metadata.pluginDisplayNames
292
+ pluginDisplayNames: metadata.pluginDisplayNames,
293
+ ...metadata.toolSummaries ? { toolSummaries: metadata.toolSummaries } : {}
287
294
  }];
288
295
  }),
289
296
  installedApps: apps
@@ -348,7 +355,10 @@ function buildCodexPluginAppCacheKey(params) {
348
355
  accountId: params.accountId,
349
356
  envApiKeyFingerprint: params.envApiKeyFingerprint,
350
357
  appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
351
- runtimeIdentity: params.runtimeIdentity
358
+ runtimeIdentity: params.desktopGenerationFingerprint ? {
359
+ ...params.runtimeIdentity,
360
+ desktopGeneration: params.desktopGenerationFingerprint
361
+ } : params.runtimeIdentity
352
362
  }, OPENCLAW_VERSION, CODEX_PLUGIN_VERSION);
353
363
  }
354
364
  /** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
@@ -417,4 +427,40 @@ function fingerprintCodexPluginAppCacheCredentials(startOptions) {
417
427
  return `sha256:${hash.digest("hex")}`;
418
428
  }
419
429
  //#endregion
420
- export { resolveCodexCatalogConnectionHome as a, replaceCodexCatalogConnectionHomes as i, buildCodexAppServerRuntimeFingerprint as n, defaultCodexAppInventoryCache as o, buildCodexPluginAppCacheKey as r, serializeCodexAppInventoryError as s, buildCodexAppServerConnectionFingerprint as t };
430
+ //#region extensions/codex/src/app-server/thread-resume.ts
431
+ /** Owns Codex thread/resume subscription safety. */
432
+ /** Resumes one thread, releasing or isolating every possible native subscription. */
433
+ async function resumeCodexAppServerThread(params) {
434
+ const threadId = params.request.threadId;
435
+ let response;
436
+ try {
437
+ response = assertCodexThreadResumeResponse(await (params.requestResume ? params.requestResume(params.request) : params.client.request("thread/resume", params.request, {
438
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
439
+ ...params.signal ? { signal: params.signal } : {},
440
+ assertCurrent: params.assertCurrent
441
+ })));
442
+ assertCodexThreadResumeSubscription(threadId, response.thread.id);
443
+ } catch (error) {
444
+ if (params.isPrewriteOwnershipError?.(error) || isCodexAppServerStartSelectionChangedError(error) || isCodexAppServerStartupError(error) || error instanceof CodexAppServerScopedRequestRejectedError || isCodexAppServerPrewriteRequestCancellationError(error) || isCodexAppServerOverloadError(error)) throw error;
445
+ if (error instanceof CodexAppServerRpcError) {
446
+ if (await unsubscribeCodexThreadBestEffort(params.client, {
447
+ threadId,
448
+ timeoutMs: 5e3,
449
+ assertCurrent: params.assertCurrent
450
+ }).catch(() => false)) {
451
+ params.onSubscriptionReleased?.();
452
+ throw error;
453
+ }
454
+ }
455
+ try {
456
+ await params.abandonClient();
457
+ } catch (abandonError) {
458
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex thread/resume client could not be retired for ${threadId}`, { cause: abandonError });
459
+ }
460
+ if (error instanceof CodexAppServerUnsafeSubscriptionError) throw error;
461
+ throw new CodexAppServerUnsafeSubscriptionError(error instanceof Error ? error.message : `Codex thread/resume outcome is indeterminate for ${threadId}`, { cause: error });
462
+ }
463
+ return response;
464
+ }
465
+ //#endregion
466
+ export { replaceCodexCatalogConnectionHomes as a, serializeCodexAppInventoryError as c, buildCodexPluginAppCacheKey as i, buildCodexAppServerConnectionFingerprint as n, resolveCodexCatalogConnectionHome as o, buildCodexAppServerRuntimeFingerprint as r, defaultCodexAppInventoryCache as s, resumeCodexAppServerThread as t };
@@ -1,6 +1,6 @@
1
1
  import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
2
2
  import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
- import { embeddedAgentLog, formatErrorMessage, projectAgentHarnessTranscriptMessageForDisplay, runAgentHarnessBeforeMessageWriteHook } from "openclaw/plugin-sdk/agent-harness-runtime";
3
+ import { deliverAgentHarnessUserInputPrompt, embeddedAgentLog, formatErrorMessage, projectAgentHarnessTranscriptMessageForDisplay, runAgentHarnessBeforeMessageWriteHook } from "openclaw/plugin-sdk/agent-harness-runtime";
4
4
  import { createHash } from "node:crypto";
5
5
  import { truncateUtf8Prefix } from "openclaw/plugin-sdk/text-utility-runtime";
6
6
  import { withCodexSessionTranscriptMirrorWriteLock } from "openclaw/plugin-sdk/codex-session-transcript-runtime";
@@ -82,6 +82,8 @@ function projectCodexThreadHistory(params) {
82
82
  const role = item.type === "userMessage" ? "user" : item.type === "agentMessage" ? "assistant" : void 0;
83
83
  itemOffset += 1;
84
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";
85
87
  const message = role === "assistant" ? attachCodexMirrorIdentity({
86
88
  role,
87
89
  content: [{
@@ -94,13 +96,14 @@ function projectCodexThreadHistory(params) {
94
96
  usage: CODEX_HISTORY_ZERO_USAGE,
95
97
  stopReason: turn.status === "interrupted" ? "aborted" : turn.status === "failed" ? "error" : "stop",
96
98
  ...turn.status === "failed" && turn.error?.message ? { errorMessage: turn.error.message } : {},
99
+ ...phase ? { phase } : {},
100
+ ...asyncDelivery && itemId ? { openclawAsyncDelivery: { itemId } } : {},
97
101
  timestamp
98
102
  }, identity) : attachCodexMirrorIdentity({
99
103
  role,
100
104
  content: text,
101
105
  timestamp
102
106
  }, identity);
103
- const phase = item.phase === "commentary" || item.phase === "final_answer" ? item.phase : void 0;
104
107
  projected.push({
105
108
  message,
106
109
  responseItem: {
@@ -141,7 +144,7 @@ function projectBoundedCodexThreadHistory(params) {
141
144
  return {
142
145
  importedMessages: selected.length,
143
146
  omittedMessages: projected.length - selected.length,
144
- 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),
145
148
  transcriptMessages: selected.map(({ message }) => message)
146
149
  };
147
150
  }
@@ -150,7 +153,7 @@ function projectBoundedCodexVisibleSessionHistory(entries) {
150
153
  const projected = [];
151
154
  for (const entry of entries) {
152
155
  if (entry.role !== "user" && entry.role !== "assistant" || !("content" in entry.message)) continue;
153
- 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;
154
157
  const content = entry.message.content;
155
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);
156
159
  if (!text) continue;
@@ -175,6 +178,21 @@ const MIRROR_ORIGIN_META_KEY = "mirrorOrigin";
175
178
  const MIRROR_SOURCE_FINGERPRINT_META_KEY = "mirrorSourceFingerprint";
176
179
  const CODEX_APP_SERVER_MIRROR_ORIGIN = "codex-app-server";
177
180
  const CODEX_META_KEY = "__openclaw";
181
+ function applyCodexTranscriptTaint(message, state) {
182
+ if (message.role === "user") {
183
+ state.tainted = false;
184
+ return message;
185
+ }
186
+ const metadata = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0);
187
+ state.tainted ||= metadata?.turnTainted === true || metadata?.resultContentSource === "network";
188
+ return message.role === "assistant" && state.tainted ? {
189
+ ...message,
190
+ __openclaw: {
191
+ ...metadata,
192
+ turnTainted: true
193
+ }
194
+ } : message;
195
+ }
178
196
  function attachCodexMirrorAttestation(message, sourceFingerprint) {
179
197
  const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
180
198
  const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
@@ -270,6 +288,10 @@ async function buildResolvedCodexUserPromptMessage(params) {
270
288
  function isMirroredAgentMessage(message) {
271
289
  return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
272
290
  }
291
+ function readMirroredAssistantText(message) {
292
+ if (message?.role !== "assistant") return;
293
+ return message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n") || void 0;
294
+ }
273
295
  /** Imports a bounded, user-visible Codex history tail into a new OpenClaw transcript. */
274
296
  async function importCodexThreadHistoryToTranscript(params) {
275
297
  const projection = projectBoundedCodexThreadHistory({
@@ -318,6 +340,7 @@ async function mirrorBestEffort(params) {
318
340
  mirrorIdentity: `${params.turnId}:assistant`,
319
341
  runId: params.params.runId
320
342
  },
343
+ prepareAssistantTranscriptMessage: params.params.prepareAssistantTranscriptMessage,
321
344
  config: params.params.config
322
345
  });
323
346
  for (const receipt of mirrorResult.userMessageReceipts) try {
@@ -431,6 +454,7 @@ function buildMirrorDedupeIdentity(message) {
431
454
  async function mirror(params) {
432
455
  const messages = params.messages.filter(isMirroredAgentMessage);
433
456
  if (messages.length === 0) return {
457
+ assistantMirrorIdentitiesAppended: [],
434
458
  assistantMirrorIdentitiesOwned: [],
435
459
  anchorsByMirrorIdentity: /* @__PURE__ */ new Map(),
436
460
  messagesPresent: [],
@@ -449,11 +473,12 @@ async function mirror(params) {
449
473
  });
450
474
  const candidateIdempotencyKeys = candidates.flatMap(({ idempotencyKey }) => idempotencyKey ? [idempotencyKey] : []);
451
475
  const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
452
- const { appendedUpdates, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
476
+ const { appendedUpdates, assistantMirrorIdentitiesAppended, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
453
477
  ...transcriptTarget,
454
478
  config: params.config
455
479
  }, async (transcript) => {
456
480
  const nextAppendedUpdates = [];
481
+ const nextAssistantMirrorIdentitiesAppended = /* @__PURE__ */ new Set();
457
482
  const nextAssistantMirrorIdentitiesOwned = /* @__PURE__ */ new Set();
458
483
  const nextAnchorsByMirrorIdentity = /* @__PURE__ */ new Map();
459
484
  const nextMessagesPresent = [];
@@ -486,10 +511,12 @@ async function mirror(params) {
486
511
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
487
512
  continue;
488
513
  }
489
- const nextMessage = params.skipBeforeMessageWriteHooks ? transcriptMessage : runAgentHarnessBeforeMessageWriteHook({
514
+ const nextMessage = runAgentHarnessBeforeMessageWriteHook({
490
515
  message: transcriptMessage,
491
516
  agentId: params.agentId,
492
- sessionKey: params.sessionKey
517
+ sessionKey: params.sessionKey,
518
+ skipBeforeMessageWriteHooks: params.skipBeforeMessageWriteHooks,
519
+ prepareAssistantTranscriptMessage: ownsTerminal ? params.prepareAssistantTranscriptMessage : void 0
493
520
  });
494
521
  if (!nextMessage) {
495
522
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
@@ -501,6 +528,7 @@ async function mirror(params) {
501
528
  } : attachCodexMirrorAttestation(nextMessage, sourceFingerprint);
502
529
  if (mirrorIdentity) messageToAppend = attachCodexMirrorIdentity(messageToAppend, mirrorIdentity);
503
530
  if (ownsRun && params.runId) messageToAppend = attachCodexMirrorRunId(messageToAppend, params.runId, ownsTerminal);
531
+ if (message.role === "assistant" && message.openclawAsyncDelivery) messageToAppend = Object.assign(messageToAppend, { openclawAsyncDelivery: { itemId: message.openclawAsyncDelivery.itemId } });
504
532
  messageToAppend = projectAgentHarnessTranscriptMessageForDisplay({
505
533
  hidden: message.display === false,
506
534
  message: messageToAppend
@@ -525,11 +553,14 @@ async function mirror(params) {
525
553
  message: appendedMessage
526
554
  });
527
555
  }
528
- if (appended.appended) nextAppendedUpdates.push({
529
- messageId,
530
- message: appendedMessage,
531
- ...messageSeq !== void 0 ? { messageSeq } : {}
532
- });
556
+ if (appended.appended) {
557
+ if (message.role === "assistant") nextAssistantMirrorIdentitiesAppended.add(dedupeIdentity);
558
+ nextAppendedUpdates.push({
559
+ messageId,
560
+ message: appendedMessage,
561
+ ...messageSeq !== void 0 ? { messageSeq } : {}
562
+ });
563
+ }
533
564
  if (idempotencyKey) {
534
565
  mirrorFacts.existingIdempotencyKeys.add(idempotencyKey);
535
566
  if (appended.anchor) mirrorFacts.anchorsByIdempotencyKey.set(idempotencyKey, appended.anchor);
@@ -537,6 +568,7 @@ async function mirror(params) {
537
568
  }
538
569
  return {
539
570
  appendedUpdates: nextAppendedUpdates,
571
+ assistantMirrorIdentitiesAppended: [...nextAssistantMirrorIdentitiesAppended],
540
572
  assistantMirrorIdentitiesOwned: [...nextAssistantMirrorIdentitiesOwned],
541
573
  anchorsByMirrorIdentity: nextAnchorsByMirrorIdentity,
542
574
  messagesPresent: nextMessagesPresent,
@@ -562,6 +594,7 @@ async function mirror(params) {
562
594
  embeddedAgentLog.warn("failed to publish codex app-server transcript update", { error: formatErrorMessage(error) });
563
595
  }
564
596
  return {
597
+ assistantMirrorIdentitiesAppended,
565
598
  assistantMirrorIdentitiesOwned,
566
599
  anchorsByMirrorIdentity,
567
600
  messagesPresent,
@@ -569,10 +602,76 @@ async function mirror(params) {
569
602
  userMessagesPresent
570
603
  };
571
604
  }
605
+ async function deliverAsyncMessageBestEffort(params) {
606
+ const mirrorIdentity = `${params.turnId}:async:${params.itemId}`;
607
+ const deliveryIntentId = `block-reply:v1:codex-app-server:${[
608
+ params.threadId,
609
+ params.turnId,
610
+ params.itemId
611
+ ].map(encodeURIComponent).join(":")}`;
612
+ const target = params.params.sessionTarget;
613
+ if (!target) {
614
+ if (!params.params.onBlockReply) return "retry";
615
+ try {
616
+ await deliverAsyncBlockReply(params.params.onBlockReply, params.text, deliveryIntentId);
617
+ return "settled";
618
+ } catch (error) {
619
+ embeddedAgentLog.warn("failed to deliver codex async agent message", {
620
+ error: formatErrorMessage(error),
621
+ itemId: params.itemId,
622
+ runId: params.params.runId,
623
+ threadId: params.threadId,
624
+ turnId: params.turnId
625
+ });
626
+ return "retry";
627
+ }
628
+ }
629
+ let result;
630
+ try {
631
+ result = await mirror({
632
+ agentId: target.agentId ?? params.params.agentId,
633
+ sessionId: target.sessionId ?? params.params.sessionId,
634
+ sessionKey: target.sessionKey ?? params.params.sessionKey,
635
+ storePath: target.storePath,
636
+ cwd: params.cwd,
637
+ config: params.params.config,
638
+ messages: [attachCodexMirrorIdentity(params.message, mirrorIdentity)],
639
+ idempotencyScope: `codex-app-server:${params.threadId}`
640
+ });
641
+ } catch (error) {
642
+ embeddedAgentLog.warn("failed to persist codex async agent message", {
643
+ error: formatErrorMessage(error),
644
+ itemId: params.itemId,
645
+ runId: params.params.runId,
646
+ threadId: params.threadId,
647
+ turnId: params.turnId
648
+ });
649
+ return "retry";
650
+ }
651
+ if (!result.assistantMirrorIdentitiesOwned.includes(mirrorIdentity)) return "retry";
652
+ const persistedText = readMirroredAssistantText(result.messagesPresent.find((message) => readMirrorIdentity(message) === mirrorIdentity));
653
+ if (params.params.onBlockReply && persistedText !== void 0) try {
654
+ await deliverAsyncBlockReply(params.params.onBlockReply, persistedText, deliveryIntentId);
655
+ } catch (error) {
656
+ embeddedAgentLog.warn("failed to deliver persisted codex async agent message", {
657
+ error: formatErrorMessage(error),
658
+ itemId: params.itemId,
659
+ runId: params.params.runId,
660
+ threadId: params.threadId,
661
+ turnId: params.turnId
662
+ });
663
+ return "retry";
664
+ }
665
+ return "settled";
666
+ }
572
667
  const codexTranscriptMirrorRuntime = {
668
+ deliverAsyncMessageBestEffort,
573
669
  mirror,
574
670
  mirrorBestEffort
575
671
  };
672
+ async function deliverAsyncBlockReply(onBlockReply, text, deliveryIntentId) {
673
+ await deliverAgentHarnessUserInputPrompt({ onBlockReply: (payload) => onBlockReply(payload, { deliveryIntentId }) }, [], { intro: text });
674
+ }
576
675
  function resolveCodexMirrorTranscriptTarget(params) {
577
676
  const sessionKey = params.sessionKey?.trim();
578
677
  const storePath = params.storePath?.trim();
@@ -585,4 +684,4 @@ function resolveCodexMirrorTranscriptTarget(params) {
585
684
  };
586
685
  }
587
686
  //#endregion
588
- export { buildCodexUserPromptMessage as a, readCodexMirrorSourceFingerprint as c, projectBoundedCodexVisibleSessionHistory as d, mirrorPromptAtTurnStartBestEffort as i, serializeCodexMirrorSourceEvidence as l, createCodexAppServerUserMessagePersistenceNotifier as n, promptSnapshot as o, importCodexThreadHistoryToTranscript as r, fingerprintCodexMirrorSourceMessage as s, codexTranscriptMirrorRuntime as t, projectBoundedCodexThreadHistory as u };
687
+ export { buildCodexUserPromptMessage as a, fingerprintCodexMirrorSourceMessage as c, projectBoundedCodexThreadHistory as d, projectBoundedCodexVisibleSessionHistory as f, mirrorPromptAtTurnStartBestEffort as i, readCodexMirrorSourceFingerprint as l, createCodexAppServerUserMessagePersistenceNotifier as n, promptSnapshot as o, projectCodexUserItemText as p, importCodexThreadHistoryToTranscript as r, applyCodexTranscriptTaint as s, codexTranscriptMirrorRuntime as t, serializeCodexMirrorSourceEvidence as u };