@openclaw/codex 2026.8.1 → 2026.8.33

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 (67) hide show
  1. package/dist/{attempt-client-cleanup-CVPvp9dL.js → .setup/attempt-client-cleanup-FBnDjmtX.mjs} +1 -1
  2. package/dist/{auth-binding-Ds_QVm-X.js → .setup/auth-binding-oyIUSaFi.mjs} +1 -1
  3. package/dist/{binding-connection-CCQFs8lf.js → .setup/binding-connection-BgiXAp29.mjs} +2 -2
  4. package/dist/{bounded-turn-rq5tiSXk.js → .setup/bounded-turn-kWYLbaDH.mjs} +12 -11
  5. package/dist/{capabilities-CGm_94eL.js → .setup/capabilities-oLHKpYRj.mjs} +1 -1
  6. package/dist/{command-formatters-C54Yg3eA.js → .setup/command-formatters-DylXEqck.mjs} +4 -3
  7. package/dist/{command-handlers-BvOAHTrA.js → .setup/command-handlers-PRe4WEmx.mjs} +42 -34
  8. package/dist/{compact-Hd7SAc0N.js → .setup/compact-K2iOmzQp.mjs} +14 -12
  9. package/dist/{config-Cxw3Cl3k.js → .setup/config-ClwHKKTN.mjs} +7 -5
  10. package/dist/{conversation-binding-data-CW2GuupV.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +3 -2
  11. package/dist/{dynamic-tools-BFoUcRdx.js → .setup/dynamic-tools-XNStyzzb.mjs} +105 -108
  12. package/dist/{effective-mcp-catalog-BTJHnDSx.js → .setup/effective-mcp-catalog-BHpifbgx.mjs} +2 -2
  13. package/dist/{event-projector-assistant-message-C5-Ds8mA.js → .setup/event-projector-assistant-message-BCnzlajn.mjs} +1 -1
  14. package/dist/{event-projector-usage-D3PHFFXh.js → .setup/event-projector-usage-h7P0Raok.mjs} +7 -12
  15. package/dist/{harness-DVfUQBlQ.js → .setup/harness-CawBdltH.mjs} +14 -14
  16. package/dist/{isolated-completion-Cbbx_5Ed.js → .setup/isolated-completion-rL3zrcAe.mjs} +4 -4
  17. package/dist/{managed-binary-ZkGodW19.js → .setup/managed-binary-DlGr2kYu.mjs} +1 -1
  18. package/dist/{model-catalog-o6Cgjoss.js → .setup/model-catalog--miA1cod.mjs} +5 -5
  19. package/dist/{models-DgFWSuxA.js → .setup/models-BNPc8Vr2.mjs} +5 -4
  20. package/dist/{native-subagent-monitor-CwFyoylz.js → .setup/native-subagent-monitor-mhFvLcPG.mjs} +25 -105
  21. package/dist/{node-exec-server.runtime-DXrqpw1c.js → .setup/node-exec-server.runtime-BmAZPmrd.mjs} +3 -3
  22. package/dist/{plugin-approval-roundtrip-D80UZiJ_.js → .setup/plugin-approval-roundtrip-Dlq4n0n8.mjs} +2 -1
  23. package/dist/{plugin-marketplace-discovery-mdmScYOj.js → .setup/plugin-marketplace-discovery-KyJdBtCC.mjs} +14 -13
  24. package/dist/{plugin-metadata-cache-CulOABwu.js → .setup/plugin-metadata-cache-RRQ_VJrs.mjs} +6 -6
  25. package/dist/{rate-limits-hFtzt2Up.js → .setup/rate-limits-CQUmEcUk.mjs} +3 -2
  26. package/dist/{request-CCm4LaED.js → .setup/request-fEUi95EK.mjs} +3 -3
  27. package/dist/{run-attempt-BwNQDH2u.js → .setup/run-attempt-BJ6tOQeE.mjs} +138 -187
  28. package/dist/{runtime-artifact-DeBvleJw.js → .setup/runtime-artifact-D0ssVSlz.mjs} +3 -3
  29. package/dist/{session-binding-q2WSTVmC.js → .setup/session-binding-Bd9dh1Er.mjs} +3 -3
  30. package/dist/{session-catalog-C2Tae4rI.js → .setup/session-catalog-eQhJDU41.mjs} +234 -206
  31. package/dist/{session-catalog-home-id-DAKUrm3C.js → .setup/session-catalog-home-id-CjyBDShn.mjs} +3 -3
  32. package/dist/{session-cli-BuDjm5Ou.js → .setup/session-cli-mJePHTAs.mjs} +1 -1
  33. package/dist/.setup/session-history-Cg8PzgeU.mjs +87 -0
  34. package/dist/{session-permission-policy-gLm40Vtq.js → .setup/session-permission-policy-C0bdhR_I.mjs} +1 -1
  35. package/dist/{session-retirement-CdkI0bvb.js → .setup/session-retirement-osjW6zy5.mjs} +4 -4
  36. package/dist/{session-upstream-marker-Bcy33kam.js → .setup/session-upstream-marker-CIgMzZku.mjs} +1 -1
  37. package/dist/.setup/settled-turn-context-OxoGQWJK.mjs +290 -0
  38. package/dist/.setup/settled-turn-finalizer-D9SoKTb-.mjs +104 -0
  39. package/dist/{shared-client-kNkljY-R.js → .setup/shared-client-DG1kAfGq.mjs} +37 -39
  40. package/dist/{side-question-GwD73tX6.js → .setup/side-question-Bi9chAvD.mjs} +25 -17
  41. package/dist/{thread-lifecycle-Ss-uwnC4.js → .setup/thread-lifecycle-Cc6I-gbl.mjs} +273 -232
  42. package/dist/{thread-ownership-CeYBqg_4.js → .setup/thread-ownership-B3vjUi0P.mjs} +2 -2
  43. package/dist/{thread-resume-DF54hagX.js → .setup/thread-resume-OMjvue9F.mjs} +8 -7
  44. package/dist/{transcript-mirror-CkEQIna-.js → .setup/transcript-mirror-DN-ed7Kf.mjs} +14 -7
  45. package/dist/{transport-stdio-C7-s9TLG.js → .setup/transport-stdio-Cu0xKDRo.mjs} +41 -25
  46. package/dist/{upstream-prompt-provenance-CFmsKwr9.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +8 -4
  47. package/dist/{upstream-session-fork-BACGlOFa.js → .setup/upstream-session-fork-DL7QQ1e_.mjs} +14 -20
  48. package/dist/{usage-C2l8Mils.js → .setup/usage-dsPLHd8O.mjs} +3 -3
  49. package/dist/{web-search-provider.runtime-B2XgRdFv.js → .setup/web-search-provider.runtime-BRH3ahFN.mjs} +3 -3
  50. package/dist/api.js +4 -4
  51. package/dist/cli-metadata.js +1 -1
  52. package/dist/doctor-contract-api.js +9 -5
  53. package/dist/harness.js +1 -1
  54. package/dist/index.js +60 -41
  55. package/dist/media-understanding-provider.js +1 -1
  56. package/dist/web-search-contract-api.js +1 -1
  57. package/package.json +6 -6
  58. package/dist/settled-turn-finalizer-B8JJcxCi.js +0 -329
  59. /package/dist/{context-compaction-activity-BOeJf7yo.js → .setup/context-compaction-activity-BOeJf7yo.mjs} +0 -0
  60. /package/dist/{elicitation-input-DMkeki8d.js → .setup/elicitation-input-DMkeki8d.mjs} +0 -0
  61. /package/dist/{image-payload-sanitizer-CnfoUPCE.js → .setup/image-payload-sanitizer-CnfoUPCE.mjs} +0 -0
  62. /package/dist/{launch-args-sXOAg0SX.js → .setup/launch-args-sXOAg0SX.mjs} +0 -0
  63. /package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
  64. /package/dist/{protocol-validators-Bg5rpNxk.js → .setup/protocol-validators-Bg5rpNxk.mjs} +0 -0
  65. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  66. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  67. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -1,13 +1,13 @@
1
- import { E as resolveCodexPluginsPolicy, F as resolveCodexAppServerLocalHomeDir, M as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME, P as resolveCodexAppServerHomeDir, f as assertCodexModelBackedReviewerEffectiveConfig, j as CODEX_PLUGINS_MARKETPLACE_NAME, n as codexSandboxPolicyForTurn } from "./config-Cxw3Cl3k.js";
2
- import { $ as CodexAppServerRpcError, D as CodexThreadStartRequestError, E as CodexThreadBindingConflictError, H as getCodexAppServerClientInstanceId, Ht as isJsonObject, J as isCodexAppServerOverloadError, Q as resolveCodexAppServerClientInstanceId, St as releaseCodexAppServerLiveThread, T as CodexRestrictedToolSurfaceAttestationError, Vt as flattenCodexDynamicToolFunctions, _ as retainSharedCodexAppServerClientByInstanceId, bt as isCodexAppServerLiveThreadClaimed, dt as resolveCodexToolAbortTerminalReason, gt as consumeCodexAppServerLiveThread, n as captureExclusiveSharedCodexAppServerClient, w as CodexAdoptedThreadActiveError, wt as unsubscribeCodexAppServerLiveThread } from "./shared-client-kNkljY-R.js";
3
- import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-q2WSTVmC.js";
4
- import { a as assertCodexThreadForkResponse, r as assertCodexThreadAcceptsDirectInput, s as assertCodexThreadStartResponse, t as CodexThreadDirectInputError } from "./protocol-validators-Bg5rpNxk.js";
5
- import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, f as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-CVPvp9dL.js";
6
- import { c as serializeCodexAppInventoryError, n as buildCodexAppServerConnectionFingerprint, s as defaultCodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-DF54hagX.js";
7
- import { c as withExclusiveCodexAppServerThread, l as isIncognitoSessionKey } from "./thread-ownership-CeYBqg_4.js";
8
- import { i as readCodexSessionMeta, n as codexCatalogHomeId } from "./session-catalog-home-id-DAKUrm3C.js";
9
- import { d as projectBoundedCodexThreadHistory } from "./transcript-mirror-CkEQIna-.js";
10
- import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
1
+ import { E as resolveCodexPluginsPolicy, F as resolveCodexAppServerLocalHomeDir, M as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME, P as resolveCodexAppServerHomeDir, f as assertCodexModelBackedReviewerEffectiveConfig, j as CODEX_PLUGINS_MARKETPLACE_NAME, n as codexSandboxPolicyForTurn } from "./config-ClwHKKTN.mjs";
2
+ import { $ as CodexAppServerRpcError, D as CodexThreadStartRequestError, E as CodexThreadBindingConflictError, H as getCodexAppServerClientInstanceId, Ht as isJsonObject, J as isCodexAppServerOverloadError, Q as resolveCodexAppServerClientInstanceId, St as releaseCodexAppServerLiveThread, T as CodexRestrictedToolSurfaceAttestationError, Vt as flattenCodexDynamicToolFunctions, _ as retainSharedCodexAppServerClientByInstanceId, bt as isCodexAppServerLiveThreadClaimed, dt as resolveCodexToolAbortTerminalReason, gt as consumeCodexAppServerLiveThread, n as captureExclusiveSharedCodexAppServerClient, w as CodexAdoptedThreadActiveError, wt as unsubscribeCodexAppServerLiveThread, yt as isCodexAppServerClientRuntimeLive } from "./shared-client-DG1kAfGq.mjs";
3
+ import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-Bd9dh1Er.mjs";
4
+ import { a as assertCodexThreadForkResponse, r as assertCodexThreadAcceptsDirectInput, s as assertCodexThreadStartResponse, t as CodexThreadDirectInputError } from "./protocol-validators-Bg5rpNxk.mjs";
5
+ import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, f as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-FBnDjmtX.mjs";
6
+ import { c as serializeCodexAppInventoryError, n as buildCodexAppServerConnectionFingerprint, s as defaultCodexAppInventoryCache, t as resumeCodexAppServerThread } from "./thread-resume-OMjvue9F.mjs";
7
+ import { c as withExclusiveCodexAppServerThread, l as isIncognitoSessionKey } from "./thread-ownership-B3vjUi0P.mjs";
8
+ import { i as readCodexSessionMeta, n as codexCatalogHomeId } from "./session-catalog-home-id-CjyBDShn.mjs";
9
+ import { f as projectBoundedCodexThreadHistory } from "./transcript-mirror-DN-ed7Kf.mjs";
10
+ import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.mjs";
11
11
  import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
12
12
  import fs from "node:fs/promises";
13
13
  import path from "node:path";
@@ -1198,6 +1198,7 @@ function renderMessagesForCodexContext(messages, options) {
1198
1198
  }).filter((value) => Boolean(value)).join("\n\n");
1199
1199
  }
1200
1200
  function renderMessageBody(message, options) {
1201
+ if (message.role === "compactionSummary" || message.role === "branchSummary") return truncateText(message.summary.trim(), options.maxTextPartChars);
1201
1202
  if (!hasMessageContent(message)) return "";
1202
1203
  if (typeof message.content === "string") return truncateText(message.content.trim(), options.maxTextPartChars);
1203
1204
  if (!Array.isArray(message.content)) return "[non-text content omitted]";
@@ -1666,7 +1667,8 @@ async function collectPersonalSkillRealPaths(homes, codexHome) {
1666
1667
  }
1667
1668
  const configuredCodexHome = codexHome?.trim() || process.env.CODEX_HOME?.trim();
1668
1669
  if (configuredCodexHome) {
1669
- const stateOwned = isPathInside(realStateDir, await canonicalizeExistingPath(configuredCodexHome));
1670
+ const realCodexHome = await canonicalizeExistingPath(configuredCodexHome);
1671
+ const stateOwned = isPathInside(realStateDir, realCodexHome);
1670
1672
  roots.push({
1671
1673
  dir: path.join(configuredCodexHome, "skills"),
1672
1674
  onlyEscapedStateTargets: stateOwned
@@ -1729,12 +1731,14 @@ async function collectPersonalSkillRealPaths(homes, codexHome) {
1729
1731
  try {
1730
1732
  const stat = await fs.stat(entryPath);
1731
1733
  if (entry.name === "SKILL.md" && stat.isFile()) await recordSkillFile(entryPath, current.onlyEscapedStateTargets);
1732
- else if (stat.isDirectory()) if (current.depth < MAX_PERSONAL_SKILL_DEPTH) queue.push({
1733
- dir: entryPath,
1734
- depth: current.depth + 1,
1735
- onlyEscapedStateTargets: current.onlyEscapedStateTargets
1736
- });
1737
- else complete = false;
1734
+ else if (stat.isDirectory()) {
1735
+ if (current.depth < MAX_PERSONAL_SKILL_DEPTH) queue.push({
1736
+ dir: entryPath,
1737
+ depth: current.depth + 1,
1738
+ onlyEscapedStateTargets: current.onlyEscapedStateTargets
1739
+ });
1740
+ else complete = false;
1741
+ }
1738
1742
  } catch (error) {
1739
1743
  if (!isMissingPathError(error)) complete = false;
1740
1744
  }
@@ -1852,6 +1856,10 @@ function managedThreadStoreKey(sourceHomeId, threadId) {
1852
1856
  /** Durable ownership index for Codex threads created by OpenClaw. */
1853
1857
  function createCodexManagedThreadStore(state) {
1854
1858
  return {
1859
+ async has(sourceHomeId, threadId) {
1860
+ const parsed = managedThreadSchema.safeParse(state.lookup(managedThreadStoreKey(sourceHomeId, threadId)));
1861
+ return parsed.success && parsed.data.sourceHomeId === sourceHomeId && parsed.data.threadId === threadId;
1862
+ },
1855
1863
  async mark(params) {
1856
1864
  try {
1857
1865
  const value = managedThreadSchema.parse({
@@ -1981,56 +1989,6 @@ function buildStartedCodexThreadBinding(input) {
1981
1989
  };
1982
1990
  }
1983
1991
  //#endregion
1984
- //#region extensions/codex/src/app-server/reasoning-effort.ts
1985
- const CODEX_REASONING_EFFORTS = [
1986
- "minimal",
1987
- "low",
1988
- "medium",
1989
- "high",
1990
- "xhigh",
1991
- "max",
1992
- "ultra"
1993
- ];
1994
- const LEGACY_PRO_REASONING_EFFORTS = [
1995
- "medium",
1996
- "high",
1997
- "xhigh"
1998
- ];
1999
- const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
2000
- const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
2001
- /** Read reasoning metadata after the Codex app-server route has been selected. */
2002
- function readCodexSupportedReasoningEfforts(compat) {
2003
- if (!compat || typeof compat !== "object" || Array.isArray(compat)) return;
2004
- const efforts = compat.supportedReasoningEfforts;
2005
- if (!Array.isArray(efforts)) return;
2006
- return efforts.filter((effort) => typeof effort === "string");
2007
- }
2008
- function resolveSupportedReasoningEffort(params) {
2009
- const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
2010
- const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
2011
- if (supported.includes(params.requested)) return params.requested;
2012
- const fallbackEfforts = params.requested === "ultra" ? supported : supported.filter((effort) => effort !== "ultra");
2013
- const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
2014
- return fallbackEfforts.find((effort) => CODEX_REASONING_EFFORTS.indexOf(effort) >= requestedRank) ?? fallbackEfforts.at(-1);
2015
- }
2016
- /** Resolve a turn effort from the selected model's provider-owned metadata. */
2017
- function resolveCodexAppServerReasoningEffort(params) {
2018
- if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
2019
- if (params.thinkLevel === "adaptive") return null;
2020
- if (params.supportedReasoningEfforts) return resolveSupportedReasoningEffort({
2021
- requested: params.thinkLevel,
2022
- supportedReasoningEfforts: params.supportedReasoningEfforts
2023
- }) ?? null;
2024
- const modelId = params.modelId.trim().toLowerCase();
2025
- if (LEGACY_PRO_MODEL_ID_RE.test(modelId)) return resolveSupportedReasoningEffort({
2026
- requested: params.thinkLevel,
2027
- supportedReasoningEfforts: LEGACY_PRO_REASONING_EFFORTS
2028
- }) ?? null;
2029
- if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
2030
- if (params.thinkLevel === "minimal" || params.thinkLevel === "low" || params.thinkLevel === "medium" || params.thinkLevel === "high" || params.thinkLevel === "xhigh") return params.thinkLevel;
2031
- return null;
2032
- }
2033
- //#endregion
2034
1992
  //#region extensions/codex/src/app-server/thread-model-selection.ts
2035
1993
  const CODEX_NATIVE_PERSONALITY_NONE = "none";
2036
1994
  function resolveCodexBindingModelProviderFallback(params) {
@@ -2098,16 +2056,9 @@ function resolveCodexAppServerModelProvider(params) {
2098
2056
  if (isCodexAppServerNativeAuthProfile(params) && normalizedLower === "openai") return;
2099
2057
  return normalizedLower === "openai" ? "openai" : normalized;
2100
2058
  }
2101
- function resolveReasoningEffort(thinkLevel, modelId, supportedReasoningEfforts) {
2102
- return resolveCodexAppServerReasoningEffort({
2103
- thinkLevel,
2104
- modelId,
2105
- supportedReasoningEfforts
2106
- });
2107
- }
2108
2059
  //#endregion
2109
2060
  //#region extensions/codex/src/app-server/project-doc-thread-config.ts
2110
- const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 128 * 1024;
2061
+ const CODEX_NATIVE_PROJECT_DOC_MAX_BYTES = 131072;
2111
2062
  function buildCodexProjectDocThreadConfig(config) {
2112
2063
  const defaults = { project_doc_max_bytes: CODEX_NATIVE_PROJECT_DOC_MAX_BYTES };
2113
2064
  return mergeCodexThreadConfigs(defaults, config) ?? defaults;
@@ -2634,6 +2585,7 @@ async function resumeExistingCodexThread(params, context) {
2634
2585
  const { binding: resumeBinding, bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, dynamicToolsContainDeferred, webSearchThreadConfigFingerprint, nativeSkillIsolationFingerprint, userMcpServersFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, networkProxyConfigFingerprint, contextEngineBinding, environmentSelectionFingerprint, hostSystemAgentActive, ringZeroActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, clearCurrentBinding } = context;
2635
2586
  let resumeReservation;
2636
2587
  let resumeResponseAccepted = false;
2588
+ let checkingLoadedPluginThreadConfig = false;
2637
2589
  const abandonClient = params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client));
2638
2590
  try {
2639
2591
  const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
@@ -2644,7 +2596,8 @@ async function resumeExistingCodexThread(params, context) {
2644
2596
  configPatch: params.finalConfigPatch,
2645
2597
  nativeHookRelayGeneration: params.nativeHookRelayGeneration
2646
2598
  };
2647
- const pluginAppsConfigPatch = context.prebuiltPluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && resumeBinding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(resumeBinding.pluginAppPolicyContext) : void 0);
2599
+ const pluginThreadConfig = context.prebuiltPluginThreadConfig ?? (params.pluginThreadConfig?.requiresCurrentPolicyCheck ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0);
2600
+ const pluginAppsConfigPatch = pluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && resumeBinding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(resumeBinding.pluginAppPolicyContext) : void 0);
2648
2601
  const resumeConfig = applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, finalConfigPatch.configPatch), nativeSkillIsolation);
2649
2602
  const resumeParams = lifecycleTiming.measureSync("thread-resume-params", () => buildThreadResumeParams(params.params, {
2650
2603
  threadId: resumeBinding.threadId,
@@ -2680,12 +2633,19 @@ async function resumeExistingCodexThread(params, context) {
2680
2633
  resumeResponseAccepted = true;
2681
2634
  assertCodexThreadAcceptsDirectInput(response.thread);
2682
2635
  context.assertResumeConfiguration?.();
2683
- if (resumeBinding.pendingResumeConfiguration) await attestCodexPluginThreadApps({
2636
+ checkingLoadedPluginThreadConfig = true;
2637
+ const loadedPluginThreadConfig = await context.buildLoadedPluginThreadConfig?.(resumeBinding);
2638
+ if (loadedPluginThreadConfig && loadedPluginThreadConfig.fingerprint !== (pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint)) {
2639
+ checkingLoadedPluginThreadConfig = false;
2640
+ throw new Error("Codex thread app policy changed; a fresh thread configuration is required");
2641
+ }
2642
+ await attestCodexPluginThreadApps({
2684
2643
  client: params.client,
2685
2644
  threadId: response.thread.id,
2686
- appIds: context.prebuiltPluginThreadConfig?.provisionalAppIds ?? [],
2645
+ appIds: loadedPluginThreadConfig?.provisionalAppIds ?? pluginThreadConfig?.provisionalAppIds ?? [],
2687
2646
  signal: params.signal
2688
2647
  });
2648
+ checkingLoadedPluginThreadConfig = false;
2689
2649
  if (ringZeroActive || isMessageOnlyCodexSourceReply(params.params) || params.params.pluginHarnessToolPolicyRestricted === true) try {
2690
2650
  await lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, response.thread.id, resumeParams.config, params.signal));
2691
2651
  } catch (error) {
@@ -2719,9 +2679,9 @@ async function resumeExistingCodexThread(params, context) {
2719
2679
  networkProxyConfigFingerprint,
2720
2680
  nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration ?? resumeBinding.nativeHookRelayGeneration,
2721
2681
  appServerRuntimeFingerprint: resumeBinding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir) : params.appServerRuntimeFingerprint,
2722
- pluginAppsFingerprint: context.prebuiltPluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint,
2723
- pluginAppsInputFingerprint: context.prebuiltPluginThreadConfig?.inputFingerprint ?? resumeBinding.pluginAppsInputFingerprint,
2724
- pluginAppPolicyContext: context.prebuiltPluginThreadConfig?.policyContext ?? resumeBinding.pluginAppPolicyContext,
2682
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint,
2683
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint ?? resumeBinding.pluginAppsInputFingerprint,
2684
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext ?? resumeBinding.pluginAppPolicyContext,
2725
2685
  contextEngine: contextEngineBinding,
2726
2686
  environmentSelectionFingerprint
2727
2687
  };
@@ -2785,7 +2745,7 @@ async function resumeExistingCodexThread(params, context) {
2785
2745
  throw new CodexAppServerUnsafeSubscriptionError("Codex thread/resume subscription cleanup failed", { cause: error });
2786
2746
  }
2787
2747
  }
2788
- if (resumeBinding.pendingResumeConfiguration || error instanceof CodexThreadDirectInputError || params.signal?.aborted) throw error;
2748
+ if (checkingLoadedPluginThreadConfig || resumeBinding.pendingResumeConfiguration || error instanceof CodexThreadDirectInputError || params.signal?.aborted) throw error;
2789
2749
  embeddedAgentLog.warn("codex app-server thread resume failed; starting a new thread", { error });
2790
2750
  await clearCurrentBinding("rotating a stale thread binding");
2791
2751
  }
@@ -2818,14 +2778,15 @@ async function startFreshCodexThread(params, context) {
2818
2778
  disableLoginShell: params.disableLoginShell
2819
2779
  }));
2820
2780
  const requestModelProvider = typeof startParams.modelProvider === "string" && startParams.modelProvider.trim() ? startParams.modelProvider : void 0;
2821
- const response = assertCodexThreadStartResponse(await lifecycleTiming.measure("thread-start-request", async () => {
2781
+ const threadStartResponse = await lifecycleTiming.measure("thread-start-request", async () => {
2822
2782
  try {
2823
2783
  return await params.client.request("thread/start", startParams, { signal: params.signal });
2824
2784
  } catch (error) {
2825
2785
  if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
2826
2786
  throw error;
2827
2787
  }
2828
- }));
2788
+ });
2789
+ const response = assertCodexThreadStartResponse(threadStartResponse);
2829
2790
  const provisionalAppIds = pluginThreadConfig?.provisionalAppIds;
2830
2791
  if (provisionalAppIds?.length) try {
2831
2792
  await lifecycleTiming.measure("plugin-app-attestation", () => attestCodexPluginThreadApps({
@@ -3010,52 +2971,67 @@ async function releaseCodexRetainedLiveThread(options) {
3010
2971
  }
3011
2972
  /** Reuses one safely owned, fully matching subscription on its original client. */
3012
2973
  async function tryReuseCodexLiveThread(options) {
3013
- const { params, binding, bindingIdentity, clientId, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, lifecycleTiming, nativeSkillIsolation, releaseConsumedThread, ringZeroActive, restrictedToolSurfaceInheritedMcpServerNames, startModelProvider, startModelSelection, throwIfAborted, userMcpServersConfigPatch } = options;
3014
- if (!binding.clientId || binding.clientId !== clientId || binding.preserveNativeModel === true || binding.connectionScope === "supervision" || ringZeroActive) return {};
3015
- const prebuiltFinalConfigPatch = params.buildFinalConfigPatch?.({
3016
- action: "resume",
3017
- binding
3018
- }) ?? {
3019
- configPatch: params.finalConfigPatch,
3020
- nativeHookRelayGeneration: params.nativeHookRelayGeneration
2974
+ const { params, binding, bindingIdentity, clientId, dynamicToolsFingerprint, environmentSelectionFingerprint, hostSystemAgentActive, lifecycleTiming, nativeSkillIsolation, ringZeroActive, restrictedToolSurfaceInheritedMcpServerNames, startModelProvider, startModelSelection, throwIfAborted, userMcpServersConfigPatch } = options;
2975
+ if (!binding.clientId || binding.clientId !== clientId || binding.preserveNativeModel === true || binding.connectionScope === "supervision" || ringZeroActive) return { kind: "resume" };
2976
+ const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
2977
+ if (!retainedThread) return { kind: "resume" };
2978
+ const assertCurrentClient = () => {
2979
+ throwIfAborted();
2980
+ if (!isCodexAppServerClientRuntimeLive(params.client)) throw params.client.getCloseError() ?? /* @__PURE__ */ new Error("codex app-server client is closed");
3021
2981
  };
3022
- const pluginAppsConfigPatch = params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0;
3023
- const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
3024
- const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
3025
- const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
3026
- threadId: binding.threadId,
3027
- cwd: params.cwd,
3028
- authProfileId: resumeAuthProfileId,
3029
- model: startModelSelection.model,
3030
- modelProvider: startModelProvider,
3031
- preserveNativeModel: false,
3032
- appServer: params.appServer,
3033
- dynamicTools: params.dynamicTools,
3034
- developerInstructions: params.developerInstructions,
3035
- config: applyCodexNativeSkillIsolation(resumeConfig, nativeSkillIsolation),
3036
- nativeCodeModeEnabled: params.nativeCodeModeEnabled,
3037
- nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
3038
- nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
3039
- webSearchAllowed: params.webSearchAllowed,
3040
- hostSystemAgentActive,
3041
- restrictedToolSurfaceInheritedMcpServerNames,
3042
- shellEnvironment: params.shellEnvironment,
3043
- disableLoginShell: params.disableLoginShell
3044
- }));
3045
- const liveThreadConfigFingerprint = fingerprintCodexThreadConfig({
3046
- ...resumeParams,
3047
- model: binding.model ?? resumeParams.model ?? null,
3048
- requestedModel: resumeParams.model ?? null,
3049
- modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3050
- requestedModelProvider: resumeParams.modelProvider ?? binding.modelProvider ?? null
3051
- }, resumeAuthProfileId, dynamicToolsFingerprint);
3052
- const retainedThread = await consumeCodexAppServerLiveThread(params.client, binding.threadId, liveThreadConfigFingerprint);
3053
- if (!retainedThread) {
3054
- const incompatibleOwnership = await consumeCodexAppServerLiveThread(params.client, binding.threadId);
3055
- if (incompatibleOwnership) await incompatibleOwnership.release(binding.threadId);
3056
- return { prebuiltFinalConfigPatch };
3057
- }
2982
+ let ownershipTransferred = false;
3058
2983
  try {
2984
+ const pluginThreadConfig = await options.buildLoadedPluginThreadConfig(binding);
2985
+ assertCurrentClient();
2986
+ if (pluginThreadConfig && pluginThreadConfig.fingerprint !== binding.pluginAppsFingerprint) return { kind: "rotate" };
2987
+ const prebuiltFinalConfigPatch = params.buildFinalConfigPatch?.({
2988
+ action: "resume",
2989
+ binding
2990
+ }) ?? {
2991
+ configPatch: params.finalConfigPatch,
2992
+ nativeHookRelayGeneration: params.nativeHookRelayGeneration
2993
+ };
2994
+ const pluginAppsConfigPatch = pluginThreadConfig?.configPatch ?? (params.pluginThreadConfig?.enabled && binding.pluginAppPolicyContext ? buildCodexPluginAppsConfigPatchFromPolicyContext(binding.pluginAppPolicyContext) : void 0);
2995
+ const resumeAuthProfileId = params.params.authProfileId ?? binding.authProfileId;
2996
+ const resumeConfig = mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, prebuiltFinalConfigPatch.configPatch);
2997
+ const resumeParams = lifecycleTiming.measureSync("warm-thread-resume-params", () => buildThreadResumeParams(params.params, {
2998
+ threadId: binding.threadId,
2999
+ cwd: params.cwd,
3000
+ authProfileId: resumeAuthProfileId,
3001
+ model: startModelSelection.model,
3002
+ modelProvider: startModelProvider,
3003
+ preserveNativeModel: false,
3004
+ appServer: params.appServer,
3005
+ dynamicTools: params.dynamicTools,
3006
+ developerInstructions: params.developerInstructions,
3007
+ config: applyCodexNativeSkillIsolation(resumeConfig, nativeSkillIsolation),
3008
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
3009
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
3010
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
3011
+ webSearchAllowed: params.webSearchAllowed,
3012
+ hostSystemAgentActive,
3013
+ restrictedToolSurfaceInheritedMcpServerNames,
3014
+ shellEnvironment: params.shellEnvironment,
3015
+ disableLoginShell: params.disableLoginShell
3016
+ }));
3017
+ const liveThreadConfigFingerprint = fingerprintCodexThreadConfig({
3018
+ ...resumeParams,
3019
+ model: binding.model ?? resumeParams.model ?? null,
3020
+ requestedModel: resumeParams.model ?? null,
3021
+ modelProvider: binding.modelProvider ?? resumeParams.modelProvider ?? null,
3022
+ requestedModelProvider: resumeParams.modelProvider ?? binding.modelProvider ?? null
3023
+ }, resumeAuthProfileId, dynamicToolsFingerprint);
3024
+ if (retainedThread.configFingerprint !== liveThreadConfigFingerprint) return {
3025
+ kind: "resume",
3026
+ prebuiltFinalConfigPatch
3027
+ };
3028
+ await attestCodexPluginThreadApps({
3029
+ client: params.client,
3030
+ threadId: binding.threadId,
3031
+ appIds: pluginThreadConfig?.provisionalAppIds ?? [],
3032
+ signal: params.signal
3033
+ });
3034
+ assertCurrentClient();
3059
3035
  const nativeHookRelayGeneration = prebuiltFinalConfigPatch.nativeHookRelayGeneration ?? binding.nativeHookRelayGeneration;
3060
3036
  const model = startModelSelection.model;
3061
3037
  if (!await lifecycleTiming.measure("warm-thread-write-binding", () => params.bindingStore.mutate(bindingIdentity, {
@@ -3067,8 +3043,8 @@ async function tryReuseCodexLiveThread(options) {
3067
3043
  nativeHookRelayGeneration,
3068
3044
  environmentSelectionFingerprint
3069
3045
  }
3070
- }))) throw new CodexThreadBindingConflictError(binding.threadId, "committing a reused thread");
3071
- throwIfAborted();
3046
+ }, assertCurrentClient))) throw new CodexThreadBindingConflictError(binding.threadId, "committing a reused thread");
3047
+ assertCurrentClient();
3072
3048
  lifecycleTiming.mark("thread-ready");
3073
3049
  lifecycleTiming.logSummary({
3074
3050
  runId: params.params.runId,
@@ -3077,7 +3053,9 @@ async function tryReuseCodexLiveThread(options) {
3077
3053
  threadId: binding.threadId,
3078
3054
  action: "resumed"
3079
3055
  });
3056
+ ownershipTransferred = true;
3080
3057
  return {
3058
+ kind: "ready",
3081
3059
  binding: {
3082
3060
  ...binding,
3083
3061
  cwd: params.cwd,
@@ -3088,12 +3066,19 @@ async function tryReuseCodexLiveThread(options) {
3088
3066
  liveThreadOwnership: retainedThread,
3089
3067
  ...retainedThread.serviceTier && resumeParams.serviceTier === void 0 ? { clearInheritedServiceTier: true } : {},
3090
3068
  lifecycle: { action: "resumed" }
3091
- },
3092
- prebuiltFinalConfigPatch
3069
+ }
3093
3070
  };
3094
- } catch (error) {
3095
- await releaseConsumedThread(binding.threadId, error);
3096
- throw error;
3071
+ } finally {
3072
+ if (!ownershipTransferred) try {
3073
+ await retainedThread.release(binding.threadId);
3074
+ } catch (error) {
3075
+ await abandonCodexLiveThreadRelease({
3076
+ client: params.client,
3077
+ abandonClient: params.abandonClient,
3078
+ lifecycleTiming,
3079
+ threadId: binding.threadId
3080
+ }, error);
3081
+ }
3097
3082
  }
3098
3083
  }
3099
3084
  //#endregion
@@ -3244,9 +3229,9 @@ const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
3244
3229
  "before_agent_finalize"
3245
3230
  ];
3246
3231
  const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
3247
- const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
3232
+ const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 18e5;
3248
3233
  /** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
3249
- const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
3234
+ const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 3e5;
3250
3235
  const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
3251
3236
  const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
3252
3237
  const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
@@ -4311,10 +4296,28 @@ async function startOrResumeThread(params) {
4311
4296
  binding = void 0;
4312
4297
  }
4313
4298
  const requestContext = resolveRequestContext();
4314
- const { startModelSelection, startModelProvider } = requestContext;
4315
4299
  let preserveExistingBinding = transientDelegationRestriction || !ringZeroActive && params.nativeProviderWebSearchSupport === "unknown" && !binding?.threadId;
4316
4300
  let rotatedContextEngineBinding = false;
4317
4301
  let prebuiltPluginThreadConfig;
4302
+ const buildLoadedPluginThreadConfig = async (current) => {
4303
+ if (!params.pluginThreadConfig?.requiresCurrentPolicyCheck && !shouldRecheckRecoverablePluginBinding({
4304
+ binding: current,
4305
+ pluginThreadConfig: params.pluginThreadConfig
4306
+ })) return;
4307
+ try {
4308
+ prebuiltPluginThreadConfig = await lifecycleTiming.measure("plugin-config-recovery", () => params.pluginThreadConfig?.build({ threadId: current.threadId }));
4309
+ } catch (error) {
4310
+ throwIfAborted();
4311
+ if (params.pluginThreadConfig?.requiresCurrentPolicyCheck) throw error;
4312
+ embeddedAgentLog.warn("codex app-server plugin app config recovery check failed", {
4313
+ error,
4314
+ threadId: current.threadId
4315
+ });
4316
+ return;
4317
+ }
4318
+ throwIfAborted();
4319
+ return prebuiltPluginThreadConfig;
4320
+ };
4318
4321
  const webSearchBindingChanged = binding?.threadId && binding.webSearchThreadConfigFingerprint !== webSearchThreadConfigFingerprint;
4319
4322
  const explicitTransientWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed !== false && transientWebSearchRestriction;
4320
4323
  const unknownProviderWebSearchSupport = params.nativeProviderWebSearchSupport === "unknown";
@@ -4393,28 +4396,13 @@ async function startOrResumeThread(params) {
4393
4396
  binding = void 0;
4394
4397
  }
4395
4398
  if (binding?.threadId) {
4396
- let pluginBindingStale = isCodexPluginThreadBindingStale({
4399
+ if (isCodexPluginThreadBindingStale({
4397
4400
  codexPluginsEnabled: params.pluginThreadConfig?.enabled ?? false,
4398
4401
  bindingFingerprint: binding.pluginAppsFingerprint,
4399
4402
  bindingInputFingerprint: binding.pluginAppsInputFingerprint,
4400
4403
  currentInputFingerprint: params.pluginThreadConfig?.inputFingerprint,
4401
4404
  hasBindingPolicyContext: Boolean(binding.pluginAppPolicyContext)
4402
- });
4403
- if (!pluginBindingStale && (params.pluginThreadConfig?.requiresCurrentPolicyCheck || shouldRecheckRecoverablePluginBinding({
4404
- binding,
4405
- pluginThreadConfig: params.pluginThreadConfig
4406
- }))) try {
4407
- const bindingThreadId = binding.threadId;
4408
- prebuiltPluginThreadConfig = await lifecycleTiming.measure("plugin-config-recovery", () => params.pluginThreadConfig?.build({ threadId: bindingThreadId }));
4409
- pluginBindingStale = prebuiltPluginThreadConfig?.fingerprint !== binding.pluginAppsFingerprint;
4410
- } catch (error) {
4411
- if (params.pluginThreadConfig?.requiresCurrentPolicyCheck) throw error;
4412
- embeddedAgentLog.warn("codex app-server plugin app config recovery check failed", {
4413
- error,
4414
- threadId: binding.threadId
4415
- });
4416
- }
4417
- if (pluginBindingStale) {
4405
+ })) {
4418
4406
  embeddedAgentLog.debug("codex app-server plugin app config changed; starting a new thread", { threadId: binding.threadId });
4419
4407
  await clearCurrentBinding("rotating a stale thread binding");
4420
4408
  binding = void 0;
@@ -4427,75 +4415,66 @@ async function startOrResumeThread(params) {
4427
4415
  binding = void 0;
4428
4416
  }
4429
4417
  }
4430
- if (binding?.threadId) if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint, legacyDynamicToolsFingerprint)) {
4431
- assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog");
4432
- preserveExistingBinding = shouldStartTransientNoToolThread({
4433
- previous: binding.dynamicToolsFingerprint,
4434
- nextHasDynamicTools: params.dynamicTools.length > 0
4435
- });
4436
- if (preserveExistingBinding) embeddedAgentLog.debug("codex app-server dynamic tools unavailable for turn; starting transient thread", { threadId: binding.threadId });
4437
- else {
4438
- embeddedAgentLog.debug("codex app-server dynamic tool catalog changed; starting a new thread", { threadId: binding.threadId });
4439
- await clearCurrentBinding("rotating a stale thread binding");
4440
- }
4441
- } else if (incognito) {
4442
- if (binding.clientId && binding.clientId === clientId) {
4443
- params.buildFinalConfigPatch?.({
4444
- action: "resume",
4445
- binding
4418
+ if (binding?.threadId) {
4419
+ if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint, legacyDynamicToolsFingerprint)) {
4420
+ assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog");
4421
+ preserveExistingBinding = shouldStartTransientNoToolThread({
4422
+ previous: binding.dynamicToolsFingerprint,
4423
+ nextHasDynamicTools: params.dynamicTools.length > 0
4446
4424
  });
4447
- throwIfAborted();
4448
- lifecycleTiming.mark("thread-ready");
4449
- lifecycleTiming.logSummary({
4450
- runId: params.params.runId,
4451
- sessionId: params.params.sessionId,
4452
- sessionKey: params.params.sessionKey,
4453
- threadId: binding.threadId,
4454
- action: "resumed"
4425
+ if (preserveExistingBinding) embeddedAgentLog.debug("codex app-server dynamic tools unavailable for turn; starting transient thread", { threadId: binding.threadId });
4426
+ else {
4427
+ embeddedAgentLog.debug("codex app-server dynamic tool catalog changed; starting a new thread", { threadId: binding.threadId });
4428
+ await clearCurrentBinding("rotating a stale thread binding");
4429
+ }
4430
+ } else if (incognito) {
4431
+ if (binding.clientId && binding.clientId === clientId && ((await buildLoadedPluginThreadConfig(binding))?.fingerprint ?? binding.pluginAppsFingerprint) === binding.pluginAppsFingerprint) {
4432
+ params.buildFinalConfigPatch?.({
4433
+ action: "resume",
4434
+ binding
4435
+ });
4436
+ throwIfAborted();
4437
+ lifecycleTiming.mark("thread-ready");
4438
+ lifecycleTiming.logSummary({
4439
+ runId: params.params.runId,
4440
+ sessionId: params.params.sessionId,
4441
+ sessionKey: params.params.sessionKey,
4442
+ threadId: binding.threadId,
4443
+ action: "resumed"
4444
+ });
4445
+ return {
4446
+ ...binding,
4447
+ lifecycle: { action: "resumed" }
4448
+ };
4449
+ }
4450
+ await clearCurrentBinding("rotating an unavailable ephemeral thread binding");
4451
+ binding = void 0;
4452
+ } else {
4453
+ const warmReuse = await tryReuseCodexLiveThread({
4454
+ ...requestContext,
4455
+ params,
4456
+ binding,
4457
+ clientId,
4458
+ buildLoadedPluginThreadConfig
4455
4459
  });
4456
- return {
4457
- ...binding,
4458
- lifecycle: { action: "resumed" }
4459
- };
4460
+ if (warmReuse.kind === "ready") return warmReuse.binding;
4461
+ if (warmReuse.kind === "rotate") {
4462
+ throwIfAborted();
4463
+ await clearCurrentBinding("rotating a stale plugin app binding");
4464
+ } else {
4465
+ if (binding.preserveNativeModel === true) await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, requestContext);
4466
+ await releaseRetainedThread(binding.threadId);
4467
+ const resumed = await resumeExistingCodexThread(params, {
4468
+ ...requestContext,
4469
+ binding,
4470
+ clearCurrentBinding,
4471
+ prebuiltFinalConfigPatch: warmReuse.prebuiltFinalConfigPatch,
4472
+ prebuiltPluginThreadConfig,
4473
+ buildLoadedPluginThreadConfig
4474
+ });
4475
+ if (resumed) return resumed;
4476
+ }
4460
4477
  }
4461
- await clearCurrentBinding("rotating an unavailable ephemeral thread binding");
4462
- binding = void 0;
4463
- } else {
4464
- const warmReuse = await tryReuseCodexLiveThread({
4465
- params,
4466
- binding,
4467
- bindingIdentity,
4468
- clientId,
4469
- dynamicToolsFingerprint,
4470
- environmentSelectionFingerprint,
4471
- hostSystemAgentActive,
4472
- lifecycleTiming,
4473
- nativeSkillIsolation,
4474
- releaseConsumedThread: (threadId, cause) => releaseCodexConsumedLiveThread({
4475
- client: params.client,
4476
- abandonClient: params.abandonClient,
4477
- lifecycleTiming,
4478
- threadId,
4479
- cause
4480
- }),
4481
- ringZeroActive,
4482
- restrictedToolSurfaceInheritedMcpServerNames,
4483
- startModelProvider,
4484
- startModelSelection,
4485
- throwIfAborted,
4486
- userMcpServersConfigPatch
4487
- });
4488
- if (warmReuse.binding) return warmReuse.binding;
4489
- if (binding.preserveNativeModel === true) await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, requestContext);
4490
- await releaseRetainedThread(binding.threadId);
4491
- const resumed = await resumeExistingCodexThread(params, {
4492
- ...requestContext,
4493
- binding,
4494
- clearCurrentBinding,
4495
- prebuiltFinalConfigPatch: warmReuse.prebuiltFinalConfigPatch,
4496
- prebuiltPluginThreadConfig
4497
- });
4498
- if (resumed) return resumed;
4499
4478
  }
4500
4479
  if (initialBoundThreadId && !preserveExistingBinding && !replacementPredecessor) await releaseRetainedThread(initialBoundThreadId);
4501
4480
  const started = await startFreshCodexThread(params, {
@@ -4510,6 +4489,54 @@ async function startOrResumeThread(params) {
4510
4489
  });
4511
4490
  }
4512
4491
  //#endregion
4492
+ //#region extensions/codex/src/app-server/reasoning-effort.ts
4493
+ const CODEX_REASONING_EFFORTS = [
4494
+ "minimal",
4495
+ "low",
4496
+ "medium",
4497
+ "high",
4498
+ "xhigh",
4499
+ "max"
4500
+ ];
4501
+ const LEGACY_PRO_REASONING_EFFORTS = [
4502
+ "medium",
4503
+ "high",
4504
+ "xhigh"
4505
+ ];
4506
+ const LEGACY_PRO_MODEL_ID_RE = /^gpt-5\.[45]-pro$/u;
4507
+ const MODERN_GPT_5_MODEL_ID_RE = /^gpt-5\.(?:[3-9]|[1-9]\d)(?:$|-)/u;
4508
+ /** Read reasoning metadata after the Codex app-server route has been selected. */
4509
+ function readCodexSupportedReasoningEfforts(compat) {
4510
+ if (!compat || typeof compat !== "object" || Array.isArray(compat)) return;
4511
+ const efforts = compat.supportedReasoningEfforts;
4512
+ if (!Array.isArray(efforts)) return;
4513
+ return efforts.filter((effort) => typeof effort === "string");
4514
+ }
4515
+ function resolveSupportedReasoningEffort(params) {
4516
+ const declared = new Set(params.supportedReasoningEfforts.map((effort) => effort.trim().toLowerCase()));
4517
+ const supported = CODEX_REASONING_EFFORTS.filter((effort) => declared.has(effort));
4518
+ if (supported.includes(params.requested)) return params.requested;
4519
+ const requestedRank = CODEX_REASONING_EFFORTS.indexOf(params.requested);
4520
+ return supported.find((effort) => CODEX_REASONING_EFFORTS.indexOf(effort) >= requestedRank) ?? supported.at(-1);
4521
+ }
4522
+ function resolveCodexAppServerReasoningEffort(params) {
4523
+ if (params.thinkLevel === "ultra") return "ultra";
4524
+ if (params.thinkLevel === "off") return params.supportedReasoningEfforts?.includes("none") ? "none" : null;
4525
+ if (params.thinkLevel === "adaptive") return null;
4526
+ if (params.supportedReasoningEfforts) return resolveSupportedReasoningEffort({
4527
+ requested: params.thinkLevel,
4528
+ supportedReasoningEfforts: params.supportedReasoningEfforts
4529
+ }) ?? null;
4530
+ const modelId = params.modelId.trim().toLowerCase();
4531
+ if (LEGACY_PRO_MODEL_ID_RE.test(modelId)) return resolveSupportedReasoningEffort({
4532
+ requested: params.thinkLevel,
4533
+ supportedReasoningEfforts: LEGACY_PRO_REASONING_EFFORTS
4534
+ }) ?? null;
4535
+ if (params.thinkLevel === "minimal" && MODERN_GPT_5_MODEL_ID_RE.test(modelId)) return "low";
4536
+ if (params.thinkLevel === "minimal" || params.thinkLevel === "low" || params.thinkLevel === "medium" || params.thinkLevel === "high" || params.thinkLevel === "xhigh") return params.thinkLevel;
4537
+ return null;
4538
+ }
4539
+ //#endregion
4513
4540
  //#region extensions/codex/src/app-server/user-input.ts
4514
4541
  /** Builds ordered Codex user input for both new turns and same-turn steering. */
4515
4542
  function buildCodexUserInput(text, images) {
@@ -4562,12 +4589,25 @@ function buildTurnStartParams(params, options) {
4562
4589
  agentDir: params.agentDir,
4563
4590
  config: params.config
4564
4591
  });
4592
+ const collaborationMode = modelSelection ? buildTurnCollaborationMode(params, {
4593
+ model: modelSelection.model,
4594
+ turnScopedDeveloperInstructions: options.turnScopedDeveloperInstructions,
4595
+ skillsCollaborationInstructions: options.skillsCollaborationInstructions,
4596
+ memoryCollaborationInstructions: options.memoryCollaborationInstructions
4597
+ }) : void 0;
4565
4598
  const useThreadPermissionProfile = options.appServer.networkProxy && !options.sandboxPolicy;
4566
4599
  const currentSenderContext = params.trigger === "user" ? buildCodexCurrentSenderContextValue(params) : void 0;
4567
- const additionalContext = currentSenderContext ? { openclaw_current_sender: {
4600
+ let additionalContext = currentSenderContext ? { openclaw_current_sender: {
4568
4601
  kind: "untrusted",
4569
4602
  value: currentSenderContext
4570
4603
  } } : void 0;
4604
+ if (params.permissionChange?.notice) additionalContext = {
4605
+ ...additionalContext,
4606
+ openclaw_permission_change: {
4607
+ kind: "application",
4608
+ value: params.permissionChange.notice
4609
+ }
4610
+ };
4571
4611
  return {
4572
4612
  threadId: options.threadId,
4573
4613
  input: [...buildCodexUserInput(options.promptText ?? params.prompt, params.images), ...options.explicitSkillInputs ?? []],
@@ -4582,14 +4622,11 @@ function buildTurnStartParams(params, options) {
4582
4622
  personality: CODEX_NATIVE_PERSONALITY_NONE
4583
4623
  } : {},
4584
4624
  ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : options.clearInheritedServiceTier ? { serviceTier: null } : {},
4585
- ...modelSelection ? { effort: resolveReasoningEffort(params.thinkLevel, modelSelection.model, readCodexSupportedReasoningEfforts(params.model?.compat)) } : {},
4586
- ...options.environmentSelection ? { environments: options.environmentSelection } : {},
4587
- ...modelSelection ? { collaborationMode: buildTurnCollaborationMode(params, {
4588
- model: modelSelection.model,
4589
- turnScopedDeveloperInstructions: options.turnScopedDeveloperInstructions,
4590
- skillsCollaborationInstructions: options.skillsCollaborationInstructions,
4591
- memoryCollaborationInstructions: options.memoryCollaborationInstructions
4592
- }) } : {}
4625
+ ...collaborationMode ? {
4626
+ effort: collaborationMode.settings.reasoning_effort,
4627
+ collaborationMode
4628
+ } : {},
4629
+ ...options.environmentSelection ? { environments: options.environmentSelection } : {}
4593
4630
  };
4594
4631
  }
4595
4632
  function buildTurnCollaborationMode(params, options = {}) {
@@ -4598,7 +4635,11 @@ function buildTurnCollaborationMode(params, options = {}) {
4598
4635
  mode: "default",
4599
4636
  settings: {
4600
4637
  model,
4601
- reasoning_effort: resolveReasoningEffort(params.thinkLevel, model, readCodexSupportedReasoningEfforts(params.model?.compat)),
4638
+ reasoning_effort: resolveCodexAppServerReasoningEffort({
4639
+ thinkLevel: params.thinkLevel,
4640
+ modelId: model,
4641
+ supportedReasoningEfforts: readCodexSupportedReasoningEfforts(params.model?.compat)
4642
+ }),
4602
4643
  developer_instructions: buildTurnScopedCollaborationInstructions(params, options)
4603
4644
  }
4604
4645
  };
@@ -4636,4 +4677,4 @@ function joinPresentSections(...sections) {
4636
4677
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
4637
4678
  }
4638
4679
  //#endregion
4639
- export { resolveCodexContinuityProjectionMaxChars as $, readCodexSupportedReasoningEfforts as A, isMessageOnlyCodexSourceReply as B, buildCodexProjectDocThreadConfig as C, resolveCodexAppServerThreadModelSelection as D, resolveCodexAppServerRequestModelSelection as E, codexDynamicToolsFingerprint as F, buildContextEngineBinding as G, normalizeCodexDynamicToolName as H, codexLegacyDynamicToolsFingerprint as I, fitCodexProjectedContextForTurnStart as J, isContextEngineBindingCompatible as K, filterCodexDynamicTools as L, CODEX_MANAGED_THREAD_NAMESPACE as M, createCodexManagedThreadStore as N, resolveCodexBindingModelProviderFallback as O, areCodexDynamicToolFingerprintsCompatible as P, resolveCodexContextEngineProjectionReserveTokens as Q, filterCodexDynamicToolsForDisabledNativeSurface as R, buildDeveloperInstructions as S, resolveCodexAppServerModelProvider as T, resolveCodexDynamicToolsLoading as U, isSystemAgentOnlyCodexDynamicToolAllowlist as V, resolveCodexDynamicToolsLoadingForRuntime as W, projectContextEngineAssemblyForCodex as X, neutralizeCodexExplicitMentionSigils as Y, resolveCodexContextEngineProjectionMaxChars as Z, buildCodexRingZeroThreadConfigPatch as _, isCodexAppServerProfilerEnabled as a, buildPluginAppPolicyContext as at, buildCodexNativeWebSearchThreadConfig as b, buildCodexNativeHookRelayConfig as c, ensureCodexPluginActivation as ct, emitCodexNativePreToolUseFailureDiagnostic as d, isOpenAiCuratedMarketplaceName as dt, buildCodexPluginAppsConfigPatchFromPolicyContext as et, resolveCodexNativeHookRelayEvents as f, pluginReadParams as ft, attestCodexRestrictedToolSurfaceMcpServersDisabled as g, assertCodexManagedRequirementsDoNotOverrideToolPolicy as h, startOrResumeThread as i, buildDisabledAppsConfigPatch as it, CODEX_MANAGED_THREAD_MAX_ENTRIES as j, resolveReasoningEffort as k, buildCodexNativeHookRelayDisabledConfig as l, refreshCodexPluginRuntimeState as lt, scheduleCodexNativeHookRelayUnregister as m, buildTurnStartParams as n, buildCodexPluginThreadConfigInputFingerprint as nt, CODEX_NATIVE_HOOK_RELAY_EVENTS as o, mergeCodexThreadConfigs as ot, resolveCodexNativeHookRelayTtlMs as p, resolveRecoverableCodexPluginConfigKeys as pt, buildCodexContinuityCalibration as q, buildCodexUserInput as r, buildCodexPluginThreadConfigTimeoutFallback as rt, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as s, shouldBuildCodexPluginThreadConfig as st, buildTurnCollaborationMode as t, buildCodexPluginThreadConfig as tt, createCodexNativeHookRelay as u, isOpenAiCuratedMarketplace as ut, buildCodexRuntimeThreadConfig as v, CODEX_NATIVE_PERSONALITY_NONE as w, resolveCodexWebSearchPlan as x, readCodexInheritedMcpServerNames as y, isForcedPrivateQaCodexRuntime as z };
4680
+ export { resolveCodexContinuityProjectionMaxChars as $, resolveCodexBindingModelProviderFallback as A, isMessageOnlyCodexSourceReply as B, resolveCodexWebSearchPlan as C, resolveCodexAppServerModelProvider as D, CODEX_NATIVE_PERSONALITY_NONE as E, codexDynamicToolsFingerprint as F, buildContextEngineBinding as G, normalizeCodexDynamicToolName as H, codexLegacyDynamicToolsFingerprint as I, fitCodexProjectedContextForTurnStart as J, isContextEngineBindingCompatible as K, filterCodexDynamicTools as L, CODEX_MANAGED_THREAD_NAMESPACE as M, createCodexManagedThreadStore as N, resolveCodexAppServerRequestModelSelection as O, areCodexDynamicToolFingerprintsCompatible as P, resolveCodexContextEngineProjectionReserveTokens as Q, filterCodexDynamicToolsForDisabledNativeSurface as R, buildCodexNativeWebSearchThreadConfig as S, buildCodexProjectDocThreadConfig as T, resolveCodexDynamicToolsLoading as U, isSystemAgentOnlyCodexDynamicToolAllowlist as V, resolveCodexDynamicToolsLoadingForRuntime as W, projectContextEngineAssemblyForCodex as X, neutralizeCodexExplicitMentionSigils as Y, resolveCodexContextEngineProjectionMaxChars as Z, assertCodexManagedRequirementsDoNotOverrideToolPolicy as _, resolveCodexAppServerReasoningEffort as a, buildPluginAppPolicyContext as at, buildCodexRuntimeThreadConfig as b, CODEX_NATIVE_HOOK_RELAY_EVENTS as c, ensureCodexPluginActivation as ct, buildCodexNativeHookRelayDisabledConfig as d, isOpenAiCuratedMarketplaceName as dt, buildCodexPluginAppsConfigPatchFromPolicyContext as et, createCodexNativeHookRelay as f, pluginReadParams as ft, scheduleCodexNativeHookRelayUnregister as g, resolveCodexNativeHookRelayTtlMs as h, readCodexSupportedReasoningEfforts as i, buildDisabledAppsConfigPatch as it, CODEX_MANAGED_THREAD_MAX_ENTRIES as j, resolveCodexAppServerThreadModelSelection as k, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as l, refreshCodexPluginRuntimeState as lt, resolveCodexNativeHookRelayEvents as m, buildTurnStartParams as n, buildCodexPluginThreadConfigInputFingerprint as nt, startOrResumeThread as o, mergeCodexThreadConfigs as ot, emitCodexNativePreToolUseFailureDiagnostic as p, resolveRecoverableCodexPluginConfigKeys as pt, buildCodexContinuityCalibration as q, buildCodexUserInput as r, buildCodexPluginThreadConfigTimeoutFallback as rt, isCodexAppServerProfilerEnabled as s, shouldBuildCodexPluginThreadConfig as st, buildTurnCollaborationMode as t, buildCodexPluginThreadConfig as tt, buildCodexNativeHookRelayConfig as u, isOpenAiCuratedMarketplace as ut, attestCodexRestrictedToolSurfaceMcpServersDisabled as v, buildDeveloperInstructions as w, readCodexInheritedMcpServerNames as x, buildCodexRingZeroThreadConfigPatch as y, isForcedPrivateQaCodexRuntime as z };