@openclaw/codex 2026.9.2 → 2026.9.4

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 (120) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +29 -26
  3. package/dist/apply-CvT8tW5i.js +356 -0
  4. package/dist/{attempt-client-cleanup-Bp1ZOnk2.js → attempt-client-cleanup-DKHzbwt5.js} +38 -214
  5. package/dist/{attempt-context-CSazkWns.js → attempt-context-D44yeDII.js} +9 -7
  6. package/dist/{event-projector-usage-ZqEVbAEY.js → attempt-notifications-C9XufG6l.js} +3 -106
  7. package/dist/{auth-binding-Ds_QVm-X.js → auth-binding-CWlKVccJ.js} +2 -2
  8. package/dist/auth-cache-key-7orQae_j.js +498 -0
  9. package/dist/auth-profile-CwzO4_RG.js +43 -0
  10. package/dist/auth-profile-selection-DFu9e167.js +45 -0
  11. package/dist/binding-connection-D3udKbIE.js +60 -0
  12. package/dist/{bounded-turn-DxGJRYbY.js → bounded-turn-C_Hneydj.js} +28 -125
  13. package/dist/build-state-BCmg9-5p.js +19 -0
  14. package/dist/{capabilities-B1mgvpP8.js → capabilities-8vx68WLH.js} +1 -1
  15. package/dist/cli-metadata.js +1 -1
  16. package/dist/client-B57KWPQx.js +4005 -0
  17. package/dist/command-dispatch-BpduNGVf.js +21 -0
  18. package/dist/{command-formatters-DSbGMXA0.js → command-formatters-lxlkNZgU.js} +4 -3
  19. package/dist/{command-handlers-DOJvGv6-.js → command-handlers-tiL9iWj7.js} +788 -135
  20. package/dist/command-rpc-CR5EOEZX.js +233 -0
  21. package/dist/{compact-Y_xBqrHN.js → compact-B_H3AOd7.js} +19 -14
  22. package/dist/config-oIORaQ5T.js +106 -0
  23. package/dist/{config-CyapYSji.js → config-options-CXMq1T-C.js} +205 -593
  24. package/dist/config-runtime-D0zGNIHu.js +11 -0
  25. package/dist/{config-utils-C57JiJrU.js → config-utils-DujwEnhg.js} +2 -4
  26. package/dist/conversation-binding-DsB4-O7U.js +900 -0
  27. package/dist/{plugin-marketplace-discovery-B7gHXJ3d.js → conversation-control-CtUu1b3m.js} +11 -143
  28. package/dist/doctor-contract-api.js +5 -5
  29. package/dist/{dynamic-tools-BwpvTxaX.js → dynamic-tools-CmN5RAip.js} +133 -76
  30. package/dist/{effective-mcp-catalog-CY9Jn4bA.js → effective-mcp-catalog-Bd73bqA8.js} +3 -3
  31. package/dist/{elicitation-input-DMkeki8d.js → elicitation-input-DPoK8F7w.js} +8 -22
  32. package/dist/ephemeral-turn-D78_VmzO.js +101 -0
  33. package/dist/{event-projector-assistant-message-B9kp6iGC.js → event-projector-assistant-message-BmBM4qBV.js} +12 -25
  34. package/dist/event-projector-items-5VhsECCO.js +200 -0
  35. package/dist/event-projector-usage-BfXmpOec.js +102 -0
  36. package/dist/{harness-Czh2Sdoc.js → harness-C7rRa7bm.js} +48 -24
  37. package/dist/harness.js +1 -1
  38. package/dist/history-rejection-B4nOXNXF.js +13 -0
  39. package/dist/incognito-session-uhrBF6wJ.js +15 -0
  40. package/dist/index.js +406 -2915
  41. package/dist/inference-context-Dr_mzvk4.js +94 -0
  42. package/dist/inference-proxy-HGXKUIre.js +311 -0
  43. package/dist/{isolated-completion-CRh-51AK.js → isolated-completion-DWVb5U2J.js} +7 -4
  44. package/dist/launch-args-RXQwn8zV.js +90 -0
  45. package/dist/{managed-binary-DcpnJF9x.js → managed-binary-D22rNEcR.js} +13 -103
  46. package/dist/managed-thread-store-D1t5jh3G.js +66 -0
  47. package/dist/media-understanding-provider.js +4 -1
  48. package/dist/migration-provider-api.js +2 -0
  49. package/dist/{model-catalog-DT5vo6qo.js → model-catalog-Dq2n8f_p.js} +6 -5
  50. package/dist/{models-CcrgSMQR.js → models-PCKOim-h.js} +3 -3
  51. package/dist/native-execution-policy-umd0tgh4.js +128 -0
  52. package/dist/native-subagent-history-DjtPloaU.js +140 -0
  53. package/dist/native-subagent-history-owner-Pcp7JuVF.js +34 -0
  54. package/dist/{native-subagent-monitor-B3bvQGcg.js → native-subagent-monitor-fQ7eIXEf.js} +115 -460
  55. package/dist/native-subagent-task-ids-BzTdT0Uw.js +387 -0
  56. package/dist/node-cli-sessions-DKaOmVUh.js +527 -0
  57. package/dist/{node-exec-server.runtime-nfbUOtUB.js → node-exec-server.runtime-Cl2vapEi.js} +55 -24
  58. package/dist/plan-7uG-Fp36.js +947 -0
  59. package/dist/plugin-activation-BYQculil.js +138 -0
  60. package/dist/{thread-resume-BLgqkUc1.js → plugin-app-cache-key-d0eKxy7b.js} +4 -52
  61. package/dist/{plugin-approval-roundtrip-aQVdyL5g.js → plugin-approval-roundtrip-Bz3FT8W5.js} +1 -1
  62. package/dist/plugin-inventory-oL4Na1ZG.js +328 -0
  63. package/dist/plugin-marketplace-discovery-P-Vndfqq.js +137 -0
  64. package/dist/{plugin-metadata-cache-BwCLTY_U.js → plugin-metadata-cache-ClPJpRio.js} +17 -9
  65. package/dist/protocol-5bh1G-H7.js +275 -0
  66. package/dist/provider-MQ8PVkuE.js +50 -0
  67. package/dist/{provider-capabilities-BpG9Ltc5.js → provider-capabilities-BvCUL69A.js} +2 -2
  68. package/dist/{rate-limits-Fx_l4eNa.js → rate-limits-CBMmWBr9.js} +1 -1
  69. package/dist/request-B7hEkBGq.js +212 -0
  70. package/dist/rpc-error-ttN_QjEm.js +30 -0
  71. package/dist/{run-attempt-BzthFQSM.js → run-attempt-CvsAAGa0.js} +664 -377
  72. package/dist/{runtime-artifact-Bh_gf6-t.js → runtime-artifact-BJ0rXBZ_.js} +27 -27
  73. package/dist/sandbox-guard-BxgyoM8M.js +166 -0
  74. package/dist/{session-binding-4Ki04sW-.js → session-binding-CI8UuilT.js} +30 -48
  75. package/dist/{session-binding-record-CyaXZvTe.js → session-binding-record-Bcvslnhf.js} +12 -26
  76. package/dist/session-catalog-adoption-tcZi1IfX.js +251 -0
  77. package/dist/session-catalog-archive-CwKg8Xz2.js +56 -0
  78. package/dist/session-catalog-ct-AH01I.js +1477 -0
  79. package/dist/session-catalog-home-id-CwhLdC03.js +18 -0
  80. package/dist/session-catalog-node-adoption-B1tgDW-m.js +182 -0
  81. package/dist/session-catalog-node-continue-Ci-DXyJP.js +238 -0
  82. package/dist/session-catalog-provenance-D-dIfRAH.js +96 -0
  83. package/dist/{session-cli-BjLhpmS1.js → session-cli-DNN_jhGc.js} +3 -2
  84. package/dist/{session-history-DWmMqiqW.js → session-history-Cz-tOOYj.js} +6 -3
  85. package/dist/{session-upstream-marker-DReTpGz6.js → session-history-import-DwyijFI6.js} +5 -50
  86. package/dist/{session-history-read-LHldwvyh.js → session-history-read-cxPUxyVV.js} +21 -7
  87. package/dist/session-history-worker-runtime.js +18 -6
  88. package/dist/session-history.worker-BeK1YOyT.js +378 -0
  89. package/dist/session-history.worker.js +1 -1
  90. package/dist/{session-initialization-BCFVnLL4.js → session-initialization-Ct0_Hzmg.js} +2 -2
  91. package/dist/{session-permission-policy-BaueHmSj.js → session-permission-policy-BBmXA8Eg.js} +4 -7
  92. package/dist/{session-retirement-DNdmYdFc.js → session-retirement-B2YfbAAT.js} +6 -5
  93. package/dist/session-upstream-marker-D15C9NHp.js +46 -0
  94. package/dist/{settled-turn-context-BOM3Y1pl.js → settled-turn-context-Du6gdUDd.js} +9 -9
  95. package/dist/{settled-turn-finalizer-BI-b1sry.js → settled-turn-finalizer-Dn91stmc.js} +8 -7
  96. package/dist/shared-client-CscigXXL.js +3109 -0
  97. package/dist/{side-question-B6DWAw1A.js → side-question-BGMJQf4U.js} +65 -170
  98. package/dist/source-CElXU0Oy.js +518 -0
  99. package/dist/thread-archive-guard-DfpBr-Sz.js +53 -0
  100. package/dist/thread-history-page-D0JIp48V.js +361 -0
  101. package/dist/{thread-lifecycle-DPK30jad.js → thread-lifecycle-DXl1-I6b.js} +187 -639
  102. package/dist/{thread-ownership-CbucAmmp.js → thread-ownership-BsDRTsyp.js} +13 -15
  103. package/dist/thread-policy-BuEQfE0g.js +54 -0
  104. package/dist/thread-resume-DsDOZpFg.js +52 -0
  105. package/dist/timeout-BVw8aaM1.js +33 -0
  106. package/dist/transcript-history-projection-v17wXgdK.js +238 -0
  107. package/dist/{transcript-mirror-_njEB84z.js → transcript-mirror-C5CKgNy6.js} +50 -260
  108. package/dist/{transcript-mirror-attestation-Byl34PC-.js → transcript-mirror-attestation-DibE0krH.js} +17 -4
  109. package/dist/{transport-stdio-CzTngV0j.js → transport-stdio-BGjHoYLr.js} +73 -43
  110. package/dist/{upstream-session-fork-1fwbNKzQ.js → upstream-session-fork-BZerMte_.js} +27 -19
  111. package/dist/{usage-i9fv5-4m.js → usage-tCk-mg_x.js} +4 -3
  112. package/dist/version-omm6IPI3.js +12 -0
  113. package/dist/{web-search-provider.runtime-DKQn67A7.js → web-search-provider.runtime-B7bGbGWq.js} +3 -3
  114. package/openclaw.plugin.json +23 -1
  115. package/package.json +4 -4
  116. package/dist/request-C8H22rPi.js +0 -475
  117. package/dist/session-catalog-B47uwekb.js +0 -3272
  118. package/dist/session-history.worker-zZVcx0ME.js +0 -267
  119. package/dist/shared-client-CKhX2kFt.js +0 -7505
  120. package/dist/thread-policy-CTalhWFy.js +0 -105
