@openclaw/codex 2026.8.1-beta.2 → 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 +146 -0
  2. package/dist/{attempt-client-cleanup-DMLXUfa8.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-I5Bo-AsX.js → binding-connection-CCQFs8lf.js} +15 -3
  5. package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-rq5tiSXk.js} +27 -26
  6. package/dist/{capabilities-CybGI1oz.js → capabilities-CGm_94eL.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-C54Yg3eA.js} +2 -2
  9. package/dist/{command-handlers-Db8pu_ds.js → command-handlers-BvOAHTrA.js} +111 -67
  10. package/dist/{compact-LspQaGfl.js → compact-Hd7SAc0N.js} +35 -30
  11. package/dist/{session-binding-DPxIvMgE.js → config-Cxw3Cl3k.js} +361 -1161
  12. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  13. package/dist/doctor-contract-api.js +128 -26
  14. package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-BFoUcRdx.js} +1341 -1464
  15. package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-BTJHnDSx.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-D3PHFFXh.js} +18 -18
  19. package/dist/harness-DVfUQBlQ.js +248 -0
  20. package/dist/harness.js +2 -226
  21. package/dist/index.js +405 -299
  22. package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cbbx_5Ed.js} +4 -4
  23. package/dist/launch-args-sXOAg0SX.js +84 -0
  24. package/dist/managed-binary-ZkGodW19.js +248 -0
  25. package/dist/media-understanding-provider.js +2 -2
  26. package/dist/model-catalog-o6Cgjoss.js +101 -0
  27. package/dist/{models-BFlpn1Ex.js → models-DgFWSuxA.js} +25 -28
  28. package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-CwFyoylz.js} +385 -94
  29. package/dist/node-exec-server.runtime-DXrqpw1c.js +195 -0
  30. package/dist/plugin-approval-roundtrip-D80UZiJ_.js +95 -0
  31. package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-mdmScYOj.js} +60 -55
  32. package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CulOABwu.js} +164 -134
  33. package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-Bg5rpNxk.js} +203 -7
  34. package/dist/{rate-limits-DZXmOL8-.js → rate-limits-hFtzt2Up.js} +1 -1
  35. package/dist/{sandbox-guard-Cmwc9eIk.js → request-CCm4LaED.js} +207 -20
  36. package/dist/{run-attempt-P8BdxC1I.js → run-attempt-BwNQDH2u.js} +1506 -836
  37. package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-DeBvleJw.js} +4 -7
  38. package/dist/session-binding-q2WSTVmC.js +947 -0
  39. package/dist/{session-catalog-xwNi_SDM.js → session-catalog-C2Tae4rI.js} +1698 -1346
  40. package/dist/session-catalog-home-id-DAKUrm3C.js +112 -0
  41. package/dist/{session-cli-7hgXZDV7.js → session-cli-BuDjm5Ou.js} +20 -7
  42. package/dist/session-permission-policy-gLm40Vtq.js +160 -0
  43. package/dist/session-retirement-CdkI0bvb.js +90 -0
  44. package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-Bcy33kam.js} +2 -3
  45. package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-B8JJcxCi.js} +27 -22
  46. package/dist/{shared-client-kIBbGjk4.js → shared-client-kNkljY-R.js} +2023 -607
  47. package/dist/{side-question-9HAL26l9.js → side-question-GwD73tX6.js} +109 -57
  48. package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-Ss-uwnC4.js} +1208 -497
  49. package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-CeYBqg_4.js} +18 -8
  50. package/dist/{plugin-app-cache-key-C3H2CVp6.js → thread-resume-DF54hagX.js} +64 -6
  51. package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-CkEQIna-.js} +158 -41
  52. package/dist/transport-stdio-C7-s9TLG.js +708 -0
  53. package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
  54. package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-BACGlOFa.js} +86 -88
  55. package/dist/{usage-CHlV0e-o.js → usage-C2l8Mils.js} +3 -3
  56. package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-B2XgRdFv.js} +3 -3
  57. package/openclaw.plugin.json +50 -2
  58. package/package.json +9 -8
  59. package/dist/app-server-policy-zcBDc1JU.js +0 -49
  60. package/dist/incognito-session-ET_ufDH-.js +0 -2
  61. package/dist/request-BRl5_UfX.js +0 -157
  62. package/dist/session-retirement-DoMMJFKm.js +0 -36
  63. package/dist/thread-resume-CPrJNQVM.js +0 -30
  64. package/dist/transport-stdio-DIImwDVS.js +0 -99
