@openclaw/codex 2026.5.18 → 2026.5.19-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.
Files changed (24) hide show
  1. package/dist/{client-6FkrXfaz.js → client-BCJaLwdZ.js} +1 -1
  2. package/dist/{client-factory-9L6Ie1dC.js → client-factory-By1f68U_.js} +1 -1
  3. package/dist/{command-formatters-BRW7_Nu7.js → command-formatters-BpPOTePl.js} +2 -1
  4. package/dist/{command-handlers-DcoFMn4e.js → command-handlers-CFFYwpt4.js} +78 -7
  5. package/dist/{compact-UKyG6Pw2.js → compact-BPnB6ZWJ.js} +6 -6
  6. package/dist/{computer-use-UJ3dxrXF.js → computer-use-BD8UmXB-.js} +2 -2
  7. package/dist/{config-B5pq6hEz.js → config-B5rU0vP3.js} +2 -0
  8. package/dist/harness.js +8 -8
  9. package/dist/index.js +54 -10
  10. package/dist/media-understanding-provider.js +3 -3
  11. package/dist/{models-C1zn2RN0.js → models-6ViLQ-HQ.js} +1 -1
  12. package/dist/{node-cli-sessions-C9rlYMPw.js → node-cli-sessions-douLgfcf.js} +5 -5
  13. package/dist/{plugin-activation-B49xb7pI.js → plugin-activation-Dtcfb3sk.js} +65 -6
  14. package/dist/provider.js +2 -2
  15. package/dist/{request-XPjLayGw.js → request-BLCZjckr.js} +3 -3
  16. package/dist/{run-attempt-DyLQRA61.js → run-attempt-BqRPAaHk.js} +469 -118
  17. package/dist/{session-binding-DqApZIgD.js → session-binding-D9ejASYj.js} +1 -1
  18. package/dist/{shared-client-DlvmoLBJ.js → shared-client-DWgKldR5.js} +2 -2
  19. package/dist/{side-question-CfRPUq5X.js → side-question-DjyRnjPQ.js} +50 -17
  20. package/dist/test-api.js +8 -4
  21. package/dist/{thread-lifecycle-5SBrtWFl.js → thread-lifecycle-C07GnPSH.js} +141 -57
  22. package/dist/{vision-tools-BX9YuTEK.js → vision-tools-CDoJ4rDN.js} +61 -7
  23. package/openclaw.plugin.json +9 -0
  24. package/package.json +4 -4
@@ -1,26 +1,26 @@
1
- import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-B5pq6hEz.js";
1
+ import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-B5rU0vP3.js";
2
2
  import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-BGBspNmF.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
- import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-6FkrXfaz.js";
5
- import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-XPjLayGw.js";
6
- import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-BRW7_Nu7.js";
7
- import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, f as resolveCodexAppServerHomeDir, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DlvmoLBJ.js";
8
- import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DqApZIgD.js";
9
- import { a as defaultCodexAppInventoryCache } from "./plugin-activation-B49xb7pI.js";
10
- import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicTools, T as resolveCodexDynamicToolsLoading, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, w as normalizeCodexDynamicToolName, x as sanitizeCodexHistoryImagePayloads, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-5SBrtWFl.js";
11
- import { t as defaultCodexAppServerClientFactory } from "./client-factory-9L6Ie1dC.js";
12
- import { a as handleCodexAppServerElicitationRequest, i as buildCodexNativeHookRelayDisabledConfig, n as CODEX_NATIVE_HOOK_RELAY_EVENTS, o as handleCodexAppServerApprovalRequest, r as buildCodexNativeHookRelayConfig, t as filterToolsForVisionInputs } from "./vision-tools-BX9YuTEK.js";
13
- import { t as ensureCodexComputerUse } from "./computer-use-UJ3dxrXF.js";
4
+ import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-BCJaLwdZ.js";
5
+ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-BLCZjckr.js";
6
+ import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-BpPOTePl.js";
7
+ import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, f as resolveCodexAppServerHomeDir, l as resolveCodexAppServerAuthProfileId, s as refreshCodexAppServerAuthTokens, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DWgKldR5.js";
8
+ import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-D9ejASYj.js";
9
+ import { a as defaultCodexAppInventoryCache } from "./plugin-activation-Dtcfb3sk.js";
10
+ import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicTools, T as resolveCodexDynamicToolsLoading, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, w as normalizeCodexDynamicToolName, x as sanitizeCodexHistoryImagePayloads, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-C07GnPSH.js";
11
+ import { t as defaultCodexAppServerClientFactory } from "./client-factory-By1f68U_.js";
12
+ import { a as handleCodexAppServerElicitationRequest, c as emitDynamicToolTerminalDiagnostic, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerApprovalRequest, n as CODEX_NATIVE_HOOK_RELAY_EVENTS, o as emitDynamicToolErrorDiagnostic, r as buildCodexNativeHookRelayConfig, s as emitDynamicToolStartedDiagnostic, t as filterToolsForVisionInputs } from "./vision-tools-CDoJ4rDN.js";
13
+ import { t as ensureCodexComputerUse } from "./computer-use-BD8UmXB-.js";
14
14
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
15
15
  import { createHash } from "node:crypto";
16
16
  import nodeFs from "node:fs";
17
- import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
17
+ import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, compactContextEngineWithSafetyTimeout, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, hasSandboxBindContainerPathAliases, hasSandboxBindReadonlyHostShadows, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveCompactionTimeoutMs, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockOptions, resolveUserPath, resolveWritableSandboxBindHostRoots, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
18
18
  import fs from "node:fs/promises";
19
19
  import path from "node:path";
20
20
  import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
