@openclaw/codex 2026.8.1-beta.3 → 2026.9.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +3 -3
- package/dist/{attempt-client-cleanup-URjUlCHg.js → attempt-client-cleanup-bfsmcQ6m.js} +21 -2
- package/dist/{binding-connection-DAvZwp96.js → binding-connection-BMvPX73o.js} +2 -2
- package/dist/{bounded-turn-4BjrZEwW.js → bounded-turn-B7iBUcuP.js} +8 -8
- package/dist/{capabilities-CH3K57v4.js → capabilities-BRMh0aIq.js} +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-D0nZ3qtd.js → command-formatters-DEsIufkt.js} +2 -2
- package/dist/{command-handlers-DC86lgT4.js → command-handlers-D_-1_qRp.js} +43 -32
- package/dist/{command-rpc-xUIIonsO.js → command-rpc-CCeCkf_v.js} +4 -4
- package/dist/{compact-COqgBRny.js → compact-BglNFZrQ.js} +8 -8
- package/dist/{config-CpNeo5AE.js → config-giW8X0QA.js} +82 -28
- package/dist/doctor-contract-api.js +9 -8
- package/dist/{dynamic-tools-fJZhl4CE.js → dynamic-tools-Dnlfa--w.js} +108 -820
- package/dist/{effective-mcp-catalog-4YKn51aG.js → effective-mcp-catalog-CTeGrnfO.js} +2 -2
- package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
- package/dist/{event-projector-usage-CLwNEJqW.js → event-projector-usage-Bk1I90Bg.js} +3 -3
- package/dist/{harness-DoKQcF8n.js → harness-Csz0F-DK.js} +11 -11
- package/dist/harness.js +1 -1
- package/dist/index.js +130 -172
- package/dist/{isolated-completion-DPMtlH9r.js → isolated-completion-Cv6FqygM.js} +4 -4
- package/dist/{managed-binary-By4FZC6i.js → managed-binary-DFYK4DWq.js} +43 -7
- package/dist/media-understanding-provider.js +1 -1
- package/dist/{model-catalog-CmGoqVKB.js → model-catalog-i9rNBthX.js} +4 -4
- package/dist/{models-CZw1wClT.js → models-TS3HBU-q.js} +4 -3
- package/dist/{native-subagent-monitor-GGq3RnOo.js → native-subagent-monitor-4Mfq2HDs.js} +176 -19
- package/dist/{node-exec-server.runtime-Bsu1LdFZ.js → node-exec-server.runtime-BpWqJO1V.js} +2 -2
- package/dist/{plugin-app-cache-key-DMNQ8Zi8.js → plugin-app-cache-key-C1CAdfcP.js} +6 -3
- package/dist/{plugin-approval-roundtrip-C75Yiiwc.js → plugin-approval-roundtrip-bUm777tR.js} +1 -1
- package/dist/{plugin-marketplace-discovery-CSWDkMrP.js → plugin-marketplace-discovery-B9DvaAG-.js} +29 -38
- package/dist/{plugin-metadata-cache-BXH5NF-4.js → plugin-metadata-cache-CTCT3w5L.js} +162 -135
- package/dist/{protocol-validators-VAVyEnDp.js → protocol-validators-VeJxxJ0U.js} +25 -3
- package/dist/{rate-limits-BI1dMHDG.js → rate-limits-C5_D8Gmb.js} +1 -1
- package/dist/{request-DSK0W6YI.js → request-DXXGHko0.js} +2 -2
- package/dist/{run-attempt-BV3HzuCf.js → run-attempt-DYc0QCBF.js} +346 -267
- package/dist/{sandbox-guard-C1qEeZ5C.js → sandbox-guard-kuWTn9C5.js} +1 -1
- package/dist/{session-binding-BTrLf9Qm.js → session-binding-Bcynfd-_.js} +1 -1
- package/dist/{session-catalog-ezP_UcRM.js → session-catalog-DaLKVtpH.js} +17 -16
- package/dist/{session-cli-B1hKvfkI.js → session-cli-DMc4oS2w.js} +1 -1
- package/dist/session-permission-policy-BrNH1bjy.js +160 -0
- package/dist/{session-retirement-CE4iMiLh.js → session-retirement-CcNC3YSY.js} +3 -3
- package/dist/{session-upstream-marker-D_2npHlA.js → session-upstream-marker-BIkusb95.js} +1 -1
- package/dist/{settled-turn-finalizer-Dx1onIqg.js → settled-turn-finalizer-Dc3ApjU4.js} +4 -4
- package/dist/{shared-client-Dw-rzii0.js → shared-client-DKz23hHY.js} +1026 -248
- package/dist/{side-question-DbXkJZzg.js → side-question-DjA_jsNe.js} +65 -36
- package/dist/{thread-lifecycle-DKdrnTMX.js → thread-lifecycle-L7oEkTlq.js} +850 -35
- package/dist/{thread-ownership-i2NBwDUL.js → thread-ownership-DZeuKH1j.js} +2 -2
- package/dist/{thread-resume-CdJk2Ehf.js → thread-resume-BE9qNEW0.js} +3 -3
- package/dist/{transcript-mirror-BU0_LKAL.js → transcript-mirror-DsCMWBca.js} +91 -10
- package/dist/{upstream-session-fork-BDVJCLAD.js → upstream-session-fork-DlaHxSLC.js} +3 -3
- package/dist/{usage-9dKJCgcy.js → usage-ROIaW3wo.js} +3 -3
- package/dist/{web-search-provider.runtime-DCdx4DGu.js → web-search-provider.runtime-ClaNPV7N.js} +3 -3
- package/openclaw.plugin.json +18 -1
- package/package.json +8 -8
- package/dist/app-server-policy-bg5QPSVP.js +0 -25
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { _ as CODEX_PLUGINS_MARKETPLACE_NAME, g as resolveCodexPluginsPolicy, n as codexSandboxPolicyForTurn, v as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-
|
|
4
|
-
import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, d as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-
|
|
5
|
-
import { a as assertCodexThreadStartResponse, r as assertCodexThreadForkResponse } from "./protocol-validators-
|
|
6
|
-
import { o as defaultCodexAppInventoryCache, s as serializeCodexAppInventoryError, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-
|
|
1
|
+
import { _ as CODEX_PLUGINS_MARKETPLACE_NAME, b as assertCodexModelBackedReviewerEffectiveConfig, g as resolveCodexPluginsPolicy, n as codexSandboxPolicyForTurn, v as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME } from "./config-giW8X0QA.js";
|
|
2
|
+
import { G as CodexAppServerRpcError, J as consumeCodexAppServerLiveThread, L as isCodexAppServerConnectionClosedError, P as getCodexAppServerClientInstanceId, St as resolveCodexAppServerLocalHomeDir, U as resolveCodexAppServerClientInstanceId, _t as flattenCodexDynamicToolFunctions, c as isCodexAppServerStartSelectionChangedError, h as retainSharedCodexAppServerClientByInstanceId, vt as isJsonObject } from "./shared-client-DKz23hHY.js";
|
|
3
|
+
import { a as hashCodexAppServerBindingFingerprint, c as reclaimCurrentCodexSessionGeneration, d as sessionBindingIdentity, i as createCodexSessionGenerationSupersededError, n as assertCodexBindingMayBeReplaced, o as isCodexAppServerNativeAuthProfile, s as normalizeCodexAppServerBindingModelProvider } from "./session-binding-Bcynfd-_.js";
|
|
4
|
+
import { a as closeCodexStartupClientBestEffort, c as isCodexAppServerUnsafeSubscriptionError, d as unsubscribeCodexThreadBestEffort, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError } from "./attempt-client-cleanup-bfsmcQ6m.js";
|
|
5
|
+
import { a as assertCodexThreadStartResponse, r as assertCodexThreadForkResponse } from "./protocol-validators-VeJxxJ0U.js";
|
|
6
|
+
import { o as defaultCodexAppInventoryCache, s as serializeCodexAppInventoryError, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-C1CAdfcP.js";
|
|
7
7
|
import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
|
|
8
8
|
import { n as codexCatalogHomeId } from "./session-catalog-home-id-BNwAJ9D7.js";
|
|
9
|
-
import { t as resumeCodexAppServerThread } from "./thread-resume-
|
|
10
|
-
import { u as projectBoundedCodexThreadHistory } from "./transcript-mirror-
|
|
9
|
+
import { t as resumeCodexAppServerThread } from "./thread-resume-BE9qNEW0.js";
|
|
10
|
+
import { u as projectBoundedCodexThreadHistory } from "./transcript-mirror-DsCMWBca.js";
|
|
11
11
|
import { r as sanitizeInlineImageDataUrl, t as invalidInlineImageText } from "./image-payload-sanitizer-CnfoUPCE.js";
|
|
12
12
|
import { asOptionalRecord, isRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
13
|
import fs from "node:fs/promises";
|
|
14
14
|
import path from "node:path";
|
|
15
|
-
import {
|
|
15
|
+
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
16
|
+
import { addTimerTimeoutGraceMs, finiteSecondsToTimerSafeMilliseconds, parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
|
|
17
|
+
import { SKILL_WORKSHOP_TOOL_NAME, TRANSCRIPT_CREDENTIAL_SAFETY_PROMPT, buildDelegationGuidanceSection, buildHarnessVisibleReplyGuidance, buildSkillWorkshopPromptSection, embeddedAgentLog, formatErrorMessage, formatToolExecutionErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive, resolveMainSessionDelegationMode, resolveToolExecutionErrorKind } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
16
18
|
import * as crypto$1 from "node:crypto";
|
|
17
19
|
import crypto, { createHash } from "node:crypto";
|
|
18
20
|
import os from "node:os";
|
|
@@ -26,8 +28,8 @@ import { resolveRequiredHomeDir, resolveStateDir } from "openclaw/plugin-sdk/sta
|
|
|
26
28
|
import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
|
|
27
29
|
import { buildHostnameAllowlistPolicyFromSuffixAllowlist } from "openclaw/plugin-sdk/ssrf-policy";
|
|
28
30
|
import { buildCodexUserMcpServersThreadConfigPatchForRuntime } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
29
|
-
import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
30
|
-
import {
|
|
31
|
+
import { emitTrustedDiagnosticEvent, hasPendingInternalDiagnosticEvent, isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
32
|
+
import { registerRetainedNativeHookRelayForBundledRuntime } from "openclaw/plugin-sdk/native-hook-relay-runtime";
|
|
31
33
|
//#region extensions/codex/src/app-server/plugin-inventory.ts
|
|
32
34
|
/**
|
|
33
35
|
* Reads Codex plugin marketplace state and app inventory to decide which
|
|
@@ -457,12 +459,21 @@ function activationFailure(identity, reason, diagnostic, extraDiagnostics = [])
|
|
|
457
459
|
}
|
|
458
460
|
//#endregion
|
|
459
461
|
//#region extensions/codex/src/app-server/plugin-thread-app-admission.ts
|
|
462
|
+
function resolveCodexPluginThreadAppCacheKey(params) {
|
|
463
|
+
return params.threadId ? `${params.appCacheKey}:thread:${encodeURIComponent(params.threadId)}` : params.appCacheKey;
|
|
464
|
+
}
|
|
465
|
+
function createCodexPluginThreadAppInventoryRequest(params) {
|
|
466
|
+
return async (method, requestParams) => await params.request(method, (method === "app/installed" || method === "app/read") && params.threadId ? {
|
|
467
|
+
...requestParams,
|
|
468
|
+
threadId: params.threadId
|
|
469
|
+
} : requestParams);
|
|
470
|
+
}
|
|
460
471
|
async function refreshCodexPluginAppInventory(params, appCache, options = {}) {
|
|
461
472
|
if (!params.appCacheKey) return;
|
|
462
|
-
const request =
|
|
473
|
+
const request = createCodexPluginThreadAppInventoryRequest(params);
|
|
463
474
|
try {
|
|
464
475
|
return await appCache.refreshNow({
|
|
465
|
-
key: params
|
|
476
|
+
key: resolveCodexPluginThreadAppCacheKey(params),
|
|
466
477
|
request,
|
|
467
478
|
nowMs: params.nowMs,
|
|
468
479
|
forceRefetch: options.forceRefetch,
|
|
@@ -499,9 +510,9 @@ function normalizeCodexPluginOwnerName(name) {
|
|
|
499
510
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
500
511
|
}
|
|
501
512
|
async function readCodexThreadAdmissibleAccountApps(params, appCache) {
|
|
502
|
-
const request =
|
|
513
|
+
const request = createCodexPluginThreadAppInventoryRequest(params);
|
|
503
514
|
const cachedInventory = appCache.read({
|
|
504
|
-
key: params
|
|
515
|
+
key: resolveCodexPluginThreadAppCacheKey(params),
|
|
505
516
|
request,
|
|
506
517
|
nowMs: params.nowMs,
|
|
507
518
|
suppressRefresh: true
|
|
@@ -616,6 +627,11 @@ function buildCodexPluginThreadConfigTimeoutFallback(params) {
|
|
|
616
627
|
/** Builds the Codex apps config patch and policy context for a native thread. */
|
|
617
628
|
async function buildCodexPluginThreadConfig(params) {
|
|
618
629
|
const appCache = params.appCache ?? defaultCodexAppInventoryCache;
|
|
630
|
+
const threadAppCacheKey = resolveCodexPluginThreadAppCacheKey(params);
|
|
631
|
+
const threadRequest = (method, requestParams) => params.request(method, (method === "app/installed" || method === "app/read") && params.threadId && isJsonObject(requestParams) ? {
|
|
632
|
+
...requestParams,
|
|
633
|
+
threadId: params.threadId
|
|
634
|
+
} : requestParams);
|
|
619
635
|
let inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
|
|
620
636
|
pluginConfig: params.pluginConfig,
|
|
621
637
|
appCacheKey: params.appCacheKey
|
|
@@ -629,9 +645,9 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
629
645
|
let inventory = policy.pluginPolicies.length > 0 ? await readCodexPluginInventory({
|
|
630
646
|
pluginConfig: params.pluginConfig,
|
|
631
647
|
policy,
|
|
632
|
-
request:
|
|
648
|
+
request: threadRequest,
|
|
633
649
|
appCache,
|
|
634
|
-
appCacheKey:
|
|
650
|
+
appCacheKey: threadAppCacheKey,
|
|
635
651
|
configCwd: params.configCwd,
|
|
636
652
|
metadataCache: params.metadataCache,
|
|
637
653
|
nowMs: params.nowMs,
|
|
@@ -647,9 +663,9 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
647
663
|
inventory = await readCodexPluginInventory({
|
|
648
664
|
pluginConfig: params.pluginConfig,
|
|
649
665
|
policy,
|
|
650
|
-
request:
|
|
666
|
+
request: threadRequest,
|
|
651
667
|
appCache,
|
|
652
|
-
appCacheKey:
|
|
668
|
+
appCacheKey: threadAppCacheKey,
|
|
653
669
|
configCwd: params.configCwd,
|
|
654
670
|
metadataCache: params.metadataCache,
|
|
655
671
|
nowMs: params.nowMs
|
|
@@ -665,9 +681,9 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
665
681
|
if (!record.activationRequired) continue;
|
|
666
682
|
const activation = await ensureCodexPluginActivation({
|
|
667
683
|
identity: record.policy,
|
|
668
|
-
request:
|
|
684
|
+
request: threadRequest,
|
|
669
685
|
appCache,
|
|
670
|
-
appCacheKey:
|
|
686
|
+
appCacheKey: threadAppCacheKey,
|
|
671
687
|
configCwd: params.configCwd,
|
|
672
688
|
metadataCache: params.metadataCache,
|
|
673
689
|
deferAppInventoryRefresh: true,
|
|
@@ -691,9 +707,9 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
691
707
|
inventory = await readCodexPluginInventory({
|
|
692
708
|
pluginConfig: params.pluginConfig,
|
|
693
709
|
policy,
|
|
694
|
-
request:
|
|
710
|
+
request: threadRequest,
|
|
695
711
|
appCache,
|
|
696
|
-
appCacheKey:
|
|
712
|
+
appCacheKey: threadAppCacheKey,
|
|
697
713
|
configCwd: params.configCwd,
|
|
698
714
|
metadataCache: params.metadataCache,
|
|
699
715
|
nowMs: params.nowMs
|
|
@@ -712,9 +728,9 @@ async function buildCodexPluginThreadConfig(params) {
|
|
|
712
728
|
inventory = await readCodexPluginInventory({
|
|
713
729
|
pluginConfig: params.pluginConfig,
|
|
714
730
|
policy,
|
|
715
|
-
request:
|
|
731
|
+
request: threadRequest,
|
|
716
732
|
appCache,
|
|
717
|
-
appCacheKey:
|
|
733
|
+
appCacheKey: threadAppCacheKey,
|
|
718
734
|
configCwd: params.configCwd,
|
|
719
735
|
metadataCache: params.metadataCache,
|
|
720
736
|
nowMs: params.nowMs
|
|
@@ -2261,7 +2277,8 @@ function resolveCodexWebSearchPlan(params) {
|
|
|
2261
2277
|
const CODEX_CODE_MODE_THREAD_CONFIG = {
|
|
2262
2278
|
"features.code_mode": true,
|
|
2263
2279
|
"features.code_mode_only": false,
|
|
2264
|
-
"features.apply_patch_streaming_events": true
|
|
2280
|
+
"features.apply_patch_streaming_events": true,
|
|
2281
|
+
suppress_unstable_features_warning: true
|
|
2265
2282
|
};
|
|
2266
2283
|
const CODEX_GOAL_CONTINUATION_DISABLED_THREAD_CONFIG = { "features.goals": false };
|
|
2267
2284
|
const CODEX_NATIVE_UPDATE_PLAN_DISABLED_THREAD_CONFIG = { "tools.update_plan.enabled": false };
|
|
@@ -2958,6 +2975,805 @@ async function startFreshCodexThread(params, context) {
|
|
|
2958
2975
|
});
|
|
2959
2976
|
}
|
|
2960
2977
|
//#endregion
|
|
2978
|
+
//#region extensions/codex/src/app-server/dynamic-tool-response-state.ts
|
|
2979
|
+
/** Retains the host-owned app preview without adding it to Codex's response payload. */
|
|
2980
|
+
function withDynamicToolTranscriptDetails(response, details) {
|
|
2981
|
+
if (details === void 0) return response;
|
|
2982
|
+
Object.defineProperty(response, "transcriptDetails", {
|
|
2983
|
+
configurable: true,
|
|
2984
|
+
enumerable: false,
|
|
2985
|
+
value: details
|
|
2986
|
+
});
|
|
2987
|
+
return response;
|
|
2988
|
+
}
|
|
2989
|
+
function withDynamicToolTerminalResolution(response, terminalResolution) {
|
|
2990
|
+
if (terminalResolution) {
|
|
2991
|
+
Object.defineProperties(response, {
|
|
2992
|
+
terminalResolution: {
|
|
2993
|
+
configurable: true,
|
|
2994
|
+
enumerable: false,
|
|
2995
|
+
value: terminalResolution
|
|
2996
|
+
},
|
|
2997
|
+
executionStarted: {
|
|
2998
|
+
configurable: true,
|
|
2999
|
+
enumerable: false,
|
|
3000
|
+
value: terminalResolution.executionStarted
|
|
3001
|
+
},
|
|
3002
|
+
...terminalResolution.executedArguments ? { executedArguments: {
|
|
3003
|
+
configurable: true,
|
|
3004
|
+
enumerable: false,
|
|
3005
|
+
value: terminalResolution.executedArguments
|
|
3006
|
+
} } : {}
|
|
3007
|
+
});
|
|
3008
|
+
withDynamicToolSideEffectEvidence(response, terminalResolution.sideEffectEvidence);
|
|
3009
|
+
}
|
|
3010
|
+
return response;
|
|
3011
|
+
}
|
|
3012
|
+
function withDynamicToolExecutionState(response, state) {
|
|
3013
|
+
Object.defineProperties(response, {
|
|
3014
|
+
executedArguments: {
|
|
3015
|
+
configurable: true,
|
|
3016
|
+
enumerable: false,
|
|
3017
|
+
value: state.executedArguments
|
|
3018
|
+
},
|
|
3019
|
+
executionStarted: {
|
|
3020
|
+
configurable: true,
|
|
3021
|
+
enumerable: false,
|
|
3022
|
+
value: state.executionStarted
|
|
3023
|
+
}
|
|
3024
|
+
});
|
|
3025
|
+
return withDynamicToolSideEffectEvidence(response, state.sideEffectEvidence === true);
|
|
3026
|
+
}
|
|
3027
|
+
function withDynamicToolSideEffectEvidence(response, sideEffectEvidence) {
|
|
3028
|
+
if (!sideEffectEvidence) {
|
|
3029
|
+
delete response.sideEffectEvidence;
|
|
3030
|
+
return response;
|
|
3031
|
+
}
|
|
3032
|
+
Object.defineProperty(response, "sideEffectEvidence", {
|
|
3033
|
+
configurable: true,
|
|
3034
|
+
enumerable: false,
|
|
3035
|
+
value: true
|
|
3036
|
+
});
|
|
3037
|
+
return response;
|
|
3038
|
+
}
|
|
3039
|
+
function createFailedDynamicToolResponse(message, options) {
|
|
3040
|
+
const response = {
|
|
3041
|
+
contentItems: [{
|
|
3042
|
+
type: "inputText",
|
|
3043
|
+
text: message
|
|
3044
|
+
}],
|
|
3045
|
+
success: false
|
|
3046
|
+
};
|
|
3047
|
+
Object.defineProperties(response, {
|
|
3048
|
+
diagnosticTerminalReason: {
|
|
3049
|
+
configurable: true,
|
|
3050
|
+
enumerable: false,
|
|
3051
|
+
value: options?.terminalReason ?? "failed"
|
|
3052
|
+
},
|
|
3053
|
+
diagnosticTerminalType: {
|
|
3054
|
+
configurable: true,
|
|
3055
|
+
enumerable: false,
|
|
3056
|
+
value: "error"
|
|
3057
|
+
}
|
|
3058
|
+
});
|
|
3059
|
+
if (options?.executionStarted !== void 0) Object.defineProperty(response, "executionStarted", {
|
|
3060
|
+
configurable: true,
|
|
3061
|
+
enumerable: false,
|
|
3062
|
+
value: options.executionStarted
|
|
3063
|
+
});
|
|
3064
|
+
if (options?.executedArguments !== void 0) Object.defineProperty(response, "executedArguments", {
|
|
3065
|
+
configurable: true,
|
|
3066
|
+
enumerable: false,
|
|
3067
|
+
value: options.executedArguments
|
|
3068
|
+
});
|
|
3069
|
+
return withDynamicToolSideEffectEvidence(response, options?.sideEffectEvidence === true);
|
|
3070
|
+
}
|
|
3071
|
+
//#endregion
|
|
3072
|
+
//#region extensions/codex/src/app-server/tool-abort-terminal-reason.ts
|
|
3073
|
+
/** Leaf helper shared by native and dynamic tool diagnostics. */
|
|
3074
|
+
const CODEX_TIMEOUT_ABORT_REASONS = /* @__PURE__ */ new Set([
|
|
3075
|
+
"codex_startup_timeout",
|
|
3076
|
+
"turn_completion_idle_timeout",
|
|
3077
|
+
"turn_progress_idle_timeout",
|
|
3078
|
+
"turn_terminal_idle_timeout"
|
|
3079
|
+
]);
|
|
3080
|
+
/** Preserves timeout provenance when an enclosing run aborts an active tool. */
|
|
3081
|
+
function resolveCodexToolAbortTerminalReason(signal) {
|
|
3082
|
+
try {
|
|
3083
|
+
const reason = signal.reason;
|
|
3084
|
+
if (typeof reason === "string") {
|
|
3085
|
+
if (CODEX_TIMEOUT_ABORT_REASONS.has(reason)) return "timed_out";
|
|
3086
|
+
return reason === "client_closed" ? "failed" : "cancelled";
|
|
3087
|
+
}
|
|
3088
|
+
if (reason && typeof reason === "object") {
|
|
3089
|
+
const record = reason;
|
|
3090
|
+
if (record.name === "TimeoutError" || record.reason === "timeout") return "timed_out";
|
|
3091
|
+
}
|
|
3092
|
+
} catch {
|
|
3093
|
+
return "cancelled";
|
|
3094
|
+
}
|
|
3095
|
+
return "cancelled";
|
|
3096
|
+
}
|
|
3097
|
+
//#endregion
|
|
3098
|
+
//#region extensions/codex/src/app-server/dynamic-tool-execution.ts
|
|
3099
|
+
/**
|
|
3100
|
+
* Timeout, terminal-release, and diagnostic helpers for Codex dynamic tool
|
|
3101
|
+
* calls.
|
|
3102
|
+
*/
|
|
3103
|
+
/** Default timeout for Codex dynamic tool calls. */
|
|
3104
|
+
const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 9e4;
|
|
3105
|
+
/** Hard cap for per-call Codex dynamic tool timeout overrides. */
|
|
3106
|
+
const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
|
|
3107
|
+
const CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS = 3e4;
|
|
3108
|
+
const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
|
|
3109
|
+
const CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS = 3e4;
|
|
3110
|
+
const CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS = 3e4;
|
|
3111
|
+
/** Timeout for image-understanding style dynamic tool calls. */
|
|
3112
|
+
const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
|
|
3113
|
+
/** Timeout for message-delivery dynamic tool calls. */
|
|
3114
|
+
const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 6e5;
|
|
3115
|
+
/** Outer default for collector waits: full swarm budget plus completion grace. */
|
|
3116
|
+
const CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS = 63e4;
|
|
3117
|
+
const LOG_FIELD_MAX_LENGTH = 160;
|
|
3118
|
+
function normalizeLogField(value) {
|
|
3119
|
+
if (typeof value !== "string") return;
|
|
3120
|
+
const normalized = value.replaceAll(String.fromCharCode(27), " ").replaceAll("\r", " ").replaceAll("\n", " ").replaceAll(" ", " ").trim();
|
|
3121
|
+
if (!normalized) return;
|
|
3122
|
+
return normalized.length > LOG_FIELD_MAX_LENGTH ? `${truncateUtf16Safe(normalized, LOG_FIELD_MAX_LENGTH - 3)}...` : normalized;
|
|
3123
|
+
}
|
|
3124
|
+
function readNumericTimeoutMs(value) {
|
|
3125
|
+
if (typeof value === "number" && Number.isFinite(value)) return Math.max(0, Math.floor(value));
|
|
3126
|
+
if (typeof value === "string") {
|
|
3127
|
+
const parsed = parseStrictNonNegativeInteger(value);
|
|
3128
|
+
if (parsed !== void 0) return Math.max(0, Math.floor(parsed));
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
function formatDynamicToolTimeoutDetails(params) {
|
|
3132
|
+
const tool = normalizeLogField(params.call.tool) ?? "unknown";
|
|
3133
|
+
const baseMeta = {
|
|
3134
|
+
tool: params.call.tool,
|
|
3135
|
+
toolCallId: params.call.callId,
|
|
3136
|
+
threadId: params.call.threadId,
|
|
3137
|
+
turnId: params.call.turnId,
|
|
3138
|
+
timeoutMs: params.timeoutMs,
|
|
3139
|
+
timeoutKind: "codex_dynamic_tool_rpc"
|
|
3140
|
+
};
|
|
3141
|
+
if (tool !== "process" || !isJsonObject(params.call.arguments)) return {
|
|
3142
|
+
responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms while running tool ${tool}.`,
|
|
3143
|
+
consoleMessage: `codex dynamic tool timeout: tool=${tool} toolTimeoutMs=${params.timeoutMs}; per-tool-call watchdog, not session idle`,
|
|
3144
|
+
meta: baseMeta
|
|
3145
|
+
};
|
|
3146
|
+
const action = normalizeLogField(params.call.arguments.action);
|
|
3147
|
+
const sessionId = normalizeLogField(params.call.arguments.sessionId);
|
|
3148
|
+
const requestedTimeoutMs = readNumericTimeoutMs(params.call.arguments.timeout);
|
|
3149
|
+
const actionPart = action ? ` action=${action}` : "";
|
|
3150
|
+
const sessionPart = sessionId ? ` sessionId=${sessionId}` : "";
|
|
3151
|
+
const requestedPart = requestedTimeoutMs === void 0 ? "" : ` requestedWaitMs=${requestedTimeoutMs}`;
|
|
3152
|
+
const retryHint = action === "poll" ? "; repeated lines usually mean process-poll retry churn, not model progress" : "";
|
|
3153
|
+
const responseTarget = action || sessionId ? ` while waiting for process${actionPart}${sessionPart}` : " while waiting for the process tool";
|
|
3154
|
+
return {
|
|
3155
|
+
responseMessage: `OpenClaw dynamic tool call timed out after ${params.timeoutMs}ms${responseTarget}. This is a tool RPC timeout, not a session idle timeout.`,
|
|
3156
|
+
consoleMessage: `codex process tool timeout:${actionPart}${sessionPart} toolTimeoutMs=${params.timeoutMs}${requestedPart}; per-tool-call watchdog, not session idle${retryHint}`,
|
|
3157
|
+
meta: {
|
|
3158
|
+
...baseMeta,
|
|
3159
|
+
processAction: action,
|
|
3160
|
+
processSessionId: sessionId,
|
|
3161
|
+
processRequestedTimeoutMs: requestedTimeoutMs
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
/**
|
|
3166
|
+
* Runs a dynamic tool call with run-abort and per-call timeout handling,
|
|
3167
|
+
* returning a Codex protocol response instead of throwing.
|
|
3168
|
+
*/
|
|
3169
|
+
async function handleDynamicToolCallWithTimeout(params) {
|
|
3170
|
+
let didNotifyAgentToolResult = false;
|
|
3171
|
+
const conservativeRaceResponses = /* @__PURE__ */ new WeakSet();
|
|
3172
|
+
const finalizeTerminal = (response) => {
|
|
3173
|
+
const executionSnapshot = params.toolBridge.consumeToolExecutionSnapshot?.(params.call.callId);
|
|
3174
|
+
const ownerKey = params.toolBridge.sideEffectOwnerKeyForTool?.(params.call.tool);
|
|
3175
|
+
const observedExecutionStarted = executionSnapshot?.executionStarted ?? (conservativeRaceResponses.has(response) ? void 0 : response.executionStarted);
|
|
3176
|
+
const terminalResolution = params.observeToolTerminal?.({
|
|
3177
|
+
toolCallId: params.call.callId,
|
|
3178
|
+
toolName: params.call.tool,
|
|
3179
|
+
arguments: response.executedArguments ?? executionSnapshot?.executedArguments ?? params.call.arguments,
|
|
3180
|
+
...params.toolMeta ? { meta: params.toolMeta } : {},
|
|
3181
|
+
...ownerKey ? { ownerMutation: { ownerKey } } : {},
|
|
3182
|
+
...observedExecutionStarted !== void 0 ? { executionStarted: observedExecutionStarted } : {},
|
|
3183
|
+
outcome: response.success ? "success" : "failure",
|
|
3184
|
+
...!response.success ? { failure: { error: readDynamicToolResponseText(response) } } : {}
|
|
3185
|
+
});
|
|
3186
|
+
return withDynamicToolTerminalResolution(response, terminalResolution);
|
|
3187
|
+
};
|
|
3188
|
+
const createFailedAfterPossibleDispatch = (message, terminalReason) => {
|
|
3189
|
+
const response = createFailedDynamicToolResponse(message, {
|
|
3190
|
+
executionStarted: true,
|
|
3191
|
+
sideEffectEvidence: true,
|
|
3192
|
+
terminalReason
|
|
3193
|
+
});
|
|
3194
|
+
conservativeRaceResponses.add(response);
|
|
3195
|
+
return response;
|
|
3196
|
+
};
|
|
3197
|
+
const notifyAgentToolResult = (event) => {
|
|
3198
|
+
if (didNotifyAgentToolResult) return;
|
|
3199
|
+
didNotifyAgentToolResult = true;
|
|
3200
|
+
try {
|
|
3201
|
+
params.onAgentToolResult?.(event);
|
|
3202
|
+
} catch (error) {
|
|
3203
|
+
embeddedAgentLog.warn(`onAgentToolResult handler failed: tool=${params.call.tool} error=${String(error)}`);
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
const notifyFailedToolResult = (message, terminalReason = "failed") => {
|
|
3207
|
+
notifyAgentToolResult({
|
|
3208
|
+
toolName: params.call.tool,
|
|
3209
|
+
result: {
|
|
3210
|
+
content: [{
|
|
3211
|
+
type: "text",
|
|
3212
|
+
text: message
|
|
3213
|
+
}],
|
|
3214
|
+
details: {
|
|
3215
|
+
status: terminalReason,
|
|
3216
|
+
error: message
|
|
3217
|
+
}
|
|
3218
|
+
},
|
|
3219
|
+
isError: true
|
|
3220
|
+
});
|
|
3221
|
+
};
|
|
3222
|
+
if (params.signal.aborted) {
|
|
3223
|
+
const message = "OpenClaw dynamic tool call aborted before execution.";
|
|
3224
|
+
const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
|
|
3225
|
+
params.onFallbackSelected?.();
|
|
3226
|
+
notifyFailedToolResult(message, terminalReason);
|
|
3227
|
+
return finalizeTerminal(createFailedDynamicToolResponse(message, {
|
|
3228
|
+
executionStarted: false,
|
|
3229
|
+
terminalReason
|
|
3230
|
+
}));
|
|
3231
|
+
}
|
|
3232
|
+
const controller = new AbortController();
|
|
3233
|
+
let timeout;
|
|
3234
|
+
let timedOut = false;
|
|
3235
|
+
let resolveAbort;
|
|
3236
|
+
const abortFromRun = () => {
|
|
3237
|
+
const message = "OpenClaw dynamic tool call aborted.";
|
|
3238
|
+
const terminalReason = resolveCodexToolAbortTerminalReason(params.signal);
|
|
3239
|
+
params.onFallbackSelected?.();
|
|
3240
|
+
controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
|
|
3241
|
+
notifyFailedToolResult(message, terminalReason);
|
|
3242
|
+
resolveAbort?.(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
3243
|
+
};
|
|
3244
|
+
const abortPromise = new Promise((resolve) => {
|
|
3245
|
+
resolveAbort = resolve;
|
|
3246
|
+
});
|
|
3247
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
3248
|
+
const timeoutMs = clampDynamicToolTimeoutMs(params.timeoutMs);
|
|
3249
|
+
timeout = setTimeout(() => {
|
|
3250
|
+
timedOut = true;
|
|
3251
|
+
const timeoutDetails = formatDynamicToolTimeoutDetails({
|
|
3252
|
+
call: params.call,
|
|
3253
|
+
timeoutMs
|
|
3254
|
+
});
|
|
3255
|
+
params.onFallbackSelected?.();
|
|
3256
|
+
controller.abort(new Error(timeoutDetails.responseMessage));
|
|
3257
|
+
params.onTimeout?.();
|
|
3258
|
+
embeddedAgentLog.warn("codex dynamic tool call timed out", {
|
|
3259
|
+
...timeoutDetails.meta,
|
|
3260
|
+
consoleMessage: timeoutDetails.consoleMessage
|
|
3261
|
+
});
|
|
3262
|
+
notifyFailedToolResult(timeoutDetails.responseMessage, "timed_out");
|
|
3263
|
+
resolve(createFailedAfterPossibleDispatch(timeoutDetails.responseMessage, "timed_out"));
|
|
3264
|
+
}, timeoutMs);
|
|
3265
|
+
timeout.unref?.();
|
|
3266
|
+
});
|
|
3267
|
+
try {
|
|
3268
|
+
params.signal.addEventListener("abort", abortFromRun, { once: true });
|
|
3269
|
+
if (params.signal.aborted) abortFromRun();
|
|
3270
|
+
const response = await Promise.race([
|
|
3271
|
+
params.toolBridge.handleToolCall(params.call, {
|
|
3272
|
+
signal: controller.signal,
|
|
3273
|
+
onAgentToolResult: notifyAgentToolResult,
|
|
3274
|
+
toolCallOrdinal: params.toolCallOrdinal,
|
|
3275
|
+
retainExecutionSnapshot: true
|
|
3276
|
+
}),
|
|
3277
|
+
abortPromise,
|
|
3278
|
+
timeoutPromise
|
|
3279
|
+
]);
|
|
3280
|
+
if (!response.success && !didNotifyAgentToolResult) notifyFailedToolResult(readDynamicToolResponseText(response), response.diagnosticTerminalReason ?? "failed");
|
|
3281
|
+
return finalizeTerminal(response);
|
|
3282
|
+
} catch (error) {
|
|
3283
|
+
const terminalReason = params.signal.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : resolveToolExecutionErrorKind(error);
|
|
3284
|
+
const message = formatToolExecutionErrorMessage(error, "OpenClaw dynamic tool call failed.");
|
|
3285
|
+
notifyFailedToolResult(message, terminalReason);
|
|
3286
|
+
return finalizeTerminal(createFailedAfterPossibleDispatch(message, terminalReason));
|
|
3287
|
+
} finally {
|
|
3288
|
+
if (timeout) clearTimeout(timeout);
|
|
3289
|
+
params.signal.removeEventListener("abort", abortFromRun);
|
|
3290
|
+
resolveAbort = void 0;
|
|
3291
|
+
if (!timedOut && !controller.signal.aborted) controller.abort(/* @__PURE__ */ new Error("OpenClaw dynamic tool call finished."));
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
function readDynamicToolResponseText(response) {
|
|
3295
|
+
return response.contentItems.flatMap((item) => item.type === "inputText" && typeof item.text === "string" ? [item.text] : []).join("\n").trim() || "OpenClaw dynamic tool call failed.";
|
|
3296
|
+
}
|
|
3297
|
+
/** Strips OpenClaw-only metadata before sending a dynamic tool response to Codex. */
|
|
3298
|
+
function toCodexDynamicToolProtocolResponse(response) {
|
|
3299
|
+
return {
|
|
3300
|
+
contentItems: response.contentItems,
|
|
3301
|
+
success: response.success
|
|
3302
|
+
};
|
|
3303
|
+
}
|
|
3304
|
+
/** Adds async-started progress details when a tool result continues out of band. */
|
|
3305
|
+
function toCodexDynamicToolProgressResponse(response, protocolResponse) {
|
|
3306
|
+
const transcriptDetails = isJsonObject(response.transcriptDetails) ? response.transcriptDetails : void 0;
|
|
3307
|
+
const mcpAppPreview = isJsonObject(transcriptDetails?.mcpAppPreview) ? transcriptDetails.mcpAppPreview : void 0;
|
|
3308
|
+
const progressDetails = mcpAppPreview ? { mcpAppPreview } : void 0;
|
|
3309
|
+
if (response.asyncStarted !== true && progressDetails === void 0) return protocolResponse;
|
|
3310
|
+
return {
|
|
3311
|
+
...protocolResponse,
|
|
3312
|
+
...progressDetails ? { details: progressDetails } : {},
|
|
3313
|
+
...response.asyncStarted === true ? { details: {
|
|
3314
|
+
...progressDetails,
|
|
3315
|
+
async: true,
|
|
3316
|
+
status: "started"
|
|
3317
|
+
} } : {}
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
/** Decides whether a terminal dynamic tool response can release the Codex turn. */
|
|
3321
|
+
function shouldReleaseTurnAfterTerminalDynamicTool(state) {
|
|
3322
|
+
return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
|
|
3323
|
+
}
|
|
3324
|
+
/** Returns true when a non-async result should block terminal-release shortcuts. */
|
|
3325
|
+
function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
|
|
3326
|
+
return response.asyncStarted !== true;
|
|
3327
|
+
}
|
|
3328
|
+
/** Resolves whether terminal diagnostic state should release, wait, or stay idle. */
|
|
3329
|
+
function resolveTerminalDynamicToolBatchAction(state) {
|
|
3330
|
+
if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
|
|
3331
|
+
if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
|
|
3332
|
+
if (state.hasPendingTerminalDynamicToolRelease) return "release-pending-terminal";
|
|
3333
|
+
return "idle";
|
|
3334
|
+
}
|
|
3335
|
+
/** Returns true for diagnostic events that terminate a dynamic tool call. */
|
|
3336
|
+
function isDynamicToolTerminalDiagnosticEvent(event) {
|
|
3337
|
+
return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
|
|
3338
|
+
}
|
|
3339
|
+
/** Matches terminal diagnostics to a specific dynamic tool call id/name. */
|
|
3340
|
+
function isMatchingDynamicToolTerminalDiagnostic(params) {
|
|
3341
|
+
if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
|
|
3342
|
+
if (params.runId !== void 0) return params.event.runId === params.runId;
|
|
3343
|
+
if (params.sessionId !== void 0) return params.event.sessionId === params.sessionId;
|
|
3344
|
+
if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
|
|
3345
|
+
return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
|
|
3346
|
+
}
|
|
3347
|
+
/** Checks pending diagnostics for a terminal event matching a tool call. */
|
|
3348
|
+
function hasPendingDynamicToolTerminalDiagnostic(params) {
|
|
3349
|
+
return hasPendingInternalDiagnosticEvent((event) => {
|
|
3350
|
+
if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
|
|
3351
|
+
return isMatchingDynamicToolTerminalDiagnostic({
|
|
3352
|
+
event,
|
|
3353
|
+
call: params.call,
|
|
3354
|
+
runId: params.runId,
|
|
3355
|
+
sessionId: params.sessionId,
|
|
3356
|
+
sessionKey: params.sessionKey
|
|
3357
|
+
});
|
|
3358
|
+
});
|
|
3359
|
+
}
|
|
3360
|
+
/** Resolves per-tool timeout, applying media/message defaults and hard caps. */
|
|
3361
|
+
function resolveDynamicToolCallTimeoutMs(params) {
|
|
3362
|
+
if (params.call.tool === "computer") return clampDynamicToolTimeoutMs(readComputerToolTimeoutMs(params.call.arguments));
|
|
3363
|
+
if (params.call.tool === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
|
|
3364
|
+
if (params.call.tool === "agents_wait") {
|
|
3365
|
+
const requestedMs = readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS;
|
|
3366
|
+
return Math.max(1, Math.min(63e4, Math.floor(requestedMs)));
|
|
3367
|
+
}
|
|
3368
|
+
return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
|
|
3369
|
+
}
|
|
3370
|
+
function readComputerToolTimeoutMs(value) {
|
|
3371
|
+
const args = isJsonObject(value) ? value : void 0;
|
|
3372
|
+
const action = typeof args?.action === "string" ? args.action : void 0;
|
|
3373
|
+
const gatewayTimeoutMs = readPositiveFiniteTimeoutMs(args?.timeoutMs) ?? CODEX_DYNAMIC_COMPUTER_GATEWAY_TIMEOUT_MS;
|
|
3374
|
+
const gatewayCallCount = action === "screenshot" || action === "wait" ? 3 : 4;
|
|
3375
|
+
return (action === "wait" || action === "hold_key" ? Math.max(0, Number(args?.duration) || 0) * 1e3 : 0) + gatewayCallCount * gatewayTimeoutMs + CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS;
|
|
3376
|
+
}
|
|
3377
|
+
function readDynamicToolCallTimeoutMs(value) {
|
|
3378
|
+
if (!isJsonObject(value)) return;
|
|
3379
|
+
const timeoutMs = readPositiveFiniteTimeoutMs(value.timeoutMs);
|
|
3380
|
+
if (timeoutMs !== void 0) return timeoutMs;
|
|
3381
|
+
const timeoutSecondsMs = readDynamicToolTimeoutSecondsAsMs(value.timeoutSeconds);
|
|
3382
|
+
return timeoutSecondsMs === void 0 ? void 0 : addTimerTimeoutGraceMs(timeoutSecondsMs, CODEX_DYNAMIC_TOOL_TIMEOUT_SECONDS_GRACE_MS);
|
|
3383
|
+
}
|
|
3384
|
+
function readConfiguredDynamicToolTimeoutMs(toolName, config) {
|
|
3385
|
+
if (toolName === "image_generate") {
|
|
3386
|
+
const imageModel = config?.agents?.defaults?.mediaModels?.image;
|
|
3387
|
+
if (!imageModel || typeof imageModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
|
|
3388
|
+
return readPositiveFiniteTimeoutMs(imageModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
|
|
3389
|
+
}
|
|
3390
|
+
if (toolName === "view_image") {
|
|
3391
|
+
const candidates = (config?.tools?.media?.models ?? []).filter((entry) => !entry.capabilities || entry.capabilities.includes("image"));
|
|
3392
|
+
const capabilityTimeoutMs = readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds);
|
|
3393
|
+
return Math.max(capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS, ...candidates.map((entry) => readTimeoutSecondsAsMs(entry.timeoutSeconds) ?? capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS));
|
|
3394
|
+
}
|
|
3395
|
+
if (toolName === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
|
|
3396
|
+
}
|
|
3397
|
+
function readTimeoutSecondsAsMs(value) {
|
|
3398
|
+
const seconds = readPositiveFiniteTimeoutMs(value);
|
|
3399
|
+
return seconds === void 0 ? void 0 : seconds * 1e3;
|
|
3400
|
+
}
|
|
3401
|
+
function readDynamicToolTimeoutSecondsAsMs(value) {
|
|
3402
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value <= 0) return;
|
|
3403
|
+
return value * 1e3;
|
|
3404
|
+
}
|
|
3405
|
+
function readPositiveFiniteTimeoutMs(value) {
|
|
3406
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
|
|
3407
|
+
}
|
|
3408
|
+
function clampDynamicToolTimeoutMs(timeoutMs) {
|
|
3409
|
+
return Math.max(1, Math.min(CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS, Math.floor(timeoutMs)));
|
|
3410
|
+
}
|
|
3411
|
+
//#endregion
|
|
3412
|
+
//#region extensions/codex/src/app-server/native-hook-relay-state.ts
|
|
3413
|
+
const pending = /* @__PURE__ */ new Set();
|
|
3414
|
+
/** Owns delayed hook-relay cleanup across runtime scheduling and test teardown. */
|
|
3415
|
+
const nativeHookRelayUnregisterQueue = {
|
|
3416
|
+
add(entry) {
|
|
3417
|
+
pending.add(entry);
|
|
3418
|
+
},
|
|
3419
|
+
delete(entry) {
|
|
3420
|
+
return pending.delete(entry);
|
|
3421
|
+
},
|
|
3422
|
+
flush() {
|
|
3423
|
+
while (pending.size > 0) {
|
|
3424
|
+
const entry = pending.values().next().value;
|
|
3425
|
+
if (!entry) return;
|
|
3426
|
+
clearTimeout(entry.timeout);
|
|
3427
|
+
entry.unregister();
|
|
3428
|
+
}
|
|
3429
|
+
},
|
|
3430
|
+
clear() {
|
|
3431
|
+
for (const entry of pending) clearTimeout(entry.timeout);
|
|
3432
|
+
pending.clear();
|
|
3433
|
+
}
|
|
3434
|
+
};
|
|
3435
|
+
//#endregion
|
|
3436
|
+
//#region extensions/codex/src/app-server/native-hook-relay.ts
|
|
3437
|
+
/**
|
|
3438
|
+
* Bridges Codex native hook callbacks into OpenClaw's native hook relay so
|
|
3439
|
+
* app-server tool events can still run OpenClaw policy and diagnostics.
|
|
3440
|
+
*/
|
|
3441
|
+
/** Codex hook events that can be registered through OpenClaw's native relay. */
|
|
3442
|
+
const CODEX_NATIVE_HOOK_RELAY_EVENTS = [
|
|
3443
|
+
"pre_tool_use",
|
|
3444
|
+
"post_tool_use",
|
|
3445
|
+
"permission_request",
|
|
3446
|
+
"before_agent_finalize"
|
|
3447
|
+
];
|
|
3448
|
+
const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
|
|
3449
|
+
const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
|
|
3450
|
+
/** Extra relay lifetime after the expected turn budget, preventing late hook drops. */
|
|
3451
|
+
const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
|
|
3452
|
+
const CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS = 250;
|
|
3453
|
+
const CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS = 1e3;
|
|
3454
|
+
const CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC = 10;
|
|
3455
|
+
const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS = 1e4;
|
|
3456
|
+
const CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS = 5e3;
|
|
3457
|
+
const MAX_PENDING_DIRECT_CHILD_ADMISSIONS = 32;
|
|
3458
|
+
const nativeHookPolicyByClient = /* @__PURE__ */ new WeakMap();
|
|
3459
|
+
const CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID = {
|
|
3460
|
+
exec: [
|
|
3461
|
+
"Bash",
|
|
3462
|
+
"exec",
|
|
3463
|
+
"exec_command"
|
|
3464
|
+
],
|
|
3465
|
+
apply_patch: [
|
|
3466
|
+
"apply_patch",
|
|
3467
|
+
"Write",
|
|
3468
|
+
"Edit"
|
|
3469
|
+
],
|
|
3470
|
+
spawn_agent: ["spawn_agent", "Agent"]
|
|
3471
|
+
};
|
|
3472
|
+
/** Enterprise managed-only policy silently drops the session-layer hooks that enforce OpenClaw. */
|
|
3473
|
+
async function assertCodexNativeHookRelayAllowed(client, signal) {
|
|
3474
|
+
let attestation = nativeHookPolicyByClient.get(client);
|
|
3475
|
+
if (!attestation) {
|
|
3476
|
+
attestation = client.request("configRequirements/read", void 0, { signal }).then((response) => {
|
|
3477
|
+
if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid hook policy response");
|
|
3478
|
+
const requirements = response.requirements;
|
|
3479
|
+
if (requirements === null) return;
|
|
3480
|
+
if (!isJsonObject(requirements)) throw new Error("Codex configRequirements/read returned invalid hook policy requirements");
|
|
3481
|
+
const managedOnly = requirements.allowManagedHooksOnly;
|
|
3482
|
+
if (managedOnly !== void 0 && managedOnly !== null && typeof managedOnly !== "boolean") throw new Error("Codex configRequirements/read returned invalid managed-only hook policy");
|
|
3483
|
+
if (managedOnly === true) throw new Error("Codex managed-only hooks disable the OpenClaw native hook relay; refusing unenforced execution");
|
|
3484
|
+
});
|
|
3485
|
+
nativeHookPolicyByClient.set(client, attestation);
|
|
3486
|
+
attestation.catch(() => {
|
|
3487
|
+
if (nativeHookPolicyByClient.get(client) === attestation) nativeHookPolicyByClient.delete(client);
|
|
3488
|
+
});
|
|
3489
|
+
}
|
|
3490
|
+
await attestation;
|
|
3491
|
+
}
|
|
3492
|
+
/** Defers relay unregister so late native hook subprocesses can still resolve. */
|
|
3493
|
+
function scheduleCodexNativeHookRelayUnregister(params) {
|
|
3494
|
+
let pending;
|
|
3495
|
+
const unregister = () => {
|
|
3496
|
+
if (!pending) return;
|
|
3497
|
+
const current = pending;
|
|
3498
|
+
pending = void 0;
|
|
3499
|
+
if (!nativeHookRelayUnregisterQueue.delete(current)) return;
|
|
3500
|
+
params.relay.unregister();
|
|
3501
|
+
};
|
|
3502
|
+
const timeout = setTimeout(unregister, resolveCodexNativeHookRelayUnregisterGraceMs(params.hookTimeoutSec));
|
|
3503
|
+
pending = {
|
|
3504
|
+
timeout,
|
|
3505
|
+
unregister
|
|
3506
|
+
};
|
|
3507
|
+
nativeHookRelayUnregisterQueue.add(pending);
|
|
3508
|
+
timeout.unref();
|
|
3509
|
+
}
|
|
3510
|
+
/** Computes the delayed unregister window from Codex's hook timeout. */
|
|
3511
|
+
function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
|
|
3512
|
+
const hookTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 0;
|
|
3513
|
+
return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, addTimerTimeoutGraceMs(hookTimeoutMs, CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS) ?? 0);
|
|
3514
|
+
}
|
|
3515
|
+
/** Records a native pre-tool failure that Codex does not project as a tool item. */
|
|
3516
|
+
function emitCodexNativePreToolUseFailureDiagnostic(params) {
|
|
3517
|
+
emitTrustedDiagnosticEvent({
|
|
3518
|
+
type: "tool.execution.error",
|
|
3519
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
3520
|
+
sessionId: params.sessionId,
|
|
3521
|
+
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3522
|
+
runId: params.runId,
|
|
3523
|
+
toolName: params.failure.toolName,
|
|
3524
|
+
toolCallId: params.failure.toolCallId,
|
|
3525
|
+
durationMs: params.failure.durationMs,
|
|
3526
|
+
errorCategory: "before_tool_call",
|
|
3527
|
+
terminalReason: params.terminalReason ?? (params.signal?.aborted ? resolveCodexToolAbortTerminalReason(params.signal) : params.failure.disposition),
|
|
3528
|
+
...params.sourceTimestampMs !== void 0 ? { sourceTimestampMs: params.sourceTimestampMs } : {}
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3531
|
+
/** Registers an OpenClaw native hook relay for a Codex app-server turn. */
|
|
3532
|
+
function createCodexNativeHookRelay(params) {
|
|
3533
|
+
if (params.options?.enabled === false) return;
|
|
3534
|
+
const directChildClaims = /* @__PURE__ */ new Map();
|
|
3535
|
+
const pendingDirectChildAdmissions = /* @__PURE__ */ new Map();
|
|
3536
|
+
let foregroundClosed = false;
|
|
3537
|
+
let successfulYieldRetentionAuthorized = false;
|
|
3538
|
+
const assertClaim = (threadId, claim) => () => directChildClaims.get(threadId) === claim;
|
|
3539
|
+
const rejectPendingAdmissions = (reason) => {
|
|
3540
|
+
for (const pending of pendingDirectChildAdmissions.values()) pending.reject(new Error(reason));
|
|
3541
|
+
pendingDirectChildAdmissions.clear();
|
|
3542
|
+
};
|
|
3543
|
+
const relay = registerRetainedNativeHookRelayForBundledRuntime({
|
|
3544
|
+
provider: "codex",
|
|
3545
|
+
relayId: buildCodexNativeHookRelayId({
|
|
3546
|
+
agentId: params.agentId,
|
|
3547
|
+
sessionId: params.sessionId,
|
|
3548
|
+
sessionKey: params.sessionKey
|
|
3549
|
+
}),
|
|
3550
|
+
...params.generation ? { generation: params.generation } : {},
|
|
3551
|
+
...params.generationMismatchGraceMs ? { generationMismatchGraceMs: params.generationMismatchGraceMs } : {},
|
|
3552
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
3553
|
+
sessionId: params.sessionId,
|
|
3554
|
+
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3555
|
+
...params.config ? { config: params.config } : {},
|
|
3556
|
+
runId: params.runId,
|
|
3557
|
+
...params.channelId ? { channelId: params.channelId } : {},
|
|
3558
|
+
...params.requester ? { requester: params.requester } : {},
|
|
3559
|
+
...params.approvalContext ? { approvalContext: params.approvalContext } : {},
|
|
3560
|
+
allowedEvents: params.events,
|
|
3561
|
+
preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
|
|
3562
|
+
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
3563
|
+
explicitTtlMs: params.options?.ttlMs,
|
|
3564
|
+
attemptTimeoutMs: params.attemptTimeoutMs,
|
|
3565
|
+
startupTimeoutMs: params.startupTimeoutMs,
|
|
3566
|
+
turnStartTimeoutMs: params.turnStartTimeoutMs
|
|
3567
|
+
}),
|
|
3568
|
+
signal: params.signal,
|
|
3569
|
+
runBeforeToolCall: params.hostCapabilities.runBeforeToolCall,
|
|
3570
|
+
assertActive: params.hostCapabilities.assertActive,
|
|
3571
|
+
retention: {
|
|
3572
|
+
readClaim: readCodexNativeChildThreadId,
|
|
3573
|
+
shouldRetainAfterForegroundClose: () => successfulYieldRetentionAuthorized && directChildClaims.size > 0,
|
|
3574
|
+
allowPreToolUse: (childThreadId) => directChildClaims.has(childThreadId),
|
|
3575
|
+
awaitForegroundAdmission: (childThreadId) => {
|
|
3576
|
+
if (foregroundClosed) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission unavailable"));
|
|
3577
|
+
const existingClaim = directChildClaims.get(childThreadId);
|
|
3578
|
+
if (existingClaim) return Promise.resolve(assertClaim(childThreadId, existingClaim));
|
|
3579
|
+
const existingPending = pendingDirectChildAdmissions.get(childThreadId);
|
|
3580
|
+
if (existingPending) return existingPending.promise.then((claim) => assertClaim(childThreadId, claim));
|
|
3581
|
+
if (pendingDirectChildAdmissions.size >= MAX_PENDING_DIRECT_CHILD_ADMISSIONS) return Promise.reject(/* @__PURE__ */ new Error("native hook relay foreground admission capacity reached"));
|
|
3582
|
+
const { promise, resolve, reject } = createDeferred();
|
|
3583
|
+
pendingDirectChildAdmissions.set(childThreadId, {
|
|
3584
|
+
promise,
|
|
3585
|
+
resolve,
|
|
3586
|
+
reject
|
|
3587
|
+
});
|
|
3588
|
+
return promise.then((claim) => assertClaim(childThreadId, claim));
|
|
3589
|
+
},
|
|
3590
|
+
onDispose: () => {
|
|
3591
|
+
foregroundClosed = true;
|
|
3592
|
+
rejectPendingAdmissions("native hook relay registration closed");
|
|
3593
|
+
}
|
|
3594
|
+
},
|
|
3595
|
+
onPreToolUseFailure: params.onPreToolUseFailure,
|
|
3596
|
+
command: {
|
|
3597
|
+
nice: 10,
|
|
3598
|
+
timeoutMs: params.options?.gatewayTimeoutMs
|
|
3599
|
+
}
|
|
3600
|
+
});
|
|
3601
|
+
const unregister = () => {
|
|
3602
|
+
foregroundClosed = true;
|
|
3603
|
+
rejectPendingAdmissions("native hook relay foreground closed");
|
|
3604
|
+
relay.unregister();
|
|
3605
|
+
};
|
|
3606
|
+
return {
|
|
3607
|
+
...relay,
|
|
3608
|
+
unregister,
|
|
3609
|
+
authorizeRetentionAfterSuccessfulYield: () => {
|
|
3610
|
+
successfulYieldRetentionAuthorized = true;
|
|
3611
|
+
},
|
|
3612
|
+
hasClaimedDirectChild: () => directChildClaims.size > 0,
|
|
3613
|
+
rejectPendingDirectChild: (threadIdInput, reason) => {
|
|
3614
|
+
const threadId = threadIdInput.trim();
|
|
3615
|
+
const pending = threadId ? pendingDirectChildAdmissions.get(threadId) : void 0;
|
|
3616
|
+
if (!pending) return;
|
|
3617
|
+
pendingDirectChildAdmissions.delete(threadId);
|
|
3618
|
+
pending.reject(new Error(reason));
|
|
3619
|
+
},
|
|
3620
|
+
claimDirectChild: (threadIdInput) => {
|
|
3621
|
+
const threadId = threadIdInput.trim();
|
|
3622
|
+
if (!threadId) return () => void 0;
|
|
3623
|
+
if (directChildClaims.get(threadId)) return () => void 0;
|
|
3624
|
+
const claim = Symbol(threadId);
|
|
3625
|
+
directChildClaims.set(threadId, claim);
|
|
3626
|
+
const pending = pendingDirectChildAdmissions.get(threadId);
|
|
3627
|
+
pendingDirectChildAdmissions.delete(threadId);
|
|
3628
|
+
pending?.resolve(claim);
|
|
3629
|
+
let released = false;
|
|
3630
|
+
return () => {
|
|
3631
|
+
if (released) return;
|
|
3632
|
+
released = true;
|
|
3633
|
+
if (directChildClaims.get(threadId) !== claim) return;
|
|
3634
|
+
directChildClaims.delete(threadId);
|
|
3635
|
+
if (foregroundClosed && directChildClaims.size === 0) relay.unregister();
|
|
3636
|
+
};
|
|
3637
|
+
}
|
|
3638
|
+
};
|
|
3639
|
+
}
|
|
3640
|
+
function readCodexNativeChildThreadId(rawPayload) {
|
|
3641
|
+
if (!isJsonObject(rawPayload) || typeof rawPayload.agent_id !== "string") return;
|
|
3642
|
+
return rawPayload.agent_id.trim() || void 0;
|
|
3643
|
+
}
|
|
3644
|
+
/** Selects the native hook events Codex should install for the current approval mode. */
|
|
3645
|
+
function resolveCodexNativeHookRelayEvents(params) {
|
|
3646
|
+
if (params.configuredEvents?.length) return params.configuredEvents;
|
|
3647
|
+
return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
|
|
3648
|
+
}
|
|
3649
|
+
/** Derives the native hook relay TTL from the turn budget unless explicitly configured. */
|
|
3650
|
+
function resolveCodexNativeHookRelayTtlMs(params) {
|
|
3651
|
+
if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
|
|
3652
|
+
const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
|
|
3653
|
+
return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
|
|
3654
|
+
}
|
|
3655
|
+
/** Builds a stable relay id scoped to the agent and session identity. */
|
|
3656
|
+
function buildCodexNativeHookRelayId(params) {
|
|
3657
|
+
const hash = createHash("sha256");
|
|
3658
|
+
hash.update("openclaw:codex:native-hook-relay:v1");
|
|
3659
|
+
hash.update("\0");
|
|
3660
|
+
hash.update(params.agentId?.trim() || "");
|
|
3661
|
+
hash.update("\0");
|
|
3662
|
+
hash.update(params.sessionKey?.trim() || params.sessionId);
|
|
3663
|
+
return `codex-${hash.digest("hex").slice(0, 40)}`;
|
|
3664
|
+
}
|
|
3665
|
+
const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
|
|
3666
|
+
pre_tool_use: "PreToolUse",
|
|
3667
|
+
post_tool_use: "PostToolUse",
|
|
3668
|
+
permission_request: "PermissionRequest",
|
|
3669
|
+
before_agent_finalize: "Stop"
|
|
3670
|
+
};
|
|
3671
|
+
const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
|
|
3672
|
+
pre_tool_use: "pre_tool_use",
|
|
3673
|
+
post_tool_use: "post_tool_use",
|
|
3674
|
+
permission_request: "permission_request",
|
|
3675
|
+
before_agent_finalize: "stop"
|
|
3676
|
+
};
|
|
3677
|
+
const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
|
|
3678
|
+
/** Builds the Codex config overlay that installs trusted command hooks for relay events. */
|
|
3679
|
+
function buildCodexNativeHookRelayConfig(params) {
|
|
3680
|
+
const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
|
|
3681
|
+
const selectedEvents = new Set(events);
|
|
3682
|
+
const config = { "features.hooks": true };
|
|
3683
|
+
const hookState = {};
|
|
3684
|
+
for (const event of CODEX_NATIVE_HOOK_RELAY_EVENTS) {
|
|
3685
|
+
const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
|
|
3686
|
+
const selected = selectedEvents.has(event);
|
|
3687
|
+
const shouldRelay = params.relay.shouldRelayEvent(event);
|
|
3688
|
+
if (!selected || !shouldRelay) {
|
|
3689
|
+
if (selected || params.clearOmittedEvents) config[`hooks.${codexEvent}`] = [];
|
|
3690
|
+
if (params.clearOmittedEvents) for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = { enabled: false };
|
|
3691
|
+
continue;
|
|
3692
|
+
}
|
|
3693
|
+
const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
|
|
3694
|
+
const command = params.relay.commandForEvent(event, { timeoutMs: resolveCodexNativeHookRelayCommandTimeoutMs(timeout) });
|
|
3695
|
+
const matcher = buildCodexNativeToolMatcher(params.relay.toolMatcherForEvent(event));
|
|
3696
|
+
config[`hooks.${codexEvent}`] = [{
|
|
3697
|
+
...matcher ? { matcher } : {},
|
|
3698
|
+
hooks: [{
|
|
3699
|
+
type: "command",
|
|
3700
|
+
command,
|
|
3701
|
+
timeout,
|
|
3702
|
+
async: false,
|
|
3703
|
+
statusMessage: "OpenClaw native hook relay"
|
|
3704
|
+
}]
|
|
3705
|
+
}];
|
|
3706
|
+
const state = {
|
|
3707
|
+
enabled: true,
|
|
3708
|
+
trusted_hash: codexCommandHookTrustedHash({
|
|
3709
|
+
event,
|
|
3710
|
+
command,
|
|
3711
|
+
matcher,
|
|
3712
|
+
timeout,
|
|
3713
|
+
statusMessage: "OpenClaw native hook relay"
|
|
3714
|
+
})
|
|
3715
|
+
};
|
|
3716
|
+
for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
|
|
3717
|
+
}
|
|
3718
|
+
config["hooks.state"] = hookState;
|
|
3719
|
+
return config;
|
|
3720
|
+
}
|
|
3721
|
+
/** Builds a Codex config overlay that disables native hooks and clears hook arrays. */
|
|
3722
|
+
function buildCodexNativeHookRelayDisabledConfig() {
|
|
3723
|
+
return {
|
|
3724
|
+
"features.hooks": false,
|
|
3725
|
+
"hooks.PreToolUse": [],
|
|
3726
|
+
"hooks.PostToolUse": [],
|
|
3727
|
+
"hooks.PermissionRequest": [],
|
|
3728
|
+
"hooks.Stop": []
|
|
3729
|
+
};
|
|
3730
|
+
}
|
|
3731
|
+
function normalizeHookTimeoutSec(value) {
|
|
3732
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : CODEX_NATIVE_HOOK_RELAY_DEFAULT_TIMEOUT_SEC;
|
|
3733
|
+
}
|
|
3734
|
+
function resolveCodexNativeHookRelayCommandTimeoutMs(hookTimeoutSec) {
|
|
3735
|
+
const parentTimeoutMs = finiteSecondsToTimerSafeMilliseconds(normalizeHookTimeoutSec(hookTimeoutSec)) ?? 5e3;
|
|
3736
|
+
const parentMarginMs = Math.min(CODEX_NATIVE_HOOK_RELAY_COMMAND_MAX_PARENT_MARGIN_MS, Math.max(CODEX_NATIVE_HOOK_RELAY_COMMAND_MIN_PARENT_MARGIN_MS, Math.floor(parentTimeoutMs / 5)));
|
|
3737
|
+
return Math.max(1, parentTimeoutMs - parentMarginMs);
|
|
3738
|
+
}
|
|
3739
|
+
function buildCodexNativeToolMatcher(toolNames) {
|
|
3740
|
+
if (toolNames === void 0) return;
|
|
3741
|
+
if (toolNames.length === 0) throw new TypeError("Codex native hook matcher requires at least one tool name");
|
|
3742
|
+
const nativeNames = /* @__PURE__ */ new Set();
|
|
3743
|
+
let hasCustomToolName = false;
|
|
3744
|
+
for (const toolName of toolNames) {
|
|
3745
|
+
const canonicalToolName = toolName.trim();
|
|
3746
|
+
if (!canonicalToolName || canonicalToolName === "*") throw new TypeError("Codex native hook matcher requires canonical OpenClaw tool ids");
|
|
3747
|
+
const nativeAliases = CODEX_HOOK_MATCHER_NAMES_BY_TOOL_ID[canonicalToolName];
|
|
3748
|
+
if (!nativeAliases) hasCustomToolName = true;
|
|
3749
|
+
for (const nativeName of nativeAliases ?? [canonicalToolName]) nativeNames.add(nativeName);
|
|
3750
|
+
}
|
|
3751
|
+
const sortedNames = Array.from(nativeNames).toSorted();
|
|
3752
|
+
if (!hasCustomToolName && sortedNames.every((toolName) => /^[A-Za-z0-9_]+$/.test(toolName))) return sortedNames.join("|");
|
|
3753
|
+
return `(?i)^(?:${sortedNames.map((toolName) => toolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})$`;
|
|
3754
|
+
}
|
|
3755
|
+
function codexCommandHookTrustedHash(params) {
|
|
3756
|
+
const identity = {
|
|
3757
|
+
event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
|
|
3758
|
+
...params.matcher ? { matcher: params.matcher } : {},
|
|
3759
|
+
hooks: [{
|
|
3760
|
+
async: false,
|
|
3761
|
+
command: params.command,
|
|
3762
|
+
statusMessage: params.statusMessage,
|
|
3763
|
+
timeout: params.timeout,
|
|
3764
|
+
type: "command"
|
|
3765
|
+
}]
|
|
3766
|
+
};
|
|
3767
|
+
return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
|
|
3768
|
+
}
|
|
3769
|
+
function sortJsonValue(value) {
|
|
3770
|
+
if (!value || typeof value !== "object") return value;
|
|
3771
|
+
if (Array.isArray(value)) return value.map(sortJsonValue);
|
|
3772
|
+
const sorted = {};
|
|
3773
|
+
for (const [key, entry] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) sorted[key] = sortJsonValue(entry);
|
|
3774
|
+
return sorted;
|
|
3775
|
+
}
|
|
3776
|
+
//#endregion
|
|
2961
3777
|
//#region extensions/codex/src/app-server/profiler-flag.ts
|
|
2962
3778
|
const PROFILER_FLAGS = ["profiler", "codex.profiler"];
|
|
2963
3779
|
/** Checks the generic and Codex-specific profiler diagnostic flags. */
|
|
@@ -3056,6 +3872,13 @@ function createCodexThreadLifecycleTimingTracker(options = {}) {
|
|
|
3056
3872
|
//#endregion
|
|
3057
3873
|
//#region extensions/codex/src/app-server/thread-lifecycle-preflight.ts
|
|
3058
3874
|
async function prepareCodexThreadLifecyclePreflight(params) {
|
|
3875
|
+
await assertCodexModelBackedReviewerEffectiveConfig({
|
|
3876
|
+
client: params.client,
|
|
3877
|
+
approvalsReviewer: params.appServer.approvalsReviewer,
|
|
3878
|
+
cwd: params.cwd,
|
|
3879
|
+
signal: params.signal
|
|
3880
|
+
});
|
|
3881
|
+
if (params.nativeHookRelayRequired) await assertCodexNativeHookRelayAllowed(params.client, params.signal);
|
|
3059
3882
|
const lifecycleTiming = createCodexThreadLifecycleTimingTracker({
|
|
3060
3883
|
...params.timing,
|
|
3061
3884
|
enabled: params.timing?.enabled ?? isCodexAppServerProfilerEnabled(params.params.config)
|
|
@@ -4105,7 +4928,6 @@ function buildTurnCollaborationMode(params, options = {}) {
|
|
|
4105
4928
|
function buildTurnScopedCollaborationInstructions(params, options = {}) {
|
|
4106
4929
|
const contextInstructions = joinPresentSections(options.turnScopedDeveloperInstructions, options.memoryCollaborationInstructions, options.skillsCollaborationInstructions);
|
|
4107
4930
|
if (params.trigger === "cron") return joinPresentSections(buildCronCollaborationInstructions(), contextInstructions);
|
|
4108
|
-
if (params.trigger === "heartbeat") return joinPresentSections(buildHeartbeatCollaborationInstructions(), contextInstructions);
|
|
4109
4931
|
if (contextInstructions?.trim()) return joinPresentSections(buildDefaultCollaborationInstructions(), contextInstructions);
|
|
4110
4932
|
return null;
|
|
4111
4933
|
}
|
|
@@ -4132,15 +4954,8 @@ function buildCronCollaborationInstructions() {
|
|
|
4132
4954
|
"Keep output concise and automation-oriented. Prefer the final command result or a short failure summary over status narration."
|
|
4133
4955
|
].join("\n\n");
|
|
4134
4956
|
}
|
|
4135
|
-
function buildHeartbeatCollaborationInstructions() {
|
|
4136
|
-
return [
|
|
4137
|
-
"This is an OpenClaw heartbeat turn. Apply these instructions only to this heartbeat wake; ordinary chat turns should stay in Codex Default mode.",
|
|
4138
|
-
"When you are ready to end the heartbeat, prefer the structured `heartbeat_respond` tool so OpenClaw can record the wake outcome and notification decision. If `heartbeat_respond` is not already available and `tool_search` is available, search for `heartbeat_respond`, load it, then call it. Use `notify=false` when nothing should visibly interrupt the user.",
|
|
4139
|
-
GPT5_HEARTBEAT_PROMPT_OVERLAY
|
|
4140
|
-
].join("\n\n");
|
|
4141
|
-
}
|
|
4142
4957
|
function joinPresentSections(...sections) {
|
|
4143
4958
|
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
4144
4959
|
}
|
|
4145
4960
|
//#endregion
|
|
4146
|
-
export {
|
|
4961
|
+
export { isForcedPrivateQaCodexRuntime as $, attestCodexRestrictedToolSurfaceMcpServersDisabled as A, resolveCodexAppServerRequestModelSelection as B, toCodexDynamicToolProgressResponse as C, refreshCodexPluginRuntimeState as Ct, withDynamicToolExecutionState as D, resolveRecoverableCodexPluginConfigKeys as Dt, createFailedDynamicToolResponse as E, pluginReadParams as Et, resolveCodexWebSearchPlan as F, CODEX_MANAGED_THREAD_MAX_ENTRIES as G, resolveCodexBindingModelProviderFallback as H, buildDeveloperInstructions as I, areCodexDynamicToolFingerprintsCompatible as J, CODEX_MANAGED_THREAD_NAMESPACE as K, buildCodexProjectDocThreadConfig as L, buildCodexRuntimeThreadConfig as M, readCodexInheritedMcpServerNames as N, withDynamicToolTranscriptDetails as O, buildCodexNativeWebSearchThreadConfig as P, filterCodexDynamicToolsForDisabledNativeSurface as Q, CODEX_NATIVE_PERSONALITY_NONE as R, shouldReleaseTurnAfterTerminalDynamicTool as S, ensureCodexPluginActivation as St, resolveCodexToolAbortTerminalReason as T, isOpenAiCuratedMarketplaceName as Tt, resolveReasoningEffort as U, resolveCodexAppServerThreadModelSelection as V, readCodexSupportedReasoningEfforts as W, codexLegacyDynamicToolsFingerprint as X, codexDynamicToolsFingerprint as Y, filterCodexDynamicTools as Z, isDynamicToolTerminalDiagnosticEvent as _, buildCodexPluginThreadConfigTimeoutFallback as _t, isCodexAppServerProfilerEnabled as a, buildContextEngineBinding as at, resolveTerminalDynamicToolBatchAction as b, mergeCodexThreadConfigs as bt, buildCodexNativeHookRelayConfig as c, fitCodexProjectedContextForTurnStart as ct, emitCodexNativePreToolUseFailureDiagnostic as d, resolveCodexContextEngineProjectionMaxChars as dt, isMessageOnlyCodexSourceReply as et, resolveCodexNativeHookRelayEvents as f, resolveCodexContextEngineProjectionReserveTokens as ft, hasPendingDynamicToolTerminalDiagnostic as g, buildCodexPluginThreadConfigInputFingerprint as gt, handleDynamicToolCallWithTimeout as h, buildCodexPluginThreadConfig as ht, startOrResumeThread as i, resolveCodexDynamicToolsLoadingForRuntime as it, buildCodexRingZeroThreadConfigPatch as j, assertCodexManagedRequirementsDoNotOverrideToolPolicy as k, buildCodexNativeHookRelayDisabledConfig as l, neutralizeCodexExplicitMentionSigils as lt, scheduleCodexNativeHookRelayUnregister as m, buildCodexPluginAppsConfigPatchFromPolicyContext as mt, buildTurnStartParams as n, normalizeCodexDynamicToolName as nt, CODEX_NATIVE_HOOK_RELAY_EVENTS as o, isContextEngineBindingCompatible as ot, resolveCodexNativeHookRelayTtlMs as p, resolveCodexContinuityProjectionMaxChars as pt, createCodexManagedThreadStore as q, buildCodexUserInput as r, resolveCodexDynamicToolsLoading as rt, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as s, buildCodexContinuityCalibration as st, buildTurnCollaborationMode as t, isSystemAgentOnlyCodexDynamicToolAllowlist as tt, createCodexNativeHookRelay as u, projectContextEngineAssemblyForCodex as ut, isMatchingDynamicToolTerminalDiagnostic as v, buildDisabledAppsConfigPatch as vt, toCodexDynamicToolProtocolResponse as w, isOpenAiCuratedMarketplace as wt, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as x, shouldBuildCodexPluginThreadConfig as xt, resolveDynamicToolCallTimeoutMs as y, buildPluginAppPolicyContext as yt, resolveCodexAppServerModelProvider as z };
|