@openclaw/codex 2026.8.1-beta.3 → 2026.8.2

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 (69) hide show
  1. package/dist/api.js +5 -6
  2. package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-CpVfwctT.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-CF7BmrDk.js} +2 -2
  5. package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-DRC3hcjm.js} +16 -20
  6. package/dist/{capabilities-CH3K57v4.js → capabilities-D6m_TdVy.js} +1 -1
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-D0nZ3qtd.js → command-formatters--UToCokS.js} +4 -3
  9. package/dist/{command-handlers-DC86lgT4.js → command-handlers-CLFx2Ypa.js} +114 -79
  10. package/dist/{compact-COqgBRny.js → compact-5xqW1oCh.js} +13 -12
  11. package/dist/{config-CpNeo5AE.js → config-CcYL77O6.js} +350 -288
  12. package/dist/{conversation-binding-data-CW2GuupV.js → conversation-binding-data-BiodpIzq.js} +2 -1
  13. package/dist/doctor-contract-api.js +121 -16
  14. package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-BmeXjwNZ.js} +243 -1002
  15. package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-XXQKgK1U.js} +2 -2
  16. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  17. package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-B2r5vhWH.js} +9 -14
  18. package/dist/{harness-DoKQcF8n.js → harness-BgeB7LnD.js} +42 -52
  19. package/dist/harness.js +1 -1
  20. package/dist/index.js +308 -306
  21. package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-CxTus3vZ.js} +4 -4
  22. package/dist/launch-args-sXOAg0SX.js +84 -0
  23. package/dist/{managed-binary-By4FZC6i.js → managed-binary-ZkGodW19.js} +43 -7
  24. package/dist/media-understanding-provider.js +1 -1
  25. package/dist/model-catalog-DULBcniB.js +101 -0
  26. package/dist/{models-CZw1wClT.js → models-DaWfETQk.js} +27 -29
  27. package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-vXYUZH37.js} +226 -129
  28. package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-DirKVZ5h.js} +9 -6
  29. package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-CCWQGlAI.js} +2 -1
  30. package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-BXjIFEiw.js} +38 -46
  31. package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-DQQm4gWT.js} +163 -136
  32. package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-Bg5rpNxk.js} +148 -5
  33. package/dist/{rate-limits-BI1dMHDG.js → rate-limits-BqHEHXQJ.js} +3 -2
  34. package/dist/{sandbox-guard-C1qEeZ5C.js → request-BWxweEdK.js} +183 -2
  35. package/dist/{run-attempt-BV3HzuCf.js → run-attempt-BVLE4Gbi.js} +706 -517
  36. package/dist/{runtime-artifact-BvyT1uyd.js → runtime-artifact-D9pYp4zL.js} +3 -3
  37. package/dist/{session-binding-BTrLf9Qm.js → session-binding-D0zinCP1.js} +195 -122
  38. package/dist/{session-catalog-ezP_UcRM.js → session-catalog-eMhVm0Ql.js} +448 -313
  39. package/dist/session-catalog-home-id-Dt2GiG5o.js +112 -0
  40. package/dist/{session-cli-B1hKvfkI.js → session-cli-B2lyjJA0.js} +1 -1
  41. package/dist/session-history-C5J1AKzG.js +87 -0
  42. package/dist/session-permission-policy-ScnAyG90.js +160 -0
  43. package/dist/session-retirement-CtUtUTr9.js +90 -0
  44. package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-gqrYIRHk.js} +2 -3
  45. package/dist/settled-turn-context-Bk3IUwod.js +290 -0
  46. package/dist/settled-turn-finalizer-BXLN9PfJ.js +104 -0
  47. package/dist/{shared-client-Dw-rzii0.js → shared-client-B1tT5U6r.js} +1738 -806
  48. package/dist/{side-question-DbXkJZzg.js → side-question-CZ-mCw-t.js} +76 -43
  49. package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-CGGKP720.js} +991 -455
  50. package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-RkaoZCmQ.js} +18 -8
  51. package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → thread-resume-BFt1-ZDa.js} +55 -8
  52. package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-1ep4XjzF.js} +124 -18
  53. package/dist/transport-stdio-NT_Dpd9V.js +724 -0
  54. package/dist/{upstream-prompt-provenance-CFmsKwr9.js → upstream-prompt-provenance-LphB8slG.js} +8 -4
  55. package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-Dc8BFExw.js} +76 -90
  56. package/dist/{usage-9dKJCgcy.js → usage-DUhd58gI.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-BEmlE7ov.js} +3 -3
  58. package/openclaw.plugin.json +19 -1
  59. package/package.json +8 -8
  60. package/dist/app-server-policy-bg5QPSVP.js +0 -25
  61. package/dist/command-rpc-xUIIonsO.js +0 -90
  62. package/dist/incognito-session-ET_ufDH-.js +0 -2
  63. package/dist/model-catalog-CmGoqVKB.js +0 -48
  64. package/dist/request-DSK0W6YI.js +0 -157
  65. package/dist/session-catalog-home-id-BNwAJ9D7.js +0 -18
  66. package/dist/session-retirement-CE4iMiLh.js +0 -36
  67. package/dist/settled-turn-finalizer-Dx1onIqg.js +0 -328
  68. package/dist/thread-resume-CdJk2Ehf.js +0 -30
  69. 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-B1tT5U6r.js";