21
21
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
22
22
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
23
- import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
23
+ import { emitTrustedDiagnosticEvent, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
24
24
  import { CODEX_NATIVE_SUBAGENT_RUNTIME, CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX, CODEX_NATIVE_SUBAGENT_TASK_KIND, createRunningTaskRun, finalizeTaskRunByRunId, recordTaskRunProgressByRunId } from "openclaw/plugin-sdk/codex-native-task-runtime";
25
25
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
26
26
  //#region extensions/codex/src/app-server/local-runtime-attribution.ts
@@ -164,9 +164,27 @@ var CodexNativeSubagentTaskMirror = class {
164
164
  if (!item || readString$3(item, "type") !== "collabAgentToolCall") return;
165
165
  if (readString$3(item, "senderThreadId") !== this.params.parentThreadId) return;
166
166
  const receiverThreadIds = readStringArray(item.receiverThreadIds);
167
- if (normalizeToolName(readString$3(item, "tool")) === "spawnagent") for (const receiverThreadId of receiverThreadIds) this.createTaskFromCollabSpawnItem(receiverThreadId, item);
167
+ const isSpawnAgentTool = normalizeToolName(readString$3(item, "tool")) === "spawnagent";
168
+ if (isSpawnAgentTool) for (const receiverThreadId of receiverThreadIds) this.createTaskFromCollabSpawnItem(receiverThreadId, item);
168
169
  const agentsStates = readAgentsStates(item.agentsStates);
169
- for (const [threadId, state] of agentsStates) this.applyCollabAgentStatus(threadId, state.status, state.message);
170
+ const toolCallStatus = normalizeCollabToolCallStatus(readString$3(item, "status"));
171
+ const terminalToolCallThreadIds = /* @__PURE__ */ new Set();
172
+ if (isSpawnAgentTool && isBlockedOrFailedCollabToolCallStatus(toolCallStatus)) {
173
+ for (const threadId of receiverThreadIds) terminalToolCallThreadIds.add(threadId);
174
+ for (const threadId of agentsStates.keys()) terminalToolCallThreadIds.add(threadId);
175
+ }
176
+ const terminalAgentStateThreadIds = /* @__PURE__ */ new Set();
177
+ for (const [threadId, state] of agentsStates) {
178
+ const normalizedStatus = normalizeAgentStateStatus(state.status);
179
+ if (terminalToolCallThreadIds.has(threadId) && isNonTerminalAgentStateStatus(normalizedStatus)) continue;
180
+ this.applyCollabAgentStatus(threadId, normalizedStatus, state.message);
181
+ if (isTerminalAgentStateStatus(normalizedStatus)) terminalAgentStateThreadIds.add(threadId);
182
+ }
183
+ if (isBlockedOrFailedCollabToolCallStatus(toolCallStatus)) for (const threadId of terminalToolCallThreadIds) {
184
+ if (terminalAgentStateThreadIds.has(threadId)) continue;
185
+ const state = agentsStates.get(threadId);
186
+ this.applyCollabAgentStatus(threadId, toolCallStatus, state?.message);
187
+ }
170
188
  }
171
189
  createTaskFromCollabSpawnItem(threadId, item) {
172
190
  const normalizedThreadId = threadId.trim();
@@ -200,6 +218,7 @@ var CodexNativeSubagentTaskMirror = class {
200
218
  const normalizedStatus = normalizeAgentStateStatus(status);
201
219
  if (!normalizedStatus) return;
202
220
  const runId = codexNativeSubagentRunId(threadId);
221
+ if (this.terminalRunIds.has(runId) && isNonTerminalAgentStateStatus(normalizedStatus)) return;
203
222
  const eventAt = this.now();
204
223
  if (normalizedStatus === "pendingInit" || normalizedStatus === "running") {
205
224
  this.runtime.recordTaskRunProgressByRunId({
@@ -223,6 +242,20 @@ var CodexNativeSubagentTaskMirror = class {
223
242
  });
224
243
  return;
225
244
  }
245
+ if (normalizedStatus === "blocked") {
246
+ this.terminalRunIds.add(runId);
247
+ this.runtime.finalizeTaskRunByRunId({
248
+ runId,
249
+ runtime: CODEX_NATIVE_SUBAGENT_RUNTIME,
250
+ status: "succeeded",
251
+ endedAt: eventAt,
252
+ lastEventAt: eventAt,
253
+ progressSummary: trimOptional(message) ?? "Codex native subagent blocked.",
254
+ terminalSummary: trimOptional(message) ?? "Codex native subagent blocked.",
255
+ terminalOutcome: "blocked"
256
+ });
257
+ return;
258
+ }
226
259
  this.terminalRunIds.add(runId);
227
260
  this.runtime.finalizeTaskRunByRunId({
228
261
  runId,
@@ -293,6 +326,23 @@ function readNullableString$1(value, key) {
293
326
  function normalizeToolName(value) {
294
327
  return value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
295
328
  }
329
+ function normalizeCollabToolCallStatus(value) {
330
+ const key = value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
331
+ if (key === "completed" || key === "succeeded" || key === "success") return "completed";
332
+ if (key === "failed" || key === "error" || key === "errored") return "failed";
333
+ if (key === "blocked" || key === "declined") return "blocked";
334
+ if (key === "inprogress" || key === "running") return "running";
335
+ return value?.trim();
336
+ }
337
+ function isBlockedOrFailedCollabToolCallStatus(value) {
338
+ return value === "failed" || value === "blocked";
339
+ }
340
+ function isNonTerminalAgentStateStatus(value) {
341
+ return value === "pendingInit" || value === "running";
342
+ }
343
+ function isTerminalAgentStateStatus(value) {
344
+ return value !== void 0 && !isNonTerminalAgentStateStatus(value);
345
+ }
296
346
  function normalizeAgentStateStatus(value) {
297
347
  const key = value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
298
348
  if (!key) return;
@@ -301,6 +351,7 @@ function normalizeAgentStateStatus(value) {
301
351
  if (key === "completed" || key === "succeeded" || key === "success") return "completed";
302
352
  if (key === "interrupted" || key === "cancelled" || key === "canceled" || key === "shutdown") return key === "shutdown" ? "shutdown" : "interrupted";
303
353
  if (key === "failed" || key === "error" || key === "systemerror") return "failed";
354
+ if (key === "blocked" || key === "declined") return "blocked";
304
355
  return value?.trim();
305
356
  }
306
357
  function secondsToMillis(value) {
@@ -411,7 +462,7 @@ function buildCodexUserPromptMessage(params) {
411
462
  */
412
463
  function attachCodexMirrorIdentity(message, identity) {
413
464
  const record = message;
414
- const existing = record.__openclaw;
465
+ const existing = record["__openclaw"];
415
466
  const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
416
467
  return {
417
468
  ...record,
@@ -422,7 +473,7 @@ function attachCodexMirrorIdentity(message, identity) {
422
473
  };
423
474
  }
424
475
  function readMirrorIdentity(message) {
425
- const meta = message.__openclaw;
476
+ const meta = message["__openclaw"];
426
477
  if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
427
478
  const id = meta[MIRROR_IDENTITY_META_KEY];
428
479
  return typeof id === "string" && id.length > 0 ? id : void 0;
@@ -2311,6 +2362,7 @@ function readRequestId(record) {
2311
2362
  //#region extensions/codex/src/app-server/run-attempt.ts
2312
2363
  const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 3e4;
2313
2364
  const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
2365
+ const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
2314
2366
  const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
2315
2367
  const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
2316
2368
  const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100;
@@ -2325,6 +2377,13 @@ const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
2325
2377
  const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
2326
2378
  const LOG_FIELD_MAX_LENGTH = 160;
2327
2379
  const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
2380
+ const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set([
2381
+ "identity.md",
2382
+ "soul.md",
2383
+ "tools.md",
2384
+ "user.md"
2385
+ ]);
2386
+ const CODEX_HEARTBEAT_CONTEXT_BASENAME = "heartbeat.md";
2328
2387
  const CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS = CODEX_NATIVE_HOOK_RELAY_EVENTS.filter((event) => event !== "permission_request");
2329
2388
  const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
2330
2389
  ["soul.md", 10],
@@ -2485,9 +2544,11 @@ function toCodexTextInput(text) {
2485
2544
  function resolveCodexAppServerSandboxPolicyForOpenClawSandbox(appServer, sandbox, cwd) {
2486
2545
  if (!sandbox?.enabled || appServer.sandbox === "read-only") return;
2487
2546
  const networkAccess = codexNetworkAccessForOpenClawSandbox(sandbox);
2547
+ const writableRoots = new Set([cwd]);
2548
+ if (sandbox.backendId === "docker") for (const root of resolveWritableSandboxBindHostRoots(sandbox.docker.binds)) writableRoots.add(root);
2488
2549
  return {
2489
2550
  type: "workspaceWrite",
2490
- writableRoots: [cwd],
2551
+ writableRoots: [...writableRoots],
2491
2552
  networkAccess,
2492
2553
  excludeTmpdirEnvVar: false,
2493
2554
  excludeSlashTmp: false
@@ -2765,7 +2826,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2765
2826
  disableTools: params.disableTools,
2766
2827
  toolsAllow: params.toolsAllow
2767
2828
  });
2768
- const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(params);
2829
+ const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(params, sandbox);
2769
2830
  for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
2770
2831
  const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
2771
2832
  const hookChannelId = resolveCodexAppServerHookChannelId(params, sandboxSessionKey);
@@ -2777,6 +2838,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2777
2838
  effectiveWorkspace,
2778
2839
  sandboxSessionKey,
2779
2840
  sandbox,
2841
+ nativeToolSurfaceEnabled,
2780
2842
  runAbortController,
2781
2843
  sessionAgentId,
2782
2844
  pluginConfig,
@@ -2837,7 +2899,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
2837
2899
  });
2838
2900
  historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
2839
2901
  }
2840
- const baseDeveloperInstructions = buildDeveloperInstructions(params);
2841
2902
  const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
2842
2903
  params,
2843
2904
  resolvedWorkspace,
@@ -2845,14 +2906,19 @@ async function runCodexAppServerAttempt(params, options = {}) {
2845
2906
  sessionKey: sandboxSessionKey,
2846
2907
  sessionAgentId
2847
2908
  });
2848
- const workspaceBootstrapInstructions = workspaceBootstrapContext.instructions;
2909
+ const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(params, { dynamicTools: toolBridge.specs }), workspaceBootstrapContext.developerInstructions);
2910
+ const openClawPromptContext = buildCodexOpenClawPromptContext({
2911
+ params,
2912
+ skillsPrompt: params.skillsSnapshot?.prompt,
2913
+ workspacePromptContext: workspaceBootstrapContext.promptContext
2914
+ });
2849
2915
  let promptText = params.prompt;
2850
- let developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
2916
+ let developerInstructions = baseDeveloperInstructions;
2851
2917
  let prePromptMessageCount = historyMessages.length;
2852
2918
  let contextEngineProjection;
2853
2919
  const resetCodexPromptInputs = () => {
2854
2920
  promptText = params.prompt;
2855
- developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
2921
+ developerInstructions = baseDeveloperInstructions;
2856
2922
  prePromptMessageCount = historyMessages.length;
2857
2923
  contextEngineProjection = void 0;
2858
2924
  };
@@ -2909,7 +2975,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
2909
2975
  developerInstructionAdditionChars: projection.developerInstructionAddition?.length ?? 0
2910
2976
  });
2911
2977
  promptText = projectionDecision.project ? projection.promptText : params.prompt;
2912
- developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions, projection.developerInstructionAddition);
2978
+ developerInstructions = joinPresentSections(baseDeveloperInstructions, projection.developerInstructionAddition);
2913
2979
  prePromptMessageCount = projection.prePromptMessageCount;
2914
2980
  };
2915
2981
  if (activeContextEngine) try {
@@ -2937,19 +3003,25 @@ async function runCodexAppServerAttempt(params, options = {}) {
2937
3003
  ctx: hookContext
2938
3004
  });
2939
3005
  let promptBuild = await buildPromptFromCurrentInputs();
3006
+ const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext);
3007
+ let codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
3008
+ const refreshCodexTurnPromptText = () => {
3009
+ codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
3010
+ };
2940
3011
  const systemPromptReport = buildCodexSystemPromptReport({
2941
3012
  attempt: params,
2942
3013
  sessionKey: sandboxSessionKey,
2943
3014
  workspaceDir: effectiveWorkspace,
2944
3015
  developerInstructions: promptBuild.developerInstructions,
2945
3016
  workspaceBootstrapContext,
3017
+ skillsPrompt: openClawPromptContext ? params.skillsSnapshot?.prompt ?? "" : "",
2946
3018
  tools: toolBridge.specs
2947
3019
  });
2948
3020
  const trajectoryRecorder = createCodexTrajectoryRecorder({
2949
3021
  attempt: params,
2950
3022
  cwd: effectiveWorkspace,
2951
3023
  developerInstructions: promptBuild.developerInstructions,
2952
- prompt: promptBuild.prompt,
3024
+ prompt: codexTurnPromptText,
2953
3025
  tools: toolBridge.specs
2954
3026
  });
2955
3027
  let client;
@@ -3002,6 +3074,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
3002
3074
  }) : void 0;
3003
3075
  const resolvedPluginPolicy = pluginThreadConfigRequired ? resolveCodexPluginsPolicy(pluginThreadConfigPluginConfig) : void 0;
3004
3076
  const enabledPluginConfigKeys = resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0;
3077
+ embeddedAgentLog.info("codex plugin thread config eligibility", buildCodexPluginThreadConfigEligibilityLogData({
3078
+ sessionId: params.sessionId,
3079
+ sessionKey: sandboxSessionKey,
3080
+ pluginThreadConfigRequired,
3081
+ resolvedPluginPolicy,
3082
+ enabledPluginConfigKeys,
3083
+ pluginAppCacheKey,
3084
+ startupAuthProfileId,
3085
+ appServer
3086
+ }));
3005
3087
  pluginAppServer = resolvedPluginPolicy?.enabled === true ? {
3006
3088
  ...appServer,
3007
3089
  approvalPolicy: withMcpElicitationsApprovalPolicy(appServer.approvalPolicy)
@@ -3032,6 +3114,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3032
3114
  config: threadConfig,
3033
3115
  finalConfigPatch: nativeHookRelayConfig,
3034
3116
  nativeCodeModeEnabled: nativeToolSurfaceEnabled,
3117
+ nativeCodeModeOnlyEnabled: appServer.codeModeOnly,
3035
3118
  userMcpServersEnabled: nativeToolSurfaceEnabled,
3036
3119
  mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
3037
3120
  mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
@@ -3110,7 +3193,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3110
3193
  attempt: params,
3111
3194
  cwd: effectiveWorkspace,
3112
3195
  developerInstructions: promptBuild.developerInstructions,
3113
- prompt: promptBuild.prompt,
3196
+ prompt: codexTurnPromptText,
3114
3197
  tools: toolBridge.specs
3115
3198
  });
3116
3199
  let projector;
@@ -3156,7 +3239,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3156
3239
  let turnAttemptLastProgressDetails;
3157
3240
  let nativeHookRelayLastRenewedAt = 0;
3158
3241
  let activeAppServerTurnRequests = 0;
3159
- const activeOpenClawDynamicToolCallIds = /* @__PURE__ */ new Set();
3242
+ const pendingOpenClawDynamicToolCompletionIds = /* @__PURE__ */ new Set();
3160
3243
  const activeTurnItemIds = /* @__PURE__ */ new Set();
3161
3244
  let turnCrossedToolHandoff = false;
3162
3245
  const clearTurnCompletionIdleTimer = () => {
@@ -3465,7 +3548,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3465
3548
  };
3466
3549
  const isTerminalTurnNotificationForTurn = (notification, notificationTurnId) => {
3467
3550
  if (!isTurnNotification(notification.params, thread.threadId, notificationTurnId)) return false;
3468
- return notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
3551
+ return notification.method === "turn/completed" || isCodexTurnAbortMarkerNotification(notification, { currentPromptTexts: [codexTurnPromptText] });
3469
3552
  };
3470
3553
  const handleNotification = async (notification) => {
3471
3554
  userInputBridge?.handleNotification(notification);
@@ -3484,7 +3567,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3484
3567
  }
3485
3568
  if (isCurrentTurnNotification) updateActiveTurnItemIds(notification, activeTurnItemIds);
3486
3569
  const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnAssistantCompletionIdleWatchArmed && notification.method === "item/completed" && activeTurnItemIds.size === 0;
3487
- const trackedDynamicToolCompletion = isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds);
3570
+ const trackedDynamicToolCompletion = isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds);
3488
3571
  const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
