@openclaw/codex 2026.9.8 → 2026.10.1-beta.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/README.md +8 -0
- package/dist/.setup/{account-usage-runtime-G348lY1q.mjs → account-usage-runtime-DGqFpAud.mjs} +5 -5
- package/dist/.setup/app-server-policy-Bg4FZw1f.mjs +23 -0
- package/dist/.setup/{apply-Cqb-YoCS.mjs → apply-CXTudl9p.mjs} +48 -39
- package/dist/.setup/attempt-client-cleanup-BH0hW2xU.mjs +155 -0
- package/dist/.setup/{attempt-workspace-context-BJ5Z_olH.mjs → attempt-workspace-context-BY0jprWJ.mjs} +11 -15
- package/dist/.setup/{auth-binding-BLWz7stm.mjs → auth-binding-BoMwpuPN.mjs} +17 -25
- package/dist/.setup/{auth-cache-key-Dnps4W4_.mjs → auth-cache-key-CGm0UJOr.mjs} +244 -82
- package/dist/.setup/{auth-profile-B0okYl2D.mjs → auth-profile-CgHQ8Vot.mjs} +2 -1
- package/dist/.setup/{auth-profile-selection-DFu9e167.mjs → auth-profile-selection-hr8ocLtz.mjs} +5 -7
- package/dist/.setup/{binding-connection-DTtN1KrX.mjs → binding-connection-C-08ez1w.mjs} +2 -2
- package/dist/.setup/{binding-connection.runtime-6TpgD1M6.mjs → binding-connection.runtime-Dn2p-fdy.mjs} +3 -3
- package/dist/.setup/{bounded-turn-isolation-B8K_ylqk.mjs → bounded-turn-isolation-DklXNk3k.mjs} +4 -4
- package/dist/.setup/{bounded-turn-BNunZPtz.mjs → bounded-turn-pGsfXcmH.mjs} +14 -13
- package/dist/.setup/{build-state-DIQ5O_-S.mjs → build-state-CqQnsg7T.mjs} +1 -1
- package/dist/.setup/{capabilities-B3WEZl4e.mjs → capabilities-kQntafj_.mjs} +1 -1
- package/dist/.setup/{client-qyUBJlGZ.mjs → client-C8lgBOoO.mjs} +438 -160
- package/dist/.setup/{client-catalog-response-DRvx_wCC.mjs → client-catalog-response-Bqp7WG51.mjs} +57 -25
- package/dist/.setup/command-authorization-AikPDtcc.mjs +15 -0
- package/dist/.setup/{command-dispatch-Btrs1D6f.mjs → command-dispatch-DhBbFIQ5.mjs} +3 -3
- package/dist/.setup/{command-formatters-R3ckE3Co.mjs → command-formatters-DV3DHhdr.mjs} +7 -5
- package/dist/.setup/{command-handlers-DvlCHJch.mjs → command-handlers-ztOOzm6O.mjs} +82 -144
- package/dist/.setup/{command-rpc-skzRq4wD.mjs → command-rpc-CuC5fPom.mjs} +23 -31
- package/dist/.setup/{compact-8ttks5U5.mjs → compact-tUb9AYfH.mjs} +117 -65
- package/dist/.setup/{plugin-metadata-cache-BRwtRct9.mjs → computer-use-BBN9y326.mjs} +65 -202
- package/dist/.setup/{config-DKhXquav.mjs → config-0Gxk3_eq.mjs} +5 -6
- package/dist/.setup/{config-options-CzyWLTJt.mjs → config-options-HG_Rr3W_.mjs} +13 -23
- package/dist/.setup/{config-parsing-b088LyhT.mjs → config-parsing-BQq-CHTF.mjs} +41 -4
- package/dist/.setup/{config-runtime-C0NbLms1.mjs → config-runtime-cUYrqu_a.mjs} +2 -2
- package/dist/.setup/{config-security-CE-FcGw9.mjs → config-security-KAPScztc.mjs} +20 -36
- package/dist/.setup/{context-engine-projection-PezSESth.mjs → context-engine-projection-CsgYSQhW.mjs} +11 -14
- package/dist/.setup/{conversation-binding-74LaGGH-.mjs → conversation-binding-B3MNMVzb.mjs} +36 -48
- package/dist/.setup/{conversation-binding-data-C746z5Pn.mjs → conversation-binding-data-DJ4ix-W5.mjs} +1 -1
- package/dist/.setup/{conversation-control-OrN6zuaY.mjs → conversation-control-CYsMlCuE.mjs} +19 -21
- package/dist/.setup/{cyber-failover-XV0nNRZu.mjs → cyber-failover-Bb1J6hS1.mjs} +1 -1
- package/dist/.setup/{cyber-failover-notice-RNpGpTyP.mjs → cyber-failover-notice-XR03ef31.mjs} +1 -1
- package/dist/.setup/doctor-start-options-DPW9JxIE.mjs +63 -0
- package/dist/.setup/dynamic-tool-build-C8xGEXmR.mjs +463 -0
- package/dist/.setup/{dynamic-tools-Db2sY5cZ.mjs → dynamic-tools-DyERJnR6.mjs} +238 -878
- package/dist/.setup/{effective-mcp-catalog-Bi6-SQ7i.mjs → effective-mcp-catalog-C26Mio5l.mjs} +83 -11
- package/dist/.setup/{elicitation-input-DPoK8F7w.mjs → elicitation-input-r9axtppm.mjs} +4 -2
- package/dist/.setup/{ephemeral-turn-DiCS1ijR.mjs → ephemeral-turn-D8VcDTNo.mjs} +2 -2
- package/dist/.setup/{event-projector-assistant-message-MV_1dj-3.mjs → event-projector-assistant-message-BN7CNUB5.mjs} +2 -2
- package/dist/.setup/{event-projector-values-DJSz8BTk.mjs → event-projector-values-DTqZHizf.mjs} +2 -12
- package/dist/.setup/{inference-dispatch-CMZtjQyz.mjs → inference-dispatch-B5UKEUyC.mjs} +12 -21
- package/dist/.setup/{inference-proxy-DhcXOgUE.mjs → inference-proxy-DUO5E2QQ.mjs} +6 -5
- package/dist/.setup/{isolated-completion-D80IXfQF.mjs → isolated-completion-C0jrcplS.mjs} +8 -8
- package/dist/.setup/{managed-binary-kiWRhNRE.mjs → managed-binary-C1VFoVPf.mjs} +31 -38
- package/dist/.setup/mcp-app-session-preparation-BxN0_CYe.mjs +223 -0
- package/dist/.setup/mcp-tool-metadata-j10HhfTC.mjs +43 -0
- package/dist/.setup/{model-catalog-DiC0Tkha.mjs → model-catalog-DZyNeDKG.mjs} +7 -7
- package/dist/.setup/{models-DfLmPV0k.mjs → models-DSseKSMg.mjs} +10 -7
- package/dist/.setup/{native-auth-CuG53tu4.mjs → native-auth-Cjb9y7IZ.mjs} +5 -6
- package/dist/.setup/{native-execution-policy-BxZJy5mP.mjs → native-execution-policy-ClzpdG3D.mjs} +1 -12
- package/dist/.setup/native-mcp-app-CqcPVmhH.mjs +310 -0
- package/dist/.setup/{native-subagent-monitor-BwkQXf9e.mjs → native-subagent-monitor-BUYOUp9X.mjs} +235 -318
- package/dist/.setup/{native-subagent-pending-assignments-DwkCzLvD.mjs → native-subagent-pending-assignments-BDqhOdJp.mjs} +0 -4
- package/dist/.setup/{native-task-assignments-DMQ0g3hu.mjs → native-task-assignments-C6KVqiN1.mjs} +9 -8
- package/dist/.setup/{node-cli-sessions-HC4W6FLI.mjs → node-cli-sessions-B5oNDkUS.mjs} +11 -17
- package/dist/.setup/{node-exec-server.runtime-BgBfWQqo.mjs → node-exec-server.runtime-0xSEjKYt.mjs} +2 -2
- package/dist/.setup/{plan-DPdMk1Oy.mjs → plan-BJ37d2Og.mjs} +67 -89
- package/dist/.setup/{plugin-activation-cNHRfaxU.mjs → plugin-activation-BcyBv8PG.mjs} +4 -4
- package/dist/.setup/{plugin-app-cache-key-BL9B5H0L.mjs → plugin-app-cache-key-BW8rd98k.mjs} +11 -15
- package/dist/.setup/plugin-approval-roundtrip-CuahdPLC.mjs +109 -0
- package/dist/.setup/{plugin-inventory-Cky2XJUw.mjs → plugin-inventory-Bf0_piTw.mjs} +29 -51
- package/dist/.setup/{plugin-marketplace-discovery-D_dV9FXa.mjs → plugin-marketplace-discovery-SQPhSuic.mjs} +2 -16
- package/dist/.setup/plugin-metadata-cache-DWnB7VMj.mjs +84 -0
- package/dist/.setup/plugin-thread-config-deadline-B8LGaZNW.mjs +124 -0
- package/dist/.setup/{provider-D6F_7p1I.mjs → provider-BnwHVD_z.mjs} +4 -4
- package/dist/.setup/provider-capabilities-D68Whix6.mjs +50 -0
- package/dist/.setup/{rate-limits-B7-X2TgG.mjs → rate-limits-CMPy24F5.mjs} +1 -5
- package/dist/.setup/{request-BZOfsSXW.mjs → request-jSbhc1sg.mjs} +189 -49
- package/dist/.setup/rpc-error-hmWM21RB.mjs +57 -0
- package/dist/.setup/{run-attempt-dYJhjZrp.mjs → run-attempt-BLDZeYLD.mjs} +553 -727
- package/dist/.setup/{run-attempt-lifecycle-C-6O3Exn.mjs → run-attempt-lifecycle-BuZgVbDA.mjs} +19 -3
- package/dist/.setup/{runtime-artifact-DDQ-HGXf.mjs → runtime-artifact-CUTOOnKw.mjs} +5 -6
- package/dist/.setup/{runtime-artifact-connection-D68qQn1m.mjs → runtime-artifact-connection-CADz3_BY.mjs} +5 -4
- package/dist/.setup/{sandbox-guard-DjCz2eOw.mjs → sandbox-guard-WqE8yPge.mjs} +3 -3
- package/dist/.setup/service-tier-normalization-Cei89SW6.mjs +15 -0
- package/dist/.setup/{session-binding-DGCYAfvD.mjs → session-binding-Ce7BqiPN.mjs} +92 -102
- package/dist/.setup/session-binding-meta-Lkm5Lpf4.mjs +15 -0
- package/dist/.setup/session-binding-record-BZB8RgcF.mjs +179 -0
- package/dist/.setup/session-binding-record-codec-z4ZpDn6E.mjs +216 -0
- package/dist/.setup/{session-binding-sidecars-jo6H8dFr.mjs → session-binding-sidecars-BrdV95Fg.mjs} +8 -2
- package/dist/.setup/{session-catalog-adoption-BU_pHWG7.mjs → session-catalog-adoption-CPIP4S_y.mjs} +34 -18
- package/dist/.setup/{session-catalog-archive-spHfihri.mjs → session-catalog-archive-DcgwvSbF.mjs} +24 -29
- package/dist/.setup/{session-catalog-events-BMCFMZw-.mjs → session-catalog-events-Bdjw9HEn.mjs} +5 -5
- package/dist/.setup/{session-catalog-index-DwJjnF5k.mjs → session-catalog-index-DufISKJ6.mjs} +361 -72
- package/dist/.setup/{session-catalog-index-order-BcQpHks3.mjs → session-catalog-index-order-nhyO0wdW.mjs} +1 -1
- package/dist/.setup/{session-catalog-limits-DDxOsQeC.mjs → session-catalog-limits-DEU36Qlo.mjs} +1 -1
- package/dist/.setup/{session-catalog-index-state-TeO7EyO-.mjs → session-catalog-list-request-tXephOB4.mjs} +180 -6
- package/dist/.setup/{session-catalog-native-projection-CuaFZuQE.mjs → session-catalog-native-projection-D6IiLtMb.mjs} +7 -6
- package/dist/.setup/{session-catalog-node-adoption-DgXvSGu0.mjs → session-catalog-node-adoption-7-WEQTB1.mjs} +12 -2
- package/dist/.setup/{session-catalog-node-continue-DjKXHBbi.mjs → session-catalog-node-continue-DLWBwAAO.mjs} +11 -15
- package/dist/.setup/{session-catalog-node-lookup-CtAXI5W5.mjs → session-catalog-node-lookup-Uufckwcm.mjs} +2 -2
- package/dist/.setup/{session-catalog-parsing-CPGaPYr-.mjs → session-catalog-parsing-B-qWJh2x.mjs} +70 -28
- package/dist/.setup/{session-catalog-projection-CGfzfP93.mjs → session-catalog-projection-8aHNwzWD.mjs} +6 -122
- package/dist/.setup/{session-catalog-provenance-DoAvktcj.mjs → session-catalog-provenance-CmsOE5mh.mjs} +6 -1
- package/dist/.setup/{session-cli-DlmBHYIe.mjs → session-cli-kH4vuGod.mjs} +1 -2
- package/dist/.setup/{session-history-D83lJWHG.mjs → session-history-BogBHKLk.mjs} +1 -1
- package/dist/.setup/{session-history-import-WhX-X33a.mjs → session-history-import-NWKPa4ZO.mjs} +4 -4
- package/dist/.setup/{session-history-read-Ov3StuL4.mjs → session-history-read-CNN8zwbD.mjs} +8 -19
- package/dist/.setup/{session-history.worker-MnPKncqP.mjs → session-history.worker-Cq_4DYgN.mjs} +3 -3
- package/dist/.setup/{session-initialization-6aveB9qb.mjs → session-initialization-D6dtFQkE.mjs} +2 -2
- package/dist/.setup/{session-permission-policy-Ci_fVX6y.mjs → session-permission-policy-BxIUJ0Zd.mjs} +8 -37
- package/dist/.setup/{session-retirement-LlYWBKTJ.mjs → session-retirement-Czbchv_O.mjs} +14 -15
- package/dist/.setup/{settled-turn-context-D4yj4rxf.mjs → settled-turn-context-BZsMjkIO.mjs} +13 -6
- package/dist/.setup/{settled-turn-finalizer-DW9W3gza.mjs → settled-turn-finalizer-DjZsIwbZ.mjs} +8 -8
- package/dist/.setup/{shared-client-CJCTeFpQ.mjs → shared-client-qhyYWbew.mjs} +291 -272
- package/dist/.setup/{provider-capabilities-DG5qbsUZ.mjs → shell-dynamic-tools-D3Brj3g9.mjs} +16 -55
- package/dist/.setup/{side-question-BLeGj7TQ.mjs → side-question-D3NJlgbl.mjs} +99 -91
- package/dist/.setup/{source-CJis_1EF.mjs → source-BYu0T780.mjs} +24 -40
- package/dist/.setup/{thread-lifecycle-_bAbjedG.mjs → thread-lifecycle-Cbz_7ySv.mjs} +262 -305
- package/dist/.setup/{thread-ownership-B6pPt21M.mjs → thread-ownership-DwuSrt3s.mjs} +10 -8
- package/dist/.setup/{thread-policy-gNPzzpVp.mjs → thread-policy-DoNxbhqt.mjs} +22 -21
- package/dist/.setup/{thread-requests-OWGOiDaV.mjs → thread-requests-CL1e8Wmx.mjs} +107 -98
- package/dist/.setup/{thread-resume-GOry0AYh.mjs → thread-resume-BT6NHMkM.mjs} +10 -18
- package/dist/.setup/{transcript-history-projection-DRSifI-1.mjs → transcript-history-projection-B9a7HwUV.mjs} +11 -16
- package/dist/.setup/{transcript-mirror-kxmCYsuF.mjs → transcript-mirror-BfLRARNL.mjs} +64 -67
- package/dist/.setup/{transport-stdio-Bdegpn2V.mjs → transport-stdio-a0HDa2Mj.mjs} +27 -8
- package/dist/.setup/{transport-websocket-BTBE-LD9.mjs → transport-websocket-zqJ0Cmtn.mjs} +3 -8
- package/dist/.setup/{attempt-client-cleanup-B-S7ngS_.mjs → turn-router-sS69wYnI.mjs} +75 -170
- package/dist/.setup/{upstream-session-fork-gkdRj2yH.mjs → upstream-session-fork-ChSld66u.mjs} +35 -46
- package/dist/.setup/{usage-CApUvLOV.mjs → usage-D8e8Xiqf.mjs} +4 -4
- package/dist/.setup/{usage-limit-error-wSMQkbpV.mjs → usage-limit-error-GbT-5NcW.mjs} +4 -4
- package/dist/.setup/{web-search-provider.runtime-UKgeiBUG.mjs → web-search-provider.runtime-dL2GD1Kl.mjs} +4 -20
- package/dist/.setup/websocket-data-XlRvt8Ys.mjs +6 -0
- package/dist/.setup/workspace-write-sandbox-probe-DmUHLrrl.mjs +118 -0
- package/dist/api.js +34 -54
- package/dist/catalog-page.worker.js +1 -1
- package/dist/cli-metadata.js +1 -1
- package/dist/doctor-contract-api.js +15 -27
- package/dist/harness.js +37 -22
- package/dist/index.js +2880 -276
- package/dist/media-understanding-provider.js +2 -2
- package/dist/migration-provider-api.js +1 -1
- package/dist/native-session-binding-api.js +2 -0
- package/dist/provider-discovery.js +1 -1
- package/dist/session-history-worker-runtime.js +33 -4
- package/dist/session-history.worker.js +1 -1
- package/openclaw.plugin.json +3 -3
- package/package.json +6 -6
- package/dist/.setup/config-utils-D0CXecki.mjs +0 -57
- package/dist/.setup/incognito-session-DWYapfwf.mjs +0 -2
- package/dist/.setup/managed-thread-store-BMqgThVL.mjs +0 -100
- package/dist/.setup/rpc-error-BlD2vuzn.mjs +0 -31
- package/dist/.setup/session-binding-meta-B7aEMU7g.mjs +0 -6
- package/dist/.setup/session-binding-record-Oe9L-CNY.mjs +0 -375
- package/dist/.setup/session-catalog-BFafIiF6.mjs +0 -2599
- package/dist/.setup/session-catalog-list-request-CvtxrYSe.mjs +0 -170
- package/dist/.setup/shared-client-lifecycle-7xgtlo15.mjs +0 -153
|
@@ -1,47 +1,42 @@
|
|
|
1
|
-
import { CODEX_NATIVE_TOOL_REQUIREMENTS } from "../native-tool-policy.js";
|
|
2
1
|
import { i as isJsonObject, r as flattenCodexDynamicToolFunctions, t as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE } from "./protocol-CANUwXJ3.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { o as
|
|
5
|
-
import { s as
|
|
6
|
-
import {
|
|
7
|
-
import "./
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { a as
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { _ as waitForPluginApprovalDecision, d as mapExecDecisionToOutcome, f as requestPluginApproval, g as truncateCodexApprovalDisplayText, h as stripDanglingCodexApprovalTerminalSequence, l as approvalRequestExplicitlyUnavailable, m as sanitizeCodexApprovalVisibleText, p as requestPluginApprovalOutcome, u as codexApprovalTimeoutText } from "./native-subagent-monitor-BwkQXf9e.mjs";
|
|
15
|
-
import { n as resolveCodexNativeExecutionPolicy, r as resolveCodexNodeExecToolOverrides } from "./native-execution-policy-BxZJy5mP.mjs";
|
|
16
|
-
import { a as CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME, c as createNodeExecAliasDynamicTool, d as isCodexDynamicToolExcluded, i as CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME, l as createSandboxExecProjection, o as createGatewayExecProjection, r as CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME, s as createGatewayProcessProjection, u as createSandboxProcessProjection } from "./provider-capabilities-DG5qbsUZ.mjs";
|
|
2
|
+
import { o as formatCodexDisplayText } from "./command-formatters-DV3DHhdr.mjs";
|
|
3
|
+
import { o as readItem } from "./event-projector-values-DTqZHizf.mjs";
|
|
4
|
+
import { s as codexAppIdentityKey } from "./plugin-app-cache-key-BW8rd98k.mjs";
|
|
5
|
+
import { r as invalidInlineImageText } from "./session-history-read-CNN8zwbD.mjs";
|
|
6
|
+
import { U as protectCodexAppServerLiveThread, _ as retainSharedCodexAppServerClientIfCurrent } from "./shared-client-qhyYWbew.mjs";
|
|
7
|
+
import { F as createFailedDynamicToolResponse, I as failedToolResult, P as resolveCodexToolAbortTerminalReason, l as CodexServerRequestResolvedError, w as createCodexElicitationResponse, x as readCodexTurnCompletedNotification } from "./client-C8lgBOoO.mjs";
|
|
8
|
+
import { t as codexWebSocketDataToBuffer } from "./websocket-data-XlRvt8Ys.mjs";
|
|
9
|
+
import { _ as itemStatus, a as isCodexNotificationForTurn, b as shouldClearTerminalPresentationForNativeItem, c as auditNativeToolName, g as itemName, l as auditNativeToolTerminalStatus, o as readCodexNotificationThreadId, s as readCodexNotificationTurnId, u as auditNativeToolUnfinishedStatus } from "./turn-router-sS69wYnI.mjs";
|
|
10
|
+
import { M as emitCodexNativePreToolUseFailureDiagnostic } from "./thread-requests-CL1e8Wmx.mjs";
|
|
11
|
+
import { a as requestPluginApprovalOutcome, c as truncateCodexApprovalDisplayText, i as requestPluginApproval, l as waitForPluginApprovalDecision, n as codexApprovalTimeoutText, o as sanitizeCodexApprovalVisibleText, r as mapExecDecisionToOutcome, s as stripDanglingCodexApprovalTerminalSequence, t as approvalRequestExplicitlyUnavailable } from "./plugin-approval-roundtrip-CuahdPLC.mjs";
|
|
12
|
+
import { d as isCodexPassThroughMediaSource, f as mapCodexAppServerLocalWorkspacePath, p as mapCodexAppServerRemoteWorkspacePath } from "./dynamic-tool-build-C8xGEXmR.mjs";
|
|
17
13
|
import { createRequire } from "node:module";
|
|
18
|
-
import { asNonArrayRecord, asOptionalRecord, isRecord, normalizeTrimmedStringList, readNonBlankString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
14
|
+
import { asNonArrayRecord, asOptionalRecord, filterStringEntries, isRecord, normalizeTrimmedStringList, readNonBlankString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
19
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
20
|
-
import { signalProcessTree, spawnTerminalPty } from "openclaw/plugin-sdk/process-runtime";
|
|
21
16
|
import { validateJsonSchemaValue } from "openclaw/plugin-sdk/json-schema-runtime";
|
|
22
17
|
import { asDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
|
18
|
+
import { signalProcessTree, spawnTerminalPty } from "openclaw/plugin-sdk/process-runtime";
|
|
23
19
|
import path, { posix } from "node:path";
|
|
24
20
|
import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
25
|
-
import { isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
26
|
-
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
21
|
+
import { createBoundedRemoteFileReader, isPathStrictlyInside, root } from "openclaw/plugin-sdk/file-access-runtime";
|
|
27
22
|
import { once } from "node:events";
|
|
28
23
|
import { spawn } from "node:child_process";
|
|
29
|
-
import {
|
|
24
|
+
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
25
|
+
import { DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS, estimateToolResultTextChars, resolveLiveToolResultMaxChars, safeParseJson, sliceToolResultTextToBudget, sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
30
26
|
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
31
27
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
32
|
-
import {
|
|
28
|
+
import { createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractMessagingToolSend, extractMessagingToolSendResult, finalizeAgentToolAvailability, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatToolExecutionErrorMessage, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, getPluginToolSideEffectOwnerKey, hasNativeHookRelayInvocation, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isDeliveredMessagingToolSendToCurrentSource, isMessagingTool, isReplaySafeToolCall, isToolResultError, isToolWrappedWithBeforeToolCallHook, projectPluginMessageDeliveryFact, projectRuntimeToolInputSchema, readEmbeddedMessageDeliveryFact, readToolOperatorHint, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, runAgentHarnessAfterToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
33
29
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
34
|
-
import {
|
|
35
|
-
import { applyEmbeddedAttemptToolsAllow, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractMessagingToolSend, extractMessagingToolSendResult, filterProviderNormalizableTools, finalizeAgentToolAvailability, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatToolExecutionErrorMessage, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, getPluginToolSideEffectOwnerKey, hasNativeHookRelayInvocation, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isDeliveredMessagingToolSendToCurrentSource, isHostScopedAgentToolActive, isMessagingTool, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, projectPluginMessageDeliveryFact, projectRuntimeToolInputSchema, readEmbeddedMessageDeliveryFact, readToolOperatorHint, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, runAgentHarnessAfterToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
30
|
+
import { sanitizeInlineImageDataUrl } from "openclaw/plugin-sdk/inline-image-data-url-runtime";
|
|
36
31
|
import { redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
37
32
|
import { formatErrorMessage as formatErrorMessage$2, redactSensitiveText as redactSensitiveText$1 } from "openclaw/plugin-sdk/security-runtime";
|
|
38
|
-
import { copyInternalToolResultState, createAgentHarnessToolExecutionBoundaryRegistry, extractMessagingToolSourceReplyPayload, getCoreTtsToolResultMediaUrls, normalizeAcceptedSessionSpawnResult, recordAgentHarnessToolResultTelemetry, runAgentHarnessToolInvocation } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
33
|
+
import { collectAgentHarnessMessagingMediaUrls, copyInternalToolResultState, createAgentHarnessToolExecutionBoundaryRegistry, extractMessagingToolSourceReplyPayload, getCoreTtsToolResultMediaUrls, mapAgentHarnessMessagingMediaValues, normalizeAcceptedSessionSpawnResult, recordAgentHarnessToolResultTelemetry, runAgentHarnessToolInvocation } from "openclaw/plugin-sdk/agent-harness-tool-runtime";
|
|
39
34
|
import { isIP } from "node:net";
|
|
40
|
-
import { formatMcpCodexApprovalRemedy, requiresMcpCodexToolApproval,
|
|
41
|
-
import { SANDBOX_COMMAND_MAX_BUFFER_BYTES, buildRemoteCommand,
|
|
35
|
+
import { formatMcpCodexApprovalRemedy, requiresMcpCodexToolApproval, resolveProjectedMcpCodexToolApprovalMode } from "openclaw/plugin-sdk/codex-mcp-projection";
|
|
36
|
+
import { SANDBOX_COMMAND_MAX_BUFFER_BYTES, buildRemoteCommand, prepareSandboxProcessCleanup, sanitizeEnvVars } from "openclaw/plugin-sdk/sandbox";
|
|
42
37
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
43
|
-
import { normalizeMediaReferenceForComparison, saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
44
38
|
import { getMediaDir } from "openclaw/plugin-sdk/media-runtime";
|
|
39
|
+
import { normalizeMediaReferenceForComparison, saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
45
40
|
import { normalizeOpenAIStrictCompatSchema } from "openclaw/plugin-sdk/provider-tools";
|
|
46
41
|
//#region extensions/codex/src/app-server/event-projector-native-tool-lifecycle.ts
|
|
47
42
|
function isMcpToolCallItemNotification(method, params) {
|
|
@@ -56,7 +51,6 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
56
51
|
this.options = options;
|
|
57
52
|
this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
|
|
58
53
|
this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
|
|
59
|
-
this.startedAtByItem = /* @__PURE__ */ new Map();
|
|
60
54
|
this.activeItems = /* @__PURE__ */ new Map();
|
|
61
55
|
this.webSearchCompletionByItem = /* @__PURE__ */ new Map();
|
|
62
56
|
this.completedItemIds = /* @__PURE__ */ new Set();
|
|
@@ -185,10 +179,9 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
185
179
|
const approvalFailureDisposition = this.approvalFailureDispositionByItem.get(toolCallId);
|
|
186
180
|
this.approvalFailureDispositionByItem.delete(toolCallId);
|
|
187
181
|
this.completedItemIds.add(toolCallId);
|
|
182
|
+
const startedAt = this.activeItems.get(toolCallId)?.startedAt;
|
|
188
183
|
this.activeItems.delete(toolCallId);
|
|
189
184
|
this.webSearchCompletionByItem.delete(toolCallId);
|
|
190
|
-
const startedAt = this.startedAtByItem.get(toolCallId);
|
|
191
|
-
this.startedAtByItem.delete(toolCallId);
|
|
192
185
|
const endedAt = options.sourceTimestampMs ?? Date.now();
|
|
193
186
|
const durationMs = options.itemDurationMs ?? (startedAt === void 0 ? 0 : Math.max(0, endedAt - startedAt));
|
|
194
187
|
if (preToolUseFailure) {
|
|
@@ -268,9 +261,9 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
268
261
|
}
|
|
269
262
|
recordStarted(toolCallId, toolName, unfinishedStatus, sourceTimestampMs, mcpToolCall, commandProcessId) {
|
|
270
263
|
if (this.activeItems.has(toolCallId)) return;
|
|
271
|
-
this.startedAtByItem.set(toolCallId, sourceTimestampMs ?? Date.now());
|
|
272
264
|
this.activeItems.set(toolCallId, {
|
|
273
265
|
toolName,
|
|
266
|
+
startedAt: sourceTimestampMs ?? Date.now(),
|
|
274
267
|
unfinishedStatus,
|
|
275
268
|
mcpToolCall,
|
|
276
269
|
commandProcessId
|
|
@@ -293,201 +286,42 @@ var CodexNativeToolLifecycleProjector = class {
|
|
|
293
286
|
}
|
|
294
287
|
};
|
|
295
288
|
//#endregion
|
|
296
|
-
//#region extensions/codex/src/app-server/remote-workspace-path.ts
|
|
297
|
-
/** Projects a gateway workspace path into the remote Codex execution workspace. */
|
|
298
|
-
function mapCodexAppServerRemoteWorkspacePath(params) {
|
|
299
|
-
if (!params.remoteWorkspaceRoot) return params.value;
|
|
300
|
-
const localRoot = normalizeWorkspaceMatchPath(params.localWorkspaceRoot);
|
|
301
|
-
const remoteRoot = normalizeWorkspaceMatchPath(params.remoteWorkspaceRoot);
|
|
302
|
-
const normalizedValue = normalizeWorkspaceMatchPath(params.value);
|
|
303
|
-
if (!localRoot || !remoteRoot) throw new Error("Codex remoteWorkspaceRoot requires non-empty workspace roots.");
|
|
304
|
-
if (normalizedValue === localRoot) return remoteRoot;
|
|
305
|
-
const prefix = `${localRoot}/`;
|
|
306
|
-
if (!normalizedValue.startsWith(prefix)) throw new Error(`Codex remoteWorkspaceRoot is configured but cwd ${params.value} is outside OpenClaw workspace root ${params.localWorkspaceRoot}; refusing to send a gateway-local cwd to the remote Codex app-server.`);
|
|
307
|
-
return joinRemoteWorkspacePath(remoteRoot, normalizedValue.slice(prefix.length));
|
|
308
|
-
}
|
|
309
|
-
/** Maps a remote workspace artifact back into the corresponding gateway workspace. */
|
|
310
|
-
function mapCodexAppServerLocalWorkspacePath(params) {
|
|
311
|
-
if (!params.remoteWorkspaceRoot) return params.value;
|
|
312
|
-
const localRoot = normalizeWorkspaceMatchPath(params.localWorkspaceRoot);
|
|
313
|
-
const remoteRoot = normalizeWorkspaceMatchPath(params.remoteWorkspaceRoot);
|
|
314
|
-
if (!localRoot || !remoteRoot) throw new Error("Codex remoteWorkspaceRoot requires non-empty workspace roots.");
|
|
315
|
-
const normalizedValue = normalizeWorkspaceMatchPath(params.value);
|
|
316
|
-
if (!normalizedValue || isCodexPassThroughMediaSource(normalizedValue)) return params.value;
|
|
317
|
-
const usesWindowsPaths = /^[a-z]:\//iu.test(remoteRoot) || remoteRoot.startsWith("//");
|
|
318
|
-
const matchValue = usesWindowsPaths ? normalizedValue.toLowerCase() : normalizedValue;
|
|
319
|
-
const matchRoot = usesWindowsPaths ? remoteRoot.toLowerCase() : remoteRoot;
|
|
320
|
-
if (matchValue === matchRoot) return params.localWorkspaceRoot;
|
|
321
|
-
const prefix = matchRoot.endsWith("/") ? matchRoot : `${matchRoot}/`;
|
|
322
|
-
const isRemoteWorkspacePath = matchValue.startsWith(prefix);
|
|
323
|
-
if (!isRemoteWorkspacePath && isAbsoluteWorkspacePath(normalizedValue)) throw new Error(`Codex remote workspace artifact ${params.value} is outside ${params.remoteWorkspaceRoot}.`);
|
|
324
|
-
const suffixSegments = (isRemoteWorkspacePath ? normalizedValue.slice(prefix.length) : normalizedValue).split("/");
|
|
325
|
-
if (suffixSegments.some((segment) => segment === "..")) throw new Error(`Codex remote workspace artifact ${params.value} must stay inside ${params.remoteWorkspaceRoot}.`);
|
|
326
|
-
return path.join(params.localWorkspaceRoot, ...suffixSegments.filter((segment) => segment !== "."));
|
|
327
|
-
}
|
|
328
|
-
function normalizeWorkspaceMatchPath(value) {
|
|
329
|
-
const normalized = value.replace(/\\/gu, "/");
|
|
330
|
-
if (/^[a-z]:\/$/iu.test(normalized)) return normalized;
|
|
331
|
-
return normalized.length > 1 ? normalized.replace(/[\\/]+$/u, "") : normalized;
|
|
332
|
-
}
|
|
333
|
-
/** Keeps remote URLs and opaque managed media references out of workspace path mapping. */
|
|
334
|
-
function isCodexPassThroughMediaSource(value) {
|
|
335
|
-
return /^(?:https?|mxc|buffer|media):\/\//iu.test(value) || /^data:/iu.test(value);
|
|
336
|
-
}
|
|
337
|
-
function isAbsoluteWorkspacePath(value) {
|
|
338
|
-
return value.startsWith("/") || /^[a-z]:\//iu.test(value) || /^[a-z][a-z0-9+.-]*:/iu.test(value);
|
|
339
|
-
}
|
|
340
|
-
function joinRemoteWorkspacePath(remoteRoot, suffix) {
|
|
341
|
-
return remoteRoot.endsWith("/") ? `${remoteRoot}${suffix}` : `${remoteRoot}/${suffix}`;
|
|
342
|
-
}
|
|
343
|
-
//#endregion
|
|
344
289
|
//#region extensions/codex/src/app-server/remote-workspace-media.ts
|
|
345
290
|
const REMOTE_WORKSPACE_MEDIA_TIMEOUT_MS = 6e4;
|
|
346
291
|
const REMOTE_WORKSPACE_MEDIA_MAX_BYTES = 67108864;
|
|
347
292
|
const REMOTE_WORKSPACE_MEDIA_MAX_ATTACHMENTS = 16;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
"const offset=Number(process.argv[3]);",
|
|
357
|
-
"const chunk=Number(process.argv[4]);",
|
|
358
|
-
"const workspace=process.argv[5];",
|
|
359
|
-
"if(!Number.isSafeInteger(max)||max<0)throw Error(\"invalid media byte limit\");",
|
|
360
|
-
"if(!Number.isSafeInteger(offset)||offset<0||!Number.isSafeInteger(chunk)||chunk<=0)throw Error(\"invalid media chunk\");",
|
|
361
|
-
"if(fs.lstatSync(file).isSymbolicLink())throw Error(\"symbolic links are not allowed\");",
|
|
362
|
-
"const noFollow=fs.constants.O_NOFOLLOW??0;",
|
|
363
|
-
"const fd=fs.openSync(file,fs.constants.O_RDONLY|noFollow);",
|
|
364
|
-
"try{",
|
|
365
|
-
"const before=fs.fstatSync(fd);",
|
|
366
|
-
"if(!before.isFile())throw Error(\"not a regular file\");",
|
|
367
|
-
"if(workspace){",
|
|
368
|
-
"const descriptor=process.platform===\"linux\"?fs.realpathSync(`/proc/self/fd/${fd}`):fs.realpathSync(file);",
|
|
369
|
-
"const relative=path.relative(fs.realpathSync(workspace),descriptor);",
|
|
370
|
-
"if(!relative||relative===\"..\"||relative.startsWith(`..${path.sep}`)||path.isAbsolute(relative))throw Error(\"file escapes remote workspace\");",
|
|
371
|
-
"const verified=fs.statSync(descriptor);",
|
|
372
|
-
"if(verified.dev!==before.dev||verified.ino!==before.ino)throw Error(\"file changed while being opened\");",
|
|
373
|
-
"}",
|
|
374
|
-
"if(before.size>max)throw Error(`file exceeds limit of ${max} bytes`);",
|
|
375
|
-
"if(offset>before.size)throw Error(\"file changed while being read\");",
|
|
376
|
-
"const expected=Math.min(chunk,before.size-offset);",
|
|
377
|
-
"const buffer=Buffer.allocUnsafe(expected);",
|
|
378
|
-
"let total=0;",
|
|
379
|
-
"while(total<buffer.length){",
|
|
380
|
-
"const count=fs.readSync(fd,buffer,total,buffer.length-total,offset+total);",
|
|
381
|
-
"if(count===0)break;total+=count;",
|
|
382
|
-
"}",
|
|
383
|
-
"if(total!==expected)throw Error(\"file changed while being read\");",
|
|
384
|
-
"const after=fs.fstatSync(fd);",
|
|
385
|
-
"const revision=stat=>[stat.dev,stat.ino,stat.size,stat.mtimeMs,stat.ctimeMs].join(\":\");",
|
|
386
|
-
"if(!after.isFile()||revision(after)!==revision(before))throw Error(\"file changed while being read\");",
|
|
387
|
-
"process.stdout.write(JSON.stringify({dataBase64:buffer.toString(\"base64\"),size:before.size,revision:revision(before)}));",
|
|
388
|
-
"}finally{fs.closeSync(fd)}",
|
|
389
|
-
"}catch(error){process.stderr.write(error instanceof Error?error.message:String(error));process.exitCode=1}"
|
|
390
|
-
].join("");
|
|
391
|
-
const MESSAGE_MEDIA_KEYS = [
|
|
392
|
-
"media",
|
|
393
|
-
"mediaUrl",
|
|
394
|
-
"media_url",
|
|
395
|
-
"path",
|
|
396
|
-
"filePath",
|
|
397
|
-
"fileUrl",
|
|
398
|
-
"imageUrl",
|
|
399
|
-
"image_url"
|
|
400
|
-
];
|
|
401
|
-
const MESSAGE_MEDIA_ARRAY_KEYS = [
|
|
402
|
-
"mediaUrls",
|
|
403
|
-
"media_urls",
|
|
404
|
-
"imageUrls",
|
|
405
|
-
"image_urls"
|
|
406
|
-
];
|
|
407
|
-
const ATTACHMENT_MEDIA_KEYS = [
|
|
408
|
-
"media",
|
|
409
|
-
"mediaUrl",
|
|
410
|
-
"path",
|
|
411
|
-
"filePath",
|
|
412
|
-
"fileUrl",
|
|
413
|
-
"url"
|
|
414
|
-
];
|
|
415
|
-
function collectCodexMessageMediaUrls(record) {
|
|
416
|
-
const urls = [];
|
|
417
|
-
mapMessageMediaValues(record, (value) => {
|
|
418
|
-
if (value.trim()) urls.push(value.trim());
|
|
419
|
-
return value;
|
|
420
|
-
});
|
|
421
|
-
return urls;
|
|
422
|
-
}
|
|
423
|
-
/** Reads actual remote bytes with a cap enforced by Codex before transport. */
|
|
424
|
-
async function readBoundedCodexRemoteWorkspaceFile(params) {
|
|
425
|
-
if (!Number.isSafeInteger(params.maxBytes) || params.maxBytes < 0) throw new Error("Codex remote workspace upload requires a valid media byte limit.");
|
|
426
|
-
params.signal?.throwIfAborted();
|
|
427
|
-
const chunks = [];
|
|
428
|
-
let offset = 0;
|
|
429
|
-
let expectedSize;
|
|
430
|
-
let expectedRevision;
|
|
431
|
-
const startedAt = performance.now();
|
|
432
|
-
do {
|
|
433
|
-
params.signal?.throwIfAborted();
|
|
434
|
-
const timeoutMs = params.timeoutMs === void 0 ? void 0 : Math.floor(params.timeoutMs - (performance.now() - startedAt));
|
|
435
|
-
if (timeoutMs !== void 0 && timeoutMs <= 0) throw new Error("Codex remote workspace file transfer timed out.");
|
|
436
|
-
let response;
|
|
437
|
-
try {
|
|
438
|
-
response = await params.client.request("command/exec", {
|
|
439
|
-
command: [
|
|
440
|
-
"node",
|
|
441
|
-
"-e",
|
|
442
|
-
CODEX_BOUNDED_REMOTE_FILE_READER,
|
|
443
|
-
"--",
|
|
444
|
-
params.path,
|
|
445
|
-
String(params.maxBytes),
|
|
446
|
-
String(offset),
|
|
447
|
-
String(CODEX_REMOTE_MEDIA_CHUNK_BYTES),
|
|
448
|
-
...params.workspaceRoot ? [params.workspaceRoot] : []
|
|
449
|
-
],
|
|
293
|
+
/** Adapts the current app-server connection without changing its Windows output cap. */
|
|
294
|
+
function createCodexRemoteWorkspaceFileReader(client, authority) {
|
|
295
|
+
const read = createBoundedRemoteFileReader({
|
|
296
|
+
outputBytesCap: 1048576,
|
|
297
|
+
assertCurrent: authority.assertCurrent,
|
|
298
|
+
execute: async (command, options) => {
|
|
299
|
+
const response = await client.request("command/exec", {
|
|
300
|
+
command,
|
|
450
301
|
env: {
|
|
451
302
|
NODE_OPTIONS: null,
|
|
452
303
|
NODE_PATH: null
|
|
453
304
|
},
|
|
454
|
-
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
305
|
+
...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
|
|
455
306
|
}, {
|
|
456
|
-
|
|
457
|
-
|
|
307
|
+
...options,
|
|
308
|
+
assertCurrent: authority.assertCurrent,
|
|
309
|
+
withCurrent: authority.withCurrent
|
|
310
|
+
}).catch((error) => {
|
|
311
|
+
if (error instanceof Error && /failed to spawn|executable.*not found|\bENOENT\b/iu.test(error.message)) throw new Error("Codex remote workspace file transfer requires Node.js on the remote app-server host.", { cause: error });
|
|
312
|
+
throw error;
|
|
458
313
|
});
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
throw error;
|
|
462
|
-
}
|
|
463
|
-
if (!response || response.exitCode !== 0) {
|
|
464
|
-
const detail = typeof response?.stderr === "string" ? response.stderr.trim() : "";
|
|
465
|
-
throw new Error(`Codex remote workspace artifact could not be read: ${params.path}${detail ? `: ${detail}` : ""}`);
|
|
314
|
+
if (!response || response.exitCode !== 0) throw new Error(`Codex remote workspace file read failed: ${response?.stderr ?? "no response"}`);
|
|
315
|
+
return response.stdout;
|
|
466
316
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
const chunk = payload;
|
|
476
|
-
if (typeof chunk.dataBase64 !== "string" || !Number.isSafeInteger(chunk.size) || chunk.size < 0 || chunk.size > params.maxBytes || typeof chunk.revision !== "string" || !chunk.revision) throw new Error("Codex remote workspace artifact returned invalid or oversized chunk data.");
|
|
477
|
-
if (expectedSize === void 0) {
|
|
478
|
-
expectedSize = chunk.size;
|
|
479
|
-
expectedRevision = chunk.revision;
|
|
480
|
-
}
|
|
481
|
-
if (chunk.size !== expectedSize || chunk.revision !== expectedRevision) throw new Error("Codex remote workspace artifact changed during chunked transfer.");
|
|
482
|
-
const remainingBytes = expectedSize - offset;
|
|
483
|
-
const expectedChunkBytes = Math.min(CODEX_REMOTE_MEDIA_CHUNK_BYTES, remainingBytes);
|
|
484
|
-
if (chunk.dataBase64.length > Math.ceil(expectedChunkBytes / 3) * 4) throw new Error("Codex remote workspace artifact returned oversized chunk data.");
|
|
485
|
-
const buffer = Buffer.from(chunk.dataBase64, "base64");
|
|
486
|
-
if (buffer.byteLength !== expectedChunkBytes || buffer.toString("base64") !== chunk.dataBase64) throw new Error("Codex remote workspace artifact returned invalid chunk data.");
|
|
487
|
-
chunks.push(buffer);
|
|
488
|
-
offset += buffer.byteLength;
|
|
489
|
-
} while (offset < (expectedSize ?? 0));
|
|
490
|
-
return { dataBase64: Buffer.concat(chunks, offset).toString("base64") };
|
|
317
|
+
});
|
|
318
|
+
return async (params) => {
|
|
319
|
+
const bytes = await read(params);
|
|
320
|
+
return authority.withCurrent(() => {
|
|
321
|
+
params.signal?.throwIfAborted();
|
|
322
|
+
return bytes;
|
|
323
|
+
});
|
|
324
|
+
};
|
|
491
325
|
}
|
|
492
326
|
/** Stages authoritative bounded remote bytes into immutable Gateway-owned media. */
|
|
493
327
|
async function prepareCodexRemoteWorkspaceMessageMedia(params) {
|
|
@@ -501,7 +335,7 @@ async function prepareCodexRemoteWorkspaceMessageMedia(params) {
|
|
|
501
335
|
const gatewayManagedPaths = /* @__PURE__ */ new Set();
|
|
502
336
|
const gatewayMediaRoot = getMediaDir();
|
|
503
337
|
let attachmentEntries = 0;
|
|
504
|
-
const mappedArgs =
|
|
338
|
+
const mappedArgs = mapAgentHarnessMessagingMediaValues(params.args, (value) => {
|
|
505
339
|
if (path.isAbsolute(value) && isPathStrictlyInside(gatewayMediaRoot, value)) {
|
|
506
340
|
attachmentEntries += 1;
|
|
507
341
|
gatewayManagedPaths.add(value);
|
|
@@ -547,24 +381,20 @@ async function prepareCodexRemoteWorkspaceMessageMedia(params) {
|
|
|
547
381
|
const remainingBytes = maxBytes - totalBytes;
|
|
548
382
|
const remainingMs = Math.floor(deadline - performance.now());
|
|
549
383
|
if (remainingMs <= 0) throw new Error("Codex remote workspace attachment batch timed out.");
|
|
550
|
-
const
|
|
384
|
+
const remoteBuffer = await readRemoteFile({
|
|
551
385
|
path: remotePath,
|
|
552
386
|
maxBytes: remainingBytes,
|
|
553
387
|
workspaceRoot: remoteWorkspaceRoot,
|
|
554
388
|
signal: params.signal,
|
|
555
389
|
timeoutMs: remainingMs
|
|
556
390
|
});
|
|
557
|
-
if (!response || typeof response.dataBase64 !== "string") throw new Error(`Codex remote workspace artifact returned no file data: ${remotePath}`);
|
|
558
|
-
if (response.dataBase64.length > Math.ceil(remainingBytes / 3) * 4) throw new Error(`Codex remote workspace artifact exceeds the limit of ${remainingBytes} bytes.`);
|
|
559
|
-
const remoteBuffer = Buffer.from(response.dataBase64, "base64");
|
|
560
|
-
if (remoteBuffer.byteLength > remainingBytes || remoteBuffer.toString("base64") !== response.dataBase64) throw new Error(`Codex remote workspace artifact returned invalid or oversized file data: ${remotePath}`);
|
|
561
391
|
totalBytes += remoteBuffer.byteLength;
|
|
562
392
|
const saved = await saveMediaBuffer(remoteBuffer, void 0, "outbound", maxBytes, path.basename(remotePath));
|
|
563
393
|
stagedPaths.set(localPath, saved.path);
|
|
564
394
|
sourcePathsByStagedPath.set(normalizeMediaReferenceForComparison(saved.path), [...sourcePaths]);
|
|
565
395
|
}
|
|
566
396
|
return {
|
|
567
|
-
args:
|
|
397
|
+
args: mapAgentHarnessMessagingMediaValues(mappedArgs, (value) => stagedPaths.get(value) ?? value),
|
|
568
398
|
sourcePathsByStagedPath
|
|
569
399
|
};
|
|
570
400
|
}
|
|
@@ -579,32 +409,6 @@ async function assertGatewayManagedMediaPath(value, mediaRoot) {
|
|
|
579
409
|
await opened[Symbol.asyncDispose]();
|
|
580
410
|
}
|
|
581
411
|
}
|
|
582
|
-
function mapMessageMediaValues(args, mapValue) {
|
|
583
|
-
const mapString = (value) => typeof value === "string" ? mapValue(value) : value;
|
|
584
|
-
const mapArray = (values, map) => {
|
|
585
|
-
const mapped = values.map(map);
|
|
586
|
-
return mapped.some((value, index) => value !== values[index]) ? mapped : values;
|
|
587
|
-
};
|
|
588
|
-
const mapRecord = (record, keys, message = false) => {
|
|
589
|
-
let mapped = record;
|
|
590
|
-
const assign = (key, value) => {
|
|
591
|
-
if (value !== record[key]) {
|
|
592
|
-
if (mapped === record) mapped = { ...record };
|
|
593
|
-
mapped[key] = value;
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
for (const key of keys) assign(key, mapString(record[key]));
|
|
597
|
-
if (message) {
|
|
598
|
-
for (const key of MESSAGE_MEDIA_ARRAY_KEYS) {
|
|
599
|
-
const value = record[key];
|
|
600
|
-
if (Array.isArray(value)) assign(key, mapArray(value, mapString));
|
|
601
|
-
}
|
|
602
|
-
if (Array.isArray(record.attachments)) assign("attachments", mapArray(record.attachments, (attachment) => isRecord(attachment) ? mapRecord(attachment, ATTACHMENT_MEDIA_KEYS) : attachment));
|
|
603
|
-
}
|
|
604
|
-
return mapped;
|
|
605
|
-
};
|
|
606
|
-
return mapRecord(args, MESSAGE_MEDIA_KEYS, true);
|
|
607
|
-
}
|
|
608
412
|
//#endregion
|
|
609
413
|
//#region extensions/codex/src/app-server/native-process-authority.ts
|
|
610
414
|
const clients = /* @__PURE__ */ new WeakMap();
|
|
@@ -617,9 +421,6 @@ function getCodexNativeProcessClient(client) {
|
|
|
617
421
|
}
|
|
618
422
|
return owner;
|
|
619
423
|
}
|
|
620
|
-
function hasCodexNativeBackgroundProcesses(client, threadId) {
|
|
621
|
-
return clients.get(client)?.hasProcesses(threadId) ?? false;
|
|
622
|
-
}
|
|
623
424
|
/** Read the native process owner's live inventory, never infer custody from a start event. */
|
|
624
425
|
async function readCodexRetainedBackgroundCommands(params) {
|
|
625
426
|
params.assertCurrent();
|
|
@@ -703,9 +504,6 @@ var CodexNativeProcessClient = class {
|
|
|
703
504
|
owner.commands.add(command);
|
|
704
505
|
return command;
|
|
705
506
|
}
|
|
706
|
-
hasProcesses(threadId) {
|
|
707
|
-
return [...this.threads.get(threadId)?.values() ?? []].some((command) => command.processes.size > 0 || command.background !== void 0);
|
|
708
|
-
}
|
|
709
507
|
claim(metadata, terminate) {
|
|
710
508
|
if (this.closed || !isJsonObject(metadata) || typeof metadata.threadId !== "string" || typeof metadata.toolCallId !== "string") throw new Error("Codex process start requires its admitted native command");
|
|
711
509
|
const command = this.threads.get(metadata.threadId)?.get(metadata.toolCallId);
|
|
@@ -777,12 +575,13 @@ var CodexNativeProcessAuthority = class {
|
|
|
777
575
|
throw error;
|
|
778
576
|
}
|
|
779
577
|
}
|
|
780
|
-
|
|
781
|
-
|
|
578
|
+
hasCurrentProcesses(client, threadId) {
|
|
579
|
+
this.assertCurrent();
|
|
580
|
+
return [...this.commands].some((command) => command.client === clients.get(client) && command.threadId === threadId && (command.processes.size > 0 || command.background?.confirmed === true));
|
|
782
581
|
}
|
|
783
|
-
|
|
582
|
+
ownsCurrentCommand(client, receipt) {
|
|
784
583
|
this.assertCurrent();
|
|
785
|
-
return [...this.commands].
|
|
584
|
+
return [...this.commands].some((command) => command.client === clients.get(client) && command.threadId === receipt.threadId && command.turnId === receipt.turnId && command.itemId === receipt.itemId && command.processes.size > 0);
|
|
786
585
|
}
|
|
787
586
|
bindTurn(client, threadId, turnId) {
|
|
788
587
|
this.parentTurn = {
|
|
@@ -943,10 +742,16 @@ const CODEX_NODE_HTTP_CREDENTIAL_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
|
943
742
|
const CODEX_NODE_HTTP_CREDENTIAL_HEADER_NAME_PATTERN = /(?:^|[-_])(?:auth(?:orization|entication)?|token|secret|api[-_]?key|apikey|key|password|passwd|pwd|passphrase|passcode|credentials?|session|jwt|assertion|verifier|sig(?:nature)?|hmac|bearer|ticket|challenge|proof|dpop|otp|totp|pin|mfa)(?:[-_]|$)/iu;
|
|
944
743
|
const CODEX_NODE_HTTP_CREDENTIAL_FIELD_NAME_PATTERN = /^(?:(?:[a-z\d]+_)*(?:token|secret|password|passwd|pwd|passphrase|passcode|credentials?|authorization|api_?key|private_key|secret_key|secret_access_key|jwt|assertion|verifier|signature|hmac|bearer|ticket|(?:oauth|consumer|auth|access)_key|otp|totp|pin)|(?:device|authorization|auth|verification|mfa)_code|session(?:_id)?|jsessionid|saml(?:_?response|_?assertion)?|auth|jwt|code|sig|signature|hmac|key|pass)$/u;
|
|
945
744
|
const nodeExecServerTextDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
745
|
+
var CodexNodeExecServerDisconnectedError = class extends Error {
|
|
746
|
+
constructor(message) {
|
|
747
|
+
super(message);
|
|
748
|
+
this.code = "codex_node_disconnected";
|
|
749
|
+
this.name = "CodexNodeExecServerDisconnectedError";
|
|
750
|
+
}
|
|
751
|
+
};
|
|
946
752
|
/** Produces the bounded, redacted terminal failure shared by pending and claimed node leases. */
|
|
947
753
|
function createCodexNodeExecServerDisconnectError(reason, cause) {
|
|
948
|
-
|
|
949
|
-
return /* @__PURE__ */ new Error(`Codex execution node disconnected; start a fresh attempt. (${reason}${detail})`);
|
|
754
|
+
return new CodexNodeExecServerDisconnectedError(`Codex execution node disconnected; start a fresh attempt. (${reason}${cause === void 0 ? "" : `: ${truncateUtf16Safe(redactSensitiveText$1(formatErrorMessage$2(cause), { mode: "tools" }), CODEX_NODE_EXEC_SERVER_MAX_FAILURE_DETAIL_CHARS)}`})`);
|
|
950
755
|
}
|
|
951
756
|
/** Relays one authorized, single-use Codex exec-server channel without interpreting its protocol. */
|
|
952
757
|
async function startCodexNodeExecServerRelay(params) {
|
|
@@ -1015,7 +820,7 @@ function sendCodexExecServerFrame(socket, frame) {
|
|
|
1015
820
|
});
|
|
1016
821
|
}
|
|
1017
822
|
function normalizeCodexExecServerFrame(data) {
|
|
1018
|
-
const frame =
|
|
823
|
+
const frame = codexWebSocketDataToBuffer(data);
|
|
1019
824
|
if (frame.length > CODEX_NODE_EXEC_SERVER_MAX_MESSAGE_BYTES$1) throw new RangeError("Codex exec-server message exceeds its 64 MiB limit.");
|
|
1020
825
|
if (frame.includes(10) || frame.includes(13)) throw new Error("Codex exec-server messages must occupy exactly one stdio line.");
|
|
1021
826
|
return frame;
|
|
@@ -1048,12 +853,8 @@ function rejectCredentialedCodexNodeHttpRequest(request) {
|
|
|
1048
853
|
return credentialBearing ? createCredentialedCodexNodeHttpRejection(request) : void 0;
|
|
1049
854
|
}
|
|
1050
855
|
function hasCredentialedCodexNodeHttpUrl(value) {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
url = new URL(value);
|
|
1054
|
-
} catch {
|
|
1055
|
-
throw new Error("Codex http/request URL must be valid.");
|
|
1056
|
-
}
|
|
856
|
+
const url = URL.parse(value);
|
|
857
|
+
if (!url) throw new Error("Codex http/request URL must be valid.");
|
|
1057
858
|
if (url.username || url.password || hasSensitiveCodexNodeText(value)) return true;
|
|
1058
859
|
let fields = 0;
|
|
1059
860
|
const hasCredentialedParameter = (name, parameterValue) => ++fields > CODEX_NODE_HTTP_CREDENTIAL_SCAN_MAX_FIELDS || isCodexNodeCredentialField(name) || hasSensitiveCodexNodeText(parameterValue);
|
|
@@ -1198,10 +999,8 @@ function sanitizeCodexExecServerEnvironment(record, key) {
|
|
|
1198
999
|
const values = {};
|
|
1199
1000
|
for (const [name, value] of Object.entries(environment)) {
|
|
1200
1001
|
if (typeof value !== "string") throw new Error(`Codex process/start ${key} values must be strings.`);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
if (url.username || url.password) continue;
|
|
1204
|
-
} catch {}
|
|
1002
|
+
const url = URL.parse(value);
|
|
1003
|
+
if (url?.username || url?.password) continue;
|
|
1205
1004
|
values[name] = value;
|
|
1206
1005
|
}
|
|
1207
1006
|
record[key] = sanitizeEnvVars(values).allowed;
|
|
@@ -1426,7 +1225,6 @@ function assertResolvedFsSandboxAccess(policy, requests) {
|
|
|
1426
1225
|
}
|
|
1427
1226
|
}
|
|
1428
1227
|
function resolveFsAccess(policy, rawPath) {
|
|
1429
|
-
if (policy.unrestricted) return "write";
|
|
1430
1228
|
const target = normalizeSandboxAbsolutePath(rawPath, "fs path");
|
|
1431
1229
|
let selected;
|
|
1432
1230
|
for (const entry of policy.entries) {
|
|
@@ -1559,7 +1357,8 @@ async function openFile(execServer, handles, params) {
|
|
|
1559
1357
|
if (handles.has(handleId)) throw new JsonRpcProtocolError(-32600, `file read handle \`${handleId}\` already exists`);
|
|
1560
1358
|
if (handles.size >= CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS) throw new JsonRpcProtocolError(-32600, `at most ${CODEX_SANDBOX_EXEC_SERVER_MAX_OPEN_FILE_READS} file reads may be open per connection`);
|
|
1561
1359
|
const filePath = resolveExecServerPath(requireString(record.path, "path"), "read path");
|
|
1562
|
-
|
|
1360
|
+
const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
|
|
1361
|
+
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
1563
1362
|
path: filePath,
|
|
1564
1363
|
access: "read"
|
|
1565
1364
|
}]);
|
|
@@ -1571,9 +1370,11 @@ async function openFile(execServer, handles, params) {
|
|
|
1571
1370
|
};
|
|
1572
1371
|
handles.set(handleId, handle);
|
|
1573
1372
|
try {
|
|
1373
|
+
const readPolicy = await authorizePhysicalReadPath(fsBridge, fsSandboxPolicy, filePath, handle.abortController.signal);
|
|
1574
1374
|
const stat = await fsBridge.stat({
|
|
1575
1375
|
filePath,
|
|
1576
|
-
signal: handle.abortController.signal
|
|
1376
|
+
signal: handle.abortController.signal,
|
|
1377
|
+
...readPolicy
|
|
1577
1378
|
});
|
|
1578
1379
|
if (handles.get(handleId) !== handle || handle.closeRequested || handles.closed) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
|
|
1579
1380
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
@@ -1584,7 +1385,8 @@ async function openFile(execServer, handles, params) {
|
|
|
1584
1385
|
const data = await fsBridge.readFile({
|
|
1585
1386
|
filePath,
|
|
1586
1387
|
maxBytes: handle.reservedBytes,
|
|
1587
|
-
signal: handle.abortController.signal
|
|
1388
|
+
signal: handle.abortController.signal,
|
|
1389
|
+
...readPolicy
|
|
1588
1390
|
});
|
|
1589
1391
|
if (handles.get(handleId) !== handle || handle.closeRequested || handles.closed) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, `unknown file read handle \`${handleId}\``);
|
|
1590
1392
|
if (data.byteLength > handle.reservedBytes) throw new JsonRpcProtocolError(-32600, "sandbox file read exceeds the per-connection buffered file limit");
|
|
@@ -1645,17 +1447,23 @@ function requireFileReadHandleId(value) {
|
|
|
1645
1447
|
async function readFile(execServer, params) {
|
|
1646
1448
|
const record = requireObject(params, "fs/readFile params");
|
|
1647
1449
|
const filePath = resolveExecServerPath(requireString(record.path, "path"), "read path");
|
|
1648
|
-
|
|
1450
|
+
const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
|
|
1451
|
+
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
1649
1452
|
path: filePath,
|
|
1650
1453
|
access: "read"
|
|
1651
1454
|
}]);
|
|
1652
1455
|
const fsBridge = execServer.fsBridge;
|
|
1653
|
-
const
|
|
1456
|
+
const readPolicy = await authorizePhysicalReadPath(fsBridge, fsSandboxPolicy, filePath);
|
|
1457
|
+
const stat = await fsBridge.stat({
|
|
1458
|
+
filePath,
|
|
1459
|
+
...readPolicy
|
|
1460
|
+
});
|
|
1654
1461
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
1655
1462
|
assertSandboxFileReadWithinLimit(stat);
|
|
1656
1463
|
return { dataBase64: (await fsBridge.readFile({
|
|
1657
1464
|
filePath,
|
|
1658
|
-
maxBytes: CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES
|
|
1465
|
+
maxBytes: CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES,
|
|
1466
|
+
...readPolicy
|
|
1659
1467
|
})).toString("base64") };
|
|
1660
1468
|
}
|
|
1661
1469
|
async function writeFile(execServer, params) {
|
|
@@ -1708,11 +1516,16 @@ async function createDirectory(execServer, params) {
|
|
|
1708
1516
|
async function getMetadata(execServer, params) {
|
|
1709
1517
|
const record = requireObject(params, "fs/getMetadata params");
|
|
1710
1518
|
const filePath = resolveExecServerPath(requireString(record.path, "path"), "metadata path");
|
|
1711
|
-
|
|
1519
|
+
const fsSandboxPolicy = resolveFsSandboxPolicy(execServer, record);
|
|
1520
|
+
assertResolvedFsSandboxAccess(fsSandboxPolicy, [{
|
|
1712
1521
|
path: filePath,
|
|
1713
1522
|
access: "read"
|
|
1714
1523
|
}]);
|
|
1715
|
-
const
|
|
1524
|
+
const readPolicy = await authorizePhysicalReadPath(execServer.fsBridge, fsSandboxPolicy, filePath);
|
|
1525
|
+
const stat = await execServer.fsBridge.stat({
|
|
1526
|
+
filePath,
|
|
1527
|
+
...readPolicy
|
|
1528
|
+
});
|
|
1716
1529
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
1717
1530
|
return {
|
|
1718
1531
|
isDirectory: stat.type === "directory",
|
|
@@ -1735,7 +1548,7 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
|
|
|
1735
1548
|
const resolved = execServer.fsBridge.resolvePath({ filePath });
|
|
1736
1549
|
if (!resolved) throw new Error(`Cannot resolve sandbox path: ${filePath}`);
|
|
1737
1550
|
const result = await execServer.backend.runShellCommand({
|
|
1738
|
-
script: "find \"$1\" -mindepth 1 -maxdepth 1 -exec sh -c 'for path do name=${path##*/}; if [ -L \"$path\" ]; then kind=o; elif [ -d \"$path\" ]; then kind=d; elif [ -f \"$path\" ]; then kind=f; else kind=o; fi; printf \"%s
|
|
1551
|
+
script: "find \"$1\" -mindepth 1 -maxdepth 1 -exec sh -c 'for path do name=${path##*/}; if [ -L \"$path\" ]; then kind=o; elif [ -d \"$path\" ]; then kind=d; elif [ -f \"$path\" ]; then kind=f; else kind=o; fi; printf \"%s%s\\000\" \"$kind\" \"$name\"; done' sh {} +",
|
|
1739
1552
|
args: [resolved.containerPath],
|
|
1740
1553
|
allowFailure: true
|
|
1741
1554
|
});
|
|
@@ -1743,14 +1556,23 @@ async function listDirectoryEntries(execServer, filePath, fsSandboxPolicy) {
|
|
|
1743
1556
|
const stderr = result.stderr.toString("utf8").trim();
|
|
1744
1557
|
throw new Error(stderr || `sandbox directory listing failed with code ${result.code}`);
|
|
1745
1558
|
}
|
|
1746
|
-
return result.stdout.toString("utf8").split("\
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1559
|
+
return result.stdout.toString("utf8").split("\0").filter(Boolean).map((entry) => ({
|
|
1560
|
+
fileName: entry.slice(1),
|
|
1561
|
+
isDirectory: entry[0] === "d",
|
|
1562
|
+
isFile: entry[0] === "f"
|
|
1563
|
+
}));
|
|
1564
|
+
}
|
|
1565
|
+
async function authorizePhysicalReadPath(fsBridge, policy, filePath, signal) {
|
|
1566
|
+
if (!policy || policy.unrestricted || !fsBridge.resolveReadPolicyPath) return {};
|
|
1567
|
+
const expectedPolicyPath = await fsBridge.resolveReadPolicyPath({
|
|
1568
|
+
filePath,
|
|
1569
|
+
signal
|
|
1753
1570
|
});
|
|
1571
|
+
assertResolvedFsSandboxAccess(policy, [{
|
|
1572
|
+
path: expectedPolicyPath,
|
|
1573
|
+
access: "read"
|
|
1574
|
+
}]);
|
|
1575
|
+
return { expectedPolicyPath };
|
|
1754
1576
|
}
|
|
1755
1577
|
async function removePath(execServer, params) {
|
|
1756
1578
|
const record = requireObject(params, "fs/remove params");
|
|
@@ -2198,7 +2020,7 @@ function readSandboxHttpResponse(params) {
|
|
|
2198
2020
|
embeddedAgentLog.warn("codex sandbox http/request cleanup failed", { error });
|
|
2199
2021
|
});
|
|
2200
2022
|
if (headerResolved) {
|
|
2201
|
-
|
|
2023
|
+
params.notifications.send("http/request/bodyDelta", {
|
|
2202
2024
|
requestId: params.requestId,
|
|
2203
2025
|
seq: lastBodySeq + 1,
|
|
2204
2026
|
deltaBase64: "",
|
|
@@ -2248,7 +2070,7 @@ function readSandboxHttpResponse(params) {
|
|
|
2248
2070
|
} else if (type === "bodyDelta") {
|
|
2249
2071
|
const seq = requireNumber(message.seq, "http body sequence");
|
|
2250
2072
|
lastBodySeq = Math.max(lastBodySeq, seq);
|
|
2251
|
-
|
|
2073
|
+
params.notifications.send("http/request/bodyDelta", {
|
|
2252
2074
|
requestId: params.requestId,
|
|
2253
2075
|
seq,
|
|
2254
2076
|
deltaBase64: typeof message.deltaBase64 === "string" ? message.deltaBase64 : "",
|
|
@@ -2875,7 +2697,7 @@ function buildEnvFromPolicy(value) {
|
|
|
2875
2697
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2876
2698
|
const policy = value;
|
|
2877
2699
|
const inheritedEnv = readEnv(policy.set);
|
|
2878
|
-
const includeOnly =
|
|
2700
|
+
const includeOnly = filterStringEntries(policy.includeOnly);
|
|
2879
2701
|
if (includeOnly.length > 0) {
|
|
2880
2702
|
const regexes = includeOnly.map(wildcardPatternToRegex);
|
|
2881
2703
|
for (const key of Object.keys(inheritedEnv)) if (!regexes.some((regex) => regex.test(key))) delete inheritedEnv[key];
|
|
@@ -2886,9 +2708,6 @@ function wildcardPatternToRegex(pattern) {
|
|
|
2886
2708
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/gu, "\\$&");
|
|
2887
2709
|
return new RegExp(`^${escaped.replaceAll("*", ".*").replaceAll("?", ".")}$`, "iu");
|
|
2888
2710
|
}
|
|
2889
|
-
function readStringList(value) {
|
|
2890
|
-
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
2891
|
-
}
|
|
2892
2711
|
//#endregion
|
|
2893
2712
|
//#region extensions/codex/src/app-server/sandbox-exec-server/session.ts
|
|
2894
2713
|
/** Owns the JSON-RPC protocol and resources of one sandbox execution connection. */
|
|
@@ -2903,7 +2722,6 @@ var CodexSandboxExecSession = class {
|
|
|
2903
2722
|
this.httpRequests = /* @__PURE__ */ new Set();
|
|
2904
2723
|
this.closeController = new AbortController();
|
|
2905
2724
|
this.notifications = {
|
|
2906
|
-
isOpen: transport.isOpen,
|
|
2907
2725
|
signal: this.closeController.signal,
|
|
2908
2726
|
send: (method, params) => {
|
|
2909
2727
|
if (transport.isOpen()) transport.send({
|
|
@@ -3050,14 +2868,10 @@ async function releaseCodexSandboxExecServerEnvironment(sandbox, environment) {
|
|
|
3050
2868
|
function canExposeLocalExecServerToAppServer(startOptions) {
|
|
3051
2869
|
if (!startOptions || startOptions.transport !== "websocket") return true;
|
|
3052
2870
|
if (typeof startOptions.url !== "string") return false;
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
return isIP(ipHost) === 4 && ipHost.split(".")[0] === "127";
|
|
3058
|
-
} catch {
|
|
3059
|
-
return false;
|
|
3060
|
-
}
|
|
2871
|
+
const host = URL.parse(startOptions.url)?.hostname.toLowerCase();
|
|
2872
|
+
if (!host) return false;
|
|
2873
|
+
const ipHost = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
2874
|
+
return host === "localhost" || ipHost === "::1" || isIP(ipHost) === 4 && ipHost.split(".")[0] === "127";
|
|
3061
2875
|
}
|
|
3062
2876
|
async function acquireOpenClawExecServer(params) {
|
|
3063
2877
|
const { sandbox, runtime, signal, onExecutionDisconnect } = params;
|
|
@@ -3178,16 +2992,16 @@ async function startOpenClawExecServer(sandbox) {
|
|
|
3178
2992
|
};
|
|
3179
2993
|
server.on("connection", (socket, request) => {
|
|
3180
2994
|
socket.on("error", handleExecServerSocketError);
|
|
3181
|
-
|
|
2995
|
+
const requestUrl = new URL(request.url ?? "", "ws://127.0.0.1");
|
|
2996
|
+
if (requestUrl.pathname !== execServer.authPath && ("node" in execServer || !execServer.processAuthorities?.has(requestUrl.pathname))) {
|
|
3182
2997
|
socket.close(1008, "unauthorized");
|
|
3183
2998
|
return;
|
|
3184
2999
|
}
|
|
3185
3000
|
if ("node" in execServer) {
|
|
3186
|
-
handleNodeConnection(execServer, socket,
|
|
3001
|
+
handleNodeConnection(execServer, socket, requestUrl);
|
|
3187
3002
|
return;
|
|
3188
3003
|
}
|
|
3189
|
-
|
|
3190
|
-
handleConnection(execServer, socket, execServer.processAuthorities?.get(requestPath));
|
|
3004
|
+
handleConnection(execServer, socket, execServer.processAuthorities?.get(requestUrl.pathname));
|
|
3191
3005
|
});
|
|
3192
3006
|
embeddedAgentLog.info("codex sandbox exec-server started", {
|
|
3193
3007
|
environmentId,
|
|
@@ -3208,10 +3022,6 @@ async function releaseOpenClawExecServer(execServer) {
|
|
|
3208
3022
|
function buildEnvironmentId(sandbox) {
|
|
3209
3023
|
return `openclaw-sandbox-${createHash("sha256").update(sandbox.runtimeId).digest("hex").slice(0, 16)}`;
|
|
3210
3024
|
}
|
|
3211
|
-
function isAuthorizedExecServerRequest(execServer, request) {
|
|
3212
|
-
const url = new URL(request.url ?? "", "ws://127.0.0.1");
|
|
3213
|
-
return url.pathname === execServer.authPath || !("node" in execServer) && execServer.processAuthorities?.has(url.pathname) === true;
|
|
3214
|
-
}
|
|
3215
3025
|
function readCodexPlacementNodeId(sandbox) {
|
|
3216
3026
|
if (!("placementExecutionMode" in sandbox) || sandbox.placementExecutionMode !== "remote-exec" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
|
|
3217
3027
|
return sandbox.placementNodeId;
|
|
@@ -3225,8 +3035,8 @@ function readCodexPlacementWorkspaceIdentity(sandbox) {
|
|
|
3225
3035
|
sessionKey: sandbox.sessionKey
|
|
3226
3036
|
};
|
|
3227
3037
|
}
|
|
3228
|
-
function handleNodeConnection(execServer, socket,
|
|
3229
|
-
const leaseId =
|
|
3038
|
+
function handleNodeConnection(execServer, socket, requestUrl) {
|
|
3039
|
+
const leaseId = requestUrl.searchParams.get("lease");
|
|
3230
3040
|
const lease = leaseId ? execServer.node.leases.get(leaseId) : void 0;
|
|
3231
3041
|
if (!lease || lease.claimed || lease.closed) {
|
|
3232
3042
|
socket.close(1008, "execution channel unavailable");
|
|
@@ -3283,435 +3093,7 @@ function handleExecServerSocketError(error) {
|
|
|
3283
3093
|
embeddedAgentLog.debug("codex sandbox exec-server websocket failed", { error });
|
|
3284
3094
|
}
|
|
3285
3095
|
async function handleMessage(session, data) {
|
|
3286
|
-
|
|
3287
|
-
await session.handleRequest(parseRequest(buffer.toString("utf8")));
|
|
3288
|
-
}
|
|
3289
|
-
//#endregion
|
|
3290
|
-
//#region extensions/codex/src/app-server/vision-tools.ts
|
|
3291
|
-
/**
|
|
3292
|
-
* Codex's enabled native surface includes its stable view_image loader. Keep
|
|
3293
|
-
* OpenClaw's view_image tool only when that surface or model vision is unavailable.
|
|
3294
|
-
*/
|
|
3295
|
-
function filterCodexVisionTools(tools, params) {
|
|
3296
|
-
if (!params.modelHasVision || !params.nativeImageInspectionEnabled) return tools;
|
|
3297
|
-
return tools.filter((tool) => tool.name !== "view_image");
|
|
3298
|
-
}
|
|
3299
|
-
//#endregion
|
|
3300
|
-
//#region extensions/codex/src/app-server/dynamic-tool-build.ts
|
|
3301
|
-
const CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW = /* @__PURE__ */ new Set(["read", "write"]);
|
|
3302
|
-
const CODEX_DISABLED_NATIVE_SHELL_DYNAMIC_TOOLS = /* @__PURE__ */ new Set([
|
|
3303
|
-
"exec",
|
|
3304
|
-
"process",
|
|
3305
|
-
"sandbox_exec",
|
|
3306
|
-
"sandbox_process",
|
|
3307
|
-
CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME,
|
|
3308
|
-
CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME,
|
|
3309
|
-
CODEX_NODE_EXEC_DYNAMIC_TOOL_NAME
|
|
3310
|
-
]);
|
|
3311
|
-
/** Keeps node filesystem and process ownership on its native exec-server. */
|
|
3312
|
-
function resolveCodexNodePlacementToolConstructionPlan(sandbox, nativeToolSurfaceEnabled) {
|
|
3313
|
-
if (!isCodexRemoteExecPlacementSandbox(sandbox) || sandbox?.backendId !== "node" || !("placementNodeId" in sandbox) || typeof sandbox.placementNodeId !== "string" || !sandbox.placementNodeId) return;
|
|
3314
|
-
if (!nativeToolSurfaceEnabled) throw new Error("Codex node execution requires its native exec-server tool surface; adjust the session tool policy and start a fresh attempt.");
|
|
3315
|
-
return {
|
|
3316
|
-
includeBaseCodingTools: false,
|
|
3317
|
-
includeShellTools: false,
|
|
3318
|
-
includeChannelTools: true,
|
|
3319
|
-
includeOpenClawTools: true,
|
|
3320
|
-
includePluginTools: true
|
|
3321
|
-
};
|
|
3322
|
-
}
|
|
3323
|
-
function preserveRingZeroSystemAgentTool(allTools, filteredTools) {
|
|
3324
|
-
const openclaw = allTools.find((tool) => tool.name === "openclaw" && tool.catalogMode === "direct-only");
|
|
3325
|
-
if (!openclaw) return filteredTools;
|
|
3326
|
-
return [openclaw, ...filteredTools.filter((tool) => tool.name !== "openclaw")];
|
|
3327
|
-
}
|
|
3328
|
-
function resolveCodexMessageToolProvider(params) {
|
|
3329
|
-
return params.messageChannel ?? params.messageProvider;
|
|
3330
|
-
}
|
|
3331
|
-
function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
3332
|
-
return buildAgentHookContextChannelFields({
|
|
3333
|
-
sessionKey: sandboxSessionKey,
|
|
3334
|
-
messageChannel: params.messageChannel,
|
|
3335
|
-
messageProvider: params.messageProvider,
|
|
3336
|
-
currentChannelId: params.currentChannelId,
|
|
3337
|
-
messageTo: params.messageTo
|
|
3338
|
-
}).channelId;
|
|
3339
|
-
}
|
|
3340
|
-
const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
|
|
3341
|
-
const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
|
|
3342
|
-
function shouldWarnCodexDynamicToolBuildStageSummary(summary, profilerEnabled = false) {
|
|
3343
|
-
const totalWarnMs = profilerEnabled ? CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS : 1e4;
|
|
3344
|
-
const stageWarnMs = profilerEnabled ? CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS : 5e3;
|
|
3345
|
-
return summary.totalMs >= totalWarnMs || summary.stages.some((stage) => stage.durationMs >= stageWarnMs);
|
|
3346
|
-
}
|
|
3347
|
-
async function buildDynamicTools(input) {
|
|
3348
|
-
const { params } = input;
|
|
3349
|
-
const messagePolicyParams = input.ignoreDisableMessageTool ? {
|
|
3350
|
-
...params,
|
|
3351
|
-
disableMessageTool: false
|
|
3352
|
-
} : params;
|
|
3353
|
-
const toolRunContext = buildEmbeddedAttemptToolRunContext({
|
|
3354
|
-
...params,
|
|
3355
|
-
forceMessageTool: shouldForceMessageTool(messagePolicyParams)
|
|
3356
|
-
});
|
|
3357
|
-
if (params.disableTools) {
|
|
3358
|
-
input.onWebSearchPolicyResolved?.(false);
|
|
3359
|
-
return [];
|
|
3360
|
-
}
|
|
3361
|
-
if (!supportsModelTools(params.model)) {
|
|
3362
|
-
input.onPersistentWebSearchPolicyResolved?.(false);
|
|
3363
|
-
input.onWebSearchPolicyResolved?.(false);
|
|
3364
|
-
return [];
|
|
3365
|
-
}
|
|
3366
|
-
const toolBuildStages = createStageTimingTracker();
|
|
3367
|
-
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
3368
|
-
const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, input.sessionAgentId);
|
|
3369
|
-
const nativeExecutionPolicy = resolveCodexNativeExecutionPolicyForRun(params, {
|
|
3370
|
-
agentId: input.policyAgentId,
|
|
3371
|
-
runtimeSessionKey: input.sandboxSessionKey,
|
|
3372
|
-
sandbox: input.sandbox
|
|
3373
|
-
});
|
|
3374
|
-
const webSearchPlan = resolveCodexWebSearchPlan({
|
|
3375
|
-
config: params.config,
|
|
3376
|
-
disableTools: params.disableTools,
|
|
3377
|
-
nativeToolSurfaceEnabled: isCodexResponsesOAuthRun(params) || input.nativeToolSurfaceEnabled,
|
|
3378
|
-
nativeProviderWebSearchSupport: input.nativeProviderWebSearchSupport
|
|
3379
|
-
});
|
|
3380
|
-
const messageToolProvider = resolveCodexMessageToolProvider(params);
|
|
3381
|
-
const webFetchHostnameAllowlistRef = {};
|
|
3382
|
-
const toolConstructionPlan = resolveCodexNodePlacementToolConstructionPlan(input.sandbox, input.nativeToolSurfaceEnabled);
|
|
3383
|
-
const options = {
|
|
3384
|
-
agentId: input.sessionAgentId,
|
|
3385
|
-
policyAgentId: input.policyAgentId,
|
|
3386
|
-
...toolRunContext,
|
|
3387
|
-
exec: {
|
|
3388
|
-
...params.execOverrides,
|
|
3389
|
-
...input.sessionPermissionPolicy ? { mode: input.sessionPermissionPolicy.execMode } : {},
|
|
3390
|
-
...resolveCodexNodeExecToolOverrides(nativeExecutionPolicy),
|
|
3391
|
-
config: params.config,
|
|
3392
|
-
elevated: params.bashElevated
|
|
3393
|
-
},
|
|
3394
|
-
sessionPermissionPolicy: input.sessionPermissionPolicy ? {
|
|
3395
|
-
mode: input.sessionPermissionPolicy.mode,
|
|
3396
|
-
root: input.sessionPermissionPolicy.root
|
|
3397
|
-
} : void 0,
|
|
3398
|
-
sandbox: input.sandbox,
|
|
3399
|
-
...toolConstructionPlan ? { toolConstructionPlan } : {},
|
|
3400
|
-
messageProvider: messageToolProvider,
|
|
3401
|
-
toolPolicyMessageProvider: params.messageProvider ?? params.messageChannel,
|
|
3402
|
-
...params.onToolResult ? { questionPrompt: {
|
|
3403
|
-
send: params.onToolResult,
|
|
3404
|
-
messageChannel: messageToolProvider
|
|
3405
|
-
} } : {},
|
|
3406
|
-
inputProvenance: params.inputProvenance,
|
|
3407
|
-
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
3408
|
-
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
|
|
3409
|
-
sessionKey: input.sandboxSessionKey,
|
|
3410
|
-
runSessionKey: params.sessionKey && params.sessionKey !== input.sandboxSessionKey ? params.sessionKey : void 0,
|
|
3411
|
-
sessionId: params.sessionId,
|
|
3412
|
-
runId: params.runId,
|
|
3413
|
-
agentDir,
|
|
3414
|
-
preparedModelRuntime: params.preparedModelRuntime,
|
|
3415
|
-
cwd: input.effectiveCwd ?? input.effectiveWorkspace,
|
|
3416
|
-
workspaceDir: input.effectiveWorkspace,
|
|
3417
|
-
spawnWorkspaceDir: input.effectiveCwd && input.effectiveCwd !== input.effectiveWorkspace ? input.resolvedWorkspace : resolveAttemptSpawnWorkspaceDir({
|
|
3418
|
-
sandbox: input.sandbox,
|
|
3419
|
-
resolvedWorkspace: input.resolvedWorkspace
|
|
3420
|
-
}),
|
|
3421
|
-
config: params.config,
|
|
3422
|
-
skillsSnapshot: params.skillsSnapshot,
|
|
3423
|
-
...params.skillLibraryAuthoring ? { skillWorkshop: { libraryAuthoring: params.skillLibraryAuthoring } } : {},
|
|
3424
|
-
authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
|
|
3425
|
-
abortSignal: input.runAbortController.signal,
|
|
3426
|
-
emitBeforeToolCallDiagnostics: false,
|
|
3427
|
-
modelProvider: params.model.provider,
|
|
3428
|
-
modelId: params.modelId,
|
|
3429
|
-
modelCompat: params.model.compat && typeof params.model.compat === "object" ? params.model.compat : void 0,
|
|
3430
|
-
modelApi: params.model.api,
|
|
3431
|
-
modelContextWindowTokens: params.model.contextWindow,
|
|
3432
|
-
delegationCapability: params.delegationCapability,
|
|
3433
|
-
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, params.toolAuthProfileStore ?? params.authProfileStore, { workspaceDir: input.effectiveWorkspace }),
|
|
3434
|
-
suppressManagedWebSearch: false,
|
|
3435
|
-
webFetchHostnameAllowlistRef,
|
|
3436
|
-
hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
|
|
3437
|
-
modelHasVision,
|
|
3438
|
-
computerContextEpoch: input.computerContextEpoch,
|
|
3439
|
-
oneShotCliRun: params.oneShotCliRun,
|
|
3440
|
-
registerRunCleanup: input.registerRunCleanup,
|
|
3441
|
-
requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
|
|
3442
|
-
disableMessageTool: input.ignoreDisableMessageTool ? false : params.disableMessageTool,
|
|
3443
|
-
forceMessageTool: shouldForceMessageTool(messagePolicyParams),
|
|
3444
|
-
enableHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
|
|
3445
|
-
forceHeartbeatTool: params.trigger === "heartbeat" || input.forceHeartbeatTool === true,
|
|
3446
|
-
onYield: (message, acknowledgment) => {
|
|
3447
|
-
input.onYieldDetected(message, acknowledgment);
|
|
3448
|
-
input.onCodexAppServerEvent?.({
|
|
3449
|
-
stream: "codex_app_server.tool",
|
|
3450
|
-
data: {
|
|
3451
|
-
name: "sessions_yield",
|
|
3452
|
-
message
|
|
3453
|
-
}
|
|
3454
|
-
});
|
|
3455
|
-
},
|
|
3456
|
-
claimYieldCompletion: input.claimYieldCompletion,
|
|
3457
|
-
recordToolPrepStage: (name) => {
|
|
3458
|
-
toolBuildStages.mark(name);
|
|
3459
|
-
},
|
|
3460
|
-
onToolOutcome: params.onToolOutcome,
|
|
3461
|
-
isTurnTainted: params.isTurnTainted,
|
|
3462
|
-
allocateToolOutcomeOrdinal: params.allocateToolOutcomeOrdinal,
|
|
3463
|
-
cronCreatorToolAllowlistRef: input.cronCreatorToolAllowlistRef,
|
|
3464
|
-
cronCreatorToolAllowlistCaptureRef: input.cronCreatorToolAllowlistCaptureRef,
|
|
3465
|
-
cronCreatorAuthorityUnavailableReason: input.cronCreatorAuthorityUnavailableReason
|
|
3466
|
-
};
|
|
3467
|
-
input.onMessageToolTargetResolved?.(options.requireExplicitMessageTarget === true);
|
|
3468
|
-
const buildOpenClawCodingTools = () => {
|
|
3469
|
-
const bindingOptions = { cwd: input.effectiveCwd ?? input.effectiveWorkspace };
|
|
3470
|
-
const createToolSurface = params.hostCapabilities.createToolSurface;
|
|
3471
|
-
if (!createToolSurface) throw new Error("Codex tool construction requires a current host capability");
|
|
3472
|
-
return createToolSurface(options, bindingOptions);
|
|
3473
|
-
};
|
|
3474
|
-
const allTools = input.resolveCronCreatorToolAuthority ? runWithCronCreatorAuthorityCapabilityResolver({
|
|
3475
|
-
capability: params.cronCreatorAuthorityCapability,
|
|
3476
|
-
runId: params.runId,
|
|
3477
|
-
resolve: input.resolveCronCreatorToolAuthority,
|
|
3478
|
-
run: buildOpenClawCodingTools
|
|
3479
|
-
}) : buildOpenClawCodingTools();
|
|
3480
|
-
toolBuildStages.mark("create-openclaw-coding-tools");
|
|
3481
|
-
const preNormalizationDiagnostics = [];
|
|
3482
|
-
const readableAllToolProjection = filterProviderNormalizableTools(allTools);
|
|
3483
|
-
preNormalizationDiagnostics.push(...readableAllToolProjection.diagnostics);
|
|
3484
|
-
const readableAllTools = [...readableAllToolProjection.tools];
|
|
3485
|
-
const normallyProfiledTools = input.nativeToolSurfaceEnabled === false ? filterCodexDynamicToolsForDisabledNativeSurface(readableAllTools, input.pluginConfig, { preserveShell: shouldKeepOpenClawShellDynamicTools(input, nativeExecutionPolicy) }) : filterCodexDynamicTools(readableAllTools, input.pluginConfig);
|
|
3486
|
-
const profileFilteredTools = (input.isHostScopedToolActive?.("openclaw") ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow) ? preserveRingZeroSystemAgentTool(readableAllTools, normallyProfiledTools) : normallyProfiledTools;
|
|
3487
|
-
const codexFilteredTools = await addNodeShellDynamicToolsIfNeeded(addGatewayShellDynamicToolsIfAvailable(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(readableAllTools) : profileFilteredTools, readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy), readableAllTools, input, nativeExecutionPolicy);
|
|
3488
|
-
toolBuildStages.mark("codex-filtering");
|
|
3489
|
-
const visionFilteredTools = filterCodexVisionTools(codexFilteredTools, {
|
|
3490
|
-
modelHasVision,
|
|
3491
|
-
nativeImageInspectionEnabled: input.nativeToolSurfaceEnabled === true
|
|
3492
|
-
});
|
|
3493
|
-
toolBuildStages.mark("vision-filtering");
|
|
3494
|
-
const webSearchPresent = visionFilteredTools.some((tool) => tool.name === "web_search");
|
|
3495
|
-
const persistentCodexWebSearchSurface = params.config?.tools?.web?.search?.enabled !== false && !(input.pluginConfig.codexDynamicToolsExclude ?? []).some((name) => normalizeCodexDynamicToolName(name) === "web_search");
|
|
3496
|
-
let persistentWebSearchAllowed = webSearchPresent;
|
|
3497
|
-
if (input.onPersistentWebSearchPolicyResolved && !webSearchPresent && persistentCodexWebSearchSurface) {
|
|
3498
|
-
const webSearchPolicy = (await import("openclaw/plugin-sdk/agent-harness")).resolveWebSearchToolPolicy({
|
|
3499
|
-
config: params.config,
|
|
3500
|
-
modelProvider: params.model.provider,
|
|
3501
|
-
modelId: params.modelId,
|
|
3502
|
-
agentId: input.policyAgentId,
|
|
3503
|
-
sessionKey: input.sandboxSessionKey,
|
|
3504
|
-
sandboxToolPolicy: input.sandbox?.tools,
|
|
3505
|
-
messageProvider: messageToolProvider,
|
|
3506
|
-
agentAccountId: params.agentAccountId,
|
|
3507
|
-
groupId: params.groupId,
|
|
3508
|
-
groupChannel: params.groupChannel,
|
|
3509
|
-
groupSpace: params.groupSpace,
|
|
3510
|
-
spawnedBy: params.spawnedBy,
|
|
3511
|
-
senderId: params.senderId,
|
|
3512
|
-
senderName: params.senderName,
|
|
3513
|
-
senderUsername: params.senderUsername,
|
|
3514
|
-
senderE164: params.senderE164,
|
|
3515
|
-
inputProvenance: params.inputProvenance,
|
|
3516
|
-
trustedInternalHandoff: params.trustedInternalHandoff,
|
|
3517
|
-
scheduledToolPolicy: params.scheduledToolPolicy
|
|
3518
|
-
});
|
|
3519
|
-
persistentWebSearchAllowed = webSearchPolicy.persistentAllowed && (!webSearchPolicy.allowed || isCodexMemoryFlushRun(params));
|
|
3520
|
-
}
|
|
3521
|
-
input.onPersistentWebSearchPolicyResolved?.(persistentWebSearchAllowed);
|
|
3522
|
-
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, toolRunContext.runtimeToolAllowlist);
|
|
3523
|
-
toolBuildStages.mark("allowlist-filter");
|
|
3524
|
-
const normalizedTools = normalizeAgentRuntimeTools({
|
|
3525
|
-
runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
|
|
3526
|
-
tools: filteredTools,
|
|
3527
|
-
provider: params.provider,
|
|
3528
|
-
config: params.config,
|
|
3529
|
-
workspaceDir: input.effectiveWorkspace,
|
|
3530
|
-
env: process.env,
|
|
3531
|
-
modelId: params.modelId,
|
|
3532
|
-
modelApi: params.model.api,
|
|
3533
|
-
model: params.model,
|
|
3534
|
-
allowProviderRuntimePluginLoad: input.ignoreRuntimePlan ? false : void 0,
|
|
3535
|
-
onPreNormalizationSchemaDiagnostics: (diagnostics) => preNormalizationDiagnostics.push(...diagnostics)
|
|
3536
|
-
});
|
|
3537
|
-
toolBuildStages.mark("runtime-normalization");
|
|
3538
|
-
const webSearchAllowed = normalizedTools.some((tool) => tool.name === "web_search");
|
|
3539
|
-
webFetchHostnameAllowlistRef.value = webSearchAllowed ? webSearchPlan.webFetchHostnameAllowlist : void 0;
|
|
3540
|
-
input.onWebSearchPolicyResolved?.(webSearchAllowed);
|
|
3541
|
-
const exposedTools = placeDisabledNativeShellToolsInDirectNamespace(webSearchPlan.suppressManagedWebSearch ? normalizedTools.filter((tool) => tool.name !== "web_search") : normalizedTools, input.nativeToolSurfaceEnabled);
|
|
3542
|
-
if (preNormalizationDiagnostics.length > 0) embeddedAgentLog.warn(`codex app-server quarantined ${preNormalizationDiagnostics.length} unsupported runtime tool schema${preNormalizationDiagnostics.length === 1 ? "" : "s"} before dynamic tool registration`, {
|
|
3543
|
-
runId: params.runId,
|
|
3544
|
-
sessionId: params.sessionId,
|
|
3545
|
-
diagnostics: preNormalizationDiagnostics.map((diagnostic) => ({
|
|
3546
|
-
index: diagnostic.toolIndex,
|
|
3547
|
-
tool: diagnostic.toolName,
|
|
3548
|
-
violations: diagnostic.violations.slice(0, 12),
|
|
3549
|
-
violationCount: diagnostic.violations.length
|
|
3550
|
-
}))
|
|
3551
|
-
});
|
|
3552
|
-
const summary = toolBuildStages.snapshot();
|
|
3553
|
-
if (shouldWarnCodexDynamicToolBuildStageSummary(summary, input.profilerEnabled)) {
|
|
3554
|
-
const phase = input.forceHeartbeatTool ? "registered-tools" : "runtime-tools";
|
|
3555
|
-
embeddedAgentLog.warn(`codex app-server dynamic tool build timings runId=${params.runId} sessionId=${params.sessionId} phase=${phase} totalMs=${summary.totalMs} stages=${formatStageTimings(summary.stages)}`, {
|
|
3556
|
-
runId: params.runId,
|
|
3557
|
-
sessionId: params.sessionId,
|
|
3558
|
-
phase,
|
|
3559
|
-
totalMs: summary.totalMs,
|
|
3560
|
-
stages: summary.stages,
|
|
3561
|
-
allToolCount: readableAllTools.length,
|
|
3562
|
-
codexFilteredToolCount: codexFilteredTools.length,
|
|
3563
|
-
visionFilteredToolCount: visionFilteredTools.length,
|
|
3564
|
-
filteredToolCount: filteredTools.length,
|
|
3565
|
-
normalizedToolCount: exposedTools.length,
|
|
3566
|
-
forceHeartbeatTool: input.forceHeartbeatTool === true,
|
|
3567
|
-
ignoreRuntimePlan: input.ignoreRuntimePlan === true,
|
|
3568
|
-
nativeToolSurfaceEnabled: input.nativeToolSurfaceEnabled === true
|
|
3569
|
-
});
|
|
3570
|
-
}
|
|
3571
|
-
return exposedTools;
|
|
3572
|
-
}
|
|
3573
|
-
/** Keeps the OpenClaw Gateway execution path available beside Codex native shell. */
|
|
3574
|
-
function addGatewayShellDynamicToolsIfAvailable(filteredTools, allTools, input, executionPolicy) {
|
|
3575
|
-
if (isCodexMemoryFlushRun(input.params) || input.nativeToolSurfaceEnabled !== true || input.sandbox?.enabled === true || !executionPolicy.nativeToolSurfaceAllowed || executionPolicy.effectiveExecHost !== "gateway") return filteredTools;
|
|
3576
|
-
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
3577
|
-
const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
|
|
3578
|
-
const existingNames = new Set(filteredTools.map((tool) => normalizeCodexDynamicToolName(tool.name)));
|
|
3579
|
-
const execExcluded = isCodexDynamicToolExcluded(input.pluginConfig, ["exec", CODEX_GATEWAY_EXEC_DYNAMIC_TOOL_NAME]);
|
|
3580
|
-
if (!execTool || execExcluded || existingNames.has("gateway_exec")) return filteredTools;
|
|
3581
|
-
const processExcluded = isCodexDynamicToolExcluded(input.pluginConfig, ["process", CODEX_GATEWAY_PROCESS_DYNAMIC_TOOL_NAME]);
|
|
3582
|
-
const processAliasAvailable = Boolean(processTool && !processExcluded && !existingNames.has("gateway_process"));
|
|
3583
|
-
const createProjection = resolveCodexScheduledToolProjectionFactory(input.params.hostCapabilities);
|
|
3584
|
-
if (!createProjection) return filteredTools;
|
|
3585
|
-
const toolsToAppend = [createGatewayExecProjection(createProjection, execTool, {
|
|
3586
|
-
processAliasAvailable,
|
|
3587
|
-
...input.sessionPermissionPolicy?.mode === "guarded" ? { ask: "always" } : {}
|
|
3588
|
-
})];
|
|
3589
|
-
if (processAliasAvailable && processTool) toolsToAppend.push(createGatewayProcessProjection(createProjection, processTool));
|
|
3590
|
-
return [...filteredTools, ...toolsToAppend];
|
|
3591
|
-
}
|
|
3592
|
-
function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
|
|
3593
|
-
if (isCodexResponsesOAuthRun(params) || params.pluginHarnessToolPolicyRestricted === true || isCodexMemoryFlushRun(params) || params.disableTools) return false;
|
|
3594
|
-
if (!resolveCodexNativeExecutionPolicyForRun(params, {
|
|
3595
|
-
agentId: options.agentId,
|
|
3596
|
-
runtimeSessionKey: options.runtimeSessionKey,
|
|
3597
|
-
sandbox
|
|
3598
|
-
}).nativeToolSurfaceAllowed) return false;
|
|
3599
|
-
const toolsAllow = params.toolsAllow;
|
|
3600
|
-
if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
3601
|
-
return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
|
|
3602
|
-
}
|
|
3603
|
-
function resolveCodexNativeExecutionPolicyForRun(params, options = {}) {
|
|
3604
|
-
return resolveCodexNativeExecutionPolicy({
|
|
3605
|
-
config: params.config,
|
|
3606
|
-
sessionKey: options.runtimeSessionKey?.trim() || params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId,
|
|
3607
|
-
sessionId: params.sessionId,
|
|
3608
|
-
agentId: options.agentId,
|
|
3609
|
-
execOverrides: params.execOverrides,
|
|
3610
|
-
sandboxAvailable: options.sandbox === null ? false : options.sandbox?.enabled,
|
|
3611
|
-
readRuntimeSessionEntry: true
|
|
3612
|
-
});
|
|
3613
|
-
}
|
|
3614
|
-
function canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options = {}) {
|
|
3615
|
-
if (!sandbox?.enabled) return true;
|
|
3616
|
-
if (options.sandboxExecServerEnabled === true && (sandbox.backend || isCodexRemoteExecPlacementSandbox(sandbox)) && canSandboxToolPolicyExposeCodexNativeToolSurface(sandbox)) return true;
|
|
3617
|
-
return false;
|
|
3618
|
-
}
|
|
3619
|
-
function canSandboxToolPolicyExposeCodexNativeToolSurface(sandbox) {
|
|
3620
|
-
return CODEX_NATIVE_TOOL_REQUIREMENTS.every((toolName) => isToolAllowed(sandbox.tools, toolName));
|
|
3621
|
-
}
|
|
3622
|
-
function isCodexMemoryFlushRun(params) {
|
|
3623
|
-
return params?.trigger === "memory" && Boolean(params.memoryFlushWritePath?.trim());
|
|
3624
|
-
}
|
|
3625
|
-
function filterCodexMemoryFlushDynamicTools(tools) {
|
|
3626
|
-
return tools.filter((tool) => CODEX_MEMORY_FLUSH_DYNAMIC_TOOL_ALLOW.has(normalizeCodexDynamicToolName(tool.name)));
|
|
3627
|
-
}
|
|
3628
|
-
/** Requires a Codex sandbox environment only when native tools must run inside OpenClaw sandboxing. */
|
|
3629
|
-
function shouldRequireCodexSandboxExecServerEnvironment(params) {
|
|
3630
|
-
return Boolean(isCodexRemoteExecPlacementSandbox(params.sandbox) || params.sandbox?.enabled && params.nativeToolSurfaceEnabled && params.sandboxExecServerEnabled);
|
|
3631
|
-
}
|
|
3632
|
-
function resolveCodexSandboxEnvironmentSelection(environment, nativeToolSurfaceEnabled) {
|
|
3633
|
-
return nativeToolSurfaceEnabled ? environment ? [environment] : void 0 : [];
|
|
3634
|
-
}
|
|
3635
|
-
function resolveCodexAppServerExecutionCwd(params) {
|
|
3636
|
-
return mapCodexAppServerRemoteWorkspacePath({
|
|
3637
|
-
value: params.environment && params.nativeToolSurfaceEnabled ? params.environment.cwd : params.effectiveCwd,
|
|
3638
|
-
localWorkspaceRoot: params.localWorkspaceRoot,
|
|
3639
|
-
remoteWorkspaceRoot: params.remoteWorkspaceRoot
|
|
3640
|
-
});
|
|
3641
|
-
}
|
|
3642
|
-
function resolveCodexExternalSandboxPolicyForOpenClawSandbox(sandbox) {
|
|
3643
|
-
return {
|
|
3644
|
-
type: "externalSandbox",
|
|
3645
|
-
networkAccess: codexNetworkAccessForOpenClawSandbox(sandbox) ? "enabled" : "restricted"
|
|
3646
|
-
};
|
|
3647
|
-
}
|
|
3648
|
-
function usesDockerNetworkConfig(sandbox) {
|
|
3649
|
-
const backendId = sandbox?.backendId.trim().toLowerCase();
|
|
3650
|
-
return backendId === "docker" || backendId === "podman";
|
|
3651
|
-
}
|
|
3652
|
-
function codexNetworkAccessForOpenClawSandbox(sandbox) {
|
|
3653
|
-
if (!usesDockerNetworkConfig(sandbox)) return true;
|
|
3654
|
-
const network = sandbox?.docker?.network?.trim().toLowerCase();
|
|
3655
|
-
return Boolean(network && network !== "none");
|
|
3656
|
-
}
|
|
3657
|
-
function disableCodexPluginThreadConfig(pluginConfig) {
|
|
3658
|
-
const config = readCodexPluginConfig(pluginConfig);
|
|
3659
|
-
return {
|
|
3660
|
-
...config,
|
|
3661
|
-
codexPlugins: {
|
|
3662
|
-
...config.codexPlugins,
|
|
3663
|
-
enabled: false
|
|
3664
|
-
}
|
|
3665
|
-
};
|
|
3666
|
-
}
|
|
3667
|
-
/** Adds sandbox_exec/process aliases when native Code Mode cannot directly honor the sandbox. */
|
|
3668
|
-
function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input, executionPolicy) {
|
|
3669
|
-
if (isCodexMemoryFlushRun(input.params) || !executionPolicy.nativeToolSurfaceAllowed || !input.sandbox?.enabled || !input.sandbox.backendId.trim() || input.nativeToolSurfaceEnabled !== false || isCodexDynamicToolExcluded(input.pluginConfig, [
|
|
3670
|
-
"exec",
|
|
3671
|
-
"sandbox_exec",
|
|
3672
|
-
"process",
|
|
3673
|
-
"sandbox_process"
|
|
3674
|
-
])) return filteredTools;
|
|
3675
|
-
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
3676
|
-
const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
|
|
3677
|
-
if (!execTool) return filteredTools;
|
|
3678
|
-
const sandboxTools = [...filteredTools, createSandboxExecProjection(execTool)];
|
|
3679
|
-
return processTool ? [...sandboxTools, createSandboxProcessProjection(processTool)] : sandboxTools;
|
|
3680
|
-
}
|
|
3681
|
-
async function addNodeShellDynamicToolsIfNeeded(filteredTools, allTools, input, nodePolicy) {
|
|
3682
|
-
if (isCodexMemoryFlushRun(input.params)) return filteredTools;
|
|
3683
|
-
const nodeExecIsDefault = nodePolicy.effectiveExecHost === "node";
|
|
3684
|
-
const nodeExecAvailableFromAuto = nodePolicy.requestedExecHost === "auto" && nodePolicy.effectiveExecHost === "gateway";
|
|
3685
|
-
if (!nodeExecIsDefault && !nodeExecAvailableFromAuto) return filteredTools;
|
|
3686
|
-
const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
|
|
3687
|
-
if (!execTool || isCodexDynamicToolExcluded(input.pluginConfig, ["exec", "node_exec"]) || filteredTools.some((tool) => normalizeCodexDynamicToolName(tool.name) === "node_exec")) return filteredTools;
|
|
3688
|
-
const nodeExec = await createNodeExecAliasDynamicTool(execTool, nodePolicy.node, input.runAbortController.signal, input.nodeExecAvailability);
|
|
3689
|
-
return nodeExec ? [...filteredTools, nodeExec] : filteredTools;
|
|
3690
|
-
}
|
|
3691
|
-
function shouldKeepOpenClawShellDynamicTools(input, nodePolicy) {
|
|
3692
|
-
return !isCodexMemoryFlushRun(input.params) && input.nativeToolSurfaceEnabled === false && input.sandbox?.enabled !== true && nodePolicy.effectiveExecHost !== "node";
|
|
3693
|
-
}
|
|
3694
|
-
/** Keeps replacement shell tools direct even when model metadata mandates Codex Code Mode. */
|
|
3695
|
-
function placeDisabledNativeShellToolsInDirectNamespace(tools, nativeToolSurfaceEnabled) {
|
|
3696
|
-
if (nativeToolSurfaceEnabled !== false) return tools;
|
|
3697
|
-
for (const tool of tools) if (CODEX_DISABLED_NATIVE_SHELL_DYNAMIC_TOOLS.has(normalizeCodexDynamicToolName(tool.name))) tool.catalogMode = "direct-only";
|
|
3698
|
-
return tools;
|
|
3699
|
-
}
|
|
3700
|
-
/** Applies a normalized tool allowlist while preserving shell aliases for exec/process. */
|
|
3701
|
-
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
3702
|
-
return applyEmbeddedAttemptToolsAllow(tools, toolsAllow, {
|
|
3703
|
-
toolMeta: getPluginToolMeta,
|
|
3704
|
-
toolAliases: (tool) => {
|
|
3705
|
-
const normalized = normalizeCodexDynamicToolName(tool.name);
|
|
3706
|
-
return normalized === "sandbox_exec" || normalized === "gateway_exec" || normalized === "node_exec" ? ["exec"] : normalized === "sandbox_process" || normalized === "gateway_process" ? ["exec", "process"] : [];
|
|
3707
|
-
}
|
|
3708
|
-
});
|
|
3709
|
-
}
|
|
3710
|
-
function hasWildcardCodexToolsAllow(toolsAllow) {
|
|
3711
|
-
return toolsAllow.some((name) => normalizeCodexDynamicToolName(name) === "*");
|
|
3712
|
-
}
|
|
3713
|
-
function shouldForceMessageTool(params) {
|
|
3714
|
-
return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
|
|
3096
|
+
await session.handleRequest(parseRequest(codexWebSocketDataToBuffer(data).toString("utf8")));
|
|
3715
3097
|
}
|
|
3716
3098
|
//#endregion
|
|
3717
3099
|
//#region extensions/codex/src/app-server/native-command-approval.ts
|
|
@@ -3796,12 +3178,17 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
3796
3178
|
method: params.method,
|
|
3797
3179
|
requestParams
|
|
3798
3180
|
});
|
|
3799
|
-
const emitEvent = (data) =>
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3181
|
+
const emitEvent = (data) => {
|
|
3182
|
+
params.paramsForRun.onAgentEvent?.({
|
|
3183
|
+
stream: "approval",
|
|
3184
|
+
data: {
|
|
3185
|
+
kind: context.kind,
|
|
3186
|
+
title: context.title,
|
|
3187
|
+
...context.eventDetails,
|
|
3188
|
+
...data
|
|
3189
|
+
}
|
|
3190
|
+
});
|
|
3191
|
+
};
|
|
3805
3192
|
if (params.signal?.aborted) {
|
|
3806
3193
|
if (params.signal.reason instanceof CodexServerRequestResolvedError) return;
|
|
3807
3194
|
recordNativeToolFailureDisposition(params, context, "cancelled");
|
|
@@ -4138,8 +3525,8 @@ function readNativeRelayPreToolUseDecision(response) {
|
|
|
4138
3525
|
};
|
|
4139
3526
|
const stdout = response.stdout?.trim();
|
|
4140
3527
|
if (!stdout) return { blocked: false };
|
|
4141
|
-
const parsed =
|
|
4142
|
-
const output = isJsonObject(parsed
|
|
3528
|
+
const parsed = safeParseJson(stdout);
|
|
3529
|
+
const output = isJsonObject(parsed) && isJsonObject(parsed.hookSpecificOutput) ? parsed.hookSpecificOutput : void 0;
|
|
4143
3530
|
if (output?.permissionDecision === "deny") return {
|
|
4144
3531
|
blocked: true,
|
|
4145
3532
|
reason: readStringField(output, "permissionDecisionReason") || "OpenClaw native hook policy denied Codex app-server approval.",
|
|
@@ -4151,14 +3538,6 @@ function readNativeRelayPreToolUseDecision(response) {
|
|
|
4151
3538
|
failureDisposition: "failed"
|
|
4152
3539
|
};
|
|
4153
3540
|
}
|
|
4154
|
-
function parseRelayJsonResponse(text) {
|
|
4155
|
-
try {
|
|
4156
|
-
const parsed = JSON.parse(text);
|
|
4157
|
-
return isJsonObject(parsed) ? parsed : void 0;
|
|
4158
|
-
} catch {
|
|
4159
|
-
return;
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
3541
|
function sanitizeRelayDecisionReason(value) {
|
|
4163
3542
|
return sanitizeApprovalPreview(value ? {
|
|
4164
3543
|
value,
|
|
@@ -4378,12 +3757,6 @@ function approvalResolutionMessage(outcome) {
|
|
|
4378
3757
|
function approvalEventScope(method, outcome) {
|
|
4379
3758
|
return method === "item/permissions/requestApproval" ? { scope: outcome === "approved-session" ? "session" : "turn" } : {};
|
|
4380
3759
|
}
|
|
4381
|
-
function emitApprovalEvent(params, data) {
|
|
4382
|
-
params.onAgentEvent?.({
|
|
4383
|
-
stream: "approval",
|
|
4384
|
-
data: { ...data }
|
|
4385
|
-
});
|
|
4386
|
-
}
|
|
4387
3760
|
function readPolicyCommand(record) {
|
|
4388
3761
|
const command = record?.command;
|
|
4389
3762
|
if (typeof command === "string") return command;
|
|
@@ -4474,9 +3847,6 @@ function joinDescriptionLinesWithinLimit(lines, maxLength) {
|
|
|
4474
3847
|
}
|
|
4475
3848
|
//#endregion
|
|
4476
3849
|
//#region extensions/codex/src/app-server/dynamic-tool-diagnostics.ts
|
|
4477
|
-
/**
|
|
4478
|
-
* Trusted diagnostics emitted around Codex dynamic tool execution lifecycle.
|
|
4479
|
-
*/
|
|
4480
3850
|
function diagnosticToolIdentity(params) {
|
|
4481
3851
|
return {
|
|
4482
3852
|
agentId: params.agentId,
|
|
@@ -4487,14 +3857,12 @@ function diagnosticToolIdentity(params) {
|
|
|
4487
3857
|
toolCallId: params.call.callId
|
|
4488
3858
|
};
|
|
4489
3859
|
}
|
|
4490
|
-
/** Emits a start event for one Codex dynamic tool call. */
|
|
4491
3860
|
function emitDynamicToolStartedDiagnostic(params) {
|
|
4492
3861
|
emitTrustedDiagnosticEvent({
|
|
4493
3862
|
type: "tool.execution.started",
|
|
4494
3863
|
...diagnosticToolIdentity(params)
|
|
4495
3864
|
});
|
|
4496
3865
|
}
|
|
4497
|
-
/** Emits an error event for one Codex dynamic tool call. */
|
|
4498
3866
|
function emitDynamicToolErrorDiagnostic(params) {
|
|
4499
3867
|
emitTrustedDiagnosticEvent({
|
|
4500
3868
|
type: "tool.execution.error",
|
|
@@ -5152,17 +4520,11 @@ function createCodexDynamicToolSpecs(params) {
|
|
|
5152
4520
|
deferLoading: true
|
|
5153
4521
|
});
|
|
5154
4522
|
}
|
|
5155
|
-
if (
|
|
4523
|
+
for (const [name, tools] of [[CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE, namespaceTools], [CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, directOnlyNamespaceTools]]) if (tools.length > 0) specs.push({
|
|
5156
4524
|
type: "namespace",
|
|
5157
|
-
name
|
|
5158
|
-
description: "",
|
|
5159
|
-
tools: namespaceTools
|
|
5160
|
-
});
|
|
5161
|
-
if (directOnlyNamespaceTools.length > 0) specs.push({
|
|
5162
|
-
type: "namespace",
|
|
5163
|
-
name: CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE,
|
|
4525
|
+
name,
|
|
5164
4526
|
description: "",
|
|
5165
|
-
tools
|
|
4527
|
+
tools
|
|
5166
4528
|
});
|
|
5167
4529
|
return specs;
|
|
5168
4530
|
}
|
|
@@ -5298,6 +4660,97 @@ function finalizeCodexToolAvailability(entries) {
|
|
|
5298
4660
|
};
|
|
5299
4661
|
}
|
|
5300
4662
|
//#endregion
|
|
4663
|
+
//#region extensions/codex/src/app-server/dynamic-tool-content.ts
|
|
4664
|
+
function enforceWholeSkillResult(toolName, result, maxChars) {
|
|
4665
|
+
if (toolName !== "skills_read" || isToolResultError(result)) return result;
|
|
4666
|
+
return sanitizeToolTextRuns(result.content).reduce((total, item) => total + (item.type === "text" ? estimateToolResultTextChars(item.text) : 0), 0) <= maxChars ? result : failedToolResult(`This Codex turn cannot deliver the whole skill within its ${maxChars}-character weighted output budget. No instructions were returned; use a harness with a larger instruction budget.`);
|
|
4667
|
+
}
|
|
4668
|
+
function sanitizeToolTextRuns(rawContent) {
|
|
4669
|
+
const content = [];
|
|
4670
|
+
for (let index = 0; index < rawContent.length;) {
|
|
4671
|
+
const item = rawContent[index];
|
|
4672
|
+
if (item.type !== "text") {
|
|
4673
|
+
content.push(item);
|
|
4674
|
+
index += 1;
|
|
4675
|
+
continue;
|
|
4676
|
+
}
|
|
4677
|
+
const textRun = [];
|
|
4678
|
+
while (index < rawContent.length) {
|
|
4679
|
+
const next = rawContent[index];
|
|
4680
|
+
if (next.type !== "text") break;
|
|
4681
|
+
textRun.push(next);
|
|
4682
|
+
index += 1;
|
|
4683
|
+
}
|
|
4684
|
+
const sanitizedText = sanitizeToolResult(textRun.map((entry) => entry.text).join(""));
|
|
4685
|
+
let offset = 0;
|
|
4686
|
+
content.push(...textRun.map((entry, runIndex) => {
|
|
4687
|
+
const targetEnd = runIndex === textRun.length - 1 ? sanitizedText.length : Math.min(sanitizedText.length, offset + entry.text.length);
|
|
4688
|
+
const text = sliceUtf16Safe(sanitizedText, offset, targetEnd);
|
|
4689
|
+
const sanitized = Object.assign({}, entry, { text });
|
|
4690
|
+
offset += text.length;
|
|
4691
|
+
return sanitized;
|
|
4692
|
+
}));
|
|
4693
|
+
}
|
|
4694
|
+
return content;
|
|
4695
|
+
}
|
|
4696
|
+
function convertToolContents(rawContent, maxChars) {
|
|
4697
|
+
const content = sanitizeToolTextRuns(rawContent);
|
|
4698
|
+
const totalTextChars = content.reduce((total, item) => total + (item.type === "text" ? item.text.length : 0), 0);
|
|
4699
|
+
if (content.reduce((total, item) => total + (item.type === "text" ? estimateToolResultTextChars(item.text) : 0), 0) <= maxChars) return content.map(convertToolContent);
|
|
4700
|
+
const noticeText = `...(OpenClaw truncated dynamic tool result: original ${totalTextChars} chars, weighted budget ${maxChars}; rerun with narrower args.)`;
|
|
4701
|
+
const notice = `\n${noticeText}`;
|
|
4702
|
+
const noticeChars = estimateToolResultTextChars(notice);
|
|
4703
|
+
let remainingTextBudget = Math.max(0, maxChars - noticeChars);
|
|
4704
|
+
let appendedNotice = false;
|
|
4705
|
+
const output = [];
|
|
4706
|
+
for (const item of content) {
|
|
4707
|
+
if (item.type !== "text") {
|
|
4708
|
+
output.push(convertToolContent(item));
|
|
4709
|
+
continue;
|
|
4710
|
+
}
|
|
4711
|
+
if (appendedNotice) continue;
|
|
4712
|
+
if (noticeChars >= maxChars) {
|
|
4713
|
+
output.push({
|
|
4714
|
+
type: "inputText",
|
|
4715
|
+
text: sliceToolResultTextToBudget(noticeText, maxChars)
|
|
4716
|
+
});
|
|
4717
|
+
appendedNotice = true;
|
|
4718
|
+
continue;
|
|
4719
|
+
}
|
|
4720
|
+
const text = sliceToolResultTextToBudget(item.text, remainingTextBudget);
|
|
4721
|
+
remainingTextBudget -= estimateToolResultTextChars(text);
|
|
4722
|
+
if (remainingTextBudget <= 0 || text.length < item.text.length) {
|
|
4723
|
+
output.push({
|
|
4724
|
+
type: "inputText",
|
|
4725
|
+
text: `${text.trimEnd()}${notice}`
|
|
4726
|
+
});
|
|
4727
|
+
appendedNotice = true;
|
|
4728
|
+
} else if (text.length > 0) output.push({
|
|
4729
|
+
type: "inputText",
|
|
4730
|
+
text
|
|
4731
|
+
});
|
|
4732
|
+
}
|
|
4733
|
+
if (!appendedNotice) output.push({
|
|
4734
|
+
type: "inputText",
|
|
4735
|
+
text: sliceToolResultTextToBudget(noticeText, maxChars)
|
|
4736
|
+
});
|
|
4737
|
+
return output;
|
|
4738
|
+
}
|
|
4739
|
+
function convertToolContent(content) {
|
|
4740
|
+
if (content.type === "text") return {
|
|
4741
|
+
type: "inputText",
|
|
4742
|
+
text: content.text
|
|
4743
|
+
};
|
|
4744
|
+
const imageUrl = sanitizeInlineImageDataUrl(`data:${content.mimeType};base64,${content.data}`);
|
|
4745
|
+
return imageUrl ? {
|
|
4746
|
+
type: "inputImage",
|
|
4747
|
+
imageUrl
|
|
4748
|
+
} : {
|
|
4749
|
+
type: "inputText",
|
|
4750
|
+
text: invalidInlineImageText("codex dynamic tool")
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
//#endregion
|
|
5301
4754
|
//#region extensions/codex/src/app-server/dynamic-tool-executable-projection.ts
|
|
5302
4755
|
function projectCodexExecutableDynamicToolSurface(tools, hookContext) {
|
|
5303
4756
|
const { tools: projectedTools, quarantinedTools } = projectCodexDynamicTools(tools);
|
|
@@ -5345,7 +4798,7 @@ function assertCodexDynamicToolInputMatchesSchema(params) {
|
|
|
5345
4798
|
throw new Error(`Invalid arguments for tool "${params.toolName}": ${details}${omittedSuffix}.`);
|
|
5346
4799
|
}
|
|
5347
4800
|
function applyCurrentMessageProvider(toolName, args, currentProvider) {
|
|
5348
|
-
const hasProvider = typeof args.provider === "string" && args.provider.trim().length > 0
|
|
4801
|
+
const hasProvider = typeof args.provider === "string" && args.provider.trim().length > 0 || typeof args.channel === "string" && args.channel.trim().length > 0;
|
|
5349
4802
|
const provider = currentProvider?.trim();
|
|
5350
4803
|
if (toolName !== "message" || hasProvider || !provider) return args;
|
|
5351
4804
|
return {
|
|
@@ -5597,7 +5050,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5597
5050
|
isError: rawIsErrorForPresentation,
|
|
5598
5051
|
result: event.result
|
|
5599
5052
|
});
|
|
5600
|
-
const
|
|
5053
|
+
const extendedResult = await legacyExtensionRunner.applyToolResultExtensions({
|
|
5601
5054
|
threadId: call.threadId,
|
|
5602
5055
|
turnId: call.turnId,
|
|
5603
5056
|
toolCallId: call.callId,
|
|
@@ -5605,6 +5058,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5605
5058
|
args: structuredClone(executedArgsForPresentation),
|
|
5606
5059
|
result: middlewareResult
|
|
5607
5060
|
});
|
|
5061
|
+
const result = enforceWholeSkillResult(toolName, extendedResult, toolResultMaxChars);
|
|
5608
5062
|
presentationIsError = rawIsErrorForPresentation || isToolResultError(result);
|
|
5609
5063
|
const acceptedSessionSpawn = toolName === "sessions_spawn" && !rawIsErrorForPresentation ? normalizeAcceptedSessionSpawnResult(telemetryRawResultForPresentation) : null;
|
|
5610
5064
|
if (acceptedSessionSpawn) telemetry.acceptedSessionSpawns.push(acceptedSessionSpawn);
|
|
@@ -5617,11 +5071,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5617
5071
|
runAgentHarnessAfterToolCallHook({
|
|
5618
5072
|
toolName,
|
|
5619
5073
|
toolCallId: call.callId,
|
|
5620
|
-
|
|
5621
|
-
agentId: toolResultHookContext.agentId,
|
|
5622
|
-
sessionId: toolResultHookContext.sessionId,
|
|
5623
|
-
sessionKey: toolResultHookContext.sessionKey,
|
|
5624
|
-
channelId: toolResultHookContext.channelId,
|
|
5074
|
+
...toolResultHookContext,
|
|
5625
5075
|
startArgs: executedArgs,
|
|
5626
5076
|
result,
|
|
5627
5077
|
startedAt
|
|
@@ -5645,7 +5095,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5645
5095
|
const autoDeliveryTtsMediaUrls = getCoreTtsToolResultMediaUrls(rawResult);
|
|
5646
5096
|
recordAgentHarnessToolResultTelemetry({
|
|
5647
5097
|
extractSourceReplyPayload: extractMessagingToolSourceReplyPayload,
|
|
5648
|
-
collectMessagingMediaUrls:
|
|
5098
|
+
collectMessagingMediaUrls: collectAgentHarnessMessagingMediaUrls,
|
|
5649
5099
|
resolveMessagingMediaSourceUrls: (mediaUrls) => resolveCodexMediaSourceUrls(mediaUrls, preparedMessageMedia?.sourcePathsByStagedPath),
|
|
5650
5100
|
toolName,
|
|
5651
5101
|
args: executedArgs,
|
|
@@ -5688,11 +5138,7 @@ function createCodexDynamicToolBridge(params) {
|
|
|
5688
5138
|
runAgentHarnessAfterToolCallHook({
|
|
5689
5139
|
toolName,
|
|
5690
5140
|
toolCallId: call.callId,
|
|
5691
|
-
|
|
5692
|
-
agentId: toolResultHookContext.agentId,
|
|
5693
|
-
sessionId: toolResultHookContext.sessionId,
|
|
5694
|
-
sessionKey: toolResultHookContext.sessionKey,
|
|
5695
|
-
channelId: toolResultHookContext.channelId,
|
|
5141
|
+
...toolResultHookContext,
|
|
5696
5142
|
startArgs: executedArgs,
|
|
5697
5143
|
error: errorMessage,
|
|
5698
5144
|
startedAt
|
|
@@ -5783,91 +5229,5 @@ function isAsyncStartedToolResult(result) {
|
|
|
5783
5229
|
const details = result.details;
|
|
5784
5230
|
return isRecord(details) && details.async === true && details.status === "started";
|
|
5785
5231
|
}
|
|
5786
|
-
function sanitizeToolTextRuns(rawContent) {
|
|
5787
|
-
const content = [];
|
|
5788
|
-
for (let index = 0; index < rawContent.length;) {
|
|
5789
|
-
const item = rawContent[index];
|
|
5790
|
-
if (item.type !== "text") {
|
|
5791
|
-
content.push(item);
|
|
5792
|
-
index += 1;
|
|
5793
|
-
continue;
|
|
5794
|
-
}
|
|
5795
|
-
const textRun = [];
|
|
5796
|
-
while (index < rawContent.length) {
|
|
5797
|
-
const next = rawContent[index];
|
|
5798
|
-
if (next.type !== "text") break;
|
|
5799
|
-
textRun.push(next);
|
|
5800
|
-
index += 1;
|
|
5801
|
-
}
|
|
5802
|
-
const sanitizedText = sanitizeToolResult(textRun.map((entry) => entry.text).join(""));
|
|
5803
|
-
let offset = 0;
|
|
5804
|
-
content.push(...textRun.map((entry, runIndex) => {
|
|
5805
|
-
const targetEnd = runIndex === textRun.length - 1 ? sanitizedText.length : Math.min(sanitizedText.length, offset + entry.text.length);
|
|
5806
|
-
const text = sliceUtf16Safe(sanitizedText, offset, targetEnd);
|
|
5807
|
-
const sanitized = Object.assign({}, entry, { text });
|
|
5808
|
-
offset += text.length;
|
|
5809
|
-
return sanitized;
|
|
5810
|
-
}));
|
|
5811
|
-
}
|
|
5812
|
-
return content;
|
|
5813
|
-
}
|
|
5814
|
-
function convertToolContents(rawContent, maxChars) {
|
|
5815
|
-
const content = sanitizeToolTextRuns(rawContent);
|
|
5816
|
-
const totalTextChars = content.reduce((total, item) => total + (item.type === "text" ? item.text.length : 0), 0);
|
|
5817
|
-
if (content.reduce((total, item) => total + (item.type === "text" ? estimateToolResultTextChars(item.text) : 0), 0) <= maxChars) return content.flatMap(convertToolContent);
|
|
5818
|
-
const noticeText = `...(OpenClaw truncated dynamic tool result: original ${totalTextChars} chars, weighted budget ${maxChars}; rerun with narrower args.)`;
|
|
5819
|
-
const notice = `\n${noticeText}`;
|
|
5820
|
-
const noticeChars = estimateToolResultTextChars(notice);
|
|
5821
|
-
let remainingTextBudget = Math.max(0, maxChars - noticeChars);
|
|
5822
|
-
let appendedNotice = false;
|
|
5823
|
-
const output = [];
|
|
5824
|
-
for (const item of content) {
|
|
5825
|
-
if (item.type !== "text") {
|
|
5826
|
-
output.push(...convertToolContent(item));
|
|
5827
|
-
continue;
|
|
5828
|
-
}
|
|
5829
|
-
if (appendedNotice) continue;
|
|
5830
|
-
if (noticeChars >= maxChars) {
|
|
5831
|
-
output.push({
|
|
5832
|
-
type: "inputText",
|
|
5833
|
-
text: sliceToolResultTextToBudget(noticeText, maxChars)
|
|
5834
|
-
});
|
|
5835
|
-
appendedNotice = true;
|
|
5836
|
-
continue;
|
|
5837
|
-
}
|
|
5838
|
-
const text = sliceToolResultTextToBudget(item.text, remainingTextBudget);
|
|
5839
|
-
remainingTextBudget -= estimateToolResultTextChars(text);
|
|
5840
|
-
if (remainingTextBudget <= 0 || text.length < item.text.length) {
|
|
5841
|
-
output.push({
|
|
5842
|
-
type: "inputText",
|
|
5843
|
-
text: `${text.trimEnd()}${notice}`
|
|
5844
|
-
});
|
|
5845
|
-
appendedNotice = true;
|
|
5846
|
-
} else if (text.length > 0) output.push({
|
|
5847
|
-
type: "inputText",
|
|
5848
|
-
text
|
|
5849
|
-
});
|
|
5850
|
-
}
|
|
5851
|
-
if (!appendedNotice) output.push({
|
|
5852
|
-
type: "inputText",
|
|
5853
|
-
text: sliceToolResultTextToBudget(noticeText, maxChars)
|
|
5854
|
-
});
|
|
5855
|
-
return output;
|
|
5856
|
-
}
|
|
5857
|
-
function convertToolContent(content) {
|
|
5858
|
-
if (content.type === "text") return [{
|
|
5859
|
-
type: "inputText",
|
|
5860
|
-
text: content.text
|
|
5861
|
-
}];
|
|
5862
|
-
const imageUrl = sanitizeInlineImageDataUrl(`data:${content.mimeType};base64,${content.data}`);
|
|
5863
|
-
if (!imageUrl) return [{
|
|
5864
|
-
type: "inputText",
|
|
5865
|
-
text: invalidInlineImageText("codex dynamic tool")
|
|
5866
|
-
}];
|
|
5867
|
-
return [{
|
|
5868
|
-
type: "inputImage",
|
|
5869
|
-
imageUrl
|
|
5870
|
-
}];
|
|
5871
|
-
}
|
|
5872
5232
|
//#endregion
|
|
5873
|
-
export {
|
|
5233
|
+
export { emitDynamicToolStartedDiagnostic as a, ensureCodexSandboxExecServerEnvironment as c, CodexNativeProcessAuthority as d, readCodexRetainedBackgroundCommands as f, emitDynamicToolErrorDiagnostic as i, releaseCodexSandboxExecServerEnvironment as l, CodexNativeToolLifecycleProjector as m, projectCodexExecutableDynamicTools as n, emitDynamicToolTerminalDiagnostic as o, createCodexRemoteWorkspaceFileReader as p, routeCodexAppServerElicitationRequest as r, handleCodexAppServerApprovalRequest as s, createCodexDynamicToolBridge as t, createCodexNativePreToolUseFailureBuffer as u };
|