@@ -1,486 +1,53 @@
1
- import { h as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME, m as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-utils-C57JiJrU.js";
2
- import { l as sessionBindingIdentity } from "./session-binding-record-CyaXZvTe.js";
3
- import { B as isJsonObject, C as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES, M as resolveCodexAppServerHomeDir, N as resolveCodexAppServerLocalHomeDir, k as resolveCodexPluginsPolicy, n as codexSandboxPolicyForTurn, p as assertCodexModelBackedReviewerEffectiveConfig, w as readCodexEffectiveConfig, z as flattenCodexDynamicToolFunctions } from "./config-CyapYSji.js";
4
- import { At as readCodexClientSessionMeta, Dt as isCodexAppServerClientRuntimeLive, E as CodexThreadStartRequestError, H as isCodexAppServerOverloadError, I as getCodexAppServerClientInstanceId, J as isCodexThreadReadMissingError, K as resolveCodexAppServerClientInstanceId, Nt as unsubscribeCodexAppServerLiveThread, Ot as isCodexAppServerLiveThreadClaimed, Pt as withAbortableTimeout, Q as assertCodexThreadAcceptsDirectInput, T as CodexThreadBindingConflictError, W as isCodexAppServerRequestTimeoutError, Xt as readCodexSessionMeta, _ as retainSharedCodexAppServerClientByInstanceId, et as assertCodexThreadForkResponse, jt as releaseCodexAppServerLiveThread, n as captureCodexAppServerClientLifetime, nt as assertCodexThreadStartResponse, q as CodexAppServerRpcError, w as CodexAdoptedThreadActiveError, wt as consumeCodexAppServerLiveThread, yt as resolveCodexToolAbortTerminalReason } from "./shared-client-CKhX2kFt.js";
5
- import { a as isCodexAppServerNativeAuthProfile, i as hashCodexAppServerBindingFingerprint, l as resolveCodexSessionBinding, n as assertCodexBindingMayBeReplaced, o as normalizeCodexAppServerBindingModelProvider } from "./session-binding-4Ki04sW-.js";
6
- import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, l as retireUnsafeCodexTurnClientBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as isCodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-Bp1ZOnk2.js";
7
- import { c as defaultCodexAppInventoryCache, l as serializeCodexAppInventoryError, n as buildCodexAppServerConnectionFingerprint, s as CodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-BLgqkUc1.js";
8
- import { c as withExclusiveCodexAppServerThread, l as isIncognitoSessionKey, o as withCodexAppServerThreadMutation, r as retainCodexAppServerBindingSubscription } from "./thread-ownership-CbucAmmp.js";
9
- import { a as assertCodexSessionRuntimeOwnership, i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, r as assertCodexSupervisionThreadLineage, t as CodexIncognitoPolicyChangeError } from "./thread-policy-CTalhWFy.js";
10
- import { d as codexCatalogHomeId, s as projectBoundedCodexThreadHistory } from "./transcript-mirror-_njEB84z.js";
1
+ import { a as readCodexPluginInventory, o as resolveOwnedAppApprovalOverrideKeys } from "./plugin-inventory-oL4Na1ZG.js";
2
+ import { l as sessionBindingIdentity, n as assertCodexBindingMayBeReplaced } from "./session-binding-record-Bcvslnhf.js";
3
+ import { f as assertCodexModelBackedReviewerEffectiveConfig, g as readCodexEffectiveConfig, h as CODEX_SESSION_OVERRIDABLE_LAYER_TYPES, n as codexSandboxPolicyForTurn } from "./config-options-CXMq1T-C.js";
4
+ import { S as resolveCodexPluginsPolicy, a as flattenCodexDynamicToolFunctions, c as resolveCodexAppServerLocalHomeDir, o as isJsonObject, s as resolveCodexAppServerHomeDir } from "./protocol-5bh1G-H7.js";
5
+ import { L as resolveCodexToolAbortTerminalReason, _ as assertCodexThreadAcceptsDirectInput, b as assertCodexThreadStartResponse, d as isCodexAppServerRequestTimeoutError, l as isCodexAppServerOverloadError, p as resolveCodexAppServerClientInstanceId, r as getCodexAppServerClientInstanceId, v as assertCodexThreadForkResponse } from "./client-B57KWPQx.js";
6
+ import { i as markStartedCodexManagedThread } from "./managed-thread-store-D1t5jh3G.js";
7
+ import { n as withCodexAppServerThreadMutation, t as isIncognitoSessionKey } from "./incognito-session-uhrBF6wJ.js";
8
+ import { n as isCodexThreadReadMissingError, t as CodexAppServerRpcError } from "./rpc-error-ttN_QjEm.js";
9
+ import { t as projectBoundedCodexThreadHistory } from "./transcript-history-projection-v17wXgdK.js";
10
+ import { c as serializeCodexAppInventoryError, o as CodexAppInventoryCache, s as defaultCodexAppInventoryCache, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-d0eKxy7b.js";
11
+ import { t as withAbortableTimeout } from "./timeout-BVw8aaM1.js";
12
+ import { n as codexCatalogHomeId } from "./session-catalog-home-id-CwhLdC03.js";
13
+ import { n as readCodexSessionMeta } from "./session-catalog-provenance-D-dIfRAH.js";
14
+ import "./config-oIORaQ5T.js";
11
15
  import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-tupAr-2o.js";
16
+ import { t as assertCodexSessionRuntimeOwnership } from "./binding-connection-D3udKbIE.js";
17
+ import { n as normalizeCodexAppServerBindingModelProvider, t as isCodexAppServerNativeAuthProfile } from "./auth-profile-CwzO4_RG.js";
18
+ import { C as CodexThreadBindingConflictError, D as bindCodexInferenceThread, E as assertCodexInferenceRouteConfig, H as isCodexAppServerClientRuntimeLive, K as readCodexClientSessionMeta, R as consumeCodexAppServerLiveThread, S as CodexAdoptedThreadActiveError, U as isCodexAppServerLiveThreadClaimed, Y as unsubscribeCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientByInstanceId, k as prepareCodexInferenceThreadConfig, n as captureCodexAppServerClientLifetime, q as releaseCodexAppServerLiveThread, w as CodexThreadStartRequestError } from "./shared-client-CscigXXL.js";
19
+ import { a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, l as retireUnsafeCodexTurnClientBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as isCodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-DKHzbwt5.js";
20
+ import { t as ensureCodexPluginActivation } from "./plugin-activation-BYQculil.js";
21
+ import { o as resolveCodexSessionBinding, r as hashCodexAppServerBindingFingerprint } from "./session-binding-CI8UuilT.js";
22
+ import { i as refreshCodexThreadPolicy, n as CodexThreadPolicyHandoffError, r as assertCodexSupervisionThreadLineage, t as CodexIncognitoPolicyChangeError } from "./thread-policy-BuEQfE0g.js";
23
+ import { t as resumeCodexAppServerThread } from "./thread-resume-DsDOZpFg.js";
24
+ import { r as retainCodexAppServerBindingSubscription, s as withExclusiveCodexAppServerThread } from "./thread-ownership-BsDRTsyp.js";
25
+ import "./transcript-mirror-C5CKgNy6.js";
12
26
  import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
27
  import * as crypto$1 from "node:crypto";
14
28
  import crypto, { createHash } from "node:crypto";
15
29
  import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
16
- import { z } from "zod";
17
30
  import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
18
- import fs from "node:fs/promises";
19
31
  import path from "node:path";
32
+ import os from "node:os";
33
+ import fs from "node:fs/promises";
34
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
35
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
20
36
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
21
- import { AgentHarnessPreflightError, SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, buildTemporalContextText, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
37
+ import { createStageTimingTracker, formatStageTimings } from "openclaw/plugin-sdk/time-runtime";
22
38
  import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
23
- import os from "node:os";
39
+ import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
40
+ import { AgentHarnessPreflightError, SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, buildTemporalContextText, buildUiPresentationPrompt, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, isOpenClawRuntimeContextCustomMessage, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
24
41
  import { isDeepStrictEqual } from "node:util";
25
- import { resolveAgentDir as resolveAgentDir$2 } from "openclaw/plugin-sdk/agent-runtime";
26
- import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
27
- import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
28
42
  import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
29
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
30
43
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
44
+ import { IMAGE_BLOCK_TOKENS } from "openclaw/plugin-sdk/agent-core";
31
45
  import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/state-paths";
32
46
  import { buildCodexUserMcpServersThreadConfigPatchForRun } from "openclaw/plugin-sdk/codex-mcp-projection";
33
47
  import { registerRetainedNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
34
48
  import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-flags";
35
49
  import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
36
50
  import { buildHostnameAllowlistPolicyFromSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
37
- //#region extensions/codex/src/app-server/plugin-inventory.ts
38
- /**
39
- * Reads Codex plugin marketplace state and app inventory to decide which
40
- * plugin-owned apps can be exposed to a native Codex thread.
41
- */
42
- const CODEX_PLUGINS_REMOTE_MARKETPLACE_NAME = `${CODEX_PLUGINS_MARKETPLACE_NAME}-remote`;
43
- const CODEX_PLUGINS_API_MARKETPLACE_NAME = "openai-api-curated";
44
- /** Reads configured Codex plugin state and maps owned apps to readiness diagnostics. */
45
- async function readCodexPluginInventory(params) {
46
- const policy = params.policy ?? resolveCodexPluginsPolicy(params.pluginConfig);
47
- if (!policy.enabled) return {
48
- policy,
49
- records: [],
50
- diagnostics: [{
51
- code: "disabled",
52
- message: "Native Codex plugin support is disabled."
53
- }]
54
- };
55
- const appInventory = readCachedAppInventory(params);
56
- const installedPlugins = await readInstalledCodexPluginMetadata({
57
- ...params,
58
- policy
59
- });
60
- const pluginCatalogs = /* @__PURE__ */ new Map();
61
- const diagnostics = [];
62
- const records = [];
63
- if (appInventory?.state === "missing") diagnostics.push({
64
- code: "app_inventory_missing",
65
- message: "Cached Codex app inventory is missing; plugin apps are excluded for this setup."
66
- });
67
- else if (appInventory?.state === "stale") diagnostics.push({
68
- code: "app_inventory_stale",
69
- message: "Cached Codex app inventory is stale; using stale app readiness and refreshing."
70
- });
71
- for (const pluginPolicy of policy.pluginPolicies) {
72
- if (!pluginPolicy.enabled && !policy.allowAllPlugins) continue;
73
- let listed = installedPlugins;
74
- let resolvedPlugin = findConfiguredMarketplacePlugin(listed, pluginPolicy);
75
- if (!resolvedPlugin && pluginPolicy.enabled && pluginPolicy.marketplaceName !== "workspace-directory") {
76
- const requestParams = buildPluginCatalogRequestParams(params, pluginPolicy.marketplaceName);
77
- const catalogKey = JSON.stringify([requestParams, pluginMetadataCatalogScope(pluginPolicy.marketplaceName)]);
78
- let catalog = pluginCatalogs.get(catalogKey);
79
- if (!catalog) {
80
- catalog = listCodexPluginMetadata(params, pluginPolicy.marketplaceName);
81
- pluginCatalogs.set(catalogKey, catalog);
82
- }
83
- listed = await catalog;
84
- resolvedPlugin = findConfiguredMarketplacePlugin(listed, pluginPolicy);
85
- }
86
- if (!listed.marketplaces.some((marketplace) => marketplaceMatchesConfiguredName(marketplace, pluginPolicy.marketplaceName))) {
87
- diagnostics.push({
88
- code: "marketplace_missing",
89
- plugin: pluginPolicy,
90
- message: `Codex marketplace ${pluginPolicy.marketplaceName} was not found.`
91
- });
92
- continue;
93
- }
94
- if (!resolvedPlugin) {
95
- diagnostics.push({
96
- code: "plugin_missing",
97
- plugin: pluginPolicy,
98
- message: `${pluginPolicy.pluginName} was not found in ${pluginPolicy.marketplaceName}.`
99
- });
100
- continue;
101
- }
102
- const { summary } = resolvedPlugin;
103
- const unavailableByMarketplacePolicy = summary.availability === "DISABLED_BY_ADMIN" || summary.installPolicy === "NOT_AVAILABLE";
104
- if (unavailableByMarketplacePolicy) {
105
- diagnostics.push({
106
- code: "plugin_disabled",
107
- plugin: pluginPolicy,
108
- message: `${pluginPolicy.pluginName} is unavailable in ${pluginPolicy.marketplaceName}.`
109
- });
110
- if (!summary.installed) continue;
111
- }
112
- const detail = await readPluginDetail(params, marketplaceRef(resolvedPlugin.marketplace, pluginPolicy.marketplaceName), pluginPolicy, summary, diagnostics);
113
- const ownedAppIds = detail?.apps.map((app) => app.id).filter(Boolean).toSorted() ?? [];
114
- const appOwnership = resolveAppOwnership({
115
- detail,
116
- appInventory,
117
- summary
118
- });
119
- if (appOwnership === "ambiguous") diagnostics.push({
120
- code: "app_ownership_ambiguous",
121
- plugin: pluginPolicy,
122
- message: `${pluginPolicy.pluginName} has only display-name app matches; apps are not exposed until ownership is stable.`
123
- });
124
- if (summary.installed && !summary.enabled) diagnostics.push({
125
- code: "plugin_disabled",
126
- plugin: pluginPolicy,
127
- message: `${pluginPolicy.pluginName} is installed in Codex but disabled.`
128
- });
129
- const apps = resolveOwnedApps({
130
- pluginPolicy,
131
- detail,
132
- appInventory
133
- });
134
- records.push({
135
- policy: pluginPolicy,
136
- summary,
137
- ...detail ? { detail } : {},
138
- activationRequired: pluginPolicy.enabled && (unavailableByMarketplacePolicy || !summary.installed || !summary.enabled),
139
- authRequired: apps.some((app) => app.needsAuth || !app.accessible),
140
- appOwnership,
141
- ownedAppIds,
142
- apps
143
- });
144
- }
145
- return {
146
- policy,
147
- records,
148
- diagnostics,
149
- ...appInventory ? { appInventory } : {}
150
- };
151
- }
152
- /** Finds a configured plugin only in its authorized marketplace identity. */
153
- function findCodexMarketplacePluginSummary(listed, marketplaceName, pluginName) {
154
- const resolved = findConfiguredMarketplacePlugin(listed, {
155
- marketplaceName,
156
- pluginName
157
- });
158
- return resolved ? {
159
- marketplace: marketplaceRef(resolved.marketplace, marketplaceName),
160
- summary: resolved.summary
161
- } : void 0;
162
- }
163
- /** Builds plugin/read or plugin/install params from a marketplace reference. */
164
- function pluginReadParams(marketplace, pluginName) {
165
- return {
166
- ...marketplace.path ? { marketplacePath: marketplace.path } : {},
167
- ...marketplace.remoteMarketplaceName ? { remoteMarketplaceName: marketplace.remoteMarketplaceName } : {},
168
- pluginName
169
- };
170
- }
171
- /** Returns configured plugin keys whose current metadata may still recover. */
172
- function resolveRecoverableCodexPluginConfigKeys(params) {
173
- return params.policy.pluginPolicies.filter((pluginPolicy) => pluginPolicy.enabled && !isSettledMissingPluginPolicy({
174
- pluginPolicy,
175
- metadataCache: params.metadataCache,
176
- appCacheKey: params.appCacheKey,
177
- configCwd: params.configCwd
178
- })).map((pluginPolicy) => pluginPolicy.configKey).toSorted();
179
- }
180
- async function listCodexPluginMetadata(params, marketplaceName) {
181
- const requestParams = buildPluginCatalogRequestParams(params, marketplaceName);
182
- if (!params.metadataCache || !params.appCacheKey) return await params.request("plugin/list", requestParams);
183
- return (await params.metadataCache.load({
184
- appCacheKey: params.appCacheKey,
185
- queryKind: "curated-global",
186
- requestParams,
187
- catalogScope: pluginMetadataCatalogScope(marketplaceName),
188
- request: async (method, listedParams) => await params.request(method, listedParams),
189
- cacheable: (response) => response.marketplaces.some((marketplace) => marketplaceMatchesConfiguredName(marketplace, marketplaceName))
190
- })).response;
191
- }
192
- async function readInstalledCodexPluginMetadata(params) {
193
- const requestParams = params.configCwd ? { cwds: [params.configCwd] } : {};
194
- if (!params.metadataCache || !params.appCacheKey) return await params.request("plugin/installed", requestParams);
195
- return (await params.metadataCache.load({
196
- appCacheKey: params.appCacheKey,
197
- queryKind: "installed",
198
- requestParams,
199
- request: async (method, installedParams) => await params.request(method, installedParams),
200
- cacheable: (response) => params.policy.pluginPolicies.every((pluginPolicy) => {
201
- if (!pluginPolicy.enabled && !params.policy.allowAllPlugins) return true;
202
- return Boolean(findConfiguredMarketplacePlugin(response, pluginPolicy));
203
- })
204
- })).response;
205
- }
206
- function isSettledMissingPluginPolicy(params) {
207
- const queryKind = params.pluginPolicy.marketplaceName === "workspace-directory" ? "installed" : "curated-global";
208
- const requestParams = queryKind === "installed" ? params.configCwd ? { cwds: [params.configCwd] } : {} : buildPluginCatalogRequestParams(params, params.pluginPolicy.marketplaceName);
209
- const listed = params.metadataCache.read(params.appCacheKey, queryKind, requestParams, queryKind === "curated-global" ? pluginMetadataCatalogScope(params.pluginPolicy.marketplaceName) : void 0)?.response;
210
- if (!listed) return false;
211
- return !findConfiguredMarketplacePlugin(listed, params.pluginPolicy);
212
- }
213
- function pluginMetadataCatalogScope(marketplaceName) {
214
- return isOpenAiCuratedMarketplaceName(marketplaceName) ? void 0 : marketplaceName;
215
- }
216
- function buildPluginCatalogRequestParams(params, marketplaceName) {
217
- const marketplaceKinds = marketplaceName === "created-by-me-remote" ? ["created-by-me-remote"] : marketplaceName.startsWith("workspace-shared-with-me") ? ["shared-with-me"] : void 0;
218
- return {
219
- ...params.configCwd ? { cwds: [params.configCwd] } : {},
220
- ...marketplaceKinds ? { marketplaceKinds: [...marketplaceKinds] } : {}
221
- };
222
- }
223
- function readCachedAppInventory(params) {
224
- if (!params.appCache || !params.appCacheKey) return;
225
- const request = async (method, requestParams) => await params.request(method, requestParams);
226
- return params.appCache.read({
227
- key: params.appCacheKey,
228
- request,
229
- nowMs: params.nowMs,
230
- suppressRefresh: params.suppressAppInventoryRefresh
231
- });
232
- }
233
- async function readPluginDetail(params, marketplace, pluginPolicy, summary, diagnostics) {
234
- if (params.readPluginDetails === false) return;
235
- if (marketplace.remoteMarketplaceName && !summary.remotePluginId) {
236
- diagnostics.push({
237
- code: "plugin_detail_unavailable",
238
- plugin: pluginPolicy,
239
- message: `${pluginPolicy.pluginName} detail unavailable: Codex did not return a remote plugin id.`
240
- });
241
- return;
242
- }
243
- try {
244
- return (await params.request("plugin/read", pluginReadParams(marketplace, marketplace.remoteMarketplaceName && summary.remotePluginId ? summary.remotePluginId : pluginPolicy.pluginName))).plugin;
245
- } catch (error) {
246
- diagnostics.push({
247
- code: "plugin_detail_unavailable",
248
- plugin: pluginPolicy,
249
- message: `${pluginPolicy.pluginName} detail unavailable: ${error instanceof Error ? error.message : String(error)}`
250
- });
251
- return;
252
- }
253
- }
254
- function resolveAppOwnership(params) {
255
- if (params.detail && params.detail.apps.length > 0) return "proven";
256
- return (params.appInventory?.snapshot?.apps ?? []).filter((app) => app.pluginDisplayNames.some((displayName) => displayName === params.summary.name)).length > 0 ? "ambiguous" : "none";
257
- }
258
- function resolveOwnedApps(params) {
259
- const detailApps = params.detail?.apps ?? [];
260
- if (detailApps.length === 0) return [];
261
- if (params.appInventory?.state === "missing") {
262
- embeddedAgentLog.warn("codex plugin inventory missing app inventory for detail apps", {
263
- configKey: params.pluginPolicy.configKey,
264
- pluginName: params.pluginPolicy.pluginName,
265
- appIds: detailApps.map((app) => app.id).toSorted()
266
- });
267
- return [];
268
- }
269
- const appInfoById = new Map((params.appInventory?.snapshot?.apps ?? []).map((app) => [app.id, app]));
270
- return detailApps.map((app) => {
271
- const info = appInfoById.get(app.id);
272
- if (!info) return {
273
- id: app.id,
274
- name: app.name,
275
- accessible: false,
276
- enabled: false,
277
- needsAuth: true
278
- };
279
- return Object.assign({
280
- id: app.id,
281
- name: app.name,
282
- accessible: info.isAccessible,
283
- enabled: info.isEnabled,
284
- needsAuth: !info.isAccessible
285
- }, resolveOwnedAppApprovalOverrideKeys(info));
286
- }).toSorted((left, right) => left.id.localeCompare(right.id));
287
- }
288
- /** Returns current tool keys whose overrides could bypass the requested reviewer. */
289
- function resolveOwnedAppApprovalOverrideKeys(app) {
290
- if (!app.toolSummaries) return {};
291
- const appName = app.name.trim();
292
- const appNameLower = appName.toLowerCase();
293
- const keys = app.toolSummaries.filter((tool) => !tool.isReadOnly).flatMap((tool) => resolveAppToolConfigKeys({
294
- appName,
295
- appNameLower,
296
- tool
297
- }));
298
- return { approvalOverrideToolConfigKeys: Array.from(new Set(keys)).toSorted() };
299
- }
300
- function resolveAppToolConfigKeys(params) {
301
- const keys = [params.tool.name];
302
- if (params.tool.title) keys.push(params.tool.title);
303
- if (params.appName) keys.push(`${params.appName}_${params.tool.name}`);
304
- if (params.appNameLower && params.appNameLower !== params.appName) keys.push(`${params.appNameLower}_${params.tool.name}`);
305
- return keys;
306
- }
307
- function findPluginSummary(marketplace, pluginName) {
308
- const exact = marketplace.plugins.find((plugin) => plugin.id === pluginName || plugin.id === `${pluginName}@${marketplace.name}`);
309
- if (exact) return exact;
310
- const matches = marketplace.plugins.filter((plugin) => plugin.name === pluginName || pluginNameFromPluginId(plugin.id, marketplace.name) === pluginName);
311
- return matches.length === 1 ? matches[0] : void 0;
312
- }
313
- function findConfiguredMarketplacePlugin(listed, plugin) {
314
- if (plugin.marketplaceName === "workspace-directory") return findWorkspaceMarketplacePlugin(listed, plugin.pluginName);
315
- for (const marketplace of listed.marketplaces) {
316
- if (!marketplaceMatchesConfiguredName(marketplace, plugin.marketplaceName)) continue;
317
- const summary = findPluginSummary(marketplace, plugin.pluginName);
318
- if (summary) return {
319
- marketplace,
320
- summary
321
- };
322
- }
323
- }
324
- function marketplaceMatchesConfiguredName(marketplace, configuredMarketplaceName) {
325
- return isOpenAiCuratedMarketplaceName(configuredMarketplaceName) ? isOpenAiCuratedMarketplace(marketplace) : marketplace.name === configuredMarketplaceName;
326
- }
327
- function findWorkspaceMarketplacePlugin(listed, pluginName) {
328
- const marketplace = listed.marketplaces.find((entry) => entry.name === CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME);
329
- const summary = marketplace?.plugins.find((plugin) => plugin.id === pluginName);
330
- return marketplace && summary ? {
331
- marketplace,
332
- summary
333
- } : void 0;
334
- }
335
- function pluginNameFromPluginId(pluginId, marketplaceName) {
336
- const trimmed = pluginId.trim();
337
- if (!trimmed) return;
338
- const marketplaceSuffix = `@${marketplaceName}`;
339
- return (trimmed.endsWith(marketplaceSuffix) ? trimmed.slice(0, -marketplaceSuffix.length) : trimmed).split("/").at(-1)?.trim() || void 0;
340
- }
341
- function marketplaceRef(marketplace, name) {
342
- return {
343
- name,
344
- ...marketplace.path ? { path: marketplace.path } : {},
345
- ...!marketplace.path ? { remoteMarketplaceName: marketplace.name } : {}
346
- };
347
- }
348
- /** True for any supported OpenAI curated marketplace wire name, matching Codex's own curated predicate. */
349
- function isOpenAiCuratedMarketplace(marketplace) {
350
- return isOpenAiCuratedMarketplaceName(marketplace.name);
351
- }
352
- /** True for all Codex wire aliases of the same OpenAI-curated catalog. */
353
- function isOpenAiCuratedMarketplaceName(marketplaceName) {
354
- return marketplaceName === "openai-curated" || marketplaceName === CODEX_PLUGINS_REMOTE_MARKETPLACE_NAME || marketplaceName === CODEX_PLUGINS_API_MARKETPLACE_NAME;
355
- }
356
- //#endregion
357
- //#region extensions/codex/src/app-server/plugin-activation.ts
358
- /**
359
- * Activates legacy curated Codex plugins while requiring owner-managed
360
- * installation for every other marketplace.
361
- */
362
- /** Activates legacy curated plugins without granting install authority to other marketplaces. */
363
- async function ensureCodexPluginActivation(params) {
364
- if (params.identity.marketplaceName === "workspace-directory") return activationFailure(params.identity, "disabled", { message: "workspace-directory plugins must be installed and enabled outside OpenClaw before use." });
365
- if (!isOpenAiCuratedMarketplaceName(params.identity.marketplaceName)) {
366
- const target = params.identity.pluginName.endsWith(`@${params.identity.marketplaceName}`) ? params.identity.pluginName : `${params.identity.pluginName}@${params.identity.marketplaceName}`;
367
- return activationFailure(params.identity, "disabled", { message: `${params.identity.marketplaceName} plugins must be installed and enabled by an owner before use. Run /codex plugins install ${target}.` });
368
- }
369
- const listed = await listCuratedCodexPluginMetadata(params);
370
- const resolved = findCodexMarketplacePluginSummary(listed, params.identity.marketplaceName, params.identity.pluginName);
371
- if (!resolved) {
372
- if (!listed.marketplaces.some((marketplace) => isOpenAiCuratedMarketplace(marketplace))) return activationFailure(params.identity, "marketplace_missing", { message: `Codex marketplace ${CODEX_PLUGINS_MARKETPLACE_NAME} was not found.` });
373
- return activationFailure(params.identity, "plugin_missing", { message: `${params.identity.pluginName} was not found in ${CODEX_PLUGINS_MARKETPLACE_NAME}.` });
374
- }
375
- if (resolved.marketplace.remoteMarketplaceName && !resolved.summary.remotePluginId) return activationFailure(params.identity, "plugin_missing", { message: `${params.identity.pluginName} detail unavailable: Codex did not return a remote plugin id.` });
376
- if (resolved.summary.availability === "DISABLED_BY_ADMIN" || resolved.summary.installPolicy === "NOT_AVAILABLE") return activationFailure(params.identity, "disabled", { message: `${params.identity.pluginName} was disabled or made unavailable by its marketplace administrator.` });
377
- if (resolved.summary.installed && resolved.summary.enabled && !params.installEvenIfActive) return {
378
- identity: params.identity,
379
- ok: true,
380
- reason: "already_active",
381
- installAttempted: false,
382
- marketplace: resolved.marketplace,
383
- diagnostics: []
384
- };
385
- const remotePluginId = resolved.marketplace.remoteMarketplaceName ? resolved.summary.remotePluginId : void 0;
386
- let installResponse;
387
- try {
388
- installResponse = await params.request("plugin/install", pluginReadParams(resolved.marketplace, remotePluginId ?? params.identity.pluginName));
389
- } catch (error) {
390
- if (!(error instanceof CodexAppServerRpcError) || error.code !== -32600 || !remotePluginId || error.message !== `remote plugin ${remotePluginId} is disabled by admin` && error.message !== `remote plugin ${remotePluginId} is not available for install`) throw error;
391
- return {
392
- identity: params.identity,
393
- ok: false,
394
- reason: "install_failed",
395
- installAttempted: true,
396
- marketplace: resolved.marketplace,
397
- diagnostics: [{ message: `Codex plugin install failed: ${coerceErrorMessage(error)}` }]
398
- };
399
- }
400
- if (params.metadataCache && params.appCacheKey) params.metadataCache.invalidate(params.appCacheKey);
401
- const refreshDiagnostics = [];
402
- let refreshFailed = false;
403
- try {
404
- const refreshResult = await refreshCodexPluginRuntimeState({
405
- request: params.request,
406
- appCache: params.appCache,
407
- appCacheKey: params.appCacheKey,
408
- configCwd: params.configCwd,
409
- metadataCache: params.metadataCache,
410
- deferAppInventoryRefresh: params.deferAppInventoryRefresh,
411
- targetAppIds: params.targetAppIds
412
- });
413
- refreshDiagnostics.push(...refreshResult.diagnostics);
414
- } catch (error) {
415
- refreshFailed = true;
416
- refreshDiagnostics.push({ message: `Codex plugin runtime refresh failed after install: ${coerceErrorMessage(error)}` });
417
- }
418
- const authRequired = installResponse.appsNeedingAuth.length > 0;
419
- return {
420
- identity: params.identity,
421
- ok: !authRequired && !refreshFailed,
422
- reason: refreshFailed ? "refresh_failed" : authRequired ? "auth_required" : resolved.summary.installed && resolved.summary.enabled ? "already_active" : "installed",
423
- installAttempted: true,
424
- marketplace: resolved.marketplace,
425
- installResponse,
426
- diagnostics: [...refreshDiagnostics, ...installResponse.appsNeedingAuth.map((app) => ({ message: `${app.name} requires app authentication before plugin tools are exposed.` }))]
427
- };
428
- }
429
- /** Forces Codex plugin, skill, hook, MCP, and app inventory refreshes after activation. */
430
- async function refreshCodexPluginRuntimeState(params) {
431
- const diagnostics = [];
432
- await listCuratedCodexPluginMetadata(params, { forceRefetch: true });
433
- await params.request("skills/list", {
434
- cwds: params.configCwd ? [params.configCwd] : [],
435
- forceReload: true
436
- });
437
- try {
438
- await params.request("hooks/list", { cwds: params.configCwd ? [params.configCwd] : [] });
439
- } catch (error) {
440
- diagnostics.push({ message: `Codex hooks refresh skipped: ${coerceErrorMessage(error)}` });
441
- }
442
- await params.request("config/mcpServer/reload", void 0);
443
- if (params.appCache && params.appCacheKey) {
444
- params.appCache.invalidate(params.appCacheKey, "Codex plugin activation changed app inventory", void 0, params.targetAppIds);
445
- if (params.deferAppInventoryRefresh) return { diagnostics };
446
- const request = async (method, requestParams) => await params.request(method, requestParams);
447
- try {
448
- await params.appCache.refreshNow({
449
- key: params.appCacheKey,
450
- request,
451
- forceRefetch: true,
452
- targetAppIds: params.targetAppIds
453
- });
454
- } catch (error) {
455
- diagnostics.push({ message: `Codex app inventory refresh skipped: ${coerceErrorMessage(error)}` });
456
- }
457
- }
458
- return { diagnostics };
459
- }
460
- async function listCuratedCodexPluginMetadata(params, options = {}) {
461
- const requestParams = {
462
- ...params.configCwd ? { cwds: [params.configCwd] } : {},
463
- ...options.forceRefetch ? { forceRefetch: true } : {}
464
- };
465
- if (!params.metadataCache || !params.appCacheKey) return await params.request("plugin/list", requestParams);
466
- return (await params.metadataCache.load({
467
- appCacheKey: params.appCacheKey,
468
- queryKind: "curated-global",
469
- requestParams,
470
- request: async (method, listedParams) => await params.request(method, listedParams),
471
- cacheable: (response) => response.marketplaces.some((marketplace) => isOpenAiCuratedMarketplace(marketplace))
472
- })).response;
473
- }
474
- function activationFailure(identity, reason, diagnostic, extraDiagnostics = []) {
475
- return {
476
- identity,
477
- ok: false,
478
- reason,
479
- installAttempted: false,
480
- diagnostics: [diagnostic, ...extraDiagnostics]
481
- };
482
- }
483
- //#endregion
484
51
  //#region extensions/codex/src/app-server/plugin-app-approval-overrides.ts
485
52
  /** Projects ask approvals into the native session layer without changing saved settings. */
486
53
  function buildCodexAppApprovalOverrides(config, app) {
@@ -1050,6 +617,12 @@ function stringifyCodexPluginPolicy(value) {
1050
617
  }
1051
618
  //#endregion
1052
619
  //#region extensions/codex/src/app-server/context-engine-projection.ts
620
+ /**
621
+ * Projects OpenClaw context-engine assemblies into Codex prompt text while
622
+ * preserving safety boundaries and redacting tool payloads.
623
+ */
624
+ /** Attachment preparation must not degrade to a prompt that silently loses the saved input. */
625
+ var CodexContextAttachmentError = class extends Error {};
1053
626
  const CONTEXT_HEADER = "OpenClaw assembled context for this turn:";
1054
627
  const CONTEXT_OPEN = "<conversation_context>";
1055
628
  const CONTEXT_CLOSE = "</conversation_context>";
@@ -1068,16 +641,22 @@ const MIN_PROMPT_BUDGET_TOKENS = 8e3;
1068
641
  function neutralizeCodexExplicitMentionSigils(text) {
1069
642
  return text.replace(/\$(?=[A-Za-z0-9_:-])/gu, "$").replace(/\[@(?=[A-Za-z0-9_:-]+\]\()/gu, "[@");
1070
643
  }
644
+ /** Hidden durable notes are context; transient runtime carriers are current-turn only. */
645
+ function isCodexDurableCustomMessage(message) {
646
+ return message.role === "custom" && message.excludeFromContext !== true && !isOpenClawRuntimeContextCustomMessage(message);
647
+ }
1071
648
  /** Projects assembled OpenClaw context-engine messages into Codex prompt inputs. */
1072
- function projectContextEngineAssemblyForCodex(params) {
649
+ async function projectContextEngineAssemblyForCodex(params) {
1073
650
  const prompt = params.prompt.trim();
1074
- const contextMessages = dropDuplicateTrailingPrompt(params.assembledMessages, prompt);
1075
651
  const maxRenderedContextChars = normalizeRenderedContextMaxChars(params.maxRenderedContextChars);
1076
- const boundedContext = renderMessagesForCodexContext(contextMessages, {
652
+ const context = await renderMessagesForCodexContext(params.assembledMessages.filter((message) => message.role !== "custom" || isCodexDurableCustomMessage(message)), {
1077
653
  maxTextPartChars: resolveTextPartMaxChars(maxRenderedContextChars),
1078
654
  toolPayloadMode: params.toolPayloadMode ?? "elide",
1079
- maxRenderedContextChars
655
+ maxRenderedContextChars,
656
+ prepareFileContext: params.prepareFileContext,
657
+ currentUserTurnIdempotencyKey: params.currentUserTurnIdempotencyKey
1080
658
  });
659
+ const boundedContext = context.text;
1081
660
  const promptPrefix = boundedContext ? [
1082
661
  CONTEXT_HEADER,
1083
662
  CONTEXT_SAFETY_NOTE,
@@ -1095,7 +674,8 @@ function projectContextEngineAssemblyForCodex(params) {
1095
674
  promptText,
1096
675
  ...promptContextRange ? { promptContextRange } : {},
1097
676
  assembledMessages: params.assembledMessages,
1098
- prePromptMessageCount: params.originalHistoryMessages.length
677
+ prePromptMessageCount: params.originalHistoryMessages.length,
678
+ ...context.images.length ? { images: context.images } : {}
1099
679
  };
1100
680
  }
1101
681
  /** Resolves rendered context size from a token budget and reserve. */
@@ -1183,30 +763,43 @@ function resolveProjectionPromptBudgetTokens(params) {
1183
763
  const effectiveReserveTokens = Math.min(requestedReserveTokens, Math.max(0, params.contextTokenBudget - minPromptBudget));
1184
764
  return Math.max(1, params.contextTokenBudget - effectiveReserveTokens);
1185
765
  }
1186
- function dropDuplicateTrailingPrompt(messages, prompt) {
1187
- if (!prompt) return messages;
1188
- const trailing = messages.at(-1);
1189
- if (!trailing || trailing.role !== "user") return messages;
1190
- return extractMessageText(trailing).trim() === prompt ? messages.slice(0, -1) : messages;
1191
- }
1192
- function renderMessagesForCodexContext(messages, options) {
766
+ async function renderMessagesForCodexContext(messages, options) {
1193
767
  const tail = [];
768
+ const images = [];
769
+ let retainedImageChars = 0;
1194
770
  let totalChars = 0;
1195
771
  let retainedChars = 0;
1196
772
  for (let index = messages.length - 1; index >= 0; index--) {
1197
773
  const message = messages[index];
1198
- const text = renderMessageBody(message, options);
1199
- if (!text) continue;
774
+ if (message.role === "user" && options.currentUserTurnIdempotencyKey && Reflect.get(message, "idempotencyKey") === options.currentUserTurnIdempotencyKey) continue;
775
+ const remaining = options.maxRenderedContextChars - retainedChars;
776
+ const files = remaining > 0 && message.role === "user" ? await options.prepareFileContext?.(message, Math.min(remaining, options.maxTextPartChars)) : void 0;
777
+ const imageChars = (files?.images.length ?? 0) * IMAGE_BLOCK_TOKENS * APPROX_RENDERED_CHARS_PER_TOKEN;
778
+ const imagesFit = imageChars < remaining;
779
+ const acceptedImageChars = imagesFit ? imageChars : 0;
780
+ const text = [
781
+ renderMessageBody(message, {
782
+ ...options,
783
+ mediaPrepared: files !== void 0
784
+ }),
785
+ files?.text ? truncateText(files.text, options.maxTextPartChars) : void 0,
786
+ imageChars > 0 && !imagesFit ? "[Attachment images omitted: context budget exceeded]" : void 0
787
+ ].filter(Boolean).join("\n\n");
788
+ if (!text && acceptedImageChars === 0) continue;
1200
789
  const chunk = `[${message.role}]\n${text}${totalChars > 0 ? "\n\n" : ""}`;
1201
790
  totalChars += chunk.length;
1202
- const remaining = options.maxRenderedContextChars - retainedChars;
1203
791
  if (remaining > 0) {
1204
- const retained = neutralizeCodexExplicitMentionSigils(chunk).slice(-remaining);
792
+ const retained = neutralizeCodexExplicitMentionSigils(chunk).slice(-(remaining - acceptedImageChars));
1205
793
  tail.push(retained);
1206
- retainedChars += retained.length;
794
+ retainedChars += retained.length + acceptedImageChars;
795
+ retainedImageChars += acceptedImageChars;
796
+ if (imagesFit && files?.images.length) images.unshift(...files.images);
1207
797
  }
1208
798
  }
1209
- return truncateOlderContext(tail.toReversed().join(""), options.maxRenderedContextChars, totalChars);
799
+ return {
800
+ text: truncateOlderContext(tail.toReversed().join(""), options.maxRenderedContextChars - retainedImageChars, totalChars),
801
+ images
802
+ };
1210
803
  }
1211
804
  function renderMessageBody(message, options) {
1212
805
  if (message.role === "compactionSummary" || message.role === "branchSummary") return truncateText(message.summary.trim(), options.maxTextPartChars);
@@ -1220,7 +813,7 @@ function renderMessagePart(part, options) {
1220
813
  const record = part;
1221
814
  const type = typeof record.type === "string" ? record.type : void 0;
1222
815
  if (type === "text") return typeof record.text === "string" ? truncateText(record.text.trim(), options.maxTextPartChars) : "";
1223
- if (type === "image") return "[image omitted]";
816
+ if (type === "image") return options.mediaPrepared ? "" : "[image omitted]";
1224
817
  if (type === "toolCall" || type === "tool_use") {
1225
818
  const label = `tool call${typeof record.name === "string" ? `: ${record.name}` : ""}`;
1226
819
  if (options.toolPayloadMode === "preserve") return truncateText(`${label}\n${stableJson(renderToolCallPayload(record))}`, options.maxTextPartChars);
@@ -1303,16 +896,6 @@ function stableJson(value) {
1303
896
  return "[unserializable payload omitted]";
1304
897
  }
1305
898
  }
1306
- function extractMessageText(message) {
1307
- if (!hasMessageContent(message)) return "";
1308
- if (typeof message.content === "string") return message.content;
1309
- if (!Array.isArray(message.content)) return "";
1310
- return message.content.flatMap((part) => {
1311
- if (!part || typeof part !== "object" || !("type" in part)) return [];
1312
- const record = part;
1313
- return record.type === "text" ? [typeof record.text === "string" ? record.text : ""] : [];
1314
- }).join("\n");
1315
- }
1316
899
  function hasMessageContent(message) {
1317
900
  return "content" in message;
1318
901
  }
@@ -1549,7 +1132,7 @@ function shouldRecheckRecoverablePluginBinding(params) {
1549
1132
  //#endregion
1550
1133
  //#region extensions/codex/src/app-server/thread-fingerprints.ts
1551
1134
  function codexDynamicToolsFingerprint(dynamicTools) {
1552
- return fingerprintDynamicTools(dynamicTools);
1135
+ return hashCodexAppServerBindingFingerprint(legacyFingerprintDynamicTools(dynamicTools));
1553
1136
  }
1554
1137
  function codexLegacyDynamicToolsFingerprint(dynamicTools) {
1555
1138
  return legacyFingerprintDynamicTools(dynamicTools);
@@ -1557,11 +1140,8 @@ function codexLegacyDynamicToolsFingerprint(dynamicTools) {
1557
1140
  function areCodexDynamicToolFingerprintsCompatible(params) {
1558
1141
  return areDynamicToolFingerprintsCompatible(params.previous, params.next, params.nextLegacy);
1559
1142
  }
1560
- function fingerprintDynamicTools(dynamicTools) {
1561
- return hashCodexAppServerBindingFingerprint(legacyFingerprintDynamicTools(dynamicTools));
1562
- }
1563
1143
  function legacyFingerprintDynamicTools(dynamicTools) {
1564
- return JSON.stringify(dynamicTools.map(fingerprintDynamicToolSpec).toSorted(compareJsonFingerprint));
1144
+ return JSON.stringify(dynamicTools.map(stabilizeJsonValue).toSorted(compareJsonFingerprint));
1565
1145
  }
1566
1146
  function legacyFingerprintUserMcpServersConfigPatch(configPatch) {
1567
1147
  return configPatch ? JSON.stringify(stabilizeJsonValue(configPatch)) : void 0;
@@ -1600,9 +1180,6 @@ function fingerprintCodexThreadConfig(request, authProfileId, dynamicToolsFinger
1600
1180
  function fingerprintEnvironmentSelection(environments) {
1601
1181
  return environments ? JSON.stringify(environments.map(stabilizeJsonValue)) : void 0;
1602
1182
  }
1603
- function fingerprintDynamicToolSpec(tool) {
1604
- return stabilizeJsonValue(tool);
1605
- }
1606
1183
  function stabilizeJsonValue(value) {
1607
1184
  if (Array.isArray(value)) return value.map(stabilizeJsonValue);
1608
1185
  if (!isJsonObject(value)) return value;
@@ -1893,68 +1470,6 @@ async function loadCodexNativeToolCatalog(params) {
1893
1470
  return parseCodexNativeToolCatalog(metadata, binding.threadId, binding.dynamicToolsFingerprint);
1894
1471
  }
1895
1472
  //#endregion
1896
- //#region extensions/codex/src/app-server/managed-thread-store.ts
1897
- const CODEX_MANAGED_THREAD_NAMESPACE = "app-server-managed-threads";
1898
- const CODEX_MANAGED_THREAD_MAX_ENTRIES = 2e4;
1899
- const managedThreadSchema = z.object({
1900
- version: z.literal(1),
1901
- kind: z.literal("managed-thread"),
1902
- sourceHomeId: z.string().min(1),
1903
- threadId: z.string().min(1),
1904
- rolloutPath: z.string().min(1).optional()
1905
- });
1906
- async function markStartedCodexManagedThread(store, params) {
1907
- if (!store) return;
1908
- try {
1909
- await store.mark({
1910
- sourceHomeId: params.sourceHomeId,
1911
- threadId: params.threadId,
1912
- ...params.rolloutPath ? { rolloutPath: params.rolloutPath } : {}
1913
- });
1914
- } catch (error) {
1915
- embeddedAgentLog.warn("failed to record Codex managed thread ownership", { error });
1916
- }
1917
- }
1918
- function managedThreadStoreKey(sourceHomeId, threadId) {
1919
- return `sha256:${createHash("sha256").update("openclaw:codex-managed-thread:v1\0").update(sourceHomeId).update("\0").update(threadId).digest("hex")}`;
1920
- }
1921
- /** Durable ownership index for Codex threads created by OpenClaw. */
1922
- function createCodexManagedThreadStore(state) {
1923
- return {
1924
- async has(sourceHomeId, threadId) {
1925
- const parsed = managedThreadSchema.safeParse(state.lookup(managedThreadStoreKey(sourceHomeId, threadId)));
1926
- return parsed.success && parsed.data.sourceHomeId === sourceHomeId && parsed.data.threadId === threadId;
1927
- },
1928
- async mark(params) {
1929
- try {
1930
- const value = managedThreadSchema.parse({
1931
- version: 1,
1932
- kind: "managed-thread",
1933
- sourceHomeId: params.sourceHomeId.trim(),
1934
- threadId: params.threadId.trim(),
1935
- ...params.rolloutPath?.trim() ? { rolloutPath: params.rolloutPath.trim() } : {}
1936
- });
1937
- state.registerIfAbsent(managedThreadStoreKey(value.sourceHomeId, value.threadId), value);
1938
- return true;
1939
- } catch (error) {
1940
- embeddedAgentLog.warn("failed to record Codex managed thread ownership", { error });
1941
- return false;
1942
- }
1943
- },
1944
- async snapshot() {
1945
- const byHome = /* @__PURE__ */ new Map();
1946
- for (const entry of state.entries()) {
1947
- const parsed = managedThreadSchema.safeParse(entry.value);
1948
- if (!parsed.success) continue;
1949
- const ids = byHome.get(parsed.data.sourceHomeId) ?? /* @__PURE__ */ new Set();
1950
- ids.add(parsed.data.threadId);
1951
- byHome.set(parsed.data.sourceHomeId, ids);
1952
- }
1953
- return byHome;
1954
- }
1955
- };
1956
- }
1957
- //#endregion
1958
1473
  //#region extensions/codex/src/app-server/thread-mcp-attestation.ts
1959
1474
  async function attestCodexRestrictedToolSurfaceMcpServersDisabled(client, threadId, threadConfig, signal, expectedActiveServerNames = []) {
1960
1475
  const configuredServers = threadConfig?.mcp_servers;
@@ -2439,6 +1954,23 @@ function isCodexAppServerProfilerEnabled(config, env = process.env) {
2439
1954
  return PROFILER_FLAGS.some((flag) => isDiagnosticFlagEnabled(flag, config, env));
2440
1955
  }
2441
1956
  //#endregion
1957
+ //#region extensions/codex/src/app-server/project-doc-thread-config.ts
1958
+ const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 131072;
1959
+ function buildCodexProjectDocThreadConfig(config, effectiveNativeConfig) {
1960
+ const defaults = { project_doc_max_bytes: resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) ?? CODEX_NATIVE_PROJECT_DOC_MAX_BYTES };
1961
+ return mergeCodexThreadConfigs(defaults, config) ?? defaults;
1962
+ }
1963
+ function resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig) {
1964
+ if (effectiveNativeConfig?.origins?.project_doc_max_bytes === void 0) return;
1965
+ const authoredMaxBytes = effectiveNativeConfig.config.project_doc_max_bytes;
1966
+ if (typeof authoredMaxBytes !== "number" || !Number.isSafeInteger(authoredMaxBytes) || authoredMaxBytes < 0) throw new Error("Codex config/read returned an invalid project_doc_max_bytes value");
1967
+ return authoredMaxBytes;
1968
+ }
1969
+ function mergeCodexNativeProjectDocThreadConfig(config, effectiveNativeConfig) {
1970
+ const authoredMaxBytes = resolveCodexNativeProjectDocMaxBytes(effectiveNativeConfig);
1971
+ return authoredMaxBytes === void 0 ? config : mergeCodexThreadConfigs({ project_doc_max_bytes: authoredMaxBytes }, config);
1972
+ }
1973
+ //#endregion
2442
1974
  //#region extensions/codex/src/app-server/mcp-tool-metadata.ts
2443
1975
  /** Hosted app ownership is authoritative only on metadata supplied by Codex. */
2444
1976
  function readCodexMcpToolConnectorId(tool) {
@@ -2453,13 +1985,6 @@ function readCodexMcpToolUiVisibility(tool) {
2453
1985
  return [...new Set(visibility.filter((value) => value === "app" || value === "model"))].toSorted();
2454
1986
  }
2455
1987
  //#endregion
2456
- //#region extensions/codex/src/app-server/project-doc-thread-config.ts
2457
- const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 131072;
2458
- function buildCodexProjectDocThreadConfig(config) {
2459
- const defaults = { project_doc_max_bytes: CODEX_NATIVE_PROJECT_DOC_MAX_BYTES };
2460
- return mergeCodexThreadConfigs(defaults, config) ?? defaults;
2461
- }
2462
- //#endregion
2463
1988
  //#region extensions/codex/src/app-server/thread-model-selection.ts
2464
1989
  const CODEX_NATIVE_PERSONALITY_NONE = "none";
2465
1990
  function resolveCodexBindingModelProviderFallback(params) {
@@ -2531,17 +2056,17 @@ function resolveCodexAppServerModelProvider(params) {
2531
2056
  //#region extensions/codex/src/app-server/thread-prompt.ts
2532
2057
  function buildDeveloperInstructions(params, options = {}) {
2533
2058
  const deferredToolNames = /* @__PURE__ */ new Set();
2534
- let secretsToolName;
2535
2059
  let showWidgetToolName;
2536
2060
  let dashboardToolName;
2537
2061
  let portalToolName;
2062
+ let messageTool;
2538
2063
  let hasSkillWorkshop = false;
2539
2064
  let hasSessionsSpawn = false;
2540
2065
  let hasSessionsYield = false;
2541
2066
  let hasSubagentsList = false;
2542
2067
  let hasSessionsSend = false;
2068
+ let hasControlTools = false;
2543
2069
  let hasSeenDirectNamespace = false;
2544
- let messageToolAvailable = options.dynamicTools ? false : params.disableMessageTool !== true;
2545
2070
  for (const spec of options.dynamicTools ?? []) {
2546
2071
  const isDirectNamespace = spec.type === "namespace" && !hasSeenDirectNamespace && spec.name.trim() === "openclaw_direct";
2547
2072
  if (isDirectNamespace) hasSeenDirectNamespace = true;
@@ -2549,16 +2074,19 @@ function buildDeveloperInstructions(params, options = {}) {
2549
2074
  const name = tool.name.trim();
2550
2075
  const qualifiedName = spec.type === "namespace" ? `${spec.name}.${name}` : name;
2551
2076
  if (tool.deferLoading === true && name) deferredToolNames.add(name);
2552
- if (name === "secrets" && params.disableTools !== true) secretsToolName ??= qualifiedName;
2553
2077
  if (name === "show_widget") showWidgetToolName ??= qualifiedName;
2554
2078
  if (name === "dashboard") dashboardToolName ??= qualifiedName;
2555
2079
  if (name === "portal") portalToolName ??= qualifiedName;
2080
+ if (name === "message") messageTool ??= {
2081
+ name: qualifiedName,
2082
+ parameters: tool.inputSchema
2083
+ };
2556
2084
  hasSkillWorkshop ||= name === SKILL_WORKSHOP_TOOL_NAME;
2557
2085
  hasSessionsSpawn ||= name === "sessions_spawn";
2558
2086
  hasSessionsYield ||= isDirectNamespace && name === "sessions_yield";
2559
2087
  hasSubagentsList ||= name === "subagents";
2560
2088
  hasSessionsSend ||= name === "sessions_send";
2561
- messageToolAvailable ||= name === "message";
2089
+ hasControlTools ||= name === "openclaw" || name === "gateway";
2562
2090
  }
2563
2091
  }
2564
2092
  const nativeCommandGuidance = listRegisteredPluginAgentPromptGuidance({
@@ -2588,17 +2116,15 @@ function buildDeveloperInstructions(params, options = {}) {
2588
2116
  hasSubagentsList,
2589
2117
  hasSessionsSend
2590
2118
  }).join("\n") : void 0,
2591
- buildHarnessVisibleReplyGuidance({
2592
- sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
2593
- messageToolAvailable,
2594
- uiPresentation: params.disableTools !== true && params.promptMode !== "minimal" && params.promptMode !== "none" ? {
2595
- showWidgetToolName,
2596
- dashboardToolName,
2597
- portalToolName
2598
- } : void 0
2599
- }),
2600
- buildCredentialSafetyPrompt(secretsToolName),
2119
+ params.disableTools !== true && params.promptMode !== "minimal" && params.promptMode !== "none" ? buildUiPresentationPrompt({
2120
+ showWidgetToolName,
2121
+ dashboardToolName,
2122
+ portalToolName,
2123
+ messageTool
2124
+ }) : void 0,
2125
+ buildCredentialSafetyPrompt({ controlToolsAvailable: params.disableTools !== true && hasControlTools }),
2601
2126
  nativeCommandGuidance,
2127
+ params.gitCoauthorPrompt,
2602
2128
  params.extraSystemPrompt
2603
2129
  ].filter((section) => typeof section === "string" && section.trim()).join("\n\n");
2604
2130
  }
@@ -2938,7 +2464,7 @@ function buildRestrictedToolConfigPatch(inheritedMcpServerNames, scheduledAppAut
2938
2464
  };
2939
2465
  }
2940
2466
  async function readCodexInheritedMcpServerNames(client, cwd, signal, effectiveConfig) {
2941
- const response = effectiveConfig ?? await readCodexEffectiveConfig(client, cwd, signal);
2467
+ const response = effectiveConfig ?? await readCodexEffectiveConfig(client, cwd, { signal });
2942
2468
  if (!Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config layers");
2943
2469
  for (const layer of response.layers) {
2944
2470
  if (!isJsonObject(layer) || !isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned invalid effective config layers");
@@ -3383,51 +2909,26 @@ function shouldWarnCodexThreadLifecycleTimingSummary(summary, options = {}) {
3383
2909
  return summary.totalMs >= totalThresholdMs || summary.spans.some((span) => span.durationMs >= stageThresholdMs);
3384
2910
  }
3385
2911
  function formatCodexThreadLifecycleTimingSummary(params) {
3386
- const spans = params.summary.spans.length > 0 ? params.summary.spans.map((span) => `${span.name}:${span.durationMs}ms@${span.elapsedMs}ms`).join(",") : "none";
2912
+ const spans = formatStageTimings(params.summary.spans);
3387
2913
  return `[trace:codex-app-server] thread lifecycle: runId=${params.runId} sessionId=${params.sessionId} sessionKey=${params.sessionKey ?? "unknown"} action=${params.action} totalMs=${params.summary.totalMs} stages=${spans}`;
3388
2914
  }
3389
2915
  function createCodexThreadLifecycleTimingTracker(options = {}) {
3390
2916
  const log = options.log ?? embeddedAgentLog;
3391
- const now = options.now ?? Date.now;
3392
- const startedAt = now();
2917
+ const timing = createStageTimingTracker(options.now ?? Date.now);
3393
2918
  let didLog = false;
3394
- const spans = [];
3395
- const toMs = (value) => Math.max(0, Math.round(value));
3396
- const record = (name, spanStartedAt) => {
3397
- const currentAt = now();
3398
- spans.push({
3399
- name,
3400
- durationMs: toMs(currentAt - spanStartedAt),
3401
- elapsedMs: toMs(currentAt - startedAt)
3402
- });
3403
- };
3404
- const snapshot = () => ({
3405
- totalMs: toMs(now() - startedAt),
3406
- spans: spans.slice()
3407
- });
3408
2919
  return {
3409
- async measure(name, run) {
3410
- const spanStartedAt = now();
3411
- try {
3412
- return await run();
3413
- } finally {
3414
- record(name, spanStartedAt);
3415
- }
3416
- },
3417
- measureSync(name, run) {
3418
- const spanStartedAt = now();
3419
- try {
3420
- return run();
3421
- } finally {
3422
- record(name, spanStartedAt);
3423
- }
3424
- },
2920
+ measure: timing.measure,
2921
+ measureSync: timing.measureSync,
3425
2922
  mark(name) {
3426
- record(name, now());
2923
+ timing.measureSync(name, () => void 0);
3427
2924
  },
3428
2925
  logSummary(params) {
3429
2926
  if (didLog) return;
3430
- const summary = snapshot();
2927
+ const { totalMs, stages: spans } = timing.snapshot();
2928
+ const summary = {
2929
+ totalMs,
2930
+ spans
2931
+ };
3431
2932
  const shouldWarn = shouldWarnCodexThreadLifecycleTimingSummary(summary, {
3432
2933
  ...options,
3433
2934
  log
@@ -3463,7 +2964,7 @@ function resolveCodexThreadAgentDir(params) {
3463
2964
  sessionKey: params.params.sessionKey,
3464
2965
  agentId: params.agentId ?? params.params.agentId
3465
2966
  }).sessionAgentId;
3466
- return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$2(params.params.config ?? {}, agentId);
2967
+ return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$1(params.params.config ?? {}, agentId);
3467
2968
  }
3468
2969
  async function prepareCodexThreadLifecyclePreflight(params) {
3469
2970
  let effectiveConfig = await assertCodexModelBackedReviewerEffectiveConfig({
@@ -3522,7 +3023,8 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3522
3023
  const allowConfiguredManagedHooks = params.params.pluginHarnessToolPolicyRestricted === true && !ringZeroActive && !messageOnlySourceReply && params.params.scheduledRuntimeAuthority === void 0;
3523
3024
  const imageGenerationDenied = params.params.pluginHarnessToolPolicySafeDeniedTools?.includes("image_generate") === true;
3524
3025
  if (restrictedToolSurface && params.nativeCodeModeEnabled !== false) throw new Error("Codex restricted tool surfaces require native code mode to be disabled");
3525
- if ((restrictedToolSurface || params.nativeCodeModeEnabled !== false) && !effectiveConfig) effectiveConfig = await lifecycleTiming.measure("tool-policy-config-read", () => readCodexEffectiveConfig(params.client, params.cwd, params.signal));
3026
+ if (!effectiveConfig) effectiveConfig = await lifecycleTiming.measure("effective-config-read", () => readCodexEffectiveConfig(params.client, params.cwd, { signal: params.signal }));
3027
+ params.config = mergeCodexNativeProjectDocThreadConfig(params.config, effectiveConfig);
3526
3028
  const restrictedToolSurfaceInheritedMcpServerNames = restrictedToolSurface ? await lifecycleTiming.measure("restricted-tool-surface-mcp-policy", () => readCodexInheritedMcpServerNames(params.client, params.cwd, params.signal, effectiveConfig)) : [];
3527
3029
  if (restrictedToolSurface || imageGenerationDenied || params.nativeCodeModeEnabled !== false) await lifecycleTiming.measure("tool-policy-config-requirements-read", () => assertCodexManagedRequirementsDoNotOverrideToolPolicy(params.client, {
3528
3030
  restrictedToolSurface,
@@ -3538,7 +3040,9 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3538
3040
  baseInstructions: "",
3539
3041
  config: buildCodexRingZeroThreadConfigPatch(params.params, true, restrictedToolSurfaceInheritedMcpServerNames)
3540
3042
  }) : void 0;
3043
+ const ringZeroClientInstanceId = ringZeroActive ? getCodexAppServerClientInstanceId(params.client) : void 0;
3541
3044
  return {
3045
+ effectiveConfig,
3542
3046
  contextEngineBinding,
3543
3047
  dynamicToolsContainDeferred,
3544
3048
  dynamicToolsFingerprint,
@@ -3551,7 +3055,7 @@ async function prepareCodexThreadLifecyclePreflight(params) {
3551
3055
  nativeSkillIsolationFingerprint,
3552
3056
  networkProxyConfigFingerprint,
3553
3057
  ringZeroActive,
3554
- ringZeroClientInstanceId: ringZeroActive ? getCodexAppServerClientInstanceId(params.client) : void 0,
3058
+ ringZeroClientInstanceId,
3555
3059
  ringZeroConfigFingerprint,
3556
3060
  restrictedToolSurface,
3557
3061
  restrictedToolSurfaceInheritedMcpServerNames,
@@ -3619,11 +3123,16 @@ async function resumeExistingCodexThread(params, context) {
3619
3123
  abandonClient,
3620
3124
  request: resumeParams,
3621
3125
  signal: params.signal,
3622
- assertCurrent: configuration.assertCurrent
3126
+ assertCurrent: () => {
3127
+ configuration.assertCurrent();
3128
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, resumeParams.config);
3129
+ if (params.inferenceRoute && resumeParams.modelProvider != null && resumeParams.modelProvider !== "openai") throw new Error("Codex inference route requires the native OpenAI provider");
3130
+ }
3623
3131
  }));
3624
3132
  acceptedConfiguration = configuration;
3625
3133
  assertCodexThreadAcceptsDirectInput(response.thread);
3626
3134
  configuration.assertConfigured();
3135
+ if (requestModelProvider && response.modelProvider !== requestModelProvider) throw new Error("Codex resumed a different model provider than the one selected for this turn");
3627
3136
  const loadedPluginThreadConfig = await context.buildLoadedPluginThreadConfig?.(resumeBinding);
3628
3137
  if (loadedPluginThreadConfig && loadedPluginThreadConfig.fingerprint !== (pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint)) {
3629
3138
  ordinaryAppConfigChanged = resumeBinding.connectionScope !== "supervision" && !resumeBinding.pendingResumeConfiguration;
@@ -3657,7 +3166,7 @@ async function resumeExistingCodexThread(params, context) {
3657
3166
  cwd: params.cwd,
3658
3167
  rolloutPath: resolveCodexThreadRolloutPath(response.thread) ?? resumeBinding.rolloutPath,
3659
3168
  authProfileId,
3660
- model: response.model ?? resumeParams.model ?? params.params.modelId,
3169
+ model: resumeParams.model ?? response.model ?? params.params.modelId,
3661
3170
  preserveNativeModel: resumeBinding.preserveNativeModel === true ? true : void 0,
3662
3171
  modelProvider: normalizeBindingModelProvider(authProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider),
3663
3172
  dynamicToolsFingerprint,
@@ -3781,12 +3290,17 @@ async function startFreshCodexThread(params, context) {
3781
3290
  params.params.hostCapabilities.assertActive();
3782
3291
  params.assertCurrent?.();
3783
3292
  };
3293
+ const assertInferenceCurrent = () => {
3294
+ assertCurrent();
3295
+ assertCodexInferenceRouteConfig(params.client, params.inferenceRoute, startParams.config);
3296
+ if (params.inferenceRoute && startParams.modelProvider != null && startParams.modelProvider !== "openai") throw new Error("Codex inference route requires the native OpenAI provider");
3297
+ };
3784
3298
  const threadStartResponse = await lifecycleTiming.measure("thread-start-request", async () => {
3785
3299
  try {
3786
3300
  assertCurrent();
3787
3301
  return await params.client.request("thread/start", startParams, {
3788
3302
  signal: params.signal,
3789
- assertCurrent
3303
+ assertCurrent: assertInferenceCurrent
3790
3304
  });
3791
3305
  } catch (error) {
3792
3306
  if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
@@ -4239,8 +3753,7 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
4239
3753
  assertCurrent
4240
3754
  });
4241
3755
  assertCurrent();
4242
- const statusType = thread.status?.type;
4243
- if (thread.id !== binding.threadId || statusType !== "idle" && statusType !== "notLoaded") throw fail("the native thread is not idle; wait for its current run to finish");
3756
+ if (thread.id !== binding.threadId || !isCodexThreadNonRunning(thread.status)) throw fail("the native thread is not idle; wait for its current run to finish");
4244
3757
  assertCodexThreadAcceptsDirectInput(thread);
4245
3758
  const observation = observeCodexThreadConfiguration(params, thread, assertCurrent);
4246
3759
  const dispose = observation.dispose;
@@ -4284,8 +3797,11 @@ async function prepareCodexThreadResume(params, binding, context) {
4284
3797
  assertCurrent
4285
3798
  };
4286
3799
  }
3800
+ function isCodexThreadNonRunning(status) {
3801
+ return status?.type === "idle" || status?.type === "notLoaded" || status?.type === "systemError";
3802
+ }
4287
3803
  function observeCodexThreadConfiguration(params, thread, assertCurrent) {
4288
- if (thread.status?.type !== "idle" && thread.status?.type !== "notLoaded") throw new CodexAdoptedThreadActiveError();
3804
+ if (!isCodexThreadNonRunning(thread.status)) throw new CodexAdoptedThreadActiveError();
4289
3805
  let unloaded = thread.status.type === "notLoaded";
4290
3806
  return {
4291
3807
  dispose: params.client.addNotificationHandler((notification) => {
@@ -4689,6 +4205,23 @@ async function startOrResumeThread(input) {
4689
4205
  if (!isDeepStrictEqual(params.dynamicTools, nativeCatalog)) throw new Error("Canonical Codex declarations changed after tool preparation; retry the turn on its preserved native thread.");
4690
4206
  }
4691
4207
  const preflight = await prepareCodexThreadLifecyclePreflight(params);
4208
+ const inference = await prepareCodexInferenceThreadConfig({
4209
+ ...params,
4210
+ binding: saved,
4211
+ clientId,
4212
+ effectiveConfig: preflight.effectiveConfig,
4213
+ assertCurrent: assert
4214
+ });
4215
+ if (inference) {
4216
+ params.config = inference.config;
4217
+ params.inferenceRoute = inference.route;
4218
+ }
4219
+ const publishInferenceBinding = (readyBinding) => {
4220
+ assert();
4221
+ params.signal?.throwIfAborted();
4222
+ bindCodexInferenceThread(params.client, readyBinding.threadId, inference?.route);
4223
+ return readyBinding;
4224
+ };
4692
4225
  const { contextEngineBinding, dynamicToolsContainDeferred, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, legacyDynamicToolsFingerprint, legacyUserMcpServersFingerprint, lifecycleTiming, nativeSkillIsolation, nativeSkillIsolationFingerprint, networkProxyConfigFingerprint, ringZeroActive, ringZeroClientInstanceId, ringZeroConfigFingerprint, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, userMcpServersConfigPatch, userMcpServersFingerprint, webSearchThreadConfigFingerprint } = preflight;
4693
4226
  let replacementPredecessor;
4694
4227
  const initialBoundThreadId = binding?.threadId;
@@ -4808,13 +4341,13 @@ async function startOrResumeThread(input) {
4808
4341
  const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
4809
4342
  const transientNativeToolRestriction = params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction;
4810
4343
  const transientWebSearchRestriction = isTransientWebSearchRestriction(params);
4811
- if (binding?.pendingResumeConfiguration) return await resumePendingCodexThread(params, {
4344
+ if (binding?.pendingResumeConfiguration) return publishInferenceBinding(await resumePendingCodexThread(params, {
4812
4345
  ...resolveRequestContext(),
4813
4346
  binding,
4814
4347
  clearCurrentBinding,
4815
4348
  releaseRetainedThread: (threadId, assertCurrent) => releaseRetainedThread(threadId, initialBoundClientId, assertCurrent),
4816
4349
  transientRestriction: transientDelegationRestriction || transientNativeToolRestriction || transientWebSearchRestriction
4817
- });
4350
+ }));
4818
4351
  if (binding?.threadId && !restrictedToolSurface && binding.nativeToolPolicyRestricted === true) await clearCurrentBinding("rotating a host-policy-restricted thread binding");
4819
4352
  if (binding?.threadId && binding.nativeSkillIsolationFingerprint !== nativeSkillIsolationFingerprint) {
4820
4353
  embeddedAgentLog.debug("codex app-server native skill isolation changed; starting a new thread", { threadId: binding.threadId });
@@ -4988,7 +4521,7 @@ async function startOrResumeThread(input) {
4988
4521
  clientId,
4989
4522
  buildLoadedPluginThreadConfig
4990
4523
  });
4991
- if (warmReuse.kind === "ready") return warmReuse.binding;
4524
+ if (warmReuse.kind === "ready") return publishInferenceBinding(warmReuse.binding);
4992
4525
  if (incognito || warmReuse.kind === "rotate") {
4993
4526
  throwIfAborted();
4994
4527
  await clearCurrentBinding(incognito ? "rotating an unavailable ephemeral thread binding" : "rotating a stale plugin app binding");
@@ -5006,7 +4539,7 @@ async function startOrResumeThread(input) {
5006
4539
  await releaseRetainedThread(resumeBinding.threadId, resumeBinding.clientId, assertCurrent);
5007
4540
  }
5008
4541
  });
5009
- if (resumed) return resumed;
4542
+ if (resumed) return publishInferenceBinding(resumed);
5010
4543
  }
5011
4544
  }
5012
4545
  }
@@ -5020,7 +4553,7 @@ async function startOrResumeThread(input) {
5020
4553
  replacementPredecessor
5021
4554
  });
5022
4555
  if (replacementPredecessor) await releaseRetainedThread(replacementPredecessor.threadId, replacementPredecessor.clientId);
5023
- return started;
4556
+ return publishInferenceBinding(started);
5024
4557
  });
5025
4558
  }
5026
4559
  //#endregion
@@ -5130,9 +4663,21 @@ function buildTurnStartParams(params, options) {
5130
4663
  skillsCollaborationInstructions: options.skillsCollaborationInstructions,
5131
4664
  memoryCollaborationInstructions: options.memoryCollaborationInstructions
5132
4665
  }) : void 0;
4666
+ if (collaborationMode && options.parentLocalEgress) collaborationMode.settings.developer_instructions = null;
5133
4667
  const useThreadPermissionProfile = options.appServer.networkProxy && !options.sandboxPolicy;
5134
4668
  const currentSenderContext = params.trigger === "user" ? buildCodexCurrentSenderContextValue(params) : void 0;
5135
4669
  let additionalContext = buildCodexTemporalAdditionalContext(params, { sessionStatusAvailable: options.sessionStatusAvailable === true });
4670
+ additionalContext = {
4671
+ ...additionalContext,
4672
+ openclaw_source_delivery: {
4673
+ kind: "application",
4674
+ value: ["Current source-delivery policy for this turn (replaces earlier source-delivery guidance):", buildHarnessVisibleReplyGuidance({
4675
+ sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
4676
+ messageToolAvailable: options.messageToolAvailable === true,
4677
+ requireExplicitMessageTarget: options.requireExplicitMessageTarget
4678
+ })].join("\n")
4679
+ }
4680
+ };
5136
4681
  if (currentSenderContext) additionalContext = {
5137
4682
  ...additionalContext,
5138
4683
  openclaw_current_sender: {
@@ -5192,11 +4737,14 @@ function buildTurnCollaborationMode(params, options = {}) {
5192
4737
  }
5193
4738
  };
5194
4739
  }
5195
- function buildTurnScopedCollaborationInstructions(params, options = {}) {
4740
+ function buildCodexParentLocalInstructions(params, options = {}) {
5196
4741
  const contextInstructions = joinPresentSections(options.turnScopedDeveloperInstructions, options.memoryCollaborationInstructions, options.skillsCollaborationInstructions);
5197
4742
  if (params.trigger === "cron") return joinPresentSections(buildCronCollaborationInstructions(), contextInstructions);
5198
- if (contextInstructions?.trim()) return joinPresentSections(buildDefaultCollaborationInstructions(), contextInstructions);
5199
- return null;
4743
+ return contextInstructions || null;
4744
+ }
4745
+ function buildTurnScopedCollaborationInstructions(params, options) {
4746
+ const instructions = buildCodexParentLocalInstructions(params, options);
4747
+ return instructions && params.trigger !== "cron" ? joinPresentSections(buildDefaultCollaborationInstructions(), instructions) : instructions;
5200
4748
  }
5201
4749
  function buildDefaultCollaborationInstructions() {
5202
4750
  return [
@@ -5225,4 +4773,4 @@ function joinPresentSections(...sections) {
5225
4773
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
5226
4774
  }
5227
4775
  //#endregion
5228
- export { resolveCodexNativeSkillIsolation as $, readCodexMcpToolConnectorId as A, refreshCodexPluginRuntimeState as At, emitCodexNativePreToolUseFailureDiagnostic as B, buildDeveloperInstructions as C, buildCodexPluginThreadConfigInputFingerprint as Ct, resolveCodexAppServerThreadModelSelection as D, refreshCodexPluginAppApprovalPolicy as Dt, resolveCodexAppServerRequestModelSelection as E, mergeCodexThreadConfigs as Et, assertCodexNativeHookRelayAllowed as F, attestCodexRestrictedToolSurfaceMcpServersDisabled as G, resolveCodexNativeHookRelayTtlMs as H, buildCodexNativeHookRelayConfig as I, createCodexManagedThreadStore as J, CODEX_MANAGED_THREAD_MAX_ENTRIES as K, buildCodexNativeHookRelayDisabledConfig as L, isCodexAppServerProfilerEnabled as M, isOpenAiCuratedMarketplaceName as Mt, CODEX_NATIVE_HOOK_RELAY_EVENTS as N, pluginReadParams as Nt, resolveCodexBindingModelProviderFallback as O, shouldBuildCodexPluginThreadConfig as Ot, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as P, resolveRecoverableCodexPluginConfigKeys as Pt, applyCodexNativeSkillIsolation as Q, buildCodexNativeHookRelayId as R, resolveCodexWebSearchPlan as S, buildCodexPluginThreadConfig as St, resolveCodexAppServerModelProvider as T, buildDisabledAppsConfigPatch as Tt, scheduleCodexNativeHookRelayUnregister as U, resolveCodexNativeHookRelayEvents as V, checkCodexThreadAppAvailability as W, loadCodexNativeToolCatalog as X, hasCodexNativeToolCatalog as Y, parseCodexNativeToolCatalog as Z, buildCodexRingZeroThreadConfigPatch as _, neutralizeCodexExplicitMentionSigils as _t, readCodexSupportedReasoningEfforts as a, filterCodexDynamicTools as at, readCodexInheritedMcpServerNames as b, resolveCodexContextEngineProjectionReserveTokens as bt, assertScheduledCodexAppAuthorityRuntime as c, isMessageOnlyCodexSourceReply as ct, buildScheduledCodexAppServerConnectionIdentity as d, resolveCodexDynamicToolsLoading as dt, areCodexDynamicToolFingerprintsCompatible as et, captureScheduledCodexAppAuthority as f, resolveCodexDynamicToolsLoadingForRuntime as ft, assertCodexManagedRequirementsDoNotOverrideToolPolicy as g, fitCodexProjectedContextForTurnStart as gt, resolveScheduledCodexAppCreatorCaptureDecision as h, buildCodexContinuityCalibration as ht, buildCodexUserInput as i, fingerprintUserMcpServersConfigPatch as it, readCodexMcpToolUiVisibility as j, isOpenAiCuratedMarketplace as jt, buildCodexProjectDocThreadConfig as k, ensureCodexPluginActivation as kt, buildLegacyScheduledCodexAppRecoveryPrompt as l, isSystemAgentOnlyCodexDynamicToolAllowlist as lt, readCurrentCodexScheduledAppPolicy as m, isContextEngineBindingCompatible as mt, buildTurnCollaborationMode as n, codexLegacyDynamicToolsFingerprint as nt, resolveCodexAppServerReasoningEffort as o, filterCodexDynamicToolsForDisabledNativeSurface as ot, intersectCodexPluginThreadConfigWithScheduledAuthority as p, buildContextEngineBinding as pt, CODEX_MANAGED_THREAD_NAMESPACE as q, buildTurnStartParams as r, fingerprintJsonObject as rt, startOrResumeThread as s, isForcedPrivateQaCodexRuntime as st, buildCodexTemporalAdditionalContext as t, codexDynamicToolsFingerprint as tt, buildScheduledCodexAppAuthorityInputFingerprint as u, normalizeCodexDynamicToolName as ut, buildCodexRuntimeThreadConfig as v, projectContextEngineAssemblyForCodex as vt, CODEX_NATIVE_PERSONALITY_NONE as w, buildCodexPluginThreadConfigTimeoutFallback as wt, buildCodexNativeWebSearchThreadConfig as x, resolveCodexContinuityProjectionMaxChars as xt, buildCodexThreadConfiguration as y, resolveCodexContextEngineProjectionMaxChars as yt, createCodexNativeHookRelay as z };
4776
+ export { codexDynamicToolsFingerprint as $, readCodexMcpToolConnectorId as A, createCodexNativeHookRelay as B, resolveCodexWebSearchPlan as C, buildCodexPluginThreadConfigInputFingerprint as Ct, resolveCodexAppServerRequestModelSelection as D, refreshCodexPluginAppApprovalPolicy as Dt, resolveCodexAppServerModelProvider as E, mergeCodexThreadConfigs as Et, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as F, checkCodexThreadAppAvailability as G, resolveCodexNativeHookRelayEvents as H, assertCodexNativeHookRelayAllowed as I, loadCodexNativeToolCatalog as J, attestCodexRestrictedToolSurfaceMcpServersDisabled as K, buildCodexNativeHookRelayConfig as L, buildCodexProjectDocThreadConfig as M, isCodexAppServerProfilerEnabled as N, resolveCodexAppServerThreadModelSelection as O, shouldBuildCodexPluginThreadConfig as Ot, CODEX_NATIVE_HOOK_RELAY_EVENTS as P, areCodexDynamicToolFingerprintsCompatible as Q, buildCodexNativeHookRelayDisabledConfig as R, buildCodexNativeWebSearchThreadConfig as S, buildCodexPluginThreadConfig as St, CODEX_NATIVE_PERSONALITY_NONE as T, buildDisabledAppsConfigPatch as Tt, resolveCodexNativeHookRelayTtlMs as U, emitCodexNativePreToolUseFailureDiagnostic as V, scheduleCodexNativeHookRelayUnregister as W, applyCodexNativeSkillIsolation as X, parseCodexNativeToolCatalog as Y, resolveCodexNativeSkillIsolation as Z, assertCodexManagedRequirementsDoNotOverrideToolPolicy as _, neutralizeCodexExplicitMentionSigils as _t, buildCodexUserInput as a, isForcedPrivateQaCodexRuntime as at, buildCodexThreadConfiguration as b, resolveCodexContextEngineProjectionReserveTokens as bt, startOrResumeThread as c, normalizeCodexDynamicToolName as ct, buildScheduledCodexAppAuthorityInputFingerprint as d, buildContextEngineBinding as dt, codexLegacyDynamicToolsFingerprint as et, buildScheduledCodexAppServerConnectionIdentity as f, isContextEngineBindingCompatible as ft, resolveScheduledCodexAppCreatorCaptureDecision as g, isCodexDurableCustomMessage as gt, readCurrentCodexScheduledAppPolicy as h, fitCodexProjectedContextForTurnStart as ht, buildTurnStartParams as i, filterCodexDynamicToolsForDisabledNativeSurface as it, readCodexMcpToolUiVisibility as j, resolveCodexBindingModelProviderFallback as k, assertScheduledCodexAppAuthorityRuntime as l, resolveCodexDynamicToolsLoading as lt, intersectCodexPluginThreadConfigWithScheduledAuthority as m, buildCodexContinuityCalibration as mt, buildCodexTemporalAdditionalContext as n, fingerprintUserMcpServersConfigPatch as nt, readCodexSupportedReasoningEfforts as o, isMessageOnlyCodexSourceReply as ot, captureScheduledCodexAppAuthority as p, CodexContextAttachmentError as pt, hasCodexNativeToolCatalog as q, buildTurnCollaborationMode as r, filterCodexDynamicTools as rt, resolveCodexAppServerReasoningEffort as s, isSystemAgentOnlyCodexDynamicToolAllowlist as st, buildCodexParentLocalInstructions as t, fingerprintJsonObject as tt, buildLegacyScheduledCodexAppRecoveryPrompt as u, resolveCodexDynamicToolsLoadingForRuntime as ut, buildCodexRingZeroThreadConfigPatch as v, projectContextEngineAssemblyForCodex as vt, buildDeveloperInstructions as w, buildCodexPluginThreadConfigTimeoutFallback as wt, readCodexInheritedMcpServerNames as x, resolveCodexContinuityProjectionMaxChars as xt, buildCodexRuntimeThreadConfig as y, resolveCodexContextEngineProjectionMaxChars as yt, buildCodexNativeHookRelayId as z };