3489
3572
  if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
3490
3573
  const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
@@ -3502,7 +3585,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
3502
3585
  else if (isCurrentTurnNotification && rawToolOutputCompletion) armTurnCompletionIdleWatch();
3503
3586
  else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) disarmTurnAssistantCompletionIdleWatch();
3504
3587
  if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
3505
- const isTurnAbortMarker = isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
3588
+ if (trackedDynamicToolCompletion) {
3589
+ const itemId = readNotificationItemId(notification);
3590
+ if (itemId) pendingOpenClawDynamicToolCompletionIds.delete(itemId);
3591
+ }
3592
+ const isTurnAbortMarker = isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptTexts: [codexTurnPromptText] });
3506
3593
  const isTurnTerminal = isTerminalTurnNotificationForTurn(notification, turnId);
3507
3594
  if (isTurnTerminal) terminalTurnNotificationQueued = true;
3508
3595
  try {
@@ -3600,7 +3687,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3600
3687
  armCompletionWatchOnResponse = true;
3601
3688
  markCurrentTurnRequestProgress();
3602
3689
  turnCrossedToolHandoff = true;
3603
- activeOpenClawDynamicToolCallIds.add(call.callId);
3690
+ pendingOpenClawDynamicToolCompletionIds.add(call.callId);
3604
3691
  trajectoryRecorder?.recordEvent("tool.call", {
3605
3692
  threadId: call.threadId,
3606
3693
  turnId: call.turnId,
@@ -3618,6 +3705,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
3618
3705
  tool: call.tool,
3619
3706
  toolCallId: call.callId
3620
3707
  });
3708
+ emitDynamicToolStartedDiagnostic({
3709
+ call,
3710
+ runId: params.runId,
3711
+ sessionId: params.sessionId,
3712
+ sessionKey: params.sessionKey
3713
+ });
3621
3714
  const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
3622
3715
  const toolArgs = sanitizeCodexToolArguments(call.arguments);
3623
3716
  const shouldEmitDynamicToolProgress = shouldEmitTranscriptToolProgress(call.tool, toolArgs);
@@ -3635,47 +3728,92 @@ async function runCodexAppServerAttempt(params, options = {}) {
3635
3728
  call,
3636
3729
  config: params.config
3637
3730
  });
