@openclaw/codex 2026.6.5-beta.6 → 2026.6.6-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/{client-kMCtlApt.js → client-DovmVtbr.js} +3 -10
  2. package/dist/{client-factory-Bt49r45B.js → client-factory-XajDuvQ1.js} +1 -1
  3. package/dist/{command-handlers-DMn2M7W7.js → command-handlers-DIUFKqaF.js} +11 -9
  4. package/dist/{compact-CwnPeYnM.js → compact-BWiNkDSs.js} +96 -9
  5. package/dist/{computer-use-ClweWaMz.js → computer-use-D3pi5csE.js} +3 -2
  6. package/dist/{config-BT6SLiE6.js → config-DJXpBkGf.js} +214 -13
  7. package/dist/{conversation-binding-CzpvaBs1.js → conversation-binding-CMwrZrt7.js} +190 -65
  8. package/dist/harness.js +12 -5
  9. package/dist/index.js +11 -10
  10. package/dist/media-understanding-provider.js +6 -6
  11. package/dist/{models-DXorTaja.js → models-CQGfP7nG.js} +2 -2
  12. package/dist/{native-hook-relay-DHwz_ICg.js → native-hook-relay-CmUUO3Eu.js} +160 -4
  13. package/dist/notification-correlation-D-MYfJwV.js +382 -0
  14. package/dist/{request-D64BfplD.js → plugin-app-cache-key-NpzxEcSR.js} +4 -36
  15. package/dist/protocol-oeJQu4rs.js +9 -0
  16. package/dist/{protocol-validators-CIpP8IJ2.js → protocol-validators-B48C6S9O.js} +2296 -2273
  17. package/dist/provider-Cs6kWhDQ.js +584 -0
  18. package/dist/provider.js +1 -164
  19. package/dist/request-Dq0LUOqZ.js +36 -0
  20. package/dist/{run-attempt-BWdNnok4.js → run-attempt-DG9p9ReO.js} +374 -65
  21. package/dist/{session-binding-BgTv_YGm.js → session-binding-ElbcSq2o.js} +107 -44
  22. package/dist/{shared-client-xytpSKD0.js → shared-client-CflavQ_i.js} +3 -3
  23. package/dist/{side-question-BnvBQPqW.js → side-question-Ctu2VXAG.js} +82 -26
  24. package/dist/{thread-lifecycle-BJsazZ8j.js → thread-lifecycle-Cq1-IfZB.js} +115 -34
  25. package/npm-shrinkwrap.json +30 -30
  26. package/package.json +5 -5
  27. package/dist/notification-correlation-o8quHmTK.js +0 -656