@@ -1,15 +1,20 @@
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 { 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 { A as resolveCodexAppServerUserHomeDir } from "./session-binding-DPxIvMgE.js";
2
- import { dt as resolveCodexAppServerLocalHomeDir, ut as resolveCodexAppServerHomeDir } from "./shared-client-kIBbGjk4.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
@@ -331,6 +338,14 @@ function isSensitiveErrorDataKey(key) {
331
338
  * auth, account, and version inputs without storing secret material.
332
339
  */
333
340
  const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require: createRequire(import.meta.url) });
341
+ let catalogConnectionHomes = /* @__PURE__ */ new Map();
342
+ function catalogConnectionHomeKey(fingerprint, agentDir) {
343
+ return `${agentDir ?? ""}\0${fingerprint}`;
344
+ }
345
+ /** Replaces the lifecycle-owned catalog connection snapshot used by supervised bindings. */
346
+ function replaceCodexCatalogConnectionHomes(homes) {
347
+ catalogConnectionHomes = new Map(homes.map((home) => [catalogConnectionHomeKey(home.fingerprint, home.agentDir), home.codexHome]));
348
+ }
334
349
  /** Builds the full app inventory cache key for Codex plugin/app discovery. */
335
350
  function buildCodexPluginAppCacheKey(params) {
336
351
  return buildCodexAppInventoryCacheKey({
@@ -340,7 +355,10 @@ function buildCodexPluginAppCacheKey(params) {
340
355
  accountId: params.accountId,
341
356
  envApiKeyFingerprint: params.envApiKeyFingerprint,
342
357
  appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
343
- runtimeIdentity: params.runtimeIdentity
358
+ runtimeIdentity: params.desktopGenerationFingerprint ? {
359
+ ...params.runtimeIdentity,
360
+ desktopGeneration: params.desktopGenerationFingerprint
361
+ } : params.runtimeIdentity
344
362
  }, OPENCLAW_VERSION, CODEX_PLUGIN_VERSION);
345
363
  }
346
364
  /** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
@@ -364,6 +382,10 @@ function buildCodexAppServerConnectionFingerprint(appServer, agentDir) {
364
382
  cwd: appServer.start.cwd ?? null
365
383
  });
366
384
  }
385
+ /** Looks up a snapshotted catalog store without repeating filesystem discovery on a run. */
386
+ function resolveCodexCatalogConnectionHome(fingerprint, agentDir) {
387
+ return catalogConnectionHomes.get(catalogConnectionHomeKey(fingerprint, agentDir));
388
+ }
367
389
  function resolveCodexAppServerConnectionHome(start, agentDir) {
368
390
  const configured = start.env?.CODEX_HOME?.trim();
369
391
  if (configured) return configured;
@@ -405,4 +427,40 @@ function fingerprintCodexPluginAppCacheCredentials(startOptions) {
405
427
  return `sha256:${hash.digest("hex")}`;
406
428
  }
407
429
  //#endregion
408
- export { serializeCodexAppInventoryError as a, defaultCodexAppInventoryCache as i, buildCodexAppServerRuntimeFingerprint as n, buildCodexPluginAppCacheKey as r, 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,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,61 @@ 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";
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
+ }
186
196
  function attachCodexMirrorAttestation(message, sourceFingerprint) {
187
- const record = message;
188
- const existing = record["__openclaw"];
197
+ const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
189
198
  const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
190
199
  return {
191
- ...record,
192
- __openclaw: {
200
+ ...message,
201
+ [CODEX_META_KEY]: {
193
202
  ...baseMeta,
194
203
  [MIRROR_ORIGIN_META_KEY]: CODEX_APP_SERVER_MIRROR_ORIGIN,
195
204
  ...sourceFingerprint ? { [MIRROR_SOURCE_FINGERPRINT_META_KEY]: sourceFingerprint } : {}
196
205
  }
197
206
  };
198
207
  }
208
+ function attachCodexMirrorRunId(message, runId, terminal = false) {
209
+ const { runTerminal: _staleTerminal, ...current } = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0) ?? {};
210
+ return {
211
+ ...message,
212
+ [CODEX_META_KEY]: {
213
+ ...current,
214
+ runId,
215
+ ...terminal ? { runTerminal: true } : {}
216
+ }
217
+ };
218
+ }
199
219
  function readCodexMirrorSourceFingerprint(message) {
200
- const meta = message["__openclaw"];
220
+ const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
201
221
  if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
202
222
  const value = meta[MIRROR_SOURCE_FINGERPRINT_META_KEY];
203
223
  return typeof value === "string" && value ? value : void 0;
204
224
  }
205
225
  function serializeCodexMirrorSourceEvidence(message) {
206
- const record = message;
226
+ const content = "content" in message ? message.content : void 0;
207
227
  return JSON.stringify({
208
228
  role: message.role,
209
- content: record.content,
229
+ content,
210
230
  ...message.role === "user" ? { upstreamUserText: readUpstreamUserText(message) } : {},
211
231
  ...message.role === "toolResult" ? {
212
- toolCallId: record.toolCallId,
213
- toolName: record.toolName,
214
- isError: record.isError === true
232
+ toolCallId: message.toolCallId,
233
+ toolName: message.toolName,
234
+ isError: message.isError
215
235
  } : {}
216
236
  });
217
237
  }
@@ -247,7 +267,7 @@ function buildFromPrepared(params, preparedUserMessage) {
247
267
  ...senderUsername ? { senderUsername } : {},
248
268
  ...senderE164 ? { senderE164 } : {},
249
269
  ...senderLabel ? { senderLabel } : {},
250
- ...preparedUserMessage ? preparedUserMessage : { content: params.prompt }
270
+ ...preparedUserMessage ?? { content: params.transcriptPrompt ?? params.prompt }
251
271
  };
252
272
  }
253
273
  function buildCodexUserPromptMessage(params) {
@@ -268,6 +288,10 @@ async function buildResolvedCodexUserPromptMessage(params) {
268
288
  function isMirroredAgentMessage(message) {
269
289
  return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
270
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
+ }
271
295
  /** Imports a bounded, user-visible Codex history tail into a new OpenClaw transcript. */
272
296
  async function importCodexThreadHistoryToTranscript(params) {
273
297
  const projection = projectBoundedCodexThreadHistory({
@@ -310,6 +334,13 @@ async function mirrorBestEffort(params) {
310
334
  cwd: params.cwd,
311
335
  messages,
312
336
  idempotencyScope: `codex-app-server:${params.threadId}`,
337
+ runId: params.params.runId,
338
+ runMirrorIdentityPrefix: `${params.turnId}:`,
339
+ terminalAssistantOwner: {
340
+ mirrorIdentity: `${params.turnId}:assistant`,
341
+ runId: params.params.runId
342
+ },
343
+ prepareAssistantTranscriptMessage: params.params.prepareAssistantTranscriptMessage,
313
344
  config: params.params.config
314
345
  });
315
346
  for (const receipt of mirrorResult.userMessageReceipts) try {
@@ -327,8 +358,9 @@ async function mirrorBestEffort(params) {
327
358
  return identity !== void 0 && readCodexMirrorSourceFingerprint(message) === expectedFingerprints.get(identity);
328
359
  });
329
360
  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);
361
+ const assistantTranscriptMessage = mirroredMessages.find((message) => readMirrorIdentity(message) === assistantMirrorIdentity);
362
+ const assistantTranscriptOwned = Boolean(assistantTranscriptMessage && mirrorResult.assistantMirrorIdentitiesOwned.includes(assistantMirrorIdentity));
363
+ const assistantTranscriptIdempotencyKey = normalizeOptionalString(assistantTranscriptMessage?.idempotencyKey);
332
364
  const terminalMessage = mirroredMessages.at(-1);
333
365
  const terminalMirrorIdentity = terminalMessage ? readMirrorIdentity(terminalMessage) : void 0;
334
366
  const terminalAnchor = (terminalMirrorIdentity ? mirrorResult.anchorsByMirrorIdentity.get(terminalMirrorIdentity) : void 0) ?? params.params.userTurnTranscriptRecorder?.getAdmissionReceipt();
@@ -391,6 +423,8 @@ async function mirrorPromptAtTurnStartBestEffort(params) {
391
423
  cwd: params.cwd,
392
424
  messages: [userPromptMessage],
393
425
  idempotencyScope: `codex-app-server:${params.threadId}`,
426
+ runId: params.params.runId,
427
+ runMirrorIdentityPrefix: `${params.turnId}:`,
394
428
  config: params.params.config
395
429
  });
396
430
  for (const receipt of mirrorResult.userMessageReceipts) params.notifyUserMessagePersisted(receipt.message, receipt.anchor);
@@ -420,6 +454,7 @@ function buildMirrorDedupeIdentity(message) {
420
454
  async function mirror(params) {
421
455
  const messages = params.messages.filter(isMirroredAgentMessage);
422
456
  if (messages.length === 0) return {
457
+ assistantMirrorIdentitiesAppended: [],
423
458
  assistantMirrorIdentitiesOwned: [],
424
459
  anchorsByMirrorIdentity: /* @__PURE__ */ new Map(),
425
460
  messagesPresent: [],
@@ -431,18 +466,19 @@ async function mirror(params) {
431
466
  const sourceFingerprint = fingerprintCodexMirrorSourceMessage(message);
432
467
  return {
433
468
  dedupeIdentity,
434
- idempotencyKey: (message.role === "user" ? normalizeOptionalString(message.idempotencyKey) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0),
469
+ idempotencyKey: (message.role === "user" ? normalizeOptionalString("idempotencyKey" in message ? message.idempotencyKey : void 0) : void 0) ?? (params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0),
435
470
  message,
436
471
  sourceFingerprint
437
472
  };
438
473
  });
439
474
  const candidateIdempotencyKeys = candidates.flatMap(({ idempotencyKey }) => idempotencyKey ? [idempotencyKey] : []);
440
475
  const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
441
- const { appendedUpdates, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
476
+ const { appendedUpdates, assistantMirrorIdentitiesAppended, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
442
477
  ...transcriptTarget,
443
478
  config: params.config
444
479
  }, async (transcript) => {
445
480
  const nextAppendedUpdates = [];
481
+ const nextAssistantMirrorIdentitiesAppended = /* @__PURE__ */ new Set();
446
482
  const nextAssistantMirrorIdentitiesOwned = /* @__PURE__ */ new Set();
447
483
  const nextAnchorsByMirrorIdentity = /* @__PURE__ */ new Map();
448
484
  const nextMessagesPresent = [];
@@ -450,8 +486,12 @@ async function mirror(params) {
450
486
  const nextUserMessagesPresent = [];
451
487
  const mirrorFacts = await transcript.readMessageFacts({ idempotencyKeys: candidateIdempotencyKeys });
452
488
  for (const { dedupeIdentity, idempotencyKey, message, sourceFingerprint } of candidates) {
489
+ const mirrorIdentity = readMirrorIdentity(message);
490
+ const ownsRun = Boolean(params.runId && (!params.runMirrorIdentityPrefix || mirrorIdentity?.startsWith(params.runMirrorIdentityPrefix)));
491
+ const terminalOwner = params.terminalAssistantOwner;
492
+ const ownsTerminal = Boolean(ownsRun && terminalOwner && mirrorIdentity === terminalOwner.mirrorIdentity);
453
493
  const transcriptMessage = {
454
- ...attachCodexMirrorAttestation(message, sourceFingerprint),
494
+ ...attachCodexMirrorAttestation(ownsRun && params.runId ? attachCodexMirrorRunId(message, params.runId, ownsTerminal) : message, sourceFingerprint),
455
495
  ...idempotencyKey ? { idempotencyKey } : {}
456
496
  };
457
497
  if (idempotencyKey && mirrorFacts.existingIdempotencyKeys.has(idempotencyKey)) {
@@ -471,10 +511,12 @@ async function mirror(params) {
471
511
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
472
512
  continue;
473
513
  }
474
- const nextMessage = params.skipBeforeMessageWriteHooks ? transcriptMessage : runAgentHarnessBeforeMessageWriteHook({
514
+ const nextMessage = runAgentHarnessBeforeMessageWriteHook({
475
515
  message: transcriptMessage,
476
516
  agentId: params.agentId,
477
- sessionKey: params.sessionKey
517
+ sessionKey: params.sessionKey,
518
+ skipBeforeMessageWriteHooks: params.skipBeforeMessageWriteHooks,
519
+ prepareAssistantTranscriptMessage: ownsTerminal ? params.prepareAssistantTranscriptMessage : void 0
478
520
  });
479
521
  if (!nextMessage) {
480
522
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
@@ -484,8 +526,9 @@ async function mirror(params) {
484
526
  ...attachCodexMirrorAttestation(nextMessage, sourceFingerprint),
485
527
  idempotencyKey
486
528
  } : attachCodexMirrorAttestation(nextMessage, sourceFingerprint);
487
- const mirrorIdentity = readMirrorIdentity(message);
488
529
  if (mirrorIdentity) messageToAppend = attachCodexMirrorIdentity(messageToAppend, mirrorIdentity);
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 } });
489
532
  messageToAppend = projectAgentHarnessTranscriptMessageForDisplay({
490
533
  hidden: message.display === false,
491
534
  message: messageToAppend
@@ -510,11 +553,14 @@ async function mirror(params) {
510
553
  message: appendedMessage
511
554
  });
512
555
  }
513
- if (appended.appended) nextAppendedUpdates.push({
514
- messageId,
515
- message: appendedMessage,
516
- ...messageSeq !== void 0 ? { messageSeq } : {}
517
- });
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
+ }
518
564
  if (idempotencyKey) {
519
565
  mirrorFacts.existingIdempotencyKeys.add(idempotencyKey);
520
566
  if (appended.anchor) mirrorFacts.anchorsByIdempotencyKey.set(idempotencyKey, appended.anchor);
@@ -522,6 +568,7 @@ async function mirror(params) {
522
568
  }
523
569
  return {
524
570
  appendedUpdates: nextAppendedUpdates,
571
+ assistantMirrorIdentitiesAppended: [...nextAssistantMirrorIdentitiesAppended],
525
572
  assistantMirrorIdentitiesOwned: [...nextAssistantMirrorIdentitiesOwned],
526
573
  anchorsByMirrorIdentity: nextAnchorsByMirrorIdentity,
527
574
  messagesPresent: nextMessagesPresent,
@@ -530,6 +577,8 @@ async function mirror(params) {
530
577
  };
531
578
  });
532
579
  for (const update of appendedUpdates) try {
580
+ const terminalOwner = params.terminalAssistantOwner;
581
+ const terminalRunId = update.message.role === "assistant" && terminalOwner && readMirrorIdentity(update.message) === terminalOwner.mirrorIdentity ? terminalOwner.runId : void 0;
533
582
  await publishSessionTranscriptUpdateByIdentity({
534
583
  ...transcriptTarget,
535
584
  update: {
@@ -537,6 +586,7 @@ async function mirror(params) {
537
586
  message: update.message,
538
587
  messageId: update.messageId,
539
588
  ...update.messageSeq !== void 0 ? { messageSeq: update.messageSeq } : {},
589
+ ...terminalRunId ? { runId: terminalRunId } : {},
540
590
  sessionKey: transcriptTarget.sessionKey
541
591
  }
542
592
  });
@@ -544,6 +594,7 @@ async function mirror(params) {
544
594
  embeddedAgentLog.warn("failed to publish codex app-server transcript update", { error: formatErrorMessage(error) });
545
595
  }
546
596
  return {
597
+ assistantMirrorIdentitiesAppended,
547
598
  assistantMirrorIdentitiesOwned,
548
599
  anchorsByMirrorIdentity,
549
600
  messagesPresent,
@@ -551,10 +602,76 @@ async function mirror(params) {
551
602
  userMessagesPresent
552
603
  };
553
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
+ }
554
667
  const codexTranscriptMirrorRuntime = {
668
+ deliverAsyncMessageBestEffort,
555
669
  mirror,
556
670
  mirrorBestEffort
557
671
  };
672
+ async function deliverAsyncBlockReply(onBlockReply, text, deliveryIntentId) {
673
+ await deliverAgentHarnessUserInputPrompt({ onBlockReply: (payload) => onBlockReply(payload, { deliveryIntentId }) }, [], { intro: text });
674
+ }
558
675
  function resolveCodexMirrorTranscriptTarget(params) {
559
676
  const sessionKey = params.sessionKey?.trim();
560
677
  const storePath = params.storePath?.trim();
@@ -567,4 +684,4 @@ function resolveCodexMirrorTranscriptTarget(params) {
567
684
  };
568
685
  }
569
686
  //#endregion
570
- 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 };