3638
- const response = await handleDynamicToolCallWithTimeout({
3639
- call,
3640
- toolBridge,
3641
- signal: runAbortController.signal,
3642
- timeoutMs: dynamicToolTimeoutMs,
3643
- onTimeout: () => {
3644
- trajectoryRecorder?.recordEvent("tool.timeout", {
3645
- threadId: call.threadId,
3646
- turnId: call.turnId,
3647
- toolCallId: call.callId,
3648
- name: call.tool,
3649
- timeoutMs: dynamicToolTimeoutMs
3650
- });
3731
+ const toolStartedAt = Date.now();
3732
+ let terminalDiagnosticObserved = false;
3733
+ const unsubscribeToolDiagnosticObserver = onInternalDiagnosticEvent((event) => {
3734
+ if (isDynamicToolTerminalDiagnosticEvent(event)) {
3735
+ if (isMatchingDynamicToolTerminalDiagnostic({
3736
+ event,
3737
+ call,
3738
+ runId: params.runId,
3739
+ sessionId: params.sessionId,
3740
+ sessionKey: params.sessionKey
3741
+ })) terminalDiagnosticObserved = true;
3651
3742
  }
3652
3743
  });
3653
- trajectoryRecorder?.recordEvent("tool.result", {
3654
- threadId: call.threadId,
3655
- turnId: call.turnId,
3656
- toolCallId: call.callId,
3657
- name: call.tool,
3658
- success: response.success,
3659
- contentItems: response.contentItems
3660
- });
3661
- projector?.recordDynamicToolResult({
3662
- callId: call.callId,
3663
- tool: call.tool,
3664
- success: response.success,
3665
- contentItems: response.contentItems
3666
- });
3667
- if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
3668
- stream: "tool",
3669
- data: {
3670
- phase: "result",
3671
- name: call.tool,
3744
+ try {
3745
+ const response = await handleDynamicToolCallWithTimeout({
3746
+ call,
3747
+ toolBridge,
3748
+ signal: runAbortController.signal,
3749
+ timeoutMs: dynamicToolTimeoutMs,
3750
+ onTimeout: () => {
3751
+ trajectoryRecorder?.recordEvent("tool.timeout", {
3752
+ threadId: call.threadId,
3753
+ turnId: call.turnId,
3754
+ toolCallId: call.callId,
3755
+ name: call.tool,
3756
+ timeoutMs: dynamicToolTimeoutMs
3757
+ });
3758
+ }
3759
+ });
3760
+ const protocolResponse = toCodexDynamicToolProtocolResponse(response);
3761
+ trajectoryRecorder?.recordEvent("tool.result", {
3762
+ threadId: call.threadId,
3763
+ turnId: call.turnId,
3672
3764
  toolCallId: call.callId,
3673
- ...toolMeta ? { meta: toolMeta } : {},
3674
- isError: !response.success,
3675
- result: sanitizeCodexToolResponse(response)
3676
- }
3677
- });
3678
- return response;
3765
+ name: call.tool,
3766
+ success: protocolResponse.success,
3767
+ contentItems: protocolResponse.contentItems
3768
+ });
3769
+ projector?.recordDynamicToolResult({
3770
+ callId: call.callId,
3771
+ tool: call.tool,
3772
+ success: protocolResponse.success,
3773
+ contentItems: protocolResponse.contentItems
3774
+ });
3775
+ if (shouldEmitDynamicToolProgress) emitCodexAppServerEvent(params, {
3776
+ stream: "tool",
3777
+ data: {
3778
+ phase: "result",
3779
+ name: call.tool,
3780
+ toolCallId: call.callId,
3781
+ ...toolMeta ? { meta: toolMeta } : {},
3782
+ isError: !protocolResponse.success,
3783
+ result: sanitizeCodexToolResponse(protocolResponse)
3784
+ }
3785
+ });
3786
+ if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
3787
+ call,
3788
+ runId: params.runId,
3789
+ sessionId: params.sessionId,
3790
+ sessionKey: params.sessionKey
3791
+ })) emitDynamicToolTerminalDiagnostic({
3792
+ response,
3793
+ call,
3794
+ runId: params.runId,
3795
+ sessionId: params.sessionId,
3796
+ sessionKey: params.sessionKey,
3797
+ durationMs: Math.max(0, Date.now() - toolStartedAt)
3798
+ });
3799
+ return protocolResponse;
3800
+ } catch (error) {
3801
+ if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
3802
+ call,
3803
+ runId: params.runId,
3804
+ sessionId: params.sessionId,
3805
+ sessionKey: params.sessionKey
3806
+ })) emitDynamicToolErrorDiagnostic({
3807
+ call,
3808
+ runId: params.runId,
3809
+ sessionId: params.sessionId,
3810
+ sessionKey: params.sessionKey,
3811
+ durationMs: Math.max(0, Date.now() - toolStartedAt)
3812
+ });
3813
+ throw error;
3814
+ } finally {
3815
+ unsubscribeToolDiagnosticObserver();
3816
+ }
3679
3817
  } finally {
3680
3818
  if (requestCountsAsTurnActivity) {
3681
3819
  activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
@@ -3700,7 +3838,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3700
3838
  try {
3701
3839
  const runtimeContext = buildActiveContextEngineRuntimeContext();
3702
3840
  const overflowTokenCount = params.contextTokenBudget ?? params.contextWindowInfo?.tokens;
3703
- const compactResult = await activeContextEngine.compact({
3841
+ const compactResult = await compactContextEngineWithSafetyTimeout(activeContextEngine, {
3704
3842
  sessionId: activeSessionId,
3705
3843
  sessionKey: sandboxSessionKey,
3706
3844
  sessionFile: activeSessionFile,
@@ -3712,7 +3850,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3712
3850
  ...runtimeContext,
3713
3851
  currentTokenCount: overflowTokenCount
3714
3852
  } : runtimeContext
3715
- });
3853
+ }, resolveCompactionTimeoutMs(params.config), runAbortController.signal);
3716
3854
  embeddedAgentLog.info("codex app-server context-engine forced compaction result", {
3717
3855
  sessionId: activeSessionId,
3718
3856
  sessionKey: sandboxSessionKey,
@@ -3755,6 +3893,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3755
3893
  embeddedAgentLog.warn("context engine assemble failed after forced compaction; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
3756
3894
  }
3757
3895
  promptBuild = await buildPromptFromCurrentInputs();
3896
+ refreshCodexTurnPromptText();
3758
3897
  };
3759
3898
  const buildLlmInputEvent = () => ({
3760
3899
  runId: params.runId,
@@ -3762,21 +3901,22 @@ async function runCodexAppServerAttempt(params, options = {}) {
3762
3901
  provider: params.provider,
3763
3902
  model: params.modelId,
3764
3903
  systemPrompt: promptBuild.developerInstructions,
3765
- prompt: promptBuild.prompt,
3904
+ prompt: codexTurnPromptText,
3766
3905
  historyMessages,
3767
3906
  imagesCount: params.images?.length ?? 0
3768
3907
  });
3769
3908
  const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
3770
3909
  ...params,
3771
- prompt: promptBuild.prompt
3910
+ prompt: codexTurnPromptText
3772
3911
  })];
3773
3912
  let turn;
3774
3913
  const startCodexTurn = async () => assertCodexTurnStartResponse(await client.request("turn/start", buildTurnStartParams(params, {
3775
3914
  threadId: thread.threadId,
3776
3915
  cwd: effectiveWorkspace,
3777
3916
  appServer: pluginAppServer,
3778
- promptText: promptBuild.prompt,
3779
- sandboxPolicy: codexSandboxPolicy
3917
+ promptText: codexTurnPromptText,
3918
+ sandboxPolicy: codexSandboxPolicy,
3919
+ heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
3780
3920
  }), {
3781
3921
  timeoutMs: params.timeoutMs,
3782
3922
  signal: runAbortController.signal
@@ -3917,7 +4057,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
3917
4057
  trajectoryRecorder?.recordEvent("prompt.submitted", {
3918
4058
  threadId: thread.threadId,
3919
4059
  turnId: activeTurnId,
3920
- prompt: promptBuild.prompt,
4060
+ prompt: codexTurnPromptText,
3921
4061
  imagesCount: params.images?.length ?? 0
3922
4062
  });
3923
4063
  projector = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
@@ -4258,14 +4398,48 @@ async function handleDynamicToolCallWithTimeout(params) {
4258
4398
  }
4259
4399
  }
4260
4400
  function failedDynamicToolResponse(message) {
4261
- return {
4262
- success: false,
4401
+ const response = {
4263
4402
  contentItems: [{
4264
4403
  type: "inputText",
4265
4404
  text: message
4266
- }]
4405
+ }],
4406
+ success: false
4407
+ };
4408
+ Object.defineProperty(response, "diagnosticTerminalType", {
4409
+ configurable: true,
4410
+ enumerable: false,
4411
+ value: "error"
4412
+ });
4413
+ return response;
4414
+ }
4415
+ function toCodexDynamicToolProtocolResponse(response) {
4416
+ return {
4417
+ contentItems: response.contentItems,
4418
+ success: response.success
4267
4419
  };
4268
4420
  }
4421
+ function isDynamicToolTerminalDiagnosticEvent(event) {
4422
+ return event.type === "tool.execution.completed" || event.type === "tool.execution.error" || event.type === "tool.execution.blocked";
4423
+ }
4424
+ function isMatchingDynamicToolTerminalDiagnostic(params) {
4425
+ if (params.event.toolCallId !== params.call.callId || params.event.toolName !== params.call.tool) return false;
4426
+ if (params.runId !== void 0) return params.event.runId === params.runId;
4427
+ if (params.sessionId !== void 0) return params.event.sessionId === params.sessionId;
4428
+ if (params.sessionKey !== void 0) return params.event.sessionKey === params.sessionKey;
4429
+ return params.event.runId === void 0 && params.event.sessionId === void 0 && params.event.sessionKey === void 0;
4430
+ }
4431
+ function hasPendingDynamicToolTerminalDiagnostic(params) {
4432
+ return hasPendingInternalDiagnosticEvent((event) => {
4433
+ if (!isDynamicToolTerminalDiagnosticEvent(event)) return false;
4434
+ return isMatchingDynamicToolTerminalDiagnostic({
4435
+ event,
4436
+ call: params.call,
4437
+ runId: params.runId,
4438
+ sessionId: params.sessionId,
4439
+ sessionKey: params.sessionKey
4440
+ });
4441
+ });
4442
+ }
4269
4443
  function resolveDynamicToolCallTimeoutMs(params) {
4270
4444
  return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
4271
4445
  }
@@ -4276,8 +4450,8 @@ function readDynamicToolCallTimeoutMs(value) {
4276
4450
  function readConfiguredDynamicToolTimeoutMs(toolName, config) {
4277
4451
  if (toolName === "image_generate") {
4278
4452
  const imageGenerationModel = config?.agents?.defaults?.imageGenerationModel;
4279
- if (!imageGenerationModel || typeof imageGenerationModel !== "object") return;
4280
- return readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs);
4453
+ if (!imageGenerationModel || typeof imageGenerationModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
4454
+ return readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
4281
4455
  }
4282
4456
  if (toolName === "image") return readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds) ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS;
4283
4457
  }
@@ -4335,6 +4509,28 @@ function buildCodexNativeHookRelayId(params) {
4335
4509
  hash.update(params.sessionKey?.trim() || params.sessionId);
4336
4510
  return `codex-${hash.digest("hex").slice(0, 40)}`;
4337
4511
  }
4512
+ function fingerprintCodexLogValue(namespace, value) {
4513
+ const hash = createHash("sha256");
4514
+ hash.update(namespace);
4515
+ hash.update("\0");
4516
+ hash.update(value);
4517
+ return `sha256:${hash.digest("hex").slice(0, 16)}`;
4518
+ }
4519
+ function buildCodexPluginThreadConfigEligibilityLogData(params) {
4520
+ return {
4521
+ sessionId: params.sessionId,
4522
+ sessionKey: params.sessionKey,
4523
+ enabled: params.pluginThreadConfigRequired,
4524
+ policyConfigured: params.resolvedPluginPolicy?.configured === true,
4525
+ policyEnabled: params.resolvedPluginPolicy?.enabled === true,
4526
+ pluginConfigKeys: params.resolvedPluginPolicy?.pluginPolicies.map((plugin) => plugin.configKey).toSorted(),
4527
+ enabledPluginConfigKeys: params.enabledPluginConfigKeys,
4528
+ appCacheKeyFingerprint: fingerprintCodexLogValue("openclaw:codex:plugin-app-cache-key:v1", params.pluginAppCacheKey),
4529
+ authProfileId: params.startupAuthProfileId,
4530
+ appServerTransport: params.appServer.start.transport,
4531
+ appServerCommandSource: params.appServer.start.commandSource
4532
+ };
4533
+ }
4338
4534
  function interruptCodexTurnBestEffort(client, params) {
4339
4535
  const requestOptions = params.timeoutMs && Number.isFinite(params.timeoutMs) && params.timeoutMs > 0 ? { timeoutMs: params.timeoutMs } : void 0;
4340
4536
  const requestParams = {
@@ -4385,7 +4581,7 @@ async function buildDynamicTools(input) {
4385
4581
  const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
4386
4582
  const createOpenClawCodingTools = openClawCodingToolsFactoryForTests ?? (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
4387
4583
  const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
4388
- const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(filterCodexDynamicTools(createOpenClawCodingTools({
4584
+ const allTools = createOpenClawCodingTools({
4389
4585
  agentId: input.sessionAgentId,
4390
4586
  ...buildEmbeddedAttemptToolRunContext(params),
4391
4587
  exec: {
@@ -4417,8 +4613,9 @@ async function buildDynamicTools(input) {
4417
4613
  resolvedWorkspace: input.resolvedWorkspace
4418
4614
  }),
4419
4615
  config: params.config,
4420
- authProfileStore: params.authProfileStore,
4616
+ authProfileStore: params.toolAuthProfileStore ?? params.authProfileStore,
4421
4617
  abortSignal: input.runAbortController.signal,
4618
+ emitBeforeToolCallDiagnostics: false,
4422
4619
  modelProvider: params.model.provider,
4423
4620
  modelId: params.modelId,
4424
4621
  modelCompat: params.model.compat && typeof params.model.compat === "object" ? params.model.compat : void 0,
@@ -4450,7 +4647,8 @@ async function buildDynamicTools(input) {
4450
4647
  });
4451
4648
  input.runAbortController.abort("sessions_yield");
4452
4649
  }
4453
- }), input.pluginConfig), {
4650
+ });
4651
+ const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(addSandboxShellDynamicToolsIfAvailable(filterCodexDynamicTools(allTools, input.pluginConfig), allTools, input), {
4454
4652
  modelHasVision,
4455
4653
  hasInboundImages: (params.images?.length ?? 0) > 0
4456
4654
  }), includeForcedMessageToolAllow(params.toolsAllow, params));
@@ -4471,10 +4669,14 @@ function includeForcedMessageToolAllow(toolsAllow, params) {
4471
4669
  if (toolsAllow.length === 0) return ["message"];
4472
4670
  return new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name))).has("message") ? toolsAllow : [...toolsAllow, "message"];
4473
4671
  }
4474
- function shouldEnableCodexAppServerNativeToolSurface(params) {
4672
+ function shouldEnableCodexAppServerNativeToolSurface(params, sandbox) {
4475
4673
  const toolsAllow = includeForcedMessageToolAllow(params.toolsAllow, params);
4476
- if (toolsAllow === void 0) return true;
4477
- return hasWildcardCodexToolsAllow(toolsAllow);
4674
+ if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox);
4675
+ return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox);
4676
+ }
4677
+ function canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox) {
4678
+ if (!sandbox?.enabled || sandbox.backendId !== "docker") return true;
4679
+ return !hasSandboxBindContainerPathAliases(sandbox.docker.binds) && !hasSandboxBindReadonlyHostShadows(sandbox.docker.binds);
4478
4680
  }
