@openclaw/codex 2026.9.1 → 2026.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +6 -6
- package/dist/{attempt-client-cleanup-DYHcRQAa.js → attempt-client-cleanup-Bp1ZOnk2.js} +76 -32
- package/dist/{attempt-context-DmQUNWwT.js → attempt-context-CSazkWns.js} +6 -6
- package/dist/{bounded-turn-wzJrwKKe.js → bounded-turn-DxGJRYbY.js} +46 -45
- package/dist/{capabilities-dIjNVCYH.js → capabilities-B1mgvpP8.js} +2 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-CLHhEB1Q.js → command-formatters-DSbGMXA0.js} +2 -2
- package/dist/{command-handlers-CTGb2csu.js → command-handlers-DOJvGv6-.js} +146 -74
- package/dist/{compact-_t0HQrUS.js → compact-Y_xBqrHN.js} +83 -48
- package/dist/{config-BhmfC1s6.js → config-CyapYSji.js} +47 -105
- package/dist/config-utils-C57JiJrU.js +69 -0
- package/dist/doctor-contract-api.js +4 -5
- package/dist/{dynamic-tools-BU9tmlYm.js → dynamic-tools-BwpvTxaX.js} +678 -638
- package/dist/{effective-mcp-catalog-DzYBW4h1.js → effective-mcp-catalog-CY9Jn4bA.js} +4 -3
- package/dist/{event-projector-assistant-message-DHRFXKbS.js → event-projector-assistant-message-B9kp6iGC.js} +11 -2
- package/dist/{event-projector-usage-C5mcrGjp.js → event-projector-usage-ZqEVbAEY.js} +30 -13
- package/dist/{harness-DXVZ5II5.js → harness-Czh2Sdoc.js} +36 -13
- package/dist/harness.js +1 -1
- package/dist/{image-payload-sanitizer-CnfoUPCE.js → image-payload-sanitizer-tupAr-2o.js} +29 -15
- package/dist/index.js +68 -84
- package/dist/{isolated-completion-kg9kv4iH.js → isolated-completion-CRh-51AK.js} +9 -21
- package/dist/{managed-binary-4-Vjz5GH.js → managed-binary-DcpnJF9x.js} +105 -73
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{model-catalog-CUM68Hkl.js → model-catalog-DT5vo6qo.js} +5 -5
- package/dist/{models-sYnEc0gd.js → models-CcrgSMQR.js} +4 -4
- package/dist/{native-subagent-monitor-CnH147jH.js → native-subagent-monitor-B3bvQGcg.js} +12 -11
- package/dist/{node-exec-server.runtime-CstNHCmC.js → node-exec-server.runtime-nfbUOtUB.js} +3 -3
- package/dist/{plugin-approval-roundtrip-CNe-Xrjx.js → plugin-approval-roundtrip-aQVdyL5g.js} +1 -1
- package/dist/{plugin-marketplace-discovery-CfFlKqDl.js → plugin-marketplace-discovery-B7gHXJ3d.js} +35 -22
- package/dist/{plugin-metadata-cache-BFrPhb2c.js → plugin-metadata-cache-BwCLTY_U.js} +5 -5
- package/dist/{provider-capabilities-DW5p4k9w.js → provider-capabilities-BpG9Ltc5.js} +2 -2
- package/dist/{rate-limits-CawQJfUS.js → rate-limits-Fx_l4eNa.js} +1 -1
- package/dist/{request-DYAI5FQE.js → request-C8H22rPi.js} +2 -2
- package/dist/{run-attempt-D1hJO4fX.js → run-attempt-BzthFQSM.js} +977 -723
- package/dist/{runtime-artifact-C3jVimFn.js → runtime-artifact-Bh_gf6-t.js} +3 -3
- package/dist/{session-binding-BHuTCRZQ.js → session-binding-4Ki04sW-.js} +94 -282
- package/dist/session-binding-record-CyaXZvTe.js +270 -0
- package/dist/{session-catalog-yyvTWFOw.js → session-catalog-B47uwekb.js} +266 -114
- package/dist/{session-cli-CmFEXMAM.js → session-cli-BjLhpmS1.js} +1 -1
- package/dist/session-history-DWmMqiqW.js +93 -0
- package/dist/session-history-read-LHldwvyh.js +36 -0
- package/dist/session-history-worker-runtime.js +48 -0
- package/dist/{settled-turn-context-D3SNWtUn.js → session-history.worker-zZVcx0ME.js} +30 -31
- package/dist/session-history.worker.js +2 -0
- package/dist/{session-initialization-BeWzjGiR.js → session-initialization-BCFVnLL4.js} +2 -1
- package/dist/{session-permission-policy-DeWVTCMj.js → session-permission-policy-BaueHmSj.js} +1 -1
- package/dist/{session-retirement-BujDjXVF.js → session-retirement-DNdmYdFc.js} +7 -7
- package/dist/{session-upstream-marker-C351-5Qw.js → session-upstream-marker-DReTpGz6.js} +4 -3
- package/dist/settled-turn-context-BOM3Y1pl.js +45 -0
- package/dist/{settled-turn-finalizer-BVJx4yoc.js → settled-turn-finalizer-BI-b1sry.js} +53 -42
- package/dist/{shared-client-DxcfF9KX.js → shared-client-CKhX2kFt.js} +279 -268
- package/dist/{side-question-BTZAII4l.js → side-question-B6DWAw1A.js} +85 -36
- package/dist/{thread-lifecycle-DAcEJ_Om.js → thread-lifecycle-DPK30jad.js} +382 -388
- package/dist/{thread-ownership-zGokd8i1.js → thread-ownership-CbucAmmp.js} +5 -5
- package/dist/thread-policy-CTalhWFy.js +105 -0
- package/dist/{thread-resume-C7pyVKeW.js → thread-resume-BLgqkUc1.js} +7 -7
- package/dist/{transcript-mirror-DTUxFWa_.js → transcript-mirror-_njEB84z.js} +67 -125
- package/dist/transcript-mirror-attestation-Byl34PC-.js +76 -0
- package/dist/{transport-stdio-CyPldczm.js → transport-stdio-CzTngV0j.js} +10 -8
- package/dist/{upstream-session-fork-CYlBIGVt.js → upstream-session-fork-1fwbNKzQ.js} +85 -165
- package/dist/{usage-Bj-rrzkR.js → usage-i9fv5-4m.js} +3 -3
- package/dist/{web-search-provider.runtime-D2FWSK4w.js → web-search-provider.runtime-DKQn67A7.js} +3 -3
- package/package.json +6 -6
- package/dist/binding-connection-E6uDsPlx.js +0 -45
- package/dist/launch-args-RXQwn8zV.js +0 -90
- package/dist/session-history-C5J1AKzG.js +0 -87
- package/dist/thread-policy-g4KbJPzp.js +0 -54
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { r as
|
|
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";
|
|
11
|
+
import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-tupAr-2o.js";
|
|
10
12
|
import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
|
+
import * as crypto$1 from "node:crypto";
|
|
14
|
+
import crypto, { createHash } from "node:crypto";
|
|
15
|
+
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
11
18
|
import fs from "node:fs/promises";
|
|
12
19
|
import path from "node:path";
|
|
13
20
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
14
|
-
import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds } from "openclaw/plugin-sdk/number-runtime";
|
|
15
21
|
import { AgentHarnessPreflightError, SKILL_WORKSHOP_TOOL_NAME, buildCredentialSafetyPrompt, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, buildTemporalContextText, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, resolveMainSessionDelegationMode } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
16
22
|
import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
17
|
-
import * as crypto$1 from "node:crypto";
|
|
18
|
-
import crypto, { createHash } from "node:crypto";
|
|
19
23
|
import os from "node:os";
|
|
20
24
|
import { isDeepStrictEqual } from "node:util";
|
|
21
|
-
import { resolveAgentDir as resolveAgentDir$
|
|
22
|
-
import { resolveSessionAgentIdsStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
23
|
-
import { z } from "zod";
|
|
25
|
+
import { resolveAgentDir as resolveAgentDir$2 } from "openclaw/plugin-sdk/agent-runtime";
|
|
24
26
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
25
27
|
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
26
28
|
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
@@ -479,6 +481,30 @@ function activationFailure(identity, reason, diagnostic, extraDiagnostics = [])
|
|
|
479
481
|
};
|
|
480
482
|
}
|
|
481
483
|
//#endregion
|
|
484
|
+
//#region extensions/codex/src/app-server/plugin-app-approval-overrides.ts
|
|
485
|
+
/** Projects ask approvals into the native session layer without changing saved settings. */
|
|
486
|
+
function buildCodexAppApprovalOverrides(config, app) {
|
|
487
|
+
const appsRoot = config.apps;
|
|
488
|
+
const appConfig = isJsonObject(appsRoot) ? appsRoot[app.id] : void 0;
|
|
489
|
+
if (!isJsonObject(appConfig)) return {};
|
|
490
|
+
const overrides = {};
|
|
491
|
+
const keys = app.approvalOverrideToolConfigKeys;
|
|
492
|
+
for (const [section, fields] of [["tools", { approval_mode: "auto" }], ["links", {
|
|
493
|
+
approvals_reviewer: "user",
|
|
494
|
+
default_tools_approval_mode: "auto"
|
|
495
|
+
}]]) {
|
|
496
|
+
const entries = appConfig[section];
|
|
497
|
+
if (!isJsonObject(entries)) continue;
|
|
498
|
+
const projected = [];
|
|
499
|
+
for (const [name, value] of Object.entries(entries).toSorted(([left], [right]) => left.localeCompare(right))) {
|
|
500
|
+
if (!isJsonObject(value) || section === "tools" && keys && !keys.includes(name)) continue;
|
|
501
|
+
if (Object.keys(fields).some((field) => value[field] !== void 0 && value[field] !== null)) projected.push([name, fields]);
|
|
502
|
+
}
|
|
503
|
+
if (projected.length > 0) overrides[section] = Object.fromEntries(projected);
|
|
504
|
+
}
|
|
505
|
+
return overrides;
|
|
506
|
+
}
|
|
507
|
+
//#endregion
|
|
482
508
|
//#region extensions/codex/src/app-server/plugin-thread-app-admission.ts
|
|
483
509
|
function resolveCodexPluginThreadAppCacheKey(params) {
|
|
484
510
|
return params.threadId ? `${params.appCacheKey}:thread:${encodeURIComponent(params.threadId)}` : params.appCacheKey;
|
|
@@ -592,12 +618,15 @@ async function readCodexConfigForAppAdmission(params) {
|
|
|
592
618
|
return [];
|
|
593
619
|
}
|
|
594
620
|
if (!isJsonObject(layer.config)) throw new Error("Codex config/read returned an invalid layer config");
|
|
621
|
+
if (!isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned an invalid config layer source");
|
|
622
|
+
if (layer.config.apps !== void 0 && !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(layer.name.type)) throw new Error(`Codex app policy cannot override ${layer.name.type}; move app settings to a supported user or project config layer before exposing native apps`);
|
|
595
623
|
return [layer.config];
|
|
596
624
|
})
|
|
597
625
|
};
|
|
598
626
|
} catch (error) {
|
|
599
|
-
|
|
600
|
-
|
|
627
|
+
const details = serializeCodexAppInventoryError(error);
|
|
628
|
+
embeddedAgentLog.warn("codex plugin app admission config read failed", { error: details });
|
|
629
|
+
throw new Error(`Could not verify the Codex app allowlist: ${String(details.message)}. No native thread was started; resolve the native configuration error and retry.`, { cause: error });
|
|
601
630
|
}
|
|
602
631
|
}
|
|
603
632
|
function resolveCodexExplicitAppEnablement(layersHighestPrecedenceFirst, appId) {
|
|
@@ -617,7 +646,7 @@ function shouldForceRefreshCodexNotReadyPluginApps(params, policy, inventory) {
|
|
|
617
646
|
* Builds Codex thread config patches that expose only policy-approved apps
|
|
618
647
|
* for native Codex turns.
|
|
619
648
|
*/
|
|
620
|
-
const CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION =
|
|
649
|
+
const CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION = 6;
|
|
621
650
|
const CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION = 2;
|
|
622
651
|
/** Returns true when plugin config exists and thread config may need app patches. */
|
|
623
652
|
function shouldBuildCodexPluginThreadConfig(pluginConfig) {
|
|
@@ -763,20 +792,17 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
763
792
|
});
|
|
764
793
|
}
|
|
765
794
|
const accountAppsResult = policy.allowAllPlugins ? await readCodexThreadAdmissibleAccountApps(params, appCache) : { apps: [] };
|
|
795
|
+
let appAdmissionConfig;
|
|
796
|
+
const getAdmissionConfig = () => appAdmissionConfig ??= readCodexConfigForAppAdmission(params);
|
|
766
797
|
const diagnostics = [
|
|
767
798
|
...inventory.diagnostics,
|
|
768
799
|
...activationDiagnostics,
|
|
769
800
|
...accountAppsResult.diagnostic ? [accountAppsResult.diagnostic] : []
|
|
770
801
|
];
|
|
771
802
|
const provisionalAppIds = /* @__PURE__ */ new Set();
|
|
772
|
-
const apps =
|
|
773
|
-
enabled: false,
|
|
774
|
-
destructive_enabled: false,
|
|
775
|
-
open_world_enabled: false
|
|
776
|
-
} };
|
|
803
|
+
const { apps } = buildDisabledAppsConfigPatch();
|
|
777
804
|
const policyApps = {};
|
|
778
805
|
const pluginAppIds = {};
|
|
779
|
-
let configForAppAdmission;
|
|
780
806
|
const pluginOwnedAppIds = collectCodexReservedPluginAppIds({
|
|
781
807
|
policy,
|
|
782
808
|
inventory,
|
|
@@ -803,7 +829,7 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
803
829
|
record,
|
|
804
830
|
inventory
|
|
805
831
|
})) {
|
|
806
|
-
const admissionConfig = resolveCodexPluginAppThreadAdmission(app, inventory) === "blocked" ? void 0 : await (
|
|
832
|
+
const admissionConfig = resolveCodexPluginAppThreadAdmission(app, inventory) === "blocked" ? void 0 : await getAdmissionConfig();
|
|
807
833
|
if (!admissionConfig || resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) {
|
|
808
834
|
diagnostics.push({
|
|
809
835
|
code: "app_not_ready",
|
|
@@ -812,16 +838,8 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
812
838
|
});
|
|
813
839
|
continue;
|
|
814
840
|
}
|
|
815
|
-
if (record.policy.destructiveApprovalMode === "ask" && !await clearPersistedAppToolApprovalOverrides({
|
|
816
|
-
request: params.request,
|
|
817
|
-
configCwd: params.configCwd,
|
|
818
|
-
config: admissionConfig.config,
|
|
819
|
-
plugin: record.policy,
|
|
820
|
-
app,
|
|
821
|
-
diagnostics
|
|
822
|
-
})) continue;
|
|
823
841
|
provisionalAppIds.add(app.id);
|
|
824
|
-
apps[app.id] = buildEnabledAppConfig(record.policy);
|
|
842
|
+
apps[app.id] = buildEnabledAppConfig(record.policy, record.policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, app) : void 0);
|
|
825
843
|
policyApps[app.id] = {
|
|
826
844
|
configKey: record.policy.configKey,
|
|
827
845
|
marketplaceName: record.policy.marketplaceName,
|
|
@@ -835,26 +853,11 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
835
853
|
}
|
|
836
854
|
for (const app of unresolvedDisabledPluginOwnership ? [] : accountAppsResult.apps) {
|
|
837
855
|
if (pluginOwnedAppIds.has(app.id)) continue;
|
|
838
|
-
|
|
839
|
-
const admissionConfig = await configForAppAdmission;
|
|
840
|
-
if (!admissionConfig) {
|
|
841
|
-
diagnostics.push({
|
|
842
|
-
code: "account_app_config_unavailable",
|
|
843
|
-
message: "Codex account app configuration was unavailable; account apps were not exposed."
|
|
844
|
-
});
|
|
845
|
-
break;
|
|
846
|
-
}
|
|
856
|
+
const admissionConfig = await getAdmissionConfig();
|
|
847
857
|
if (resolveCodexExplicitAppEnablement(admissionConfig.layers, app.id) === false) continue;
|
|
848
858
|
const accountApp = toCodexPluginOwnedAccountApp(app);
|
|
849
|
-
if (policy.destructiveApprovalMode === "ask" && !await clearPersistedAppToolApprovalOverrides({
|
|
850
|
-
request: params.request,
|
|
851
|
-
configCwd: params.configCwd,
|
|
852
|
-
config: admissionConfig.config,
|
|
853
|
-
app: accountApp,
|
|
854
|
-
diagnostics
|
|
855
|
-
})) continue;
|
|
856
859
|
provisionalAppIds.add(app.id);
|
|
857
|
-
apps[app.id] = buildEnabledAppConfig(policy);
|
|
860
|
+
apps[app.id] = buildEnabledAppConfig(policy, policy.destructiveApprovalMode === "ask" ? buildCodexAppApprovalOverrides(admissionConfig.config, accountApp) : void 0);
|
|
858
861
|
policyApps[app.id] = {
|
|
859
862
|
source: "account",
|
|
860
863
|
appName: app.name,
|
|
@@ -864,7 +867,7 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
864
867
|
mcpServerNames: []
|
|
865
868
|
};
|
|
866
869
|
}
|
|
867
|
-
const configPatch = { apps };
|
|
870
|
+
const configPatch = Object.keys(policyApps).length === 0 ? buildDisabledAppsConfigPatch() : disableUnlistedCodexApps({ apps }, (await getAdmissionConfig()).config);
|
|
868
871
|
const policyContext = buildPluginAppPolicyContext(policyApps, pluginAppIds);
|
|
869
872
|
return {
|
|
870
873
|
enabled: true,
|
|
@@ -914,36 +917,76 @@ function emptyPluginThreadConfig(params) {
|
|
|
914
917
|
};
|
|
915
918
|
}
|
|
916
919
|
function buildDisabledAppsConfigPatch() {
|
|
917
|
-
return {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
920
|
+
return {
|
|
921
|
+
"features.apps": false,
|
|
922
|
+
apps: { _default: {
|
|
923
|
+
enabled: false,
|
|
924
|
+
destructive_enabled: false,
|
|
925
|
+
open_world_enabled: false
|
|
926
|
+
} }
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
function disableUnlistedCodexApps(configPatch, nativeConfig) {
|
|
930
|
+
const apps = { ...configPatch.apps };
|
|
931
|
+
for (const id of Object.keys(isJsonObject(nativeConfig.apps) ? nativeConfig.apps : {})) if (id !== "_default" && !Object.hasOwn(apps, id)) apps[id] = { enabled: false };
|
|
932
|
+
return {
|
|
933
|
+
...configPatch,
|
|
934
|
+
apps
|
|
935
|
+
};
|
|
922
936
|
}
|
|
923
|
-
function buildEnabledAppConfig(policy) {
|
|
937
|
+
function buildEnabledAppConfig(policy, approvalOverrides = {}) {
|
|
924
938
|
return {
|
|
939
|
+
...approvalOverrides,
|
|
925
940
|
enabled: true,
|
|
926
941
|
destructive_enabled: policy.allowDestructiveActions,
|
|
927
|
-
open_world_enabled:
|
|
942
|
+
open_world_enabled: policy.allowOpenWorld !== false,
|
|
928
943
|
default_tools_approval_mode: "auto",
|
|
929
944
|
...policy.destructiveApprovalMode === "ask" ? { approvals_reviewer: "user" } : {}
|
|
930
945
|
};
|
|
931
946
|
}
|
|
932
947
|
/** Rebuilds the safe per-thread apps patch persisted with a Codex thread binding. */
|
|
933
948
|
function buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext) {
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
949
|
+
const disabledConfigPatch = buildDisabledAppsConfigPatch();
|
|
950
|
+
const { apps } = disabledConfigPatch;
|
|
951
|
+
for (const [appId, policy] of Object.entries(policyContext.apps).toSorted(([left], [right]) => left.localeCompare(right))) apps[appId] = buildEnabledAppConfig(policy);
|
|
952
|
+
return Object.keys(policyContext.apps).length > 0 ? { apps } : disabledConfigPatch;
|
|
953
|
+
}
|
|
954
|
+
/** Projects current ask overrides before a side thread replays its bound app policy. */
|
|
955
|
+
async function refreshCodexPluginAppApprovalPolicy(params) {
|
|
956
|
+
if (Object.keys(params.policyContext.apps).length === 0) return {
|
|
957
|
+
policyContext: params.policyContext,
|
|
958
|
+
configPatch: buildDisabledAppsConfigPatch(),
|
|
959
|
+
diagnostics: []
|
|
960
|
+
};
|
|
961
|
+
const targetApps = Object.entries(params.policyContext.apps).filter(([, app]) => app.destructiveApprovalMode === "ask").toSorted(([left], [right]) => left.localeCompare(right));
|
|
962
|
+
const targetAppIds = targetApps.map(([id]) => id);
|
|
963
|
+
const diagnostics = [];
|
|
964
|
+
const readParams = {
|
|
965
|
+
...params,
|
|
966
|
+
appCacheKey: "approval-policy-replay"
|
|
967
|
+
};
|
|
968
|
+
const [inventory, admissionConfig] = await Promise.all([targetAppIds.length > 0 ? refreshCodexPluginAppInventory(readParams, new CodexAppInventoryCache(), { targetAppIds }) : void 0, readCodexConfigForAppAdmission(readParams)]);
|
|
969
|
+
const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(params.policyContext), admissionConfig.config);
|
|
970
|
+
const currentApps = new Map(inventory?.apps.map((app) => [app.id, toCodexPluginOwnedAccountApp(app)]));
|
|
971
|
+
const apps = { ...params.policyContext.apps };
|
|
972
|
+
for (const [id, policy] of targetApps) {
|
|
973
|
+
const app = currentApps.get(id);
|
|
974
|
+
if (!app) diagnostics.push({
|
|
975
|
+
code: "app_not_ready",
|
|
976
|
+
message: `Could not verify current Codex app approval policy for ${id}; the app was not exposed.`
|
|
977
|
+
});
|
|
978
|
+
else {
|
|
979
|
+
configPatch.apps[id] = buildEnabledAppConfig(policy, buildCodexAppApprovalOverrides(admissionConfig.config, app));
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
delete apps[id];
|
|
983
|
+
configPatch.apps[id] = { enabled: false };
|
|
984
|
+
}
|
|
985
|
+
return {
|
|
986
|
+
policyContext: buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(params.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]))),
|
|
987
|
+
configPatch,
|
|
988
|
+
diagnostics
|
|
945
989
|
};
|
|
946
|
-
return { apps };
|
|
947
990
|
}
|
|
948
991
|
function buildPluginAppPolicyContext(apps, pluginAppIds) {
|
|
949
992
|
return {
|
|
@@ -956,49 +999,6 @@ function buildPluginAppPolicyContext(apps, pluginAppIds) {
|
|
|
956
999
|
pluginAppIds
|
|
957
1000
|
};
|
|
958
1001
|
}
|
|
959
|
-
async function clearPersistedAppToolApprovalOverrides(params) {
|
|
960
|
-
try {
|
|
961
|
-
const overrideNames = readPersistedAppToolApprovalOverrideNames(params.config, params.app);
|
|
962
|
-
if (overrideNames.length === 0) return true;
|
|
963
|
-
const edits = overrideNames.map((toolName) => ({
|
|
964
|
-
keyPath: `apps.${quoteConfigKeyPathSegment(params.app.id)}.tools.${quoteConfigKeyPathSegment(toolName)}.approval_mode`,
|
|
965
|
-
value: null,
|
|
966
|
-
mergeStrategy: "replace"
|
|
967
|
-
}));
|
|
968
|
-
const response = await params.request("config/batchWrite", { edits });
|
|
969
|
-
if (!isJsonObject(response) || response.status !== "ok" && response.status !== "okOverridden") throw new Error("Codex did not confirm the approval override batch");
|
|
970
|
-
if (response.status === "okOverridden") throw new Error(`approval override for ${overrideNames.join(", ")} is controlled by another config layer`);
|
|
971
|
-
const confirmed = await params.request("config/read", {
|
|
972
|
-
includeLayers: false,
|
|
973
|
-
...params.configCwd ? { cwd: params.configCwd } : {}
|
|
974
|
-
});
|
|
975
|
-
if (!isJsonObject(confirmed) || !isJsonObject(confirmed.config)) throw new Error("Codex did not confirm effective app approval configuration");
|
|
976
|
-
const remainingOverrideNames = readPersistedAppToolApprovalOverrideNames(confirmed.config, params.app);
|
|
977
|
-
if (remainingOverrideNames.length > 0) throw new Error(`effective approval overrides remain for ${remainingOverrideNames.join(", ")}`);
|
|
978
|
-
return true;
|
|
979
|
-
} catch (error) {
|
|
980
|
-
params.diagnostics.push({
|
|
981
|
-
code: "approval_overrides_clear_failed",
|
|
982
|
-
...params.plugin ? { plugin: params.plugin } : {},
|
|
983
|
-
message: `Could not clear durable Codex app approval overrides for ${params.app.id}: ${error instanceof Error ? error.message : String(error)}`
|
|
984
|
-
});
|
|
985
|
-
return false;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
function readPersistedAppToolApprovalOverrideNames(config, app) {
|
|
989
|
-
const appsRoot = config.apps;
|
|
990
|
-
const appConfig = isJsonObject(appsRoot) ? appsRoot[app.id] : void 0;
|
|
991
|
-
const tools = isJsonObject(appConfig) ? appConfig.tools : void 0;
|
|
992
|
-
if (!isJsonObject(tools)) return [];
|
|
993
|
-
const keys = app.approvalOverrideToolConfigKeys;
|
|
994
|
-
return Object.entries(tools).flatMap(([name, value]) => (!keys || keys.includes(name)) && hasPersistedToolApprovalOverride(value) ? [name] : []).toSorted();
|
|
995
|
-
}
|
|
996
|
-
function hasPersistedToolApprovalOverride(value) {
|
|
997
|
-
return isJsonObject(value) && value.approval_mode !== void 0 && value.approval_mode !== null;
|
|
998
|
-
}
|
|
999
|
-
function quoteConfigKeyPathSegment(segment) {
|
|
1000
|
-
return `"${segment.replace(/["\\]/g, (char) => `\\${char}`)}"`;
|
|
1001
|
-
}
|
|
1002
1002
|
function shouldWaitForInitialAppInventory(params, policy, inventory) {
|
|
1003
1003
|
if (inventory.records.some((record) => record.activationRequired)) return false;
|
|
1004
1004
|
return shouldRefreshMissingAppInventory(params, policy, inventory);
|
|
@@ -1030,19 +1030,22 @@ function policyFingerprint(policy) {
|
|
|
1030
1030
|
};
|
|
1031
1031
|
}
|
|
1032
1032
|
function mergeJsonObjects(left, right) {
|
|
1033
|
-
const merged = {
|
|
1033
|
+
const merged = {
|
|
1034
|
+
...left,
|
|
1035
|
+
...right
|
|
1036
|
+
};
|
|
1034
1037
|
for (const [key, value] of Object.entries(right)) {
|
|
1035
|
-
const existing =
|
|
1036
|
-
|
|
1038
|
+
const existing = left[key];
|
|
1039
|
+
if (Object.hasOwn(left, key) && isJsonObject(existing) && isJsonObject(value)) merged[key] = mergeJsonObjects(existing, value);
|
|
1037
1040
|
}
|
|
1038
1041
|
return merged;
|
|
1039
1042
|
}
|
|
1040
1043
|
function fingerprintJson(value) {
|
|
1041
|
-
return crypto.createHash("sha256").update(
|
|
1044
|
+
return crypto.createHash("sha256").update(stringifyCodexPluginPolicy(value)).digest("hex");
|
|
1042
1045
|
}
|
|
1043
|
-
function
|
|
1044
|
-
if (Array.isArray(value)) return `[${value.map((item) =>
|
|
1045
|
-
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${
|
|
1046
|
+
function stringifyCodexPluginPolicy(value) {
|
|
1047
|
+
if (Array.isArray(value)) return `[${value.map((item) => stringifyCodexPluginPolicy(item)).join(",")}]`;
|
|
1048
|
+
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stringifyCodexPluginPolicy(item)}`).join(",")}}`;
|
|
1046
1049
|
return JSON.stringify(value);
|
|
1047
1050
|
}
|
|
1048
1051
|
//#endregion
|
|
@@ -1070,11 +1073,11 @@ function projectContextEngineAssemblyForCodex(params) {
|
|
|
1070
1073
|
const prompt = params.prompt.trim();
|
|
1071
1074
|
const contextMessages = dropDuplicateTrailingPrompt(params.assembledMessages, prompt);
|
|
1072
1075
|
const maxRenderedContextChars = normalizeRenderedContextMaxChars(params.maxRenderedContextChars);
|
|
1073
|
-
const
|
|
1076
|
+
const boundedContext = renderMessagesForCodexContext(contextMessages, {
|
|
1074
1077
|
maxTextPartChars: resolveTextPartMaxChars(maxRenderedContextChars),
|
|
1075
|
-
toolPayloadMode: params.toolPayloadMode ?? "elide"
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
+
toolPayloadMode: params.toolPayloadMode ?? "elide",
|
|
1079
|
+
maxRenderedContextChars
|
|
1080
|
+
});
|
|
1078
1081
|
const promptPrefix = boundedContext ? [
|
|
1079
1082
|
CONTEXT_HEADER,
|
|
1080
1083
|
CONTEXT_SAFETY_NOTE,
|
|
@@ -1187,10 +1190,23 @@ function dropDuplicateTrailingPrompt(messages, prompt) {
|
|
|
1187
1190
|
return extractMessageText(trailing).trim() === prompt ? messages.slice(0, -1) : messages;
|
|
1188
1191
|
}
|
|
1189
1192
|
function renderMessagesForCodexContext(messages, options) {
|
|
1190
|
-
|
|
1193
|
+
const tail = [];
|
|
1194
|
+
let totalChars = 0;
|
|
1195
|
+
let retainedChars = 0;
|
|
1196
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
1197
|
+
const message = messages[index];
|
|
1191
1198
|
const text = renderMessageBody(message, options);
|
|
1192
|
-
|
|
1193
|
-
|
|
1199
|
+
if (!text) continue;
|
|
1200
|
+
const chunk = `[${message.role}]\n${text}${totalChars > 0 ? "\n\n" : ""}`;
|
|
1201
|
+
totalChars += chunk.length;
|
|
1202
|
+
const remaining = options.maxRenderedContextChars - retainedChars;
|
|
1203
|
+
if (remaining > 0) {
|
|
1204
|
+
const retained = neutralizeCodexExplicitMentionSigils(chunk).slice(-remaining);
|
|
1205
|
+
tail.push(retained);
|
|
1206
|
+
retainedChars += retained.length;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return truncateOlderContext(tail.toReversed().join(""), options.maxRenderedContextChars, totalChars);
|
|
1194
1210
|
}
|
|
1195
1211
|
function renderMessageBody(message, options) {
|
|
1196
1212
|
if (message.role === "compactionSummary" || message.role === "branchSummary") return truncateText(message.summary.trim(), options.maxTextPartChars);
|
|
@@ -1312,13 +1328,13 @@ function truncateText(text, maxChars) {
|
|
|
1312
1328
|
const truncated = truncateUtf16Safe(text, maxChars);
|
|
1313
1329
|
return `${truncated}\n[truncated ${text.length - truncated.length} chars]`;
|
|
1314
1330
|
}
|
|
1315
|
-
function truncateOlderContext(text, maxChars) {
|
|
1316
|
-
if (
|
|
1331
|
+
function truncateOlderContext(text, maxChars, totalChars = text.length) {
|
|
1332
|
+
if (totalChars <= maxChars) return text;
|
|
1317
1333
|
if (maxChars <= 0) return "";
|
|
1318
1334
|
const buildMarker = (omittedChars) => `[truncated ${omittedChars} chars from older context]\n`;
|
|
1319
|
-
let marker = buildMarker(
|
|
1335
|
+
let marker = buildMarker(totalChars - maxChars);
|
|
1320
1336
|
let tailChars = Math.max(0, maxChars - marker.length);
|
|
1321
|
-
marker = buildMarker(
|
|
1337
|
+
marker = buildMarker(totalChars - tailChars);
|
|
1322
1338
|
if (marker.length >= maxChars) return marker.slice(0, maxChars);
|
|
1323
1339
|
tailChars = maxChars - marker.length;
|
|
1324
1340
|
return `${marker}${sliceUtf16Safe(text, -tailChars).trimStart()}`;
|
|
@@ -1556,15 +1572,10 @@ function fingerprintUserMcpServersConfigPatch(configPatch) {
|
|
|
1556
1572
|
function redactUserMcpServersFingerprintSecrets(value) {
|
|
1557
1573
|
if (Array.isArray(value)) return value.map(redactUserMcpServersFingerprintSecrets);
|
|
1558
1574
|
if (!value || typeof value !== "object") return value;
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
continue;
|
|
1564
|
-
}
|
|
1565
|
-
next[key] = redactUserMcpServersFingerprintSecrets(entry);
|
|
1566
|
-
}
|
|
1567
|
-
return next;
|
|
1575
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => {
|
|
1576
|
+
if (key === "http_headers" && entry && typeof entry === "object" && !Array.isArray(entry)) return [key, Object.fromEntries(Object.entries(entry).map(([header, headerValue]) => [header, header.toLowerCase() === "authorization" ? fingerprintUserMcpServersAuthorizationHeader(headerValue) : headerValue]))];
|
|
1577
|
+
return [key, redactUserMcpServersFingerprintSecrets(entry)];
|
|
1578
|
+
}));
|
|
1568
1579
|
}
|
|
1569
1580
|
function fingerprintUserMcpServersAuthorizationHeader(value) {
|
|
1570
1581
|
return typeof value === "string" && value.length > 0 ? `<redacted:sha256:${crypto$1.createHash("sha256").update(value).digest("hex")}>` : "<redacted>";
|
|
@@ -1595,9 +1606,7 @@ function fingerprintDynamicToolSpec(tool) {
|
|
|
1595
1606
|
function stabilizeJsonValue(value) {
|
|
1596
1607
|
if (Array.isArray(value)) return value.map(stabilizeJsonValue);
|
|
1597
1608
|
if (!isJsonObject(value)) return value;
|
|
1598
|
-
|
|
1599
|
-
for (const [key, child] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) stable[key] = stabilizeJsonValue(child);
|
|
1600
|
-
return stable;
|
|
1609
|
+
return Object.fromEntries(Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, stabilizeJsonValue(child)]));
|
|
1601
1610
|
}
|
|
1602
1611
|
function readActiveCodexTurnIds(thread) {
|
|
1603
1612
|
return (thread.turns ?? []).filter((turn) => turn.status === "inProgress").map((turn) => typeof turn.id === "string" ? turn.id : "").filter((turnId) => turnId.trim().length > 0);
|
|
@@ -1827,10 +1836,12 @@ function applyCodexNativeSkillIsolation(config, isolation) {
|
|
|
1827
1836
|
function hasCodexNativeToolCatalog(binding) {
|
|
1828
1837
|
return binding?.connectionScope === "supervision" && !binding.pendingSupervisionBranch;
|
|
1829
1838
|
}
|
|
1830
|
-
/** Pinned serde omits false deferLoading;
|
|
1839
|
+
/** Pinned serde omits empty catalogs and false deferLoading; declarations remain native-owned. */
|
|
1831
1840
|
function parseCodexNativeToolCatalog(metadata, threadId, fingerprint) {
|
|
1832
1841
|
const fail = () => /* @__PURE__ */ new Error("The canonical Codex native tool catalog is missing, corrupt, or changed; the thread is preserved. Reconnect and inspect its native metadata before retrying.");
|
|
1833
|
-
if (!isJsonObject(metadata) || metadata.id !== threadId
|
|
1842
|
+
if (!isJsonObject(metadata) || metadata.id !== threadId) throw fail();
|
|
1843
|
+
const catalog = metadata.dynamic_tools ?? [];
|
|
1844
|
+
if (!Array.isArray(catalog) || Buffer.byteLength(JSON.stringify(catalog)) > 1048576) throw fail();
|
|
1834
1845
|
const names = /* @__PURE__ */ new Set();
|
|
1835
1846
|
const namespaces = /* @__PURE__ */ new Set();
|
|
1836
1847
|
const validName = (name) => typeof name === "string" && /^[a-zA-Z0-9_-]{1,128}$/u.test(name);
|
|
@@ -1851,7 +1862,7 @@ function parseCodexNativeToolCatalog(metadata, threadId, fingerprint) {
|
|
|
1851
1862
|
...value.deferLoading === true ? { deferLoading: true } : {}
|
|
1852
1863
|
};
|
|
1853
1864
|
};
|
|
1854
|
-
const tools =
|
|
1865
|
+
const tools = catalog.map((value) => {
|
|
1855
1866
|
if (!isJsonObject(value) || value.type !== "namespace") return readFunction(value);
|
|
1856
1867
|
if (!validName(value.name) || namespaces.has(value.name) || typeof value.description !== "string" || !Array.isArray(value.tools) || !value.tools.length || Object.keys(value).some((key) => ![
|
|
1857
1868
|
"type",
|
|
@@ -1982,14 +1993,13 @@ async function attestCodexRestrictedToolSurfaceMcpServersDisabled(client, thread
|
|
|
1982
1993
|
//#endregion
|
|
1983
1994
|
//#region extensions/codex/src/app-server/plugin-thread-attestation.ts
|
|
1984
1995
|
/**
|
|
1985
|
-
*
|
|
1986
|
-
* OpenClaw commits a binding or starts a turn.
|
|
1996
|
+
* Checks app availability and enforces restricted MCP surfaces before a turn.
|
|
1987
1997
|
*/
|
|
1988
1998
|
/** Every admission path checks the same surface; its lifecycle owner keeps the claim fenced. */
|
|
1989
1999
|
async function attestCodexThreadToolSurface(params) {
|
|
1990
2000
|
params.assertCurrent();
|
|
1991
2001
|
if (params.appIds.length > 0) {
|
|
1992
|
-
await params.lifecycleTiming.measure("plugin-app-attestation", () =>
|
|
2002
|
+
await params.lifecycleTiming.measure("plugin-app-attestation", () => checkCodexThreadAppAvailability(params));
|
|
1993
2003
|
params.assertCurrent();
|
|
1994
2004
|
}
|
|
1995
2005
|
if (params.restrictedToolSurface) {
|
|
@@ -2004,7 +2014,7 @@ var CodexPluginThreadAppAttestationError = class extends Error {
|
|
|
2004
2014
|
}
|
|
2005
2015
|
};
|
|
2006
2016
|
/** Reads the existing runtime snapshot with the started thread's effective app policy. */
|
|
2007
|
-
async function
|
|
2017
|
+
async function checkCodexThreadAppAvailability(params) {
|
|
2008
2018
|
const appIds = Array.from(new Set(params.appIds.filter(Boolean))).toSorted();
|
|
2009
2019
|
if (appIds.length === 0) return;
|
|
2010
2020
|
let response;
|
|
@@ -2014,8 +2024,10 @@ async function attestCodexPluginThreadApps(params) {
|
|
|
2014
2024
|
forceRefresh: false
|
|
2015
2025
|
}, { signal: params.signal });
|
|
2016
2026
|
} catch (error) {
|
|
2027
|
+
params.signal?.throwIfAborted();
|
|
2017
2028
|
throw new CodexPluginThreadAppAttestationError(`Codex could not confirm admitted apps for thread ${params.threadId}`, { cause: error });
|
|
2018
2029
|
}
|
|
2030
|
+
params.signal?.throwIfAborted();
|
|
2019
2031
|
const installedById = new Map(response.apps.map((app) => [app.id, app]));
|
|
2020
2032
|
const failures = appIds.flatMap((appId) => {
|
|
2021
2033
|
const app = installedById.get(appId);
|
|
@@ -2023,7 +2035,10 @@ async function attestCodexPluginThreadApps(params) {
|
|
|
2023
2035
|
if (!app.enabled) return [`${appId}:disabled`];
|
|
2024
2036
|
return app.callable ? [] : [`${appId}:not-callable`];
|
|
2025
2037
|
});
|
|
2026
|
-
if (failures.length > 0)
|
|
2038
|
+
if (failures.length > 0) embeddedAgentLog.warn("codex apps unavailable; continuing with remaining tools", {
|
|
2039
|
+
threadId: params.threadId,
|
|
2040
|
+
failures
|
|
2041
|
+
});
|
|
2027
2042
|
}
|
|
2028
2043
|
/** Deletes a persistent pre-turn thread; ephemeral threads can only be unsubscribed. */
|
|
2029
2044
|
async function discardUnattestedCodexPluginThread(params) {
|
|
@@ -2207,7 +2222,10 @@ function createCodexNativeHookRelay(params) {
|
|
|
2207
2222
|
}),
|
|
2208
2223
|
signal: params.signal,
|
|
2209
2224
|
runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
|
|
2210
|
-
assertActive:
|
|
2225
|
+
assertActive: () => {
|
|
2226
|
+
params.hostCapabilities.assertActive();
|
|
2227
|
+
params.assertCurrent?.();
|
|
2228
|
+
},
|
|
2211
2229
|
retention: {
|
|
2212
2230
|
readClaim: readCodexNativeChildThreadId,
|
|
2213
2231
|
shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
|
|
@@ -2686,6 +2704,7 @@ function resolveCodexWebSearchPlan(params) {
|
|
|
2686
2704
|
const CODEX_CODE_MODE_THREAD_CONFIG = {
|
|
2687
2705
|
"features.code_mode": true,
|
|
2688
2706
|
"features.code_mode_only": false,
|
|
2707
|
+
"features.shell_tool": true,
|
|
2689
2708
|
"features.apply_patch_streaming_events": true,
|
|
2690
2709
|
suppress_unstable_features_warning: true
|
|
2691
2710
|
};
|
|
@@ -2712,6 +2731,7 @@ const CODEX_RING_ZERO_RESTRICTED_FEATURES = /* @__PURE__ */ new Set([
|
|
|
2712
2731
|
"code_mode",
|
|
2713
2732
|
"code_mode_only",
|
|
2714
2733
|
"computer_use",
|
|
2734
|
+
"context_management",
|
|
2715
2735
|
"current_time_reminder",
|
|
2716
2736
|
"default_mode_request_user_input",
|
|
2717
2737
|
"deferred_executor",
|
|
@@ -2764,15 +2784,6 @@ const CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES = /* @__PURE__ */ new Map([
|
|
|
2764
2784
|
["telepathy", "chronicle"],
|
|
2765
2785
|
["codex_hooks", "hooks"]
|
|
2766
2786
|
]);
|
|
2767
|
-
const CODEX_RING_ZERO_OVERRIDABLE_LAYER_TYPES = /* @__PURE__ */ new Set([
|
|
2768
|
-
"packagedDefaults",
|
|
2769
|
-
"mdm",
|
|
2770
|
-
"system",
|
|
2771
|
-
"enterpriseManaged",
|
|
2772
|
-
"user",
|
|
2773
|
-
"project",
|
|
2774
|
-
"sessionFlags"
|
|
2775
|
-
]);
|
|
2776
2787
|
/** Common deterministic start/resume/fork fields; no run resources or unsupported setters. */
|
|
2777
2788
|
function buildCodexThreadConfiguration(params, options) {
|
|
2778
2789
|
return {
|
|
@@ -2926,17 +2937,16 @@ function buildRestrictedToolConfigPatch(inheritedMcpServerNames, scheduledAppAut
|
|
|
2926
2937
|
...Object.keys(mcpServers).length > 0 ? { mcp_servers: mcpServers } : {}
|
|
2927
2938
|
};
|
|
2928
2939
|
}
|
|
2929
|
-
async function readCodexInheritedMcpServerNames(client, cwd, signal) {
|
|
2930
|
-
const response = await client
|
|
2931
|
-
cwd,
|
|
2932
|
-
includeLayers: true
|
|
2933
|
-
}, { signal });
|
|
2934
|
-
if (!isJsonObject(response) || !isJsonObject(response.config)) throw new Error("Codex config/read returned an invalid effective config");
|
|
2940
|
+
async function readCodexInheritedMcpServerNames(client, cwd, signal, effectiveConfig) {
|
|
2941
|
+
const response = effectiveConfig ?? await readCodexEffectiveConfig(client, cwd, signal);
|
|
2935
2942
|
if (!Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config layers");
|
|
2936
2943
|
for (const layer of response.layers) {
|
|
2937
2944
|
if (!isJsonObject(layer) || !isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned invalid effective config layers");
|
|
2938
|
-
if (layer.name.type === "legacyManagedConfigTomlFromFile" || layer.name.type === "legacyManagedConfigTomlFromMdm")
|
|
2939
|
-
|
|
2945
|
+
if (layer.name.type === "legacyManagedConfigTomlFromFile" || layer.name.type === "legacyManagedConfigTomlFromMdm") {
|
|
2946
|
+
const migrationGuidance = layer.name.type === "legacyManagedConfigTomlFromFile" ? "migrate /etc/codex/managed_config.toml to /etc/codex/requirements.toml before running restricted or isolated turns. For ChatGPT-only authentication, use allowed_login_methods = [\"chatgpt\"] in /etc/codex/requirements.toml" : "replace the legacy MDM payload with base64-encoded TOML requirements in the com.openai.codex managed preference requirements_toml_base64 before running restricted or isolated turns. For ChatGPT-only authentication, include allowed_login_methods = [\"chatgpt\"] in that TOML payload";
|
|
2947
|
+
throw new Error(`Codex restricted tool surface cannot override config layer ${layer.name.type}; ${migrationGuidance}.`);
|
|
2948
|
+
}
|
|
2949
|
+
if (!CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(layer.name.type)) throw new Error(`Codex restricted tool surface does not recognize config layer ${layer.name.type}`);
|
|
2940
2950
|
}
|
|
2941
2951
|
const configuredServers = response.config.mcp_servers;
|
|
2942
2952
|
if (configuredServers === void 0) return [];
|
|
@@ -2968,6 +2978,7 @@ async function assertCodexManagedRequirementsDoNotOverrideToolPolicy(client, opt
|
|
|
2968
2978
|
for (const [feature, enabled] of Object.entries(featureRequirements)) {
|
|
2969
2979
|
if (typeof enabled !== "boolean") throw new Error("Codex configRequirements/read returned invalid feature requirements");
|
|
2970
2980
|
const canonicalFeature = CODEX_RING_ZERO_RESTRICTED_FEATURE_ALIASES.get(feature) ?? feature;
|
|
2981
|
+
if (options.requiredNativeShell && canonicalFeature === "shell_tool" && !enabled) throw new Error("Codex native code mode requires shell_tool, but managed requirements disable it. Ask your administrator to allow the shell, or select a tool policy that disables native code mode; no automation authority was captured.");
|
|
2971
2982
|
const deniedByToolPolicy = options.restrictedToolSurface && CODEX_RING_ZERO_RESTRICTED_FEATURES.has(canonicalFeature) || additionalDeniedFeatures.has(canonicalFeature);
|
|
2972
2983
|
if (canonicalFeature === "hooks" && managedHooksAllowed) continue;
|
|
2973
2984
|
if (enabled && deniedByToolPolicy) throw new Error(`Codex tool policy cannot override required feature ${feature}`);
|
|
@@ -3262,11 +3273,6 @@ function appApprovalCeiling(mode) {
|
|
|
3262
3273
|
if (mode === "allow") return "approve";
|
|
3263
3274
|
return mode === "ask" ? "prompt" : "auto";
|
|
3264
3275
|
}
|
|
3265
|
-
function stableStringify(value) {
|
|
3266
|
-
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
3267
|
-
if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
3268
|
-
return JSON.stringify(value);
|
|
3269
|
-
}
|
|
3270
3276
|
/** Intersects a stored app-ID cap with current policy without admitting new apps. */
|
|
3271
3277
|
function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authority, currentPolicy = {
|
|
3272
3278
|
config: {},
|
|
@@ -3296,13 +3302,17 @@ function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authorit
|
|
|
3296
3302
|
};
|
|
3297
3303
|
}
|
|
3298
3304
|
const policyContext = buildPluginAppPolicyContext(apps, Object.fromEntries(Object.entries(config.policyContext.pluginAppIds).map(([key, ids]) => [key, ids.filter((id) => Object.hasOwn(apps, id))]).filter(([, ids]) => ids.length > 0)));
|
|
3299
|
-
const configPatch = buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext);
|
|
3305
|
+
const configPatch = disableUnlistedCodexApps(buildCodexPluginAppsConfigPatchFromPolicyContext(policyContext), currentPolicy.config);
|
|
3300
3306
|
const appsPatch = asOptionalRecord(configPatch.apps);
|
|
3301
3307
|
for (const [appId, captured] of capturedById) {
|
|
3302
3308
|
const appPatch = asOptionalRecord(appsPatch?.[appId]);
|
|
3303
3309
|
if (!appPatch || !Object.hasOwn(apps, appId)) continue;
|
|
3304
3310
|
const currentApp = apps[appId];
|
|
3305
3311
|
if (!currentApp) continue;
|
|
3312
|
+
if (currentApp.destructiveApprovalMode === "ask") Object.assign(appPatch, buildCodexAppApprovalOverrides(currentPolicy.config, {
|
|
3313
|
+
id: appId,
|
|
3314
|
+
approvalOverrideToolConfigKeys: []
|
|
3315
|
+
}));
|
|
3306
3316
|
const storedAppCeiling = appApprovalCeiling(captured.destructiveApprovalMode);
|
|
3307
3317
|
const currentAppCeiling = appApprovalCeiling(defaultApprovalMode(currentApp));
|
|
3308
3318
|
const tools = currentPolicy.toolsByApp.get(appId) ?? /* @__PURE__ */ new Map();
|
|
@@ -3315,7 +3325,7 @@ function intersectCodexPluginThreadConfigWithScheduledAuthority(config, authorit
|
|
|
3315
3325
|
}];
|
|
3316
3326
|
}));
|
|
3317
3327
|
}
|
|
3318
|
-
const fingerprint = crypto.createHash("sha256").update(
|
|
3328
|
+
const fingerprint = crypto.createHash("sha256").update(stringifyCodexPluginPolicy({
|
|
3319
3329
|
version: 1,
|
|
3320
3330
|
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
3321
3331
|
authority: scheduled,
|
|
@@ -3355,7 +3365,7 @@ function buildLegacyScheduledCodexAppRecoveryPrompt(params) {
|
|
|
3355
3365
|
function buildScheduledCodexAppAuthorityInputFingerprint(baseFingerprint, authority) {
|
|
3356
3366
|
const scheduled = parseScheduledCodexAppAuthority(authority);
|
|
3357
3367
|
if (!scheduled) return baseFingerprint;
|
|
3358
|
-
return crypto.createHash("sha256").update(
|
|
3368
|
+
return crypto.createHash("sha256").update(stringifyCodexPluginPolicy({
|
|
3359
3369
|
version: 1,
|
|
3360
3370
|
namespace: CODEX_SCHEDULED_APP_AUTHORITY_NAMESPACE,
|
|
3361
3371
|
baseFingerprint,
|
|
@@ -3367,8 +3377,9 @@ function buildScheduledCodexAppAuthorityInputFingerprint(baseFingerprint, author
|
|
|
3367
3377
|
const CODEX_THREAD_LIFECYCLE_TIMING_WARN_TOTAL_MS = 1e3;
|
|
3368
3378
|
const CODEX_THREAD_LIFECYCLE_TIMING_WARN_STAGE_MS = 500;
|
|
3369
3379
|
function shouldWarnCodexThreadLifecycleTimingSummary(summary, options = {}) {
|
|
3370
|
-
const
|
|
3371
|
-
const
|
|
3380
|
+
const detailed = options.enabled || options.log?.isEnabled?.("trace");
|
|
3381
|
+
const totalThresholdMs = options.totalThresholdMs ?? (detailed ? CODEX_THREAD_LIFECYCLE_TIMING_WARN_TOTAL_MS : 1e4);
|
|
3382
|
+
const stageThresholdMs = options.stageThresholdMs ?? (detailed ? CODEX_THREAD_LIFECYCLE_TIMING_WARN_STAGE_MS : 5e3);
|
|
3372
3383
|
return summary.totalMs >= totalThresholdMs || summary.spans.some((span) => span.durationMs >= stageThresholdMs);
|
|
3373
3384
|
}
|
|
3374
3385
|
function formatCodexThreadLifecycleTimingSummary(params) {
|
|
@@ -3377,16 +3388,6 @@ function formatCodexThreadLifecycleTimingSummary(params) {
|
|
|
3377
3388
|
}
|
|
3378
3389
|
function createCodexThreadLifecycleTimingTracker(options = {}) {
|
|
3379
3390
|
const log = options.log ?? embeddedAgentLog;
|
|
3380
|
-
if (!options.enabled && log.isEnabled?.("trace") !== true) return {
|
|
3381
|
-
async measure(_name, run) {
|
|
3382
|
-
return await run();
|
|
3383
|
-
},
|
|
3384
|
-
measureSync(_name, run) {
|
|
3385
|
-
return run();
|
|
3386
|
-
},
|
|
3387
|
-
mark() {},
|
|
3388
|
-
logSummary() {}
|
|
3389
|
-
};
|
|
3390
3391
|
const now = options.now ?? Date.now;
|
|
3391
3392
|
const startedAt = now();
|
|
3392
3393
|
let didLog = false;
|
|
@@ -3427,7 +3428,10 @@ function createCodexThreadLifecycleTimingTracker(options = {}) {
|
|
|
3427
3428
|
logSummary(params) {
|
|
3428
3429
|
if (didLog) return;
|
|
3429
3430
|
const summary = snapshot();
|
|
3430
|
-
const shouldWarn = shouldWarnCodexThreadLifecycleTimingSummary(summary,
|
|
3431
|
+
const shouldWarn = shouldWarnCodexThreadLifecycleTimingSummary(summary, {
|
|
3432
|
+
...options,
|
|
3433
|
+
log
|
|
3434
|
+
});
|
|
3431
3435
|
if (!shouldWarn && !log.isEnabled?.("trace")) return;
|
|
3432
3436
|
didLog = true;
|
|
3433
3437
|
const message = formatCodexThreadLifecycleTimingSummary({
|
|
@@ -3459,10 +3463,10 @@ function resolveCodexThreadAgentDir(params) {
|
|
|
3459
3463
|
sessionKey: params.params.sessionKey,
|
|
3460
3464
|
agentId: params.agentId ?? params.params.agentId
|
|
3461
3465
|
}).sessionAgentId;
|
|
3462
|
-
return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$
|
|
3466
|
+
return params.agentDir ?? params.params.agentDir ?? resolveAgentDir$2(params.params.config ?? {}, agentId);
|
|
3463
3467
|
}
|
|
3464
3468
|
async function prepareCodexThreadLifecyclePreflight(params) {
|
|
3465
|
-
await assertCodexModelBackedReviewerEffectiveConfig({
|
|
3469
|
+
let effectiveConfig = await assertCodexModelBackedReviewerEffectiveConfig({
|
|
3466
3470
|
client: params.client,
|
|
3467
3471
|
approvalsReviewer: params.appServer.approvalsReviewer,
|
|
3468
3472
|
cwd: params.cwd,
|
|
@@ -3518,13 +3522,17 @@ async function prepareCodexThreadLifecyclePreflight(params) {
|
|
|
3518
3522
|
const allowConfiguredManagedHooks = params.params.pluginHarnessToolPolicyRestricted === true && !ringZeroActive && !messageOnlySourceReply && params.params.scheduledRuntimeAuthority === void 0;
|
|
3519
3523
|
const imageGenerationDenied = params.params.pluginHarnessToolPolicySafeDeniedTools?.includes("image_generate") === true;
|
|
3520
3524
|
if (restrictedToolSurface && params.nativeCodeModeEnabled !== false) throw new Error("Codex restricted tool surfaces require native code mode to be disabled");
|
|
3521
|
-
|
|
3522
|
-
|
|
3525
|
+
if ((restrictedToolSurface || params.nativeCodeModeEnabled !== false) && !effectiveConfig) effectiveConfig = await lifecycleTiming.measure("tool-policy-config-read", () => readCodexEffectiveConfig(params.client, params.cwd, params.signal));
|
|
3526
|
+
const restrictedToolSurfaceInheritedMcpServerNames = restrictedToolSurface ? await lifecycleTiming.measure("restricted-tool-surface-mcp-policy", () => readCodexInheritedMcpServerNames(params.client, params.cwd, params.signal, effectiveConfig)) : [];
|
|
3527
|
+
if (restrictedToolSurface || imageGenerationDenied || params.nativeCodeModeEnabled !== false) await lifecycleTiming.measure("tool-policy-config-requirements-read", () => assertCodexManagedRequirementsDoNotOverrideToolPolicy(params.client, {
|
|
3523
3528
|
restrictedToolSurface,
|
|
3529
|
+
requiredNativeShell: params.nativeCodeModeEnabled !== false,
|
|
3524
3530
|
additionalDeniedFeatures: imageGenerationDenied ? ["image_generation"] : void 0,
|
|
3525
3531
|
allowedManagedRequirementsFingerprint: readScheduledCodexAppManagedRequirementsFingerprint(params.params.scheduledRuntimeAuthority),
|
|
3526
3532
|
allowConfiguredManagedHooks
|
|
3527
3533
|
}, params.signal));
|
|
3534
|
+
const features = effectiveConfig?.config.features;
|
|
3535
|
+
if (params.nativeCodeModeEnabled !== false && isJsonObject(features) && features.shell_tool === false && !CODEX_SESSION_OVERRIDABLE_LAYER_TYPES.has(effectiveConfig?.origins?.["features.shell_tool"]?.name.type ?? "")) throw new Error("Codex native code mode requires shell_tool, but the effective shell setting cannot be overridden. Ask your administrator to allow the shell, or select a tool policy that disables native code mode; no automation authority was captured.");
|
|
3528
3536
|
const ringZeroConfigFingerprint = ringZeroActive ? fingerprintJsonObject({
|
|
3529
3537
|
version: 1,
|
|
3530
3538
|
baseInstructions: "",
|
|
@@ -3553,71 +3561,26 @@ async function prepareCodexThreadLifecyclePreflight(params) {
|
|
|
3553
3561
|
};
|
|
3554
3562
|
}
|
|
3555
3563
|
//#endregion
|
|
3556
|
-
//#region extensions/codex/src/app-server/thread-lifecycle-
|
|
3564
|
+
//#region extensions/codex/src/app-server/thread-lifecycle-io.ts
|
|
3557
3565
|
function resolveCodexThreadRolloutPath(thread) {
|
|
3558
3566
|
const rolloutPath = thread.path?.trim();
|
|
3559
3567
|
if (!rolloutPath || !path.isAbsolute(rolloutPath) || path.extname(rolloutPath) !== ".jsonl" || !path.basename(rolloutPath).includes(thread.id)) return;
|
|
3560
3568
|
return rolloutPath;
|
|
3561
3569
|
}
|
|
3562
|
-
/** Materializes the public lifecycle result after a fresh thread is durably committed. */
|
|
3563
|
-
function buildStartedCodexThreadBinding(input) {
|
|
3564
|
-
const { context, params, response, startParams } = input;
|
|
3565
|
-
return {
|
|
3566
|
-
threadId: response.thread.id,
|
|
3567
|
-
...input.clientId ? { clientId: input.clientId } : {},
|
|
3568
|
-
cwd: params.cwd,
|
|
3569
|
-
...input.rolloutPath ? { rolloutPath: input.rolloutPath } : {},
|
|
3570
|
-
authProfileId: params.params.authProfileId,
|
|
3571
|
-
agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
|
|
3572
|
-
model: response.model ?? startParams.model ?? params.params.modelId,
|
|
3573
|
-
modelProvider: response.modelProvider ?? input.startModelProvider ?? input.modelProvider,
|
|
3574
|
-
dynamicToolsFingerprint: context.dynamicToolsFingerprint,
|
|
3575
|
-
dynamicToolsContainDeferred: context.dynamicToolsContainDeferred,
|
|
3576
|
-
nativeSkillIsolationFingerprint: context.nativeSkillIsolationFingerprint,
|
|
3577
|
-
userMcpServersFingerprint: context.userMcpServersFingerprint,
|
|
3578
|
-
mcpServersFingerprint: input.nextMcpServersFingerprint,
|
|
3579
|
-
configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
|
|
3580
|
-
ringZeroConfigFingerprint: context.ringZeroConfigFingerprint,
|
|
3581
|
-
ringZeroClientInstanceId: context.ringZeroClientInstanceId,
|
|
3582
|
-
networkProxyProfileName: params.appServer.networkProxy?.profileName,
|
|
3583
|
-
networkProxyConfigFingerprint: context.networkProxyConfigFingerprint,
|
|
3584
|
-
nativeHookRelayGeneration: input.finalConfigPatch.nativeHookRelayGeneration,
|
|
3585
|
-
appServerRuntimeFingerprint: params.appServerRuntimeFingerprint,
|
|
3586
|
-
pluginAppsFingerprint: input.pluginThreadConfig?.fingerprint,
|
|
3587
|
-
pluginAppsInputFingerprint: input.pluginThreadConfig?.inputFingerprint,
|
|
3588
|
-
pluginAppPolicyContext: input.pluginThreadConfig?.policyContext,
|
|
3589
|
-
contextEngine: context.contextEngineBinding,
|
|
3590
|
-
environmentSelectionFingerprint: context.environmentSelectionFingerprint,
|
|
3591
|
-
...startParams.ephemeral ? { liveThreadEphemeralPolicy: startParams.developerInstructions } : {},
|
|
3592
|
-
...!context.preserveExistingBinding ? { liveThreadConfigFingerprint: fingerprintCodexThreadConfig({
|
|
3593
|
-
...startParams,
|
|
3594
|
-
model: response.model ?? startParams.model ?? null,
|
|
3595
|
-
requestedModel: startParams.model ?? null,
|
|
3596
|
-
modelProvider: input.bindingModelProvider ?? null,
|
|
3597
|
-
requestedModelProvider: startParams.modelProvider ?? input.bindingModelProvider ?? null
|
|
3598
|
-
}, params.params.authProfileId, context.dynamicToolsFingerprint) } : {},
|
|
3599
|
-
lifecycle: {
|
|
3600
|
-
action: "started",
|
|
3601
|
-
...context.rotatedContextEngineBinding ? { rotatedContextEngineBinding: true } : {}
|
|
3602
|
-
}
|
|
3603
|
-
};
|
|
3604
|
-
}
|
|
3605
|
-
//#endregion
|
|
3606
|
-
//#region extensions/codex/src/app-server/thread-lifecycle-io.ts
|
|
3607
3570
|
async function resumeExistingCodexThread(params, context) {
|
|
3608
3571
|
const { binding: resumeBinding, bindingIdentity, startModelSelection, startModelProvider, userMcpServersConfigPatch, dynamicToolsFingerprint, dynamicToolsContainDeferred, webSearchThreadConfigFingerprint, nativeSkillIsolationFingerprint, userMcpServersFingerprint, ringZeroConfigFingerprint, ringZeroClientInstanceId, networkProxyConfigFingerprint, contextEngineBinding, environmentSelectionFingerprint, hostSystemAgentActive, restrictedToolSurface, restrictedToolSurfaceInheritedMcpServerNames, nativeSkillIsolation, lifecycleTiming, normalizeBindingModelProvider, throwIfAborted, clearCurrentBinding } = context;
|
|
3572
|
+
let acceptedConfiguration;
|
|
3573
|
+
let disposeConfiguration;
|
|
3609
3574
|
let resumeReservation;
|
|
3610
|
-
let resumeResponseAccepted = false;
|
|
3611
3575
|
let ordinaryAppConfigChanged = false;
|
|
3612
3576
|
let policyOutcome = "not-written";
|
|
3613
|
-
const assertHandoffCurrent = () => {
|
|
3614
|
-
params.params.hostCapabilities.assertActive();
|
|
3615
|
-
throwIfAborted();
|
|
3616
|
-
context.assertResumeOwnership();
|
|
3617
|
-
context.assertResumeConfiguration();
|
|
3618
|
-
};
|
|
3619
3577
|
const abandonClient = params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client));
|
|
3620
3578
|
try {
|
|
3579
|
+
const configuration = await context.prepareResume();
|
|
3580
|
+
const assertHandoffCurrent = configuration.assertConfigured;
|
|
3581
|
+
disposeConfiguration = configuration.dispose;
|
|
3582
|
+
await context.releaseRetainedThread(configuration.assertCurrent);
|
|
3583
|
+
configuration.assertCurrent();
|
|
3621
3584
|
const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
|
|
3622
3585
|
const finalConfigPatch = context.prebuiltFinalConfigPatch ?? params.buildFinalConfigPatch?.({
|
|
3623
3586
|
action: "resume",
|
|
@@ -3626,9 +3589,8 @@ async function resumeExistingCodexThread(params, context) {
|
|
|
3626
3589
|
configPatch: params.finalConfigPatch,
|
|
3627
3590
|
nativeHookRelayGeneration: params.nativeHookRelayGeneration
|
|
3628
3591
|
};
|
|
3629
|
-
const pluginThreadConfig = context.prebuiltPluginThreadConfig ?? (params.pluginThreadConfig?.
|
|
3630
|
-
const
|
|
3631
|
-
const resumeConfig = applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginAppsConfigPatch, finalConfigPatch.configPatch), nativeSkillIsolation);
|
|
3592
|
+
const pluginThreadConfig = context.prebuiltPluginThreadConfig ?? (params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0);
|
|
3593
|
+
const resumeConfig = applyCodexNativeSkillIsolation(mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginThreadConfig?.configPatch, finalConfigPatch.configPatch), nativeSkillIsolation);
|
|
3632
3594
|
const resumeParams = lifecycleTiming.measureSync("thread-resume-params", () => buildThreadResumeParams(params.params, {
|
|
3633
3595
|
threadId: resumeBinding.threadId,
|
|
3634
3596
|
cwd: params.cwd,
|
|
@@ -3657,11 +3619,11 @@ async function resumeExistingCodexThread(params, context) {
|
|
|
3657
3619
|
abandonClient,
|
|
3658
3620
|
request: resumeParams,
|
|
3659
3621
|
signal: params.signal,
|
|
3660
|
-
assertCurrent:
|
|
3622
|
+
assertCurrent: configuration.assertCurrent
|
|
3661
3623
|
}));
|
|
3662
|
-
|
|
3624
|
+
acceptedConfiguration = configuration;
|
|
3663
3625
|
assertCodexThreadAcceptsDirectInput(response.thread);
|
|
3664
|
-
|
|
3626
|
+
configuration.assertConfigured();
|
|
3665
3627
|
const loadedPluginThreadConfig = await context.buildLoadedPluginThreadConfig?.(resumeBinding);
|
|
3666
3628
|
if (loadedPluginThreadConfig && loadedPluginThreadConfig.fingerprint !== (pluginThreadConfig?.fingerprint ?? resumeBinding.pluginAppsFingerprint)) {
|
|
3667
3629
|
ordinaryAppConfigChanged = resumeBinding.connectionScope !== "supervision" && !resumeBinding.pendingResumeConfiguration;
|
|
@@ -3760,13 +3722,13 @@ async function resumeExistingCodexThread(params, context) {
|
|
|
3760
3722
|
};
|
|
3761
3723
|
} catch (error) {
|
|
3762
3724
|
resumeReservation?.release();
|
|
3763
|
-
if (!
|
|
3764
|
-
if (
|
|
3725
|
+
if (!acceptedConfiguration && (!(error instanceof CodexAppServerRpcError) || error.method === "thread/read" && !isCodexThreadReadMissingError(error, resumeBinding.threadId) || isCodexAppServerOverloadError(error))) throw error;
|
|
3726
|
+
if (acceptedConfiguration) {
|
|
3765
3727
|
const handoffError = error instanceof CodexThreadPolicyHandoffError || error instanceof CodexAppServerUnsafeSubscriptionError ? error : new CodexThreadPolicyHandoffError(policyOutcome, error);
|
|
3766
3728
|
const subscriptionReleased = await unsubscribeCodexThreadBestEffort(params.client, {
|
|
3767
3729
|
threadId: resumeBinding.threadId,
|
|
3768
3730
|
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS,
|
|
3769
|
-
assertCurrent:
|
|
3731
|
+
assertCurrent: acceptedConfiguration.assertCurrent
|
|
3770
3732
|
}).catch(() => false);
|
|
3771
3733
|
if (!subscriptionReleased || handoffError instanceof CodexThreadPolicyHandoffError && handoffError.outcome === "unknown") {
|
|
3772
3734
|
if (resumeBinding.connectionScope === "supervision") await retireUnsafeCodexTurnClientBestEffort(params.client, "session policy handoff");
|
|
@@ -3777,11 +3739,13 @@ async function resumeExistingCodexThread(params, context) {
|
|
|
3777
3739
|
}
|
|
3778
3740
|
}
|
|
3779
3741
|
if (!ordinaryAppConfigChanged || !subscriptionReleased) throw handoffError;
|
|
3780
|
-
|
|
3742
|
+
acceptedConfiguration.assertConfigured();
|
|
3781
3743
|
}
|
|
3782
|
-
if (resumeBinding.pendingResumeConfiguration || resumeBinding.connectionScope === "supervision" || params.signal?.aborted) throw error;
|
|
3744
|
+
if (resumeBinding.pendingResumeConfiguration || resumeBinding.preserveNativeModel || resumeBinding.connectionScope === "supervision" || params.signal?.aborted) throw error;
|
|
3783
3745
|
embeddedAgentLog.warn("codex app-server thread resume failed; starting a new thread", { error });
|
|
3784
3746
|
await clearCurrentBinding("rotating a stale thread binding");
|
|
3747
|
+
} finally {
|
|
3748
|
+
disposeConfiguration?.();
|
|
3785
3749
|
}
|
|
3786
3750
|
}
|
|
3787
3751
|
async function startFreshCodexThread(params, context) {
|
|
@@ -3812,9 +3776,18 @@ async function startFreshCodexThread(params, context) {
|
|
|
3812
3776
|
disableLoginShell: params.disableLoginShell
|
|
3813
3777
|
}));
|
|
3814
3778
|
const requestModelProvider = typeof startParams.modelProvider === "string" && startParams.modelProvider.trim() ? startParams.modelProvider : void 0;
|
|
3779
|
+
const assertCurrent = () => {
|
|
3780
|
+
throwIfAborted();
|
|
3781
|
+
params.params.hostCapabilities.assertActive();
|
|
3782
|
+
params.assertCurrent?.();
|
|
3783
|
+
};
|
|
3815
3784
|
const threadStartResponse = await lifecycleTiming.measure("thread-start-request", async () => {
|
|
3816
3785
|
try {
|
|
3817
|
-
|
|
3786
|
+
assertCurrent();
|
|
3787
|
+
return await params.client.request("thread/start", startParams, {
|
|
3788
|
+
signal: params.signal,
|
|
3789
|
+
assertCurrent
|
|
3790
|
+
});
|
|
3818
3791
|
} catch (error) {
|
|
3819
3792
|
if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
|
|
3820
3793
|
throw error;
|
|
@@ -3822,10 +3795,6 @@ async function startFreshCodexThread(params, context) {
|
|
|
3822
3795
|
});
|
|
3823
3796
|
const response = assertCodexThreadStartResponse(threadStartResponse);
|
|
3824
3797
|
const provisionalAppIds = pluginThreadConfig?.provisionalAppIds;
|
|
3825
|
-
const assertCurrent = () => {
|
|
3826
|
-
throwIfAborted();
|
|
3827
|
-
params.params.hostCapabilities.assertActive();
|
|
3828
|
-
};
|
|
3829
3798
|
const rejectUncommittedThread = async (cause) => {
|
|
3830
3799
|
if (!await discardUnattestedCodexPluginThread({
|
|
3831
3800
|
client: params.client,
|
|
@@ -3862,35 +3831,38 @@ async function startFreshCodexThread(params, context) {
|
|
|
3862
3831
|
});
|
|
3863
3832
|
const bindingModelProvider = normalizeBindingModelProvider(params.params.authProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider ?? modelProvider);
|
|
3864
3833
|
const nextMcpServersFingerprint = params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : void 0;
|
|
3834
|
+
const startedBinding = {
|
|
3835
|
+
threadId: response.thread.id,
|
|
3836
|
+
...clientId ? { clientId } : {},
|
|
3837
|
+
cwd: params.cwd,
|
|
3838
|
+
...rolloutPath ? { rolloutPath } : {},
|
|
3839
|
+
authProfileId: params.params.authProfileId,
|
|
3840
|
+
agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
|
|
3841
|
+
model: response.model ?? startParams.model ?? params.params.modelId,
|
|
3842
|
+
modelProvider: bindingModelProvider,
|
|
3843
|
+
dynamicToolsFingerprint,
|
|
3844
|
+
dynamicToolsContainDeferred,
|
|
3845
|
+
nativeSkillIsolationFingerprint,
|
|
3846
|
+
userMcpServersFingerprint,
|
|
3847
|
+
mcpServersFingerprint: nextMcpServersFingerprint,
|
|
3848
|
+
configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
|
|
3849
|
+
ringZeroConfigFingerprint,
|
|
3850
|
+
ringZeroClientInstanceId,
|
|
3851
|
+
networkProxyProfileName: params.appServer.networkProxy?.profileName,
|
|
3852
|
+
networkProxyConfigFingerprint,
|
|
3853
|
+
nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
|
|
3854
|
+
appServerRuntimeFingerprint: params.appServerRuntimeFingerprint,
|
|
3855
|
+
pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
|
|
3856
|
+
pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
|
|
3857
|
+
pluginAppPolicyContext: pluginThreadConfig?.policyContext,
|
|
3858
|
+
contextEngine: contextEngineBinding,
|
|
3859
|
+
environmentSelectionFingerprint
|
|
3860
|
+
};
|
|
3865
3861
|
if (!preserveExistingBinding) {
|
|
3866
3862
|
const nextBinding = {
|
|
3867
|
-
|
|
3868
|
-
...clientId ? { clientId } : {},
|
|
3869
|
-
cwd: params.cwd,
|
|
3870
|
-
...rolloutPath ? { rolloutPath } : {},
|
|
3871
|
-
authProfileId: params.params.authProfileId,
|
|
3872
|
-
agentWorkspaceDeveloperInstructions: params.agentWorkspaceDeveloperInstructions,
|
|
3873
|
-
model: response.model ?? startParams.model ?? params.params.modelId,
|
|
3874
|
-
modelProvider: bindingModelProvider,
|
|
3875
|
-
dynamicToolsFingerprint,
|
|
3876
|
-
dynamicToolsContainDeferred,
|
|
3863
|
+
...startedBinding,
|
|
3877
3864
|
webSearchThreadConfigFingerprint,
|
|
3878
|
-
|
|
3879
|
-
userMcpServersFingerprint,
|
|
3880
|
-
mcpServersFingerprint: nextMcpServersFingerprint,
|
|
3881
|
-
configuredMcpOwnershipVersion: params.configuredMcpOwnershipVersion,
|
|
3882
|
-
ringZeroConfigFingerprint,
|
|
3883
|
-
ringZeroClientInstanceId,
|
|
3884
|
-
nativeToolPolicyRestricted: restrictedToolSurface ? true : void 0,
|
|
3885
|
-
networkProxyProfileName: params.appServer.networkProxy?.profileName,
|
|
3886
|
-
networkProxyConfigFingerprint,
|
|
3887
|
-
nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
|
|
3888
|
-
appServerRuntimeFingerprint: params.appServerRuntimeFingerprint,
|
|
3889
|
-
pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
|
|
3890
|
-
pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
|
|
3891
|
-
pluginAppPolicyContext: pluginThreadConfig?.policyContext,
|
|
3892
|
-
contextEngine: contextEngineBinding,
|
|
3893
|
-
environmentSelectionFingerprint
|
|
3865
|
+
nativeToolPolicyRestricted: restrictedToolSurface ? true : void 0
|
|
3894
3866
|
};
|
|
3895
3867
|
const managedSourceHomeId = codexCatalogHomeId(resolveCodexAppServerLocalHomeDir(params.appServer.start, resolveCodexThreadAgentDir(params)));
|
|
3896
3868
|
let committed;
|
|
@@ -3931,20 +3903,22 @@ async function startFreshCodexThread(params, context) {
|
|
|
3931
3903
|
threadId: response.thread.id,
|
|
3932
3904
|
action: rotatedContextEngineBinding ? "rotated" : "started"
|
|
3933
3905
|
});
|
|
3934
|
-
return
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3906
|
+
return {
|
|
3907
|
+
...startedBinding,
|
|
3908
|
+
modelProvider: response.modelProvider ?? requestModelProvider ?? startModelProvider ?? modelProvider,
|
|
3909
|
+
...startParams.ephemeral ? { liveThreadEphemeralPolicy: startParams.developerInstructions } : {},
|
|
3910
|
+
...!preserveExistingBinding ? { liveThreadConfigFingerprint: fingerprintCodexThreadConfig({
|
|
3911
|
+
...startParams,
|
|
3912
|
+
model: response.model ?? startParams.model ?? null,
|
|
3913
|
+
requestedModel: startParams.model ?? null,
|
|
3914
|
+
modelProvider: bindingModelProvider ?? null,
|
|
3915
|
+
requestedModelProvider: startParams.modelProvider ?? bindingModelProvider ?? null
|
|
3916
|
+
}, params.params.authProfileId, dynamicToolsFingerprint) } : {},
|
|
3917
|
+
lifecycle: {
|
|
3918
|
+
action: "started",
|
|
3919
|
+
...rotatedContextEngineBinding ? { rotatedContextEngineBinding: true } : {}
|
|
3920
|
+
}
|
|
3921
|
+
};
|
|
3948
3922
|
}
|
|
3949
3923
|
//#endregion
|
|
3950
3924
|
//#region extensions/codex/src/app-server/thread-lifecycle-warm.ts
|
|
@@ -4032,6 +4006,7 @@ async function tryReuseCodexLiveThread(options) {
|
|
|
4032
4006
|
try {
|
|
4033
4007
|
retainedThread.assertCurrent();
|
|
4034
4008
|
params.params.hostCapabilities.assertActive();
|
|
4009
|
+
params.assertCurrent?.();
|
|
4035
4010
|
} catch (cause) {
|
|
4036
4011
|
throw new AgentHarnessPreflightError("Codex warm thread ownership changed before this turn could run. No turn was sent; reconnect before continuing, or start a new conversation if the original thread was closed.", { cause });
|
|
4037
4012
|
}
|
|
@@ -4163,11 +4138,14 @@ async function tryReuseCodexLiveThread(options) {
|
|
|
4163
4138
|
//#endregion
|
|
4164
4139
|
//#region extensions/codex/src/app-server/thread-lifecycle-adoption.ts
|
|
4165
4140
|
/** Passive refusal must precede releasing or acquiring any native subscription. */
|
|
4166
|
-
async function assertAdoptedCodexThreadResumeAllowed(params, threadId, context) {
|
|
4141
|
+
async function assertAdoptedCodexThreadResumeAllowed(params, threadId, context, assertCurrent) {
|
|
4167
4142
|
const { thread } = await context.lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
|
|
4168
4143
|
threadId,
|
|
4169
4144
|
includeTurns: false
|
|
4170
|
-
}, {
|
|
4145
|
+
}, {
|
|
4146
|
+
signal: params.signal,
|
|
4147
|
+
assertCurrent
|
|
4148
|
+
}));
|
|
4171
4149
|
context.throwIfAborted();
|
|
4172
4150
|
assertCodexThreadAcceptsDirectInput(thread);
|
|
4173
4151
|
if (thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
|
|
@@ -4182,13 +4160,25 @@ async function withCodexThreadLifecycleBinding(params, run) {
|
|
|
4182
4160
|
agentId: params.agentId ?? params.params.agentId,
|
|
4183
4161
|
config: params.params.config
|
|
4184
4162
|
});
|
|
4185
|
-
const snapshot = await
|
|
4163
|
+
const { binding: snapshot, assertCurrent } = await resolveCodexSessionBinding({
|
|
4164
|
+
reclaimStale: true,
|
|
4165
|
+
bindingStore: params.bindingStore,
|
|
4166
|
+
identity,
|
|
4167
|
+
config: params.params.config,
|
|
4168
|
+
storePath: params.params.sessionTarget?.storePath,
|
|
4169
|
+
assertCurrent: () => {
|
|
4170
|
+
params.params.hostCapabilities.assertActive();
|
|
4171
|
+
params.assertCurrent?.();
|
|
4172
|
+
},
|
|
4173
|
+
signal: params.signal,
|
|
4174
|
+
assertBinding: params.params.expectedSessionRuntimeOwnership ? (binding) => assertCodexSessionRuntimeOwnership(binding, params.params.expectedSessionRuntimeOwnership) : void 0
|
|
4175
|
+
});
|
|
4186
4176
|
const runWithLease = () => params.bindingStore.withLease(identity, async () => {
|
|
4187
|
-
const binding =
|
|
4177
|
+
const binding = params.bindingStore.read(identity);
|
|
4178
|
+
assertCodexSessionRuntimeOwnership(binding, params.params.expectedSessionRuntimeOwnership);
|
|
4188
4179
|
if (binding?.threadId !== snapshot?.threadId || binding?.clientId !== snapshot?.clientId) throw new CodexThreadBindingConflictError(binding?.threadId ?? snapshot?.threadId ?? params.params.sessionId, "acquiring thread lifecycle ownership");
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
return await run(identity, binding);
|
|
4180
|
+
assertCurrent();
|
|
4181
|
+
return await run(identity, binding, assertCurrent);
|
|
4192
4182
|
});
|
|
4193
4183
|
return snapshot?.pendingResumeConfiguration ? await withExclusiveCodexAppServerThread({
|
|
4194
4184
|
bindingStore: params.bindingStore,
|
|
@@ -4206,32 +4196,27 @@ async function resumePendingCodexThread(params, context) {
|
|
|
4206
4196
|
})) throw new Error(`Cannot configure resumed Codex thread ${binding.threadId} under a transient or incompatible session policy. The thread is preserved; retry from its normal session or use /new for the current policy.`);
|
|
4207
4197
|
const prebuiltPluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
|
|
4208
4198
|
const clientId = resolveCodexAppServerClientInstanceId(params.client);
|
|
4209
|
-
const
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4199
|
+
const resumed = await resumeExistingCodexThread(params, {
|
|
4200
|
+
...context,
|
|
4201
|
+
prebuiltPluginThreadConfig,
|
|
4202
|
+
prepareResume: () => preparePendingCodexThreadResume(params, binding, context.dynamicToolsFingerprint),
|
|
4203
|
+
releaseRetainedThread: async (assertCurrent) => {
|
|
4204
|
+
const released = await context.releaseRetainedThread(binding.threadId, assertCurrent);
|
|
4205
|
+
assertCurrent();
|
|
4206
|
+
if (!released || binding.clientId && binding.clientId !== clientId) await releaseCodexConsumedLiveThread({
|
|
4207
|
+
client: params.client,
|
|
4208
|
+
abandonClient: params.abandonClient,
|
|
4209
|
+
lifecycleTiming,
|
|
4210
|
+
threadId: binding.threadId,
|
|
4211
|
+
assertCurrent
|
|
4212
|
+
});
|
|
4213
|
+
}
|
|
4219
4214
|
});
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
...context,
|
|
4223
|
-
prebuiltPluginThreadConfig,
|
|
4224
|
-
assertResumeConfiguration: configuration.assertConfigured,
|
|
4225
|
-
assertResumeOwnership: configuration.assertCurrent
|
|
4226
|
-
});
|
|
4227
|
-
if (!resumed) throw new Error(`Codex did not configure resumed thread ${binding.threadId}.`);
|
|
4228
|
-
return resumed;
|
|
4229
|
-
} finally {
|
|
4230
|
-
configuration.dispose();
|
|
4231
|
-
}
|
|
4215
|
+
if (!resumed) throw new Error(`Codex did not configure resumed thread ${binding.threadId}.`);
|
|
4216
|
+
return resumed;
|
|
4232
4217
|
}
|
|
4233
4218
|
/** Manual attachment is intent, never evidence that loaded native overrides took effect. */
|
|
4234
|
-
async function preparePendingCodexThreadResume(params, binding, dynamicToolsFingerprint
|
|
4219
|
+
async function preparePendingCodexThreadResume(params, binding, dynamicToolsFingerprint) {
|
|
4235
4220
|
const fail = (reason) => /* @__PURE__ */ new Error(`Cannot configure resumed Codex thread ${binding.threadId}: ${reason}. The thread is preserved; continue it in native Codex or use /new for the current OpenClaw tools.`);
|
|
4236
4221
|
const agentDir = resolveCodexThreadAgentDir(params);
|
|
4237
4222
|
const localHome = resolveCodexAppServerLocalHomeDir(params.appServer.start, agentDir);
|
|
@@ -4240,6 +4225,7 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
|
|
|
4240
4225
|
const assertClient = captureCodexAppServerClientLifetime(params.client, "native-process");
|
|
4241
4226
|
const assertCurrent = () => {
|
|
4242
4227
|
params.params.hostCapabilities.assertActive();
|
|
4228
|
+
params.assertCurrent?.();
|
|
4243
4229
|
params.signal?.throwIfAborted();
|
|
4244
4230
|
assertClient();
|
|
4245
4231
|
if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw new CodexAdoptedThreadActiveError();
|
|
@@ -4248,7 +4234,10 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
|
|
|
4248
4234
|
const { thread } = await params.client.request("thread/read", {
|
|
4249
4235
|
threadId: binding.threadId,
|
|
4250
4236
|
includeTurns: false
|
|
4251
|
-
}, {
|
|
4237
|
+
}, {
|
|
4238
|
+
signal: params.signal,
|
|
4239
|
+
assertCurrent
|
|
4240
|
+
});
|
|
4252
4241
|
assertCurrent();
|
|
4253
4242
|
const statusType = thread.status?.type;
|
|
4254
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");
|
|
@@ -4262,8 +4251,6 @@ async function preparePendingCodexThreadResume(params, binding, dynamicToolsFing
|
|
|
4262
4251
|
const recordedTools = metadata.dynamic_tools ?? [];
|
|
4263
4252
|
if (!Array.isArray(recordedTools) || codexDynamicToolsFingerprint(recordedTools) !== dynamicToolsFingerprint) throw fail("its immutable native tool catalog does not match the current OpenClaw tools");
|
|
4264
4253
|
assertCurrent();
|
|
4265
|
-
await releaseSubscription(assertCurrent);
|
|
4266
|
-
assertCurrent();
|
|
4267
4254
|
return {
|
|
4268
4255
|
assertConfigured: observation.assertConfigured,
|
|
4269
4256
|
assertCurrent,
|
|
@@ -4279,13 +4266,18 @@ async function prepareCodexThreadResume(params, binding, context) {
|
|
|
4279
4266
|
const assertClient = captureCodexAppServerClientLifetime(params.client, binding.connectionScope === "supervision" ? "connection" : "native-process");
|
|
4280
4267
|
const assertCurrent = () => {
|
|
4281
4268
|
params.params.hostCapabilities.assertActive();
|
|
4269
|
+
params.assertCurrent?.();
|
|
4282
4270
|
params.signal?.throwIfAborted();
|
|
4283
4271
|
assertClient();
|
|
4284
4272
|
if (isCodexAppServerLiveThreadClaimed(params.client, binding.threadId)) throw new CodexAdoptedThreadActiveError();
|
|
4285
4273
|
};
|
|
4286
4274
|
assertCurrent();
|
|
4287
|
-
|
|
4288
|
-
|
|
4275
|
+
let thread;
|
|
4276
|
+
try {
|
|
4277
|
+
thread = await assertAdoptedCodexThreadResumeAllowed(params, binding.threadId, context, assertCurrent);
|
|
4278
|
+
} finally {
|
|
4279
|
+
assertCurrent();
|
|
4280
|
+
}
|
|
4289
4281
|
assertCodexSupervisionThreadLineage(binding, thread);
|
|
4290
4282
|
return {
|
|
4291
4283
|
...observeCodexThreadConfiguration(params, thread, assertCurrent),
|
|
@@ -4309,6 +4301,10 @@ function observeCodexThreadConfiguration(params, thread, assertCurrent) {
|
|
|
4309
4301
|
//#region extensions/codex/src/app-server/thread-supervision.ts
|
|
4310
4302
|
async function materializePendingSupervisionBranch(params) {
|
|
4311
4303
|
let pending = params.binding.pendingSupervisionBranch;
|
|
4304
|
+
const requestOptions = {
|
|
4305
|
+
signal: params.signal,
|
|
4306
|
+
assertCurrent: params.throwIfAborted
|
|
4307
|
+
};
|
|
4312
4308
|
const connectionFingerprint = buildCodexAppServerConnectionFingerprint(params.appServer, params.attempt.agentDir);
|
|
4313
4309
|
if (!pending.connectionFingerprint || pending.connectionFingerprint !== connectionFingerprint) throw new Error("Codex supervision source connection changed before branch materialization");
|
|
4314
4310
|
pending = await recoverPendingSupervisionArtifacts(params, pending);
|
|
@@ -4316,7 +4312,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4316
4312
|
const sourceResponse = await params.lifecycleTiming.measure("supervision-source-read", () => params.client.request("thread/read", {
|
|
4317
4313
|
threadId: pending.sourceThreadId,
|
|
4318
4314
|
includeTurns: true
|
|
4319
|
-
},
|
|
4315
|
+
}, requestOptions));
|
|
4320
4316
|
params.throwIfAborted();
|
|
4321
4317
|
const sourceThread = sourceResponse.thread;
|
|
4322
4318
|
if (sourceThread.id !== pending.sourceThreadId) throw new Error(`Codex supervision source read returned ${sourceThread.id} for ${pending.sourceThreadId}`);
|
|
@@ -4342,7 +4338,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4342
4338
|
});
|
|
4343
4339
|
} catch (error) {
|
|
4344
4340
|
try {
|
|
4345
|
-
const current =
|
|
4341
|
+
const current = params.bindingStore.read(params.bindingIdentity);
|
|
4346
4342
|
if (matchesPendingSupervisionState(current, pending)) cleanupExpected = pending;
|
|
4347
4343
|
else if (matchesPendingSupervisionState(current, expected)) cleanupExpected = expected;
|
|
4348
4344
|
else throw new CodexThreadBindingConflictError(pending.sourceThreadId, "verifying supervised Codex cleanup tracking");
|
|
@@ -4359,7 +4355,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4359
4355
|
const probeParams = buildPendingSupervisionProbeForkParams(params, pending);
|
|
4360
4356
|
const rawProbeResponse = await params.lifecycleTiming.measure("supervision-model-probe-fork", async () => {
|
|
4361
4357
|
try {
|
|
4362
|
-
return await params.client.request("thread/fork", probeParams,
|
|
4358
|
+
return await params.client.request("thread/fork", probeParams, requestOptions);
|
|
4363
4359
|
} catch (error) {
|
|
4364
4360
|
if (!(error instanceof CodexAppServerRpcError)) throw new CodexAppServerUnsafeSubscriptionError("Codex model probe fork may have materialized without a response", { cause: error });
|
|
4365
4361
|
throw error;
|
|
@@ -4414,7 +4410,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4414
4410
|
});
|
|
4415
4411
|
const rawStartResponse = await params.lifecycleTiming.measure("supervision-thread-start", async () => {
|
|
4416
4412
|
try {
|
|
4417
|
-
return await params.client.request("thread/start", startParams,
|
|
4413
|
+
return await params.client.request("thread/start", startParams, requestOptions);
|
|
4418
4414
|
} catch (error) {
|
|
4419
4415
|
if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
|
|
4420
4416
|
throw new CodexAppServerUnsafeSubscriptionError("Canonical Codex branch may have started without a response", { cause: error });
|
|
@@ -4435,7 +4431,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4435
4431
|
});
|
|
4436
4432
|
if (params.restrictedToolSurface) await params.lifecycleTiming.measure("restricted-tool-surface-mcp-attestation", () => attestCodexRestrictedToolSurfaceMcpServersDisabled(params.client, finalThreadId, startParams.config, params.signal));
|
|
4437
4433
|
if (params.provisionalAppIds?.length) try {
|
|
4438
|
-
await params.lifecycleTiming.measure("plugin-app-attestation", () =>
|
|
4434
|
+
await params.lifecycleTiming.measure("plugin-app-attestation", () => checkCodexThreadAppAvailability({
|
|
4439
4435
|
client: params.client,
|
|
4440
4436
|
threadId: finalThreadId,
|
|
4441
4437
|
appIds: params.provisionalAppIds ?? [],
|
|
@@ -4457,7 +4453,7 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4457
4453
|
await params.lifecycleTiming.measure("supervision-history-inject", () => params.client.request("thread/inject_items", {
|
|
4458
4454
|
threadId: finalThreadId,
|
|
4459
4455
|
items: history.responseItems
|
|
4460
|
-
},
|
|
4456
|
+
}, requestOptions));
|
|
4461
4457
|
params.throwIfAborted();
|
|
4462
4458
|
}
|
|
4463
4459
|
const historyCoveredThrough = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4474,11 +4470,11 @@ async function materializePendingSupervisionBranch(params) {
|
|
|
4474
4470
|
modelProvider: bindingModelProvider,
|
|
4475
4471
|
historyCoveredThrough
|
|
4476
4472
|
}
|
|
4477
|
-
});
|
|
4473
|
+
}, params.throwIfAborted);
|
|
4478
4474
|
} catch (error) {
|
|
4479
4475
|
let current;
|
|
4480
4476
|
try {
|
|
4481
|
-
current =
|
|
4477
|
+
current = params.bindingStore.read(params.bindingIdentity);
|
|
4482
4478
|
} catch (readError) {
|
|
4483
4479
|
provisionalCleanupSafe = false;
|
|
4484
4480
|
throw new CodexAppServerUnsafeSubscriptionError(`Canonical Codex branch binding could not be verified: ${finalThreadId}`, { cause: new AggregateError([error, readError]) });
|
|
@@ -4669,11 +4665,16 @@ async function archiveSupervisionArtifact(client, threadId) {
|
|
|
4669
4665
|
}
|
|
4670
4666
|
//#endregion
|
|
4671
4667
|
//#region extensions/codex/src/app-server/thread-lifecycle-run.ts
|
|
4672
|
-
async function startOrResumeThread(
|
|
4673
|
-
const incognito = isIncognitoSessionKey(
|
|
4674
|
-
const clientId = resolveCodexAppServerClientInstanceId(
|
|
4675
|
-
return await withCodexThreadLifecycleBinding(
|
|
4676
|
-
|
|
4668
|
+
async function startOrResumeThread(input) {
|
|
4669
|
+
const incognito = isIncognitoSessionKey(input.params.sessionKey);
|
|
4670
|
+
const clientId = resolveCodexAppServerClientInstanceId(input.client);
|
|
4671
|
+
return await withCodexThreadLifecycleBinding(input, async (bindingIdentity, saved, assert) => {
|
|
4672
|
+
const params = {
|
|
4673
|
+
...input,
|
|
4674
|
+
assertCurrent: assert
|
|
4675
|
+
};
|
|
4676
|
+
const expectedOwnership = params.params.expectedSessionRuntimeOwnership;
|
|
4677
|
+
let binding = saved;
|
|
4677
4678
|
if (hasCodexNativeToolCatalog(binding)) {
|
|
4678
4679
|
const nativeCatalog = await loadCodexNativeToolCatalog({
|
|
4679
4680
|
client: params.client,
|
|
@@ -4682,7 +4683,7 @@ async function startOrResumeThread(params) {
|
|
|
4682
4683
|
agentDir: resolveCodexThreadAgentDir(params),
|
|
4683
4684
|
assertCurrent: () => {
|
|
4684
4685
|
params.signal?.throwIfAborted();
|
|
4685
|
-
|
|
4686
|
+
assert();
|
|
4686
4687
|
}
|
|
4687
4688
|
});
|
|
4688
4689
|
if (!isDeepStrictEqual(params.dynamicTools, nativeCatalog)) throw new Error("Canonical Codex declarations changed after tool preparation; retry the turn on its preserved native thread.");
|
|
@@ -4709,13 +4710,6 @@ async function startOrResumeThread(params) {
|
|
|
4709
4710
|
threadId,
|
|
4710
4711
|
assertCurrent
|
|
4711
4712
|
});
|
|
4712
|
-
if (!binding && bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
|
|
4713
|
-
if (!await lifecycleTiming.measure("reclaim-binding-generation", () => reclaimCurrentCodexSessionGeneration({
|
|
4714
|
-
bindingStore: params.bindingStore,
|
|
4715
|
-
identity: bindingIdentity,
|
|
4716
|
-
config: params.params.config
|
|
4717
|
-
}))) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
|
|
4718
|
-
}
|
|
4719
4713
|
if (binding?.pendingSupervisionBranch) {
|
|
4720
4714
|
await releaseRetainedThread(binding.threadId);
|
|
4721
4715
|
const pendingBinding = binding;
|
|
@@ -4749,7 +4743,10 @@ async function startOrResumeThread(params) {
|
|
|
4749
4743
|
environmentSelection: params.environmentSelection,
|
|
4750
4744
|
provisionalAppIds: pluginThreadConfig?.provisionalAppIds,
|
|
4751
4745
|
signal: params.signal,
|
|
4752
|
-
throwIfAborted
|
|
4746
|
+
throwIfAborted: () => {
|
|
4747
|
+
throwIfAborted();
|
|
4748
|
+
assert();
|
|
4749
|
+
},
|
|
4753
4750
|
lifecycleTiming,
|
|
4754
4751
|
normalizeBindingModelProvider,
|
|
4755
4752
|
bindingPatch: {
|
|
@@ -4781,11 +4778,11 @@ async function startOrResumeThread(params) {
|
|
|
4781
4778
|
const clearCurrentBinding = async (operation) => {
|
|
4782
4779
|
const current = binding;
|
|
4783
4780
|
if (!current?.threadId) return;
|
|
4784
|
-
assertCodexBindingMayBeReplaced(current, operation);
|
|
4781
|
+
assertCodexBindingMayBeReplaced(current, operation, expectedOwnership);
|
|
4785
4782
|
if (!await params.bindingStore.mutate(bindingIdentity, {
|
|
4786
4783
|
kind: "clear",
|
|
4787
4784
|
threadId: current.threadId
|
|
4788
|
-
})) throw new CodexThreadBindingConflictError(current.threadId, operation);
|
|
4785
|
+
}, assert)) throw new CodexThreadBindingConflictError(current.threadId, operation);
|
|
4789
4786
|
binding = void 0;
|
|
4790
4787
|
};
|
|
4791
4788
|
const resolveRequestContext = () => {
|
|
@@ -4879,14 +4876,14 @@ async function startOrResumeThread(params) {
|
|
|
4879
4876
|
const unknownProviderWebSearchSupport = params.nativeProviderWebSearchSupport === "unknown";
|
|
4880
4877
|
if (binding?.threadId && (params.configuredMcpOwnershipVersion === 1 && (binding.configuredMcpOwnershipVersion !== 1 || binding.dynamicToolsFingerprint === void 0 || binding.mcpServersFingerprint !== void 0 || binding.userMcpServersFingerprint !== void 0) || params.configuredMcpOwnershipVersion !== 1 && binding.configuredMcpOwnershipVersion === 1) && binding?.threadId) {
|
|
4881
4878
|
const predecessorBinding = binding;
|
|
4882
|
-
assertCodexBindingMayBeReplaced(predecessorBinding, "changing configured MCP ownership");
|
|
4879
|
+
assertCodexBindingMayBeReplaced(predecessorBinding, "changing configured MCP ownership", expectedOwnership);
|
|
4883
4880
|
embeddedAgentLog.debug("codex app-server configured MCP ownership changed; starting a new thread", { threadId: predecessorBinding.threadId });
|
|
4884
4881
|
replacementPredecessor = predecessorBinding;
|
|
4885
4882
|
binding = void 0;
|
|
4886
4883
|
preserveExistingBinding = false;
|
|
4887
4884
|
}
|
|
4888
4885
|
if (binding?.threadId && params.mcpServersFingerprintEvaluated === true && binding.mcpServersFingerprint !== params.mcpServersFingerprint) {
|
|
4889
|
-
assertCodexBindingMayBeReplaced(binding, "changing MCP configuration");
|
|
4886
|
+
assertCodexBindingMayBeReplaced(binding, "changing MCP configuration", expectedOwnership);
|
|
4890
4887
|
if (!ringZeroActive && (transientNativeToolRestriction || webSearchBindingChanged && (explicitTransientWebSearchRestriction || unknownProviderWebSearchSupport))) {
|
|
4891
4888
|
embeddedAgentLog.debug("codex app-server MCP config changed during transient restricted turn; starting transient thread", { threadId: binding.threadId });
|
|
4892
4889
|
preserveExistingBinding = true;
|
|
@@ -4898,7 +4895,7 @@ async function startOrResumeThread(params) {
|
|
|
4898
4895
|
}
|
|
4899
4896
|
const deferLegacyWebSearchRotationToTransientNativeSurface = params.nativeCodeModeEnabled === false && binding?.webSearchThreadConfigFingerprint === void 0 && !persistentWebSearchRestriction;
|
|
4900
4897
|
if (binding?.threadId && webSearchBindingChanged && !deferLegacyWebSearchRotationToTransientNativeSurface) {
|
|
4901
|
-
assertCodexBindingMayBeReplaced(binding, "changing web-search configuration");
|
|
4898
|
+
assertCodexBindingMayBeReplaced(binding, "changing web-search configuration", expectedOwnership);
|
|
4902
4899
|
if (!ringZeroActive && transientWebSearchRestriction) {
|
|
4903
4900
|
embeddedAgentLog.debug("codex app-server tool surface restricted for turn; starting transient thread", { threadId: binding.threadId });
|
|
4904
4901
|
preserveExistingBinding = true;
|
|
@@ -4909,13 +4906,13 @@ async function startOrResumeThread(params) {
|
|
|
4909
4906
|
binding = void 0;
|
|
4910
4907
|
}
|
|
4911
4908
|
if (binding?.threadId && transientNativeToolRestriction && !ringZeroActive) {
|
|
4912
|
-
assertCodexBindingMayBeReplaced(binding, "starting a native-tool-restricted turn");
|
|
4909
|
+
assertCodexBindingMayBeReplaced(binding, "starting a native-tool-restricted turn", expectedOwnership);
|
|
4913
4910
|
embeddedAgentLog.debug("codex app-server native tool surface disabled for turn; starting transient thread", { threadId: binding.threadId });
|
|
4914
4911
|
preserveExistingBinding = true;
|
|
4915
4912
|
binding = void 0;
|
|
4916
4913
|
}
|
|
4917
4914
|
if (binding?.threadId && transientDelegationRestriction) {
|
|
4918
|
-
assertCodexBindingMayBeReplaced(binding, "starting a delegation-restricted turn");
|
|
4915
|
+
assertCodexBindingMayBeReplaced(binding, "starting a delegation-restricted turn", expectedOwnership);
|
|
4919
4916
|
embeddedAgentLog.debug("codex app-server delegation restricted for turn; starting transient thread", { threadId: binding.threadId });
|
|
4920
4917
|
binding = void 0;
|
|
4921
4918
|
}
|
|
@@ -4973,7 +4970,7 @@ async function startOrResumeThread(params) {
|
|
|
4973
4970
|
}
|
|
4974
4971
|
if (binding?.threadId) {
|
|
4975
4972
|
if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint, legacyDynamicToolsFingerprint)) {
|
|
4976
|
-
assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog");
|
|
4973
|
+
assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog", expectedOwnership);
|
|
4977
4974
|
preserveExistingBinding = shouldStartTransientNoToolThread({
|
|
4978
4975
|
previous: binding.dynamicToolsFingerprint,
|
|
4979
4976
|
nextHasDynamicTools: params.dynamicTools.length > 0
|
|
@@ -4996,27 +4993,24 @@ async function startOrResumeThread(params) {
|
|
|
4996
4993
|
throwIfAborted();
|
|
4997
4994
|
await clearCurrentBinding(incognito ? "rotating an unavailable ephemeral thread binding" : "rotating a stale plugin app binding");
|
|
4998
4995
|
} else {
|
|
4999
|
-
const
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
if (resumed) return resumed;
|
|
5014
|
-
} finally {
|
|
5015
|
-
configuration.dispose();
|
|
5016
|
-
}
|
|
4996
|
+
const resumeBinding = binding;
|
|
4997
|
+
const resumed = await resumeExistingCodexThread(params, {
|
|
4998
|
+
...requestContext,
|
|
4999
|
+
binding: resumeBinding,
|
|
5000
|
+
clearCurrentBinding,
|
|
5001
|
+
prebuiltFinalConfigPatch: warmReuse.prebuiltFinalConfigPatch,
|
|
5002
|
+
prebuiltPluginThreadConfig,
|
|
5003
|
+
buildLoadedPluginThreadConfig,
|
|
5004
|
+
prepareResume: () => prepareCodexThreadResume(params, resumeBinding, requestContext),
|
|
5005
|
+
releaseRetainedThread: async (assertCurrent) => {
|
|
5006
|
+
await releaseRetainedThread(resumeBinding.threadId, resumeBinding.clientId, assertCurrent);
|
|
5007
|
+
}
|
|
5008
|
+
});
|
|
5009
|
+
if (resumed) return resumed;
|
|
5017
5010
|
}
|
|
5018
5011
|
}
|
|
5019
5012
|
}
|
|
5013
|
+
assertCodexBindingMayBeReplaced(binding, "starting a fresh native thread", expectedOwnership);
|
|
5020
5014
|
if (initialBoundThreadId && !preserveExistingBinding && !replacementPredecessor) await releaseRetainedThread(initialBoundThreadId);
|
|
5021
5015
|
const started = await startFreshCodexThread(params, {
|
|
5022
5016
|
...requestContext,
|
|
@@ -5231,4 +5225,4 @@ function joinPresentSections(...sections) {
|
|
|
5231
5225
|
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
5232
5226
|
}
|
|
5233
5227
|
//#endregion
|
|
5234
|
-
export { resolveCodexNativeSkillIsolation as $, readCodexMcpToolConnectorId as A, refreshCodexPluginRuntimeState as At, emitCodexNativePreToolUseFailureDiagnostic as B, buildDeveloperInstructions as C,
|
|
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 };
|