@@ -1,59 +1,40 @@
1
- import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as resolveOpenClawExecPolicyForCodexAppServer, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, m as withMcpElicitationsApprovalPolicy, o as isCodexSandboxExecServerEnabled, p as shouldAutoApproveCodexAppServerApprovals, u as resolveCodexComputerUseConfig } from "./config-BT6SLiE6.js";
2
- import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-CIpP8IJ2.js";
3
- import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-kMCtlApt.js";
4
- import { A as projectContextEngineAssemblyForCodex, C as sanitizeCodexHistoryImagePayloads, D as normalizeCodexDynamicToolName$1, E as isForcedPrivateQaCodexRuntime, M as resolveCodexContextEngineProjectionReserveTokens, T as filterCodexDynamicTools, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, j as resolveCodexContextEngineProjectionMaxChars, k as resolveCodexDynamicToolsLoadingForModel, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-BJsazZ8j.js";
5
- import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-BgTv_YGm.js";
6
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-D64BfplD.js";
7
- import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-o8quHmTK.js";
8
- import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-xytpSKD0.js";
1
+ import { _ as withMcpElicitationsApprovalPolicy, a as isCodexAppServerApprovalPolicyAllowedByRequirements, d as resolveCodexAppServerRuntimeOptions, f as resolveCodexComputerUseConfig, g as shouldAutoApproveCodexAppServerApprovals, h as resolveOpenClawExecPolicyForCodexAppServer, m as resolveCodexPluginsPolicy, p as resolveCodexModelBackedReviewerPolicyContext, s as isCodexSandboxExecServerEnabled, u as readCodexPluginConfig } from "./config-DJXpBkGf.js";
2
+ import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-B48C6S9O.js";
3
+ import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
4
+ import { i as formatCodexUsageLimitErrorMessage, o as resolveCodexUsageLimitResetAtMs, s as shouldRefreshCodexRateLimitsForUsageLimitMessage } from "./provider-Cs6kWhDQ.js";
5
+ import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, n as CodexAppServerRpcError, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-DovmVtbr.js";
6
+ import { C as defaultCodexAppInventoryCache, D as filterCodexDynamicTools, M as projectContextEngineAssemblyForCodex, N as resolveCodexContextEngineProjectionMaxChars, O as isForcedPrivateQaCodexRuntime, P as resolveCodexContextEngineProjectionReserveTokens, T as sanitizeCodexHistoryImagePayloads, _ as buildCodexPluginThreadConfigInputFingerprint, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, g as buildCodexPluginThreadConfig, h as isCodexAppServerProfilerEnabled, i as buildContextEngineBinding, j as resolveCodexDynamicToolsLoadingForModel, k as normalizeCodexDynamicToolName$1, l as isContextEngineBindingCompatible, m as startOrResumeThread, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, s as buildTurnStartParams, v as mergeCodexThreadConfigs, y as shouldBuildCodexPluginThreadConfig } from "./thread-lifecycle-Cq1-IfZB.js";
7
+ import { i as isCodexAppServerNativeAuthProfile, l as writeCodexAppServerBinding, n as clearCodexAppServerBinding, o as readCodexAppServerBinding, r as clearCodexAppServerBindingForThread } from "./session-binding-ElbcSq2o.js";
8
+ import { n as CODEX_CONTROL_METHODS, t as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-NpzxEcSR.js";
9
+ import { a as resolveCodexAppServerForModelProvider, i as readCodexNotificationTurnId, l as formatCodexDisplayText, n as isCodexNotificationForTurn, o as resolveCodexAppServerForOpenClawToolPolicy, r as readCodexNotificationThreadId, t as describeCodexNotificationCorrelation } from "./notification-correlation-D-MYfJwV.js";
10
+ import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-CflavQ_i.js";
9
11
  import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-C-Yv9uwY.js";
10
- import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-Bt49r45B.js";
11
- import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-DHwz_ICg.js";
12
- import { t as ensureCodexComputerUse } from "./computer-use-ClweWaMz.js";
12
+ import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-XajDuvQ1.js";
13
+ import { S as withCodexStartupTimeout, _ as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, a as createCodexNativeHookRelay, b as resolveCodexTurnCompletionIdleTimeoutMs, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, h as handleCodexAppServerApprovalRequest, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexStartupTimeoutMs, x as resolveCodexTurnTerminalIdleTimeoutMs, y as resolveCodexTurnAssistantCompletionIdleTimeoutMs } from "./native-hook-relay-CmUUO3Eu.js";
14
+ import { t as ensureCodexComputerUse } from "./computer-use-D3pi5csE.js";
13
15
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
14
16
  import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
15
17
  import { createHash, randomUUID } from "node:crypto";
16
18
  import fsSync from "node:fs";
19
+ import path, { posix } from "node:path";
20
+ import { markAuthProfileBlockedUntil, resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
17
21
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
18
22
  import { asBoolean, asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
19
- import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentHarnessAgentEndHook, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildBootstrapContextForFiles, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, filterProviderNormalizableTools, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
23
+ import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentHarnessAgentEndHook, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildBootstrapContextForFiles, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, filterProviderNormalizableTools, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
20
24
  import { spawn } from "node:child_process";
21
25
  import { once } from "node:events";
22
26
  import { WebSocketServer } from "ws";
23
27
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
24
28
  import fs from "node:fs/promises";
25
- import path, { posix } from "node:path";
26
29
  import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
27
- import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
28
30
  import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
29
31
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
30
32
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
31
33
  import { isIP } from "node:net";
34
+ import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
32
35
  import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
33
36
  import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
34
37
  import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
35
- //#region extensions/codex/src/app-server/app-server-policy.ts
36
- /**
37
- * Promotes implicit `never` approval policy to `untrusted` only when runtime
38
- * requirements allow OpenClaw to handle tool approvals.
39
- */
40
- function resolveCodexAppServerForOpenClawToolPolicy(params) {
41
- if (!params.shouldPromote || !params.canUseUntrustedApprovalPolicy || params.appServer.approvalPolicy !== "never") return params.appServer;
42
- const explicitMode = params.execPolicy?.mode === "full" || params.pluginConfig.appServer?.mode !== void 0 || isCodexAppServerPolicyMode(params.env.OPENCLAW_CODEX_APP_SERVER_MODE);
43
- const explicitApprovalPolicy = params.pluginConfig.appServer?.approvalPolicy !== void 0 || isCodexAppServerApprovalPolicy(params.env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY) || params.appServer.approvalPolicySource === "requirements";
44
- if (explicitMode || explicitApprovalPolicy) return params.appServer;
45
- return {
46
- ...params.appServer,
47
- approvalPolicy: "untrusted"
48
- };
49
- }
50
- function isCodexAppServerPolicyMode(value) {
51
- return value === "guardian" || value === "yolo";
52
- }
53
- function isCodexAppServerApprovalPolicy(value) {
54
- return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
55
- }
56
- //#endregion
57
38
  //#region extensions/codex/src/app-server/attempt-client-cleanup.ts
58
39
  /**
59
40
  * Best-effort cleanup helpers for timed-out or aborted Codex app-server turns.
@@ -1323,7 +1304,7 @@ async function buildDynamicTools(input) {
1323
1304
  if (params.disableTools || !supportsModelTools(params.model)) return [];
1324
1305
  const toolBuildStages = createCodexDynamicToolBuildStageTracker({ enabled: input.profilerEnabled });
1325
1306
  const modelHasVision = params.model.input?.includes("image") ?? false;
1326
- const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
1307
+ const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, input.sessionAgentId);
1327
1308
  const createOpenClawCodingTools = (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
1328
1309
  toolBuildStages.mark("load-agent-harness-tools");
1329
1310
  const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
@@ -2122,9 +2103,11 @@ const SANDBOX_HTTP_STREAM_LINE_MAX_CHARS = 256 * 1024;
2122
2103
  async function httpRequest(execServer, socket, params) {
2123
2104
  const record = requireObject(params, "http/request params");
2124
2105
  const requestId = requireString(record.requestId, "requestId");
2106
+ const url = requireString(record.url, "url");
2107
+ assertSandboxHttpRequestTargetAllowed(url);
2125
2108
  const request = {
2126
2109
  method: requireString(record.method, "method"),
2127
- url: requireString(record.url, "url"),
2110
+ url,
2128
2111
  headers: readHttpHeaders(record.headers),
2129
2112
  bodyBase64: typeof record.bodyBase64 === "string" ? record.bodyBase64 : void 0,
2130
2113
  timeoutMs: typeof record.timeoutMs === "number" && record.timeoutMs > 0 ? Math.floor(record.timeoutMs) : void 0,
@@ -2136,6 +2119,16 @@ async function httpRequest(execServer, socket, params) {
2136
2119
  streamResponse: false
2137
2120
  });
2138
2121
  }
2122
+ function assertSandboxHttpRequestTargetAllowed(url) {
2123
+ let parsed;
2124
+ try {
2125
+ parsed = new URL(url);
2126
+ } catch {
2127
+ throw new SsrFBlockedError("Invalid URL supplied to sandbox http/request");
2128
+ }
2129
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new SsrFBlockedError(`Blocked non-HTTP(S) protocol in sandbox http/request: ${parsed.protocol}`);
2130
+ if (isBlockedHostnameOrIp(parsed.hostname)) throw new SsrFBlockedError(`Blocked hostname or private/internal IP in sandbox http/request: ${parsed.hostname}`);
2131
+ }
2139
2132
  async function runSandboxHttpRequest(execServer, params) {
2140
2133
  const result = await requireBackend(execServer).runShellCommand({
2141
2134
  script: SANDBOX_HTTP_REQUEST_SCRIPT,
@@ -2284,6 +2277,8 @@ trap 'rm -f "$tmp"' EXIT
2284
2277
  cat > "$tmp" <<'PY'
2285
2278
  import base64
2286
2279
  import json
2280
+ import ipaddress
2281
+ import socket
2287
2282
  import sys
2288
2283
  import urllib.error
2289
2284
  import urllib.parse
@@ -2295,6 +2290,127 @@ def emit(payload):
2295
2290
  def response_headers(response):
2296
2291
  return [{"name": name, "value": value} for name, value in response.headers.items()]
2297
2292
 
2293
+ BLOCKED_HOSTNAMES = {
2294
+ "localhost",
2295
+ "localhost.localdomain",
2296
+ "metadata.google.internal",
2297
+ }
2298
+ CLOUD_METADATA_IP_ADDRESSES = {
2299
+ "100.100.100.200",
2300
+ "fd00:ec2::254",
2301
+ }
2302
+ BLOCKED_IPV4_NETWORKS = tuple(
2303
+ ipaddress.ip_network(network)
2304
+ for network in (
2305
+ "100.64.0.0/10",
2306
+ "198.18.0.0/15",
2307
+ )
2308
+ )
2309
+ BLOCKED_IPV6_NETWORKS = tuple(
2310
+ ipaddress.ip_network(network)
2311
+ for network in (
2312
+ "100::/64",
2313
+ "2001:2::/48",
2314
+ "2001:20::/28",
2315
+ "2001:db8::/32",
2316
+ "fec0::/10",
2317
+ )
2318
+ )
2319
+ PINNED_ADDRESSES = {}
2320
+
2321
+ def normalize_hostname(hostname):
2322
+ return (hostname or "").strip("[]").rstrip(".").lower()
2323
+
2324
+ def is_blocked_hostname(hostname):
2325
+ normalized = normalize_hostname(hostname)
2326
+ return (
2327
+ normalized in BLOCKED_HOSTNAMES
2328
+ or normalized.endswith(".localhost")
2329
+ or normalized.endswith(".local")
2330
+ or normalized.endswith(".internal")
2331
+ )
2332
+
2333
+ def is_blocked_ip(address):
2334
+ try:
2335
+ parsed = ipaddress.ip_address(address)
2336
+ except ValueError:
2337
+ return False
2338
+ embedded_ipv4 = extract_embedded_ipv4(parsed)
2339
+ if embedded_ipv4 is not None and is_blocked_ip(str(embedded_ipv4)):
2340
+ return True
2341
+ if str(parsed).lower() in CLOUD_METADATA_IP_ADDRESSES:
2342
+ return True
2343
+ if isinstance(parsed, ipaddress.IPv4Address):
2344
+ if any(parsed in network for network in BLOCKED_IPV4_NETWORKS):
2345
+ return True
2346
+ else:
2347
+ if any(parsed in network for network in BLOCKED_IPV6_NETWORKS):
2348
+ return True
2349
+ return (
2350
+ parsed.is_loopback
2351
+ or parsed.is_private
2352
+ or parsed.is_link_local
2353
+ or parsed.is_multicast
2354
+ or parsed.is_reserved
2355
+ or parsed.is_unspecified
2356
+ )
2357
+
2358
+ def ipv4_from_int(value):
2359
+ return ipaddress.IPv4Address(value & 0xffffffff)
2360
+
2361
+ def extract_embedded_ipv4(address):
2362
+ if not isinstance(address, ipaddress.IPv6Address):
2363
+ return None
2364
+ if address.ipv4_mapped is not None:
2365
+ return address.ipv4_mapped
2366
+ value = int(address)
2367
+ hextets = [(value >> shift) & 0xffff for shift in range(112, -1, -16)]
2368
+ if hextets[:6] == [0, 0, 0, 0, 0, 0]:
2369
+ return ipv4_from_int(value)
2370
+ if hextets[:6] == [0x64, 0xff9b, 0, 0, 0, 0]:
2371
+ return ipv4_from_int(value)
2372
+ if hextets[:6] == [0x64, 0xff9b, 1, 0, 0, 0]:
2373
+ return ipv4_from_int(value)
2374
+ if hextets[0] == 0x2002:
2375
+ return ipv4_from_int((hextets[1] << 16) | hextets[2])
2376
+ if hextets[0] == 0x2001 and hextets[1] == 0:
2377
+ return ipv4_from_int(((hextets[6] << 16) | hextets[7]) ^ 0xffffffff)
2378
+ if (hextets[4] & 0xfcff) == 0 and hextets[5] == 0x5efe:
2379
+ return ipv4_from_int((hextets[6] << 16) | hextets[7])
2380
+ return None
2381
+
2382
+ def assert_url_allowed(url):
2383
+ parsed = urllib.parse.urlparse(url)
2384
+ if parsed.scheme not in ("http", "https"):
2385
+ raise ValueError("http/request only supports http and https URLs")
2386
+ hostname = normalize_hostname(parsed.hostname)
2387
+ if not hostname or is_blocked_hostname(hostname) or is_blocked_ip(hostname):
2388
+ raise ValueError("Blocked hostname or private/internal/special-use IP address")
2389
+ try:
2390
+ results = socket.getaddrinfo(hostname, parsed.port, proto=socket.IPPROTO_TCP)
2391
+ except socket.gaierror as error:
2392
+ raise ValueError(f"Unable to resolve hostname: {hostname}") from error
2393
+ addresses = {entry[4][0] for entry in results if entry[4]}
2394
+ if not addresses or any(is_blocked_ip(address) for address in addresses):
2395
+ raise ValueError("Blocked: resolves to private/internal/special-use IP address")
2396
+ PINNED_ADDRESSES[hostname] = sorted(addresses)
2397
+
2398
+ class GuardedRedirectHandler(urllib.request.HTTPRedirectHandler):
2399
+ def redirect_request(self, req, fp, code, msg, headers, newurl):
2400
+ assert_url_allowed(newurl)
2401
+ return super().redirect_request(req, fp, code, msg, headers, newurl)
2402
+
2403
+ def pinned_getaddrinfo(original_getaddrinfo):
2404
+ def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
2405
+ pinned = PINNED_ADDRESSES.get(normalize_hostname(host))
2406
+ if not pinned:
2407
+ return original_getaddrinfo(host, port, family, type, proto, flags)
2408
+ results = []
2409
+ for address in pinned:
2410
+ results.extend(original_getaddrinfo(address, port, family, type, proto, flags))
2411
+ return results
2412
+ return getaddrinfo
2413
+
2298
2414
  def handle_response(input_data, response):
2299
2415
  headers = response_headers(response)
2300
2416
  status = int(getattr(response, "status", getattr(response, "code", 0)))
@@ -2324,9 +2440,7 @@ def handle_response(input_data, response):
2324
2440
  def main():
2325
2441
  input_data = json.load(sys.stdin)
2326
2442
  url = str(input_data.get("url", ""))
2327
- parsed = urllib.parse.urlparse(url)
2328
- if parsed.scheme not in ("http", "https"):
2329
- raise ValueError("http/request only supports http and https URLs")
2443
+ assert_url_allowed(url)
2330
2444
  body_base64 = input_data.get("bodyBase64")
2331
2445
  data = base64.b64decode(body_base64) if isinstance(body_base64, str) else None
2332
2446
  request = urllib.request.Request(
@@ -2340,11 +2454,16 @@ def main():
2340
2454
  timeout = None
2341
2455
  if isinstance(timeout_ms, (int, float)) and timeout_ms > 0:
2342
2456
  timeout = timeout_ms / 1000
2457
+ opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), GuardedRedirectHandler)
2458
+ original_getaddrinfo = socket.getaddrinfo
2459
+ socket.getaddrinfo = pinned_getaddrinfo(original_getaddrinfo)
2343
2460
  try:
2344
- with urllib.request.urlopen(request, timeout=timeout) as response:
2461
+ with opener.open(request, timeout=timeout) as response:
2345
2462
  handle_response(input_data, response)
2346
2463
  except urllib.error.HTTPError as response:
2347
2464
  handle_response(input_data, response)
2465
+ finally:
2466
+ socket.getaddrinfo = original_getaddrinfo
2348
2467
 
2349
2468
  if __name__ == "__main__":
2350
2469
  main()
@@ -7798,6 +7917,7 @@ function readRequestId(record) {
7798
7917
  //#region extensions/codex/src/app-server/run-attempt.ts
7799
7918
  const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
7800
7919
  const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
7920
+ const CODEX_APP_SERVER_ACTIVE_NATIVE_TURN_WAIT_TIMEOUT_MS = 3e4;
7801
7921
  const ensuredCodexWorkspaceDirs = /* @__PURE__ */ new Set();
7802
7922
  function estimateCodexAppServerProjectedTurnTokens(params) {
7803
7923
  const inputChars = params.prompt.length + (params.developerInstructions?.length ?? 0);
@@ -7836,6 +7956,43 @@ function emitCodexAppServerEvent(params, event) {
7836
7956
  embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
7837
7957
  }
7838
7958
  }
7959
+ function toTranscriptToolResult(response) {
7960
+ const sanitized = sanitizeCodexToolResponse(response);
7961
+ const contentItems = Array.isArray(sanitized.contentItems) ? sanitized.contentItems : [];
7962
+ const result = {
7963
+ ...sanitized,
7964
+ content: contentItems.map(toTranscriptToolResultContentItem)
7965
+ };
7966
+ delete result.contentItems;
7967
+ delete result.success;
7968
+ return result;
7969
+ }
7970
+ function toTranscriptToolResultContentItem(item) {
7971
+ if (!item || typeof item !== "object") return {
7972
+ type: "text",
7973
+ text: ""
7974
+ };
7975
+ const record = item;
7976
+ if (record.type === "inputText") return {
7977
+ type: "text",
7978
+ text: typeof record.text === "string" ? record.text : ""
7979
+ };
7980
+ if (record.type === "inputImage") return typeof record.imageUrl === "string" ? {
7981
+ type: "image",
7982
+ url: record.imageUrl
7983
+ } : {
7984
+ type: "text",
7985
+ text: formatUnsupportedCodexDynamicToolOutput(record.type)
7986
+ };
7987
+ return {
7988
+ type: "text",
7989
+ text: formatUnsupportedCodexDynamicToolOutput(record.type)
7990
+ };
7991
+ }
7992
+ function formatUnsupportedCodexDynamicToolOutput(type) {
7993
+ const rawType = typeof type === "string" ? type.replace(/\s+/g, " ").trim() : "";
7994
+ return `[Unsupported Codex dynamic tool output: ${rawType ? rawType.slice(0, 80) : "unknown"}${rawType.length > 80 ? "..." : ""}]`;
7995
+ }
7839
7996
  function shouldAwaitCodexAgentEndHook(params) {
7840
7997
  return !params.messageChannel && !params.messageProvider;
7841
7998
  }
@@ -7856,7 +8013,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7856
8013
  const attemptClientFactory = options.clientFactory ?? defaultLeasedCodexAppServerClientFactory;
7857
8014
  const pluginConfig = readCodexPluginConfig(options.pluginConfig);
7858
8015
  const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
7859
- const { sessionAgentId } = resolveSessionAgentIds({
8016
+ const { sessionAgentId } = resolveSessionAgentIds$1({
7860
8017
  sessionKey: params.sessionKey,
7861
8018
  config: params.config,
7862
8019
  agentId: params.agentId
@@ -7880,9 +8037,44 @@ async function runCodexAppServerAttempt(params, options = {}) {
7880
8037
  config: params.config,
7881
8038
  agentId: sessionAgentId
7882
8039
  });
7883
- const configuredAppServer = resolveCodexAppServerRuntimeOptions({
8040
+ const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId);
8041
+ preDynamicStartupStages.mark("session-agent");
8042
+ const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
8043
+ const isInactiveThreadBootstrapBinding = (binding) => !activeContextEngine && binding?.contextEngine?.projection?.mode === "thread_bootstrap";
8044
+ let startupBinding = await readCodexAppServerBinding(params.sessionFile);
8045
+ preDynamicStartupStages.mark("read-binding");
8046
+ const startupBindingAuthProfileId = startupBinding?.authProfileId;
8047
+ const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
8048
+ const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
8049
+ const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
8050
+ authProfileId: startupAuthProfileCandidate,
8051
+ store: params.authProfileStore,
8052
+ config: params.config
8053
+ }) : resolveCodexAppServerAuthProfileIdForAgent({
8054
+ authProfileId: startupAuthProfileCandidate,
8055
+ agentDir,
8056
+ config: params.config
8057
+ });
8058
+ let reviewerPolicyContext = resolveCodexModelBackedReviewerPolicyContext({
8059
+ provider: params.provider,
8060
+ model: params.modelId,
8061
+ bindingModelProvider: startupBinding?.modelProvider,
8062
+ bindingModel: startupBinding?.model,
8063
+ nativeAuthProfile: isCodexAppServerNativeAuthProfile({
8064
+ authProfileId: startupAuthProfileId,
8065
+ authProfileStore: params.authProfileStore,
8066
+ agentDir,
8067
+ config: params.config
8068
+ })
8069
+ });
8070
+ preDynamicStartupStages.mark("auth-profile");
8071
+ let configuredAppServer = resolveCodexAppServerRuntimeOptions({
7884
8072
  pluginConfig,
7885
8073
  execPolicy,
8074
+ modelProvider: reviewerPolicyContext.modelProvider,
8075
+ model: reviewerPolicyContext.model,
8076
+ config: params.config,
8077
+ agentDir,
7886
8078
  openClawSandboxActive: sandbox?.enabled === true
7887
8079
  });
7888
8080
  const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
@@ -7891,7 +8083,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7891
8083
  const effectiveCwd = sandbox?.enabled ? effectiveWorkspace : requestedCwd ?? effectiveWorkspace;
7892
8084
  await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
7893
8085
  preDynamicStartupStages.mark("effective-workspace");
7894
- const appServer = resolveCodexAppServerForOpenClawToolPolicy({
8086
+ let policyAppServer = resolveCodexAppServerForOpenClawToolPolicy({
7895
8087
  appServer: configuredAppServer,
7896
8088
  pluginConfig,
7897
8089
  env: process.env,
@@ -7899,6 +8091,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
7899
8091
  execPolicy,
7900
8092
  canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
7901
8093
  });
8094
+ let appServer = resolveCodexAppServerForModelProvider({
8095
+ appServer: policyAppServer,
8096
+ provider: reviewerPolicyContext.modelProvider,
8097
+ model: reviewerPolicyContext.model,
8098
+ config: params.config,
8099
+ env: process.env,
8100
+ agentDir
8101
+ });
7902
8102
  if (configuredAppServer.approvalPolicy === "never" && appServer.approvalPolicy === "untrusted") embeddedAgentLog.info("codex app-server approval policy promoted for OpenClaw tool policy", {
7903
8103
  from: "never",
7904
8104
  to: "untrusted",
@@ -7907,7 +8107,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
7907
8107
  });
7908
8108
  preDynamicStartupStages.mark("app-server-policy");
7909
8109
  let pluginAppServer = appServer;
7910
- const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
8110
+ let nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
7911
8111
  configuredEvents: options.nativeHookRelay?.events,
7912
8112
  appServer
7913
8113
  });
@@ -7918,14 +8118,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
7918
8118
  };
7919
8119
  if (params.abortSignal?.aborted) abortFromUpstream();
7920
8120
  else params.abortSignal?.addEventListener("abort", abortFromUpstream, { once: true });
7921
- const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
7922
- preDynamicStartupStages.mark("session-agent");
7923
- const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
7924
- const isInactiveThreadBootstrapBinding = (binding) => !activeContextEngine && binding?.contextEngine?.projection?.mode === "thread_bootstrap";
7925
- let startupBinding = await readCodexAppServerBinding(params.sessionFile);
7926
- preDynamicStartupStages.mark("read-binding");
7927
- const startupBindingAuthProfileId = startupBinding?.authProfileId;
7928
- const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
7929
8121
  startupBinding = await rotateOversizedCodexAppServerStartupBinding({
7930
8122
  binding: startupBinding,
7931
8123
  sessionFile: params.sessionFile,
@@ -7936,17 +8128,48 @@ async function runCodexAppServerAttempt(params, options = {}) {
7936
8128
  });
7937
8129
  const initialInactiveThreadBootstrapBindingForcedFreshStart = initialStartupBindingHadInactiveThreadBootstrap && !startupBinding?.threadId;
7938
8130
  preDynamicStartupStages.mark("rotate-binding");
7939
- const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
7940
- const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
7941
- authProfileId: startupAuthProfileCandidate,
7942
- store: params.authProfileStore,
7943
- config: params.config
7944
- }) : resolveCodexAppServerAuthProfileIdForAgent({
7945
- authProfileId: startupAuthProfileCandidate,
8131
+ reviewerPolicyContext = resolveCodexModelBackedReviewerPolicyContext({
8132
+ provider: params.provider,
8133
+ model: params.modelId,
8134
+ bindingModelProvider: startupBinding?.modelProvider,
8135
+ bindingModel: startupBinding?.model,
8136
+ nativeAuthProfile: isCodexAppServerNativeAuthProfile({
8137
+ authProfileId: startupAuthProfileId,
8138
+ authProfileStore: params.authProfileStore,
8139
+ agentDir,
8140
+ config: params.config
8141
+ })
8142
+ });
8143
+ configuredAppServer = resolveCodexAppServerRuntimeOptions({
8144
+ pluginConfig,
8145
+ execPolicy,
8146
+ modelProvider: reviewerPolicyContext.modelProvider,
8147
+ model: reviewerPolicyContext.model,
8148
+ config: params.config,
7946
8149
  agentDir,
7947
- config: params.config
8150
+ openClawSandboxActive: sandbox?.enabled === true
8151
+ });
8152
+ policyAppServer = resolveCodexAppServerForOpenClawToolPolicy({
8153
+ appServer: configuredAppServer,
8154
+ pluginConfig,
8155
+ env: process.env,
8156
+ shouldPromote: beforeToolCallPolicy.hasBeforeToolCallHook || beforeToolCallPolicy.trustedToolPolicies.length > 0,
8157
+ execPolicy,
8158
+ canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
8159
+ });
8160
+ appServer = resolveCodexAppServerForModelProvider({
8161
+ appServer: policyAppServer,
8162
+ provider: reviewerPolicyContext.modelProvider,
8163
+ model: reviewerPolicyContext.model,
8164
+ config: params.config,
8165
+ env: process.env,
8166
+ agentDir
8167
+ });
8168
+ pluginAppServer = appServer;
8169
+ nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
8170
+ configuredEvents: options.nativeHookRelay?.events,
8171
+ appServer
7948
8172
  });
7949
- preDynamicStartupStages.mark("auth-profile");
7950
8173
  const runtimeParams = {
7951
8174
  ...params,
7952
8175
  sessionKey: contextSessionKey,
@@ -8709,6 +8932,32 @@ async function runCodexAppServerAttempt(params, options = {}) {
8709
8932
  }
8710
8933
  }
8711
8934
  };
8935
+ let activeNativeTurnCompletionWaiter;
8936
+ const waitForActiveNativeTurnCompletion = async (turnIds) => {
8937
+ const turnIdSet = turnIds?.length ? new Set(turnIds) : void 0;
8938
+ const matchesCompletion = (notification) => isCodexThreadTurnCompletedNotification(notification, thread.threadId, turnIdSet);
8939
+ if (pendingNotifications.some((notification) => matchesCompletion(notification))) return true;
8940
+ return await new Promise((resolve) => {
8941
+ let settled = false;
8942
+ const timeoutRef = {};
8943
+ const finish = (completedNativeTurn) => {
8944
+ if (settled) return;
8945
+ settled = true;
8946
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
8947
+ runAbortController.signal.removeEventListener("abort", abortListener);
8948
+ if (activeNativeTurnCompletionWaiter?.resolve === finishComplete) activeNativeTurnCompletionWaiter = void 0;
8949
+ resolve(completedNativeTurn);
8950
+ };
8951
+ const finishComplete = () => finish(true);
8952
+ const abortListener = () => finish(false);
8953
+ timeoutRef.current = setTimeout(() => finish(false), Math.min(appServer.requestTimeoutMs, CODEX_APP_SERVER_ACTIVE_NATIVE_TURN_WAIT_TIMEOUT_MS));
8954
+ activeNativeTurnCompletionWaiter = {
8955
+ matches: matchesCompletion,
8956
+ resolve: finishComplete
8957
+ };
8958
+ runAbortController.signal.addEventListener("abort", abortListener, { once: true });
8959
+ });
8960
+ };
8712
8961
  const enqueueNotification = (notification) => {
8713
8962
  const projector = projectorRef.current;
8714
8963
  const turnId = turnIdRef.current;
@@ -8720,6 +8969,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
8720
8969
  embeddedAgentLog.trace("codex app-server raw notification received", correlation);
8721
8970
  if (notification.method === "turn/completed" && correlation.matchesActiveTurn === false) if (correlation.matchesActiveThread) embeddedAgentLog.warn("codex app-server turn/completed did not match active turn", correlation);
8722
8971
  else embeddedAgentLog.debug("codex app-server turn/completed ignored for other subscribed thread", correlation);
8972
+ if (notification.method === "turn/completed" && correlation.matchesActiveThread) {
8973
+ if (activeNativeTurnCompletionWaiter?.matches(notification)) activeNativeTurnCompletionWaiter.resolve();
8974
+ }
8723
8975
  if (isCodexNotificationOutsideActiveRun(correlation)) return Promise.resolve();
8724
8976
  if (!projector || !turnId) {
8725
8977
  userInputBridge?.handleNotification(notification);
@@ -8804,6 +9056,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
8804
9056
  threadId: thread.threadId,
8805
9057
  turnId,
8806
9058
  nativeHookRelay,
9059
+ execPolicy,
9060
+ execReviewerAgentId: sessionAgentId,
9061
+ internalExecAutoReview: appServer.approvalsReviewer === "user",
8807
9062
  autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
8808
9063
  signal: runAbortController.signal
8809
9064
  });
@@ -8914,7 +9169,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8914
9169
  toolCallId: call.callId,
8915
9170
  ...toolMeta ? { meta: toolMeta } : {},
8916
9171
  isError: !protocolResponse.success,
8917
- result: sanitizeCodexToolResponse(progressResponse)
9172
+ result: toTranscriptToolResult(progressResponse)
8918
9173
  }
8919
9174
  });