4479
4681
  function disableCodexPluginThreadConfig(pluginConfig) {
4480
4682
  const config = readCodexPluginConfig(pluginConfig);
@@ -4486,18 +4688,59 @@ function disableCodexPluginThreadConfig(pluginConfig) {
4486
4688
  }
4487
4689
  };
4488
4690
  }
4691
+ function addSandboxShellDynamicToolsIfAvailable(filteredTools, allTools, input) {
4692
+ if (!shouldExposeSandboxExecDynamicTool(input) || isSandboxShellDynamicToolExcluded(input.pluginConfig)) return filteredTools;
4693
+ const execTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "exec");
4694
+ const processTool = allTools.find((tool) => normalizeCodexDynamicToolName(tool.name) === "process");
4695
+ if (!execTool || !processTool) return filteredTools;
4696
+ const sandboxExecTool = {
4697
+ ...execTool,
4698
+ name: "sandbox_exec",
4699
+ description: "Run a shell command through OpenClaw's configured sandbox backend for this session. Use only when the command must execute in the OpenClaw sandbox backend, such as an SSH-backed sandbox or Docker container-path bind layout that Codex's native shell cannot represent. Use Codex's native shell for normal local workspace commands.",
4700
+ execute: async (toolCallId, args, signal, onUpdate) => {
4701
+ const result = await execTool.execute(toolCallId, args, signal, onUpdate);
4702
+ return {
4703
+ ...result,
4704
+ content: result.content.map((item) => item.type === "text" ? Object.assign({}, item, { text: item.text.replace("Use process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.", "Use sandbox_process (list/poll/log/write/send-keys/submit/paste/kill/clear/remove) for follow-up.") }) : item)
4705
+ };
4706
+ }
4707
+ };
4708
+ const sandboxProcessTool = {
4709
+ ...processTool,
4710
+ name: "sandbox_process",
4711
+ description: "Manage sandbox_exec sessions that were started through OpenClaw's configured sandbox backend for this session: list, poll, log, write, send-keys, submit, paste, kill, clear, or remove. Use only for sandbox_exec follow-up; use Codex's native shell session handling for normal native shell commands."
4712
+ };
4713
+ return [
4714
+ ...filteredTools,
4715
+ sandboxExecTool,
4716
+ sandboxProcessTool
4717
+ ];
4718
+ }
4719
+ function shouldExposeSandboxExecDynamicTool(input) {
4720
+ const backendId = input.sandbox?.enabled ? input.sandbox.backendId.trim().toLowerCase() : "";
4721
+ return Boolean(backendId && (backendId !== "docker" || input.nativeToolSurfaceEnabled === false));
4722
+ }
4723
+ function isSandboxShellDynamicToolExcluded(config) {
4724
+ return (config.codexDynamicToolsExclude ?? []).some((name) => {
4725
+ const normalized = normalizeCodexDynamicToolName(name);
4726
+ return normalized === "exec" || normalized === "sandbox_exec" || normalized === "process" || normalized === "sandbox_process";
4727
+ });
4728
+ }
4489
4729
  function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