2
+ import { a as closeCodexStartupClientBestEffort, f as unsubscribeCodexThreadBestEffort, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-CpVfwctT.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-CcYL77O6.js";
2
+ import { $ as CodexAppServerRpcError, J as isCodexAppServerOverloadError, P as isCodexAppServerStartupError, Y as isCodexAppServerPrewriteRequestCancellationError, u as isCodexAppServerStartSelectionChangedError } from "./shared-client-B1tT5U6r.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-CpVfwctT.js";
5
+ import { t as CodexAppServerScopedRequestRejectedError } from "./request-BWxweEdK.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";
@@ -13,7 +16,7 @@ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
13
16
  * identity and safe to refresh in the background.
14
17
  */
15
18
  /** Default app inventory cache freshness window. */
16
- const CODEX_APP_INVENTORY_CACHE_TTL_MS = 3600 * 1e3;
19
+ const CODEX_APP_INVENTORY_CACHE_TTL_MS = 36e5;
17
20
  const CODEX_APP_READ_BATCH_LIMIT = 100;
18
21
  const MAX_SERIALIZED_ERROR_MESSAGE_LENGTH = 500;
19
22
  /** In-memory app inventory cache with coalesced refreshes per key. */
@@ -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
@@ -330,7 +337,8 @@ function isSensitiveErrorDataKey(key) {
330
337
  * Builds stable Codex plugin/app inventory cache keys from app-server startup,
331
338
  * auth, account, and version inputs without storing secret material.
332
339
  */
333
- const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require: createRequire(import.meta.url) });
340
+ const require = createRequire(import.meta.url);
341
+ const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require });
334
342
  let catalogConnectionHomes = /* @__PURE__ */ new Map();
335
343
  function catalogConnectionHomeKey(fingerprint, agentDir) {
336
344
  return `${agentDir ?? ""}\0${fingerprint}`;
@@ -348,7 +356,10 @@ function buildCodexPluginAppCacheKey(params) {
348
356
  accountId: params.accountId,
349
357
  envApiKeyFingerprint: params.envApiKeyFingerprint,
350
358
  appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
351
- runtimeIdentity: params.runtimeIdentity
359
+ runtimeIdentity: params.desktopGenerationFingerprint ? {
360
+ ...params.runtimeIdentity,
361
+ desktopGeneration: params.desktopGenerationFingerprint
362
+ } : params.runtimeIdentity
352
363
  }, OPENCLAW_VERSION, CODEX_PLUGIN_VERSION);
353
364
  }