8920
9175
  }
@@ -9028,6 +9283,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
9028
9283
  promptText: codexTurnPromptText,
9029
9284
  sandboxPolicy: codexSandboxPolicy,
9030
9285
  environmentSelection: codexEnvironmentSelection,
9286
+ model: thread.model,
9287
+ modelProvider: thread.modelProvider,
9031
9288
  turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
9032
9289
  skillsCollaborationInstructions,
9033
9290
  memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
@@ -9041,6 +9298,25 @@ async function runCodexAppServerAttempt(params, options = {}) {
9041
9298
  throwIfTurnStartAcceptedAfterAbort();
9042
9299
  return startedTurn;
9043
9300
  };
9301
+ const activeNativeTurnIds = thread.lifecycle.action === "resumed" ? thread.lifecycle.activeTurnIds ?? [] : [];
9302
+ if (activeNativeTurnIds.length > 0) {
9303
+ embeddedAgentLog.info("codex app-server resumed thread has active native turn; waiting before turn/start", {
9304
+ threadId: thread.threadId,
9305
+ activeTurnIds: activeNativeTurnIds
9306
+ });
9307
+ emitCodexAppServerEvent(params, {
9308
+ stream: "codex_app_server.lifecycle",
9309
+ data: {
9310
+ phase: "turn_start_waiting_for_native_turn",
9311
+ threadId: thread.threadId,
9312
+ activeTurnIds: activeNativeTurnIds
9313
+ }
9314
+ });
9315
+ if (!await waitForActiveNativeTurnCompletion(activeNativeTurnIds) && !runAbortController.signal.aborted) embeddedAgentLog.warn("codex app-server active native turn did not complete before turn/start wait timed out", {
9316
+ threadId: thread.threadId,
9317
+ activeTurnIds: activeNativeTurnIds
9318
+ });
9319
+ }
9044
9320
  try {
9045
9321
  codexModelCallDiagnostics.emitStarted();
9046
9322
  runAgentHarnessLlmInputHook({
@@ -9058,7 +9334,24 @@ async function runCodexAppServerAttempt(params, options = {}) {
9058
9334
  turn = await startCodexTurn();
9059
9335
  } catch (error) {
9060
9336
  let turnStartError = error;
9061
- if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
9337
+ if (isCodexActiveCompactTurnError(turnStartError)) {
9338
+ embeddedAgentLog.info("codex app-server turn/start blocked by active compact turn; waiting to retry", { threadId: thread.threadId });
9339
+ if (await waitForActiveNativeTurnCompletion() && !runAbortController.signal.aborted) {
9340
+ emitCodexAppServerEvent(params, {
9341
+ stream: "codex_app_server.lifecycle",
9342
+ data: {
9343
+ phase: "turn_start_retry_after_compact",
9344
+ threadId: thread.threadId
9345
+ }
9346
+ });
9347
+ try {
9348
+ turn = await startCodexTurn();
9349
+ } catch (retryError) {
9350
+ turnStartError = retryError;
9351
+ }
9352
+ }
9353
+ }
9354
+ if (turn === void 0 && shouldUseFreshCodexThreadAfterContextEngineOverflow({
9062
9355
  error: turnStartError,
9063
9356
  contextEngineActive: Boolean(activeContextEngine),
9064
9357
  thread
@@ -9598,6 +9891,19 @@ function isCodexContextWindowError(error) {
9598
9891
  const message = formatErrorMessage(error);
9599
9892
  return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
9600
9893
  }
9894
+ function isCodexActiveCompactTurnError(error) {
9895
+ if (!(error instanceof CodexAppServerRpcError)) return false;
9896
+ const data = isJsonObject(error.data) ? error.data : void 0;
9897
+ const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
9898
+ return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
9899
+ }
9900
+ function isCodexThreadTurnCompletedNotification(notification, threadId, turnIds) {
9901
+ if (notification.method !== "turn/completed") return false;
9902
+ const correlation = describeCodexNotificationCorrelation(notification, { threadId });
9903
+ if (!correlation.matchesActiveThread) return false;
9904
+ const turnId = correlation.turnId ?? correlation.nestedTurnId;
9905
+ return !turnIds || turnId !== void 0 && turnIds.has(turnId);
9906
+ }
9601
9907
  function joinPresentSections(...sections) {
9602
9908
  return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
9603
9909
  }
@@ -9648,6 +9954,9 @@ function handleApprovalRequest(params) {
9648
9954
  threadId: params.threadId,
9649
9955
  turnId: params.turnId,
9650
9956
  nativeHookRelay: params.nativeHookRelay,
9957
+ execPolicy: params.execPolicy,
9958
+ execReviewerAgentId: params.execReviewerAgentId,
9959
+ internalExecAutoReview: params.internalExecAutoReview,
9651
9960
  autoApprove: params.autoApprove,
9652
9961
  signal: params.signal
9653
9962
  });