4490
4730
  if (!toolsAllow) return tools;
4491
4731
  if (toolsAllow.length === 0) return [];
4492
4732
  if (hasWildcardCodexToolsAllow(toolsAllow)) return tools;
4493
4733
  const allowSet = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)).filter(Boolean));
4494
- return tools.filter((tool) => allowSet.has(normalizeCodexDynamicToolName(tool.name)));
4734
+ return tools.filter((tool) => {
4735
+ const normalized = normalizeCodexDynamicToolName(tool.name);
4736
+ return allowSet.has(normalized) || normalized === "sandbox_exec" && allowSet.has("exec") || normalized === "sandbox_process" && (allowSet.has("exec") || allowSet.has("process"));
4737
+ });
4495
4738
  }
4496
4739
  function hasWildcardCodexToolsAllow(toolsAllow) {
4497
4740
  return toolsAllow.some((name) => normalizeCodexDynamicToolName(name) === "*");
4498
4741
  }
4499
4742
  function shouldForceMessageTool(params) {
4500
- return params.sourceReplyDeliveryMode === "message_tool_only";
4743
+ return params.disableMessageTool !== true && params.sourceReplyDeliveryMode === "message_tool_only";
4501
4744
  }
4502
4745
  function shouldProjectMirroredHistoryForCodexStart(params) {
4503
4746
  if (!params.historyMessages.some((message) => message.role === "user")) return false;
@@ -4759,10 +5002,10 @@ function readNotificationItemId(notification) {
4759
5002
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4760
5003
  return (item ? readString(item, "id") : void 0) ?? readString(notification.params, "itemId") ?? readString(notification.params, "id");
4761
5004
  }
4762
- function isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds) {
5005
+ function isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds) {
4763
5006
  if (notification.method !== "item/completed" || !isJsonObject(notification.params)) return false;
4764
5007
  const itemId = readNotificationItemId(notification);
4765
- if (!itemId || !activeOpenClawDynamicToolCallIds.has(itemId)) return false;
5008
+ if (!itemId || !pendingOpenClawDynamicToolCompletionIds.has(itemId)) return false;
4766
5009
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
4767
5010
  const itemType = item ? readString(item, "type") : void 0;
4768
5011
  return itemType === void 0 || itemType === "dynamicToolCall";
@@ -4840,7 +5083,8 @@ function isCodexTurnAbortMarkerNotification(notification, options = {}) {
4840
5083
  const role = isJsonObject(item) ? readString(item, "role") : void 0;
4841
5084
  if (!isJsonObject(item) || role !== "user" && role !== "developer") return false;
4842
5085
  const text = extractRawResponseItemText(item).trim();
4843
- if (role === "user" && text === options.currentPromptText?.trim()) return false;
5086
+ const currentPromptTexts = [options.currentPromptText, ...options.currentPromptTexts ?? []].filter(isNonEmptyString).map((prompt) => prompt.trim());
5087
+ if (role === "user" && currentPromptTexts.includes(text)) return false;
4844
5088
  const markerBody = readCodexTurnAbortMarkerBody(text);
4845
5089
  return markerBody === CODEX_INTERRUPTED_USER_GUIDANCE || markerBody === CODEX_INTERRUPTED_DEVELOPER_GUIDANCE;
4846
5090
  }
@@ -4889,10 +5133,18 @@ async function buildCodexWorkspaceBootstrapContext(params) {
4889
5133
  sourceWorkspaceDir: params.resolvedWorkspace,
4890
5134
  targetWorkspaceDir: params.effectiveWorkspace
4891
5135
  }));