354
365
  /** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
@@ -417,4 +428,40 @@ function fingerprintCodexPluginAppCacheCredentials(startOptions) {
417
428
  return `sha256:${hash.digest("hex")}`;
418
429
  }
419
430
  //#endregion
420
- export { resolveCodexCatalogConnectionHome as a, replaceCodexCatalogConnectionHomes as i, buildCodexAppServerRuntimeFingerprint as n, defaultCodexAppInventoryCache as o, buildCodexPluginAppCacheKey as r, serializeCodexAppInventoryError as s, buildCodexAppServerConnectionFingerprint as t };
431
+ //#region extensions/codex/src/app-server/thread-resume.ts
432
+ /** Owns Codex thread/resume subscription safety. */
433
+ /** Resumes one thread, releasing or isolating every possible native subscription. */
434
+ async function resumeCodexAppServerThread(params) {
435
+ const threadId = params.request.threadId;
436
+ let response;
437
+ try {
438
+ response = assertCodexThreadResumeResponse(await (params.requestResume ? params.requestResume(params.request) : params.client.request("thread/resume", params.request, {
439
+ ...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
440
+ ...params.signal ? { signal: params.signal } : {},
441
+ assertCurrent: params.assertCurrent
442
+ })));
443
+ assertCodexThreadResumeSubscription(threadId, response.thread.id);
444
+ } catch (error) {
445
+ if (params.isPrewriteOwnershipError?.(error) || isCodexAppServerStartSelectionChangedError(error) || isCodexAppServerStartupError(error) || error instanceof CodexAppServerScopedRequestRejectedError || isCodexAppServerPrewriteRequestCancellationError(error) || isCodexAppServerOverloadError(error)) throw error;
446
+ if (error instanceof CodexAppServerRpcError) {
447
+ if (await unsubscribeCodexThreadBestEffort(params.client, {
448
+ threadId,
449
+ timeoutMs: 5e3,
450
+ assertCurrent: params.assertCurrent
451
+ }).catch(() => false)) {
452
+ params.onSubscriptionReleased?.();
453
+ throw error;
454
+ }
455
+ }
456
+ try {
457
+ await params.abandonClient();
458
+ } catch (abandonError) {
459
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex thread/resume client could not be retired for ${threadId}`, { cause: abandonError });
460
+ }
461
+ if (error instanceof CodexAppServerUnsafeSubscriptionError) throw error;
462
+ throw new CodexAppServerUnsafeSubscriptionError(error instanceof Error ? error.message : `Codex thread/resume outcome is indeterminate for ${threadId}`, { cause: error });
463
+ }
464
+ return response;
465
+ }
466
+ //#endregion
467
+ 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
- import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
1
+ import { i as readUpstreamUserText, n as attachUpstreamUserText, r as readMirrorIdentity, t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.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";
@@ -8,8 +8,8 @@ import { publishSessionTranscriptUpdateByIdentity } from "openclaw/plugin-sdk/se
8
8
  import { Buffer } from "node:buffer";
9
9
  //#region extensions/codex/src/app-server/transcript-history-projection.ts
10
10
  const CODEX_HISTORY_IMPORT_MAX_MESSAGES = 200;
11
- const CODEX_HISTORY_IMPORT_MAX_BYTES = 512 * 1024;
12
- const CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES = 64 * 1024;
11
+ const CODEX_HISTORY_IMPORT_MAX_BYTES = 524288;
12
+ const CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES = 65536;
13
13
  const CODEX_HISTORY_TRUNCATION_SUFFIX = "\n\n[Message truncated during Codex history import.]";
14
14
  const CODEX_HISTORY_ASSISTANT_API = "openai-chatgpt-responses";
15
15
  const CODEX_HISTORY_ASSISTANT_PROVIDER = "openai";
@@ -34,7 +34,8 @@ function normalizeImportedHistoryText(value) {
34
34
  if (!text) return;
35
35
  if (Buffer.byteLength(text, "utf8") <= CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES) return text;
36
36
  const suffixBytes = Buffer.byteLength(CODEX_HISTORY_TRUNCATION_SUFFIX, "utf8");
37
- return `${truncateUtf8Prefix(text, Math.max(0, CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES - suffixBytes))}${CODEX_HISTORY_TRUNCATION_SUFFIX}`;
37
+ const contentLimitBytes = Math.max(0, CODEX_HISTORY_IMPORT_MAX_MESSAGE_BYTES - suffixBytes);
38
+ return `${truncateUtf8Prefix(text, contentLimitBytes)}${CODEX_HISTORY_TRUNCATION_SUFFIX}`;
38
39
  }
39
40
  function projectCodexUserItemText(item) {
40
41
  if (!Array.isArray(item.content)) return;
@@ -82,6 +83,8 @@ function projectCodexThreadHistory(params) {
82
83
  const role = item.type === "userMessage" ? "user" : item.type === "agentMessage" ? "assistant" : void 0;
83
84
  itemOffset += 1;
84
85
  if (!text || !role) continue;
86
+ const phase = item.phase === "commentary" || item.phase === "final_answer" ? item.phase : void 0;
87
+ const asyncDelivery = item.delivery === "async";
85
88
  const message = role === "assistant" ? attachCodexMirrorIdentity({
86
89
  role,
87
90
  content: [{
@@ -94,13 +97,14 @@ function projectCodexThreadHistory(params) {
94
97
  usage: CODEX_HISTORY_ZERO_USAGE,
95
98
  stopReason: turn.status === "interrupted" ? "aborted" : turn.status === "failed" ? "error" : "stop",
96
99
  ...turn.status === "failed" && turn.error?.message ? { errorMessage: turn.error.message } : {},
100
+ ...phase ? { phase } : {},
101
+ ...asyncDelivery && itemId ? { openclawAsyncDelivery: { itemId } } : {},
97
102
  timestamp
98
103
  }, identity) : attachCodexMirrorIdentity({
99
104
  role,
100
105
  content: text,
101
106
  timestamp
102
107
  }, identity);
103
- const phase = item.phase === "commentary" || item.phase === "final_answer" ? item.phase : void 0;
104
108
  projected.push({
105
109
  message,
106
110
  responseItem: {
@@ -141,7 +145,7 @@ function projectBoundedCodexThreadHistory(params) {
141
145
  return {
142
146
  importedMessages: selected.length,
143
147
  omittedMessages: projected.length - selected.length,
144
- responseItems: selected.filter(({ message }) => message.role !== "assistant" || message.stopReason !== "aborted" && message.stopReason !== "error").map(({ responseItem }) => responseItem),
148
+ responseItems: selected.filter(({ message }) => message.role !== "assistant" || message.stopReason !== "aborted" && message.stopReason !== "error" && !("openclawAsyncDelivery" in message)).map(({ responseItem }) => responseItem),
145
149
  transcriptMessages: selected.map(({ message }) => message)
146
150
  };
147
151
  }
@@ -150,7 +154,7 @@ function projectBoundedCodexVisibleSessionHistory(entries) {
150
154
  const projected = [];
151
155
  for (const entry of entries) {
152
156
  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;
157
+ if (entry.role === "assistant" && ("stopReason" in entry.message && (entry.message.stopReason === "aborted" || entry.message.stopReason === "error") || "openclawAsyncDelivery" in entry.message)) continue;
154
158
  const content = entry.message.content;
155
159
  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
160
  if (!text) continue;
@@ -175,6 +179,22 @@ const MIRROR_ORIGIN_META_KEY = "mirrorOrigin";
175
179
  const MIRROR_SOURCE_FINGERPRINT_META_KEY = "mirrorSourceFingerprint";
176
180
  const CODEX_APP_SERVER_MIRROR_ORIGIN = "codex-app-server";
177
181
  const CODEX_META_KEY = "__openclaw";
182
+ function applyCodexTranscriptTaint(message, state) {
183
+ if (message.role === "user") {
184
+ state.tainted = false;
185
+ return message;
186
+ }
187
+ const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
188
+ const metadata = asOptionalRecord(existing);
189
+ state.tainted ||= metadata?.turnTainted === true || metadata?.resultContentSource === "network";
190
+ return message.role === "assistant" && state.tainted ? {
191
+ ...message,
192
+ __openclaw: {
193
+ ...metadata,
194
+ turnTainted: true
195
+ }
196
+ } : message;
197
+ }
178
198
  function attachCodexMirrorAttestation(message, sourceFingerprint) {
179
199
  const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
180
200
  const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
@@ -188,7 +208,8 @@ function attachCodexMirrorAttestation(message, sourceFingerprint) {
188
208
  };
189
209
  }
190
210
  function attachCodexMirrorRunId(message, runId, terminal = false) {
191
- const { runTerminal: _staleTerminal, ...current } = asOptionalRecord(CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0) ?? {};
211
+ const existing = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
212
+ const { runTerminal: _staleTerminal, ...current } = asOptionalRecord(existing) ?? {};
192
213
  return {
193
214
  ...message,
194
215
  [CODEX_META_KEY]: {
@@ -198,6 +219,10 @@ function attachCodexMirrorRunId(message, runId, terminal = false) {
198
219
  }
199
220
  };
200
221
  }
222
+ function hasCodexMirrorOrigin(message) {
223
+ const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
224
+ return asOptionalRecord(meta)?.[MIRROR_ORIGIN_META_KEY] === CODEX_APP_SERVER_MIRROR_ORIGIN;
225
+ }
201
226
  function readCodexMirrorSourceFingerprint(message) {
202
227
  const meta = CODEX_META_KEY in message ? message[CODEX_META_KEY] : void 0;
203
228
  if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
@@ -270,6 +295,10 @@ async function buildResolvedCodexUserPromptMessage(params) {
270
295
  function isMirroredAgentMessage(message) {
271
296
  return message.role === "user" || message.role === "assistant" || message.role === "toolResult";
272
297
  }
298
+ function readMirroredAssistantText(message) {
299
+ if (message?.role !== "assistant") return;
300
+ return message.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n") || void 0;
301
+ }
273
302
  /** Imports a bounded, user-visible Codex history tail into a new OpenClaw transcript. */
274
303
  async function importCodexThreadHistoryToTranscript(params) {
275
304
  const projection = projectBoundedCodexThreadHistory({
@@ -318,6 +347,7 @@ async function mirrorBestEffort(params) {
318
347
  mirrorIdentity: `${params.turnId}:assistant`,
319
348
  runId: params.params.runId
320
349
  },
350
+ prepareAssistantTranscriptMessage: params.params.prepareAssistantTranscriptMessage,
321
351
  config: params.params.config
322
352
  });
323
353
  for (const receipt of mirrorResult.userMessageReceipts) try {
@@ -431,6 +461,7 @@ function buildMirrorDedupeIdentity(message) {
431
461
  async function mirror(params) {
432
462
  const messages = params.messages.filter(isMirroredAgentMessage);
433
463
  if (messages.length === 0) return {
464
+ assistantMirrorIdentitiesAppended: [],
434
465
  assistantMirrorIdentitiesOwned: [],
435
466
  anchorsByMirrorIdentity: /* @__PURE__ */ new Map(),
436
467
  messagesPresent: [],
@@ -449,11 +480,12 @@ async function mirror(params) {
449
480
  });
450
481
  const candidateIdempotencyKeys = candidates.flatMap(({ idempotencyKey }) => idempotencyKey ? [idempotencyKey] : []);
451
482
  const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
452
- const { appendedUpdates, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
483
+ const { appendedUpdates, assistantMirrorIdentitiesAppended, assistantMirrorIdentitiesOwned, anchorsByMirrorIdentity, messagesPresent, userMessageReceipts, userMessagesPresent } = await withCodexSessionTranscriptMirrorWriteLock({
453
484
  ...transcriptTarget,
454
485
  config: params.config
455
486
  }, async (transcript) => {
456
487
  const nextAppendedUpdates = [];
488
+ const nextAssistantMirrorIdentitiesAppended = /* @__PURE__ */ new Set();
457
489
  const nextAssistantMirrorIdentitiesOwned = /* @__PURE__ */ new Set();
458
490
  const nextAnchorsByMirrorIdentity = /* @__PURE__ */ new Map();
459
491
  const nextMessagesPresent = [];
@@ -486,10 +518,12 @@ async function mirror(params) {
486
518
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
487
519
  continue;
488
520
  }
489
- const nextMessage = params.skipBeforeMessageWriteHooks ? transcriptMessage : runAgentHarnessBeforeMessageWriteHook({
521
+ const nextMessage = runAgentHarnessBeforeMessageWriteHook({
490
522
  message: transcriptMessage,
491
523
  agentId: params.agentId,
492
- sessionKey: params.sessionKey
524
+ sessionKey: params.sessionKey,
525
+ skipBeforeMessageWriteHooks: params.skipBeforeMessageWriteHooks,
526
+ prepareAssistantTranscriptMessage: ownsTerminal ? params.prepareAssistantTranscriptMessage : void 0
493
527
  });
494
528
  if (!nextMessage) {
495
529
  if (message.role === "assistant") nextAssistantMirrorIdentitiesOwned.add(dedupeIdentity);
@@ -501,6 +535,7 @@ async function mirror(params) {
501
535
  } : attachCodexMirrorAttestation(nextMessage, sourceFingerprint);
502
536
  if (mirrorIdentity) messageToAppend = attachCodexMirrorIdentity(messageToAppend, mirrorIdentity);
503
537
  if (ownsRun && params.runId) messageToAppend = attachCodexMirrorRunId(messageToAppend, params.runId, ownsTerminal);
538
+ if (message.role === "assistant" && message.openclawAsyncDelivery) messageToAppend = Object.assign(messageToAppend, { openclawAsyncDelivery: { itemId: message.openclawAsyncDelivery.itemId } });
504
539
  messageToAppend = projectAgentHarnessTranscriptMessageForDisplay({
505
540
  hidden: message.display === false,
506
541
  message: messageToAppend
@@ -525,11 +560,14 @@ async function mirror(params) {
525
560
  message: appendedMessage
526
561
  });
527
562
  }
528
- if (appended.appended) nextAppendedUpdates.push({
529
- messageId,
530
- message: appendedMessage,
531
- ...messageSeq !== void 0 ? { messageSeq } : {}
532
- });
563
+ if (appended.appended) {
564
+ if (message.role === "assistant") nextAssistantMirrorIdentitiesAppended.add(dedupeIdentity);
565
+ nextAppendedUpdates.push({
566
+ messageId,
567
+ message: appendedMessage,
568
+ ...messageSeq !== void 0 ? { messageSeq } : {}
569
+ });
570
+ }
533
571
  if (idempotencyKey) {
534
572
  mirrorFacts.existingIdempotencyKeys.add(idempotencyKey);
535
573
  if (appended.anchor) mirrorFacts.anchorsByIdempotencyKey.set(idempotencyKey, appended.anchor);
@@ -537,6 +575,7 @@ async function mirror(params) {
537
575
  }
538
576
  return {
539
577
  appendedUpdates: nextAppendedUpdates,
578
+ assistantMirrorIdentitiesAppended: [...nextAssistantMirrorIdentitiesAppended],
540
579
  assistantMirrorIdentitiesOwned: [...nextAssistantMirrorIdentitiesOwned],
541
580
  anchorsByMirrorIdentity: nextAnchorsByMirrorIdentity,
542
581
  messagesPresent: nextMessagesPresent,
@@ -562,6 +601,7 @@ async function mirror(params) {
562
601
  embeddedAgentLog.warn("failed to publish codex app-server transcript update", { error: formatErrorMessage(error) });
563
602
  }
564
603
  return {
604
+ assistantMirrorIdentitiesAppended,
565
605
  assistantMirrorIdentitiesOwned,
566
606
  anchorsByMirrorIdentity,
567
607
  messagesPresent,
@@ -569,10 +609,76 @@ async function mirror(params) {
569
609
  userMessagesPresent
570
610
  };
571
611
  }
612
+ async function deliverAsyncMessageBestEffort(params) {
613
+ const mirrorIdentity = `${params.turnId}:async:${params.itemId}`;
614
+ const deliveryIntentId = `block-reply:v1:codex-app-server:${[
615
+ params.threadId,
616
+ params.turnId,
617
+ params.itemId
618
+ ].map(encodeURIComponent).join(":")}`;
619
+ const target = params.params.sessionTarget;
620
+ if (!target) {
621
+ if (!params.params.onBlockReply) return "retry";
622
+ try {
623
+ await deliverAsyncBlockReply(params.params.onBlockReply, params.text, deliveryIntentId);
624
+ return "settled";
625
+ } catch (error) {
626
+ embeddedAgentLog.warn("failed to deliver codex async agent message", {
627
+ error: formatErrorMessage(error),
628
+ itemId: params.itemId,
629
+ runId: params.params.runId,
630
+ threadId: params.threadId,
631
+ turnId: params.turnId
632
+ });
633
+ return "retry";
634
+ }
635
+ }
636
+ let result;
637
+ try {
638
+ result = await mirror({
639
+ agentId: target.agentId ?? params.params.agentId,
640
+ sessionId: target.sessionId ?? params.params.sessionId,
641
+ sessionKey: target.sessionKey ?? params.params.sessionKey,
642
+ storePath: target.storePath,
643
+ cwd: params.cwd,
644
+ config: params.params.config,
645
+ messages: [attachCodexMirrorIdentity(params.message, mirrorIdentity)],
646
+ idempotencyScope: `codex-app-server:${params.threadId}`
647
+ });
648
+ } catch (error) {
649
+ embeddedAgentLog.warn("failed to persist codex async agent message", {
650
+ error: formatErrorMessage(error),
651
+ itemId: params.itemId,
652
+ runId: params.params.runId,
653
+ threadId: params.threadId,
654
+ turnId: params.turnId
655
+ });
656
+ return "retry";
657
+ }
658
+ if (!result.assistantMirrorIdentitiesOwned.includes(mirrorIdentity)) return "retry";
659
+ const persistedText = readMirroredAssistantText(result.messagesPresent.find((message) => readMirrorIdentity(message) === mirrorIdentity));
660
+ if (params.params.onBlockReply && persistedText !== void 0) try {
661
+ await deliverAsyncBlockReply(params.params.onBlockReply, persistedText, deliveryIntentId);
662
+ } catch (error) {
663
+ embeddedAgentLog.warn("failed to deliver persisted codex async agent message", {
664
+ error: formatErrorMessage(error),
665
+ itemId: params.itemId,
666
+ runId: params.params.runId,
667
+ threadId: params.threadId,
668
+ turnId: params.turnId
669
+ });
670
+ return "retry";
671
+ }
672
+ return "settled";
673
+ }
572
674
  const codexTranscriptMirrorRuntime = {
675
+ deliverAsyncMessageBestEffort,
573
676
  mirror,
574
677
  mirrorBestEffort
575
678
  };
679
+ async function deliverAsyncBlockReply(onBlockReply, text, deliveryIntentId) {
680
+ await deliverAgentHarnessUserInputPrompt({ onBlockReply: (payload) => onBlockReply(payload, { deliveryIntentId }) }, [], { intro: text });
681
+ }
576
682
  function resolveCodexMirrorTranscriptTarget(params) {
577
683
  const sessionKey = params.sessionKey?.trim();
578
684
  const storePath = params.storePath?.trim();
@@ -585,4 +691,4 @@ function resolveCodexMirrorTranscriptTarget(params) {
585
691
  };
586
692
  }
587
693
  //#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 };
694
+ export { buildCodexUserPromptMessage as a, fingerprintCodexMirrorSourceMessage as c, serializeCodexMirrorSourceEvidence as d, projectBoundedCodexThreadHistory as f, mirrorPromptAtTurnStartBestEffort as i, hasCodexMirrorOrigin as l, projectCodexUserItemText as m, createCodexAppServerUserMessagePersistenceNotifier as n, promptSnapshot as o, projectBoundedCodexVisibleSessionHistory as p, importCodexThreadHistoryToTranscript as r, applyCodexTranscriptTaint as s, codexTranscriptMirrorRuntime as t, readCodexMirrorSourceFingerprint as u };