5136
+ const promptContextFiles = selectCodexWorkspacePromptContextFiles(contextFiles);
5137
+ const developerInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceDeveloperInstructionFiles(contextFiles) : [];
5138
+ const heartbeatReferenceFiles = selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles);
4892
5139
  return {
4893
5140
  ...bootstrapContext,
4894
5141
  contextFiles,
4895
- instructions: renderCodexWorkspaceBootstrapInstructions(contextFiles)
5142
+ promptContextFiles,
5143
+ developerInstructionFiles,
5144
+ heartbeatReferenceFiles,
5145
+ promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
5146
+ developerInstructions: renderCodexWorkspaceDeveloperInstructions(developerInstructionFiles),
5147
+ heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
4896
5148
  };
4897
5149
  } catch (error) {
4898
5150
  embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
@@ -4905,7 +5157,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
4905
5157
  function buildCodexSystemPromptReport(params) {
4906
5158
  const toolEntries = params.tools.map(buildCodexToolReportEntry);
4907
5159
  const schemaChars = toolEntries.reduce((sum, tool) => sum + tool.schemaChars, 0);
4908
- const projectContextChars = params.workspaceBootstrapContext.instructions?.length ?? 0;
5160
+ const skillsPrompt = params.skillsPrompt.trim();
4909
5161
  const bootstrapMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapMaxChars);
4910
5162
  const bootstrapTotalMaxChars = readPositiveNumber(params.attempt.config?.agents?.defaults?.bootstrapTotalMaxChars);
4911
5163
  return {
@@ -4920,16 +5172,17 @@ function buildCodexSystemPromptReport(params) {
4920
5172
  ...bootstrapTotalMaxChars ? { bootstrapTotalMaxChars } : {},
4921
5173
  systemPrompt: {
4922
5174
  chars: params.developerInstructions.length,
4923
- projectContextChars,
4924
- nonProjectContextChars: Math.max(0, params.developerInstructions.length - projectContextChars)
5175
+ projectContextChars: 0,
5176
+ nonProjectContextChars: params.developerInstructions.length
4925
5177
  },
4926
5178
  injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
4927
5179
  bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
4928
- injectedFiles: params.workspaceBootstrapContext.contextFiles
5180
+ injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
5181
+ developerInstructionFiles: params.workspaceBootstrapContext.developerInstructionFiles ?? []
4929
5182
  }),
4930
5183
  skills: {
4931
- promptChars: 0,
4932
- entries: []
5184
+ promptChars: skillsPrompt.length,
5185
+ entries: buildCodexSkillReportEntries(skillsPrompt)
4933
5186
  },
4934
5187
  tools: {
4935
5188
  listChars: 0,
@@ -4938,6 +5191,13 @@ function buildCodexSystemPromptReport(params) {
4938
5191
  }
4939
5192
  };
4940
5193
  }
5194
+ function buildCodexSkillReportEntries(skillsPrompt) {
5195
+ if (!skillsPrompt) return [];
5196
+ return Array.from(skillsPrompt.matchAll(/<skill>[\s\S]*?<\/skill>/gi)).map((match) => match[0] ?? "").map((block) => ({
5197
+ name: block.match(/<name>\s*([^<]+?)\s*<\/name>/i)?.[1]?.trim() || "(unknown)",
5198
+ blockChars: block.length
5199
+ })).filter((entry) => entry.blockChars > 0);
5200
+ }
4941
5201
  function buildCodexToolReportEntry(tool) {
4942
5202
  const summary = tool.description.trim();
4943
5203
  if (tool.deferLoading === true) return {
@@ -4967,54 +5227,145 @@ function buildCodexToolSchemaStats(schema) {
4967
5227
  };
4968
5228
  }
4969
5229
  function buildCodexBootstrapInjectionStats(params) {
4970
- const injectedByPath = /* @__PURE__ */ new Map();
4971
- const injectedByBaseName = /* @__PURE__ */ new Map();
4972
- for (const file of params.injectedFiles) {
4973
- const pathValue = readNonEmptyString(file.path);
4974
- if (!pathValue) continue;
4975
- if (!injectedByPath.has(pathValue)) injectedByPath.set(pathValue, file.content);
4976
- const baseName = path.posix.basename(pathValue.replaceAll("\\", "/"));
4977
- if (!injectedByBaseName.has(baseName)) injectedByBaseName.set(baseName, file.content);
4978
- }
5230
+ const injectedIndex = indexCodexContextFileContent(params.injectedFiles);
5231
+ const developerInstructionIndex = indexCodexContextFileContent(params.developerInstructionFiles ?? []);
4979
5232
  return params.bootstrapFiles.map((file) => {
4980
5233
  const pathValue = readNonEmptyString(file.path) ?? file.name;
5234
+ const baseName = getCodexContextFileBasename(pathValue || file.name);
4981
5235
  const rawChars = file.missing ? 0 : (file.content ?? "").trimEnd().length;
4982
- const injectedChars = (injectedByPath.get(pathValue) ?? injectedByPath.get(file.name) ?? injectedByBaseName.get(file.name))?.length ?? 0;
5236
+ const injected = readCodexIndexedContextFileContent(injectedIndex, pathValue, file.name) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, file.name);
5237
+ let injectedChars = injected?.length ?? 0;
5238
+ let truncated = !file.missing && injectedChars < rawChars;
5239
+ if (injected === void 0) {
5240
+ if (CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
5241
+ injectedChars = rawChars;
5242
+ truncated = false;
5243
+ } else if (baseName === CODEX_HEARTBEAT_CONTEXT_BASENAME) {
5244
+ injectedChars = 0;
5245
+ truncated = false;
5246
+ }
5247
+ }
4983
5248
  return {
4984
5249
  name: file.name,
4985
5250
  path: pathValue,
4986
5251
  missing: file.missing,
4987
5252
  rawChars,
4988
5253
  injectedChars,
4989
- truncated: !file.missing && injectedChars < rawChars
5254
+ truncated
4990
5255
  };
4991
5256
  });
4992
5257
  }
5258
+ function indexCodexContextFileContent(files) {
5259
+ const byPath = /* @__PURE__ */ new Map();
5260
+ const byBaseName = /* @__PURE__ */ new Map();
5261
+ for (const file of files) {
5262
+ const pathValue = readNonEmptyString(file.path);
5263
+ if (!pathValue) continue;
5264
+ if (!byPath.has(pathValue)) byPath.set(pathValue, file.content);
5265
+ const baseName = getCodexContextFileBasename(pathValue);
5266
+ if (baseName && !byBaseName.has(baseName)) byBaseName.set(baseName, file.content);
5267
+ }
5268
+ return {
5269
+ byPath,
5270
+ byBaseName
5271
+ };
5272
+ }
5273
+ function readCodexIndexedContextFileContent(index, pathValue, fileName) {
5274
+ return index.byPath.get(pathValue) ?? index.byPath.get(fileName) ?? index.byBaseName.get(getCodexContextFileBasename(fileName));
5275
+ }
4993
5276
  function readPositiveNumber(value) {
4994
5277
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
4995
5278
  }
4996
5279
  function readNonEmptyString(value) {
4997
5280
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
4998
5281
  }
4999
- function renderCodexWorkspaceBootstrapInstructions(contextFiles) {
5000
- const files = contextFiles.filter((file) => {
5001
- const baseName = getCodexContextFileBasename(file.path);
5002
- return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName);
5003
- }).toSorted(compareCodexContextFiles);
5282
+ function buildCodexOpenClawPromptContext(params) {
5283
+ if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
5284
+ const sections = [params.skillsPrompt?.trim() ? [
5285
+ "## OpenClaw Skills",
5286
+ "",
5287
+ params.skillsPrompt.trim()
5288
+ ].join("\n") : void 0, params.workspacePromptContext?.trim() ? [
5289
+ "## OpenClaw Workspace Context",
5290
+ "",
5291
+ params.workspacePromptContext.trim()
5292
+ ].join("\n") : void 0].filter(isNonEmptyString);
5293
+ if (sections.length === 0) return;
5294
+ return [
5295
+ "OpenClaw runtime context for this turn:",
5296
+ "Treat this OpenClaw-provided context as supporting project/user reference for the current request.",
5297
+ "",
5298
+ ...sections
5299
+ ].join("\n");
5300
+ }
5301
+ function shouldInjectCodexOpenClawPromptContext(params) {
5302
+ return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
5303
+ }
5304
+ function prependCodexOpenClawPromptContext(prompt, context) {
5305
+ if (!context?.trim()) return prompt;
5306
+ const promptSection = prompt.startsWith("OpenClaw assembled context for this turn:") ? prompt : ["Current user request:", prompt].join("\n");
5307
+ return [
5308
+ context.trim(),
5309
+ "",
5310
+ promptSection
5311
+ ].join("\n");
5312
+ }
5313
+ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
5314
+ const files = selectCodexWorkspacePromptContextFiles(contextFiles);
5004
5315
  if (files.length === 0) return;
5005
- const hasSoulFile = files.some((file) => getCodexContextFileBasename(file.path) === "soul.md");
5006
5316
  const lines = [
5007
- "OpenClaw loaded these user-editable workspace files. Treat them as project/user context. Codex loads AGENTS.md natively, so AGENTS.md is not repeated here.",
5317
+ "OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. SOUL.md, IDENTITY.md, TOOLS.md, and USER.md are provided separately as Codex developer instructions. HEARTBEAT.md is handled by heartbeat collaboration-mode guidance. Those files are not repeated here.",
5008
5318
  "",
5009
5319
  "# Project Context",
5010
5320
  "",
5011
5321
  "The following project context files have been loaded:"
5012
5322
  ];
5013
- if (hasSoulFile) lines.push("SOUL.md: persona/tone. Follow it unless higher-priority instructions override.");
5014
5323
  lines.push("");
5015
5324
  for (const file of files) lines.push(`## ${file.path}`, "", file.content, "");
5016
5325
  return lines.join("\n").trim();
5017
5326
  }
5327
+ function selectCodexWorkspacePromptContextFiles(contextFiles) {
5328
+ return contextFiles.filter((file) => {
5329
+ const baseName = getCodexContextFileBasename(file.path);
5330
+ return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && baseName !== CODEX_HEARTBEAT_CONTEXT_BASENAME && !isMissingCodexBootstrapContextFile(file);
5331
+ }).toSorted(compareCodexContextFiles);
5332
+ }
5333
+ function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles) {
5334
+ return contextFiles.filter((file) => {
5335
+ const baseName = getCodexContextFileBasename(file.path);
5336
+ return baseName && CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
5337
+ }).toSorted(compareCodexContextFiles);
5338
+ }
5339
+ function renderCodexWorkspaceDeveloperInstructions(files) {
5340
+ if (files.length === 0) return;
5341
+ const lines = [
5342
+ "## OpenClaw Agent Soul",
5343
+ "",
5344
+ "OpenClaw loaded these workspace instruction files from the active agent workspace. They define who you are, how you work, what tools are available, and the human you work alongside. Internalize and follow them accordingly.",
5345
+ ""
5346
+ ];
5347
+ for (const file of files) lines.push(`### ${file.path}`, "", file.content, "");
5348
+ return lines.join("\n").trim();
5349
+ }
5350
+ function selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles) {
5351
+ return contextFiles.filter((file) => {
5352
+ return getCodexContextFileBasename(file.path) === CODEX_HEARTBEAT_CONTEXT_BASENAME && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
5353
+ }).toSorted(compareCodexContextFiles);
5354
+ }
5355
+ function renderCodexWorkspaceHeartbeatReference(files) {
5356
+ if (files.length === 0) return;
5357
+ const lines = [
5358
+ "## OpenClaw Heartbeat Workspace",
5359
+ "",
5360
+ "HEARTBEAT.md exists in the active agent workspace. Read it before proceeding with this heartbeat, then decide what action is appropriate.",
5361
+ ""
5362
+ ];
5363
+ for (const file of files) lines.push(`- ${file.path}`);
5364
+ return lines.join("\n").trim();
5365
+ }
5366
+ function isMissingCodexBootstrapContextFile(file) {
5367
+ return file.content.trimStart().startsWith("[MISSING] Expected at:");
5368
+ }
5018
5369
  function remapCodexContextFilePath(params) {
5019
5370
  const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
5020
5371
  if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;