@openclaw/codex 2026.5.25-beta.1 → 2026.5.26-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-SrtuTTVa.js → client-BVK_jmHW.js} +1 -1
- package/dist/client-factory-fW4Hh9q_.js +15 -0
- package/dist/{command-handlers-CLtPT37L.js → command-handlers-hYTtzAdy.js} +8 -8
- package/dist/{compact-acCua7zr.js → compact-C_1JAB4C.js} +26 -3
- package/dist/{computer-use-CVfE2Vfb.js → computer-use-DSdj1hJY.js} +2 -2
- package/dist/{config-D6TUuyo2.js → config-0-UN67Qg.js} +2 -1
- package/dist/{conversation-binding-B-GevkEb.js → conversation-binding-OjYqDwhw.js} +114 -88
- package/dist/{dynamic-tools-BXAE1U1-.js → dynamic-tools-DlEefKNQ.js} +61 -20
- package/dist/harness.js +5 -5
- package/dist/index.js +10 -9
- package/dist/media-understanding-provider.js +7 -7
- package/dist/{models-CC2IusQs.js → models-_XwpqjR8.js} +5 -4
- package/dist/{notification-correlation-D7tJW3FW.js → notification-correlation-YINts3PA.js} +1 -1
- package/dist/{protocol-validators-_gKDcd0x.js → protocol-validators-DtjYmUw_.js} +188 -441
- package/dist/provider.js +2 -2
- package/dist/{request-BO0z3vA8.js → request-OaxhR46w.js} +5 -4
- package/dist/{run-attempt-BjoI3hUJ.js → run-attempt-D8Vxo-Jm.js} +497 -176
- package/dist/{session-binding-CwNOIDP2.js → session-binding-UFjjws4k.js} +1 -1
- package/dist/{shared-client-CZP1DjaN.js → shared-client-8kIrP817.js} +167 -17
- package/dist/{side-question-Cb4COOQ9.js → side-question-DU7en3_R.js} +12 -11
- package/dist/test-api.js +3 -3
- package/dist/{thread-lifecycle-CXMd9UgJ.js → thread-lifecycle-CUXQezJL.js} +110 -22
- package/dist/{vision-tools-CETeQgze.js → vision-tools-DqpLmF5H.js} +5 -3
- package/npm-shrinkwrap.json +35 -105
- package/package.json +6 -6
- package/dist/client-factory-A7DQkSLq.js +0 -9
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as shouldAutoApproveCodexAppServerApprovals, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, o as isCodexSandboxExecServerEnabled, p as withMcpElicitationsApprovalPolicy, u as resolveCodexComputerUseConfig } from "./config-
|
|
3
|
-
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-
|
|
4
|
-
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-
|
|
5
|
-
import {
|
|
6
|
-
import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-
|
|
7
|
-
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-
|
|
8
|
-
import { g as shouldRefreshCodexRateLimitsForUsageLimitMessage, h as resolveCodexUsageLimitResetAtMs, i as readCodexNotificationTurnId, m as formatCodexUsageLimitErrorMessage, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-
|
|
9
|
-
import {
|
|
1
|
+
import { n as defaultLeasedCodexAppServerClientFactory } from "./client-factory-fW4Hh9q_.js";
|
|
2
|
+
import { c as readCodexPluginConfig, d as resolveCodexPluginsPolicy, f as shouldAutoApproveCodexAppServerApprovals, i as isCodexAppServerApprovalPolicyAllowedByRequirements, l as resolveCodexAppServerRuntimeOptions, o as isCodexSandboxExecServerEnabled, p as withMcpElicitationsApprovalPolicy, u as resolveCodexComputerUseConfig } from "./config-0-UN67Qg.js";
|
|
3
|
+
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-DtjYmUw_.js";
|
|
4
|
+
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-BVK_jmHW.js";
|
|
5
|
+
import { C as defaultCodexAppInventoryCache, D as projectContextEngineAssemblyForCodex, O as resolveCodexContextEngineProjectionMaxChars, T as sanitizeCodexHistoryImagePayloads, _ as buildCodexPluginThreadConfigInputFingerprint, a as buildDeveloperInstructions, c as buildTurnCollaborationMode, d as isContextEngineBindingCompatible, g as buildCodexPluginThreadConfig, h as isCodexAppServerProfilerEnabled, i as buildContextEngineBinding, k as resolveCodexContextEngineProjectionReserveTokens, l as buildTurnStartParams, m as startOrResumeThread, n as areCodexDynamicToolFingerprintsCompatible, u as codexDynamicToolsFingerprint, v as mergeCodexThreadConfigs, y as shouldBuildCodexPluginThreadConfig } from "./thread-lifecycle-CUXQezJL.js";
|
|
6
|
+
import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-UFjjws4k.js";
|
|
7
|
+
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-OaxhR46w.js";
|
|
8
|
+
import { g as shouldRefreshCodexRateLimitsForUsageLimitMessage, h as resolveCodexUsageLimitResetAtMs, i as readCodexNotificationTurnId, m as formatCodexUsageLimitErrorMessage, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-YINts3PA.js";
|
|
9
|
+
import { a as releaseLeasedSharedCodexAppServerClient, d as resolveCodexAppServerAuthProfileId, f as resolveCodexAppServerAuthProfileIdForAgent, l as refreshCodexAppServerAuthTokens, m as resolveCodexAppServerHomeDir, o as retireSharedCodexAppServerClientIfCurrent, p as resolveCodexAppServerFallbackApiKeyCacheKey, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerAuthAccountCacheKey } from "./shared-client-8kIrP817.js";
|
|
10
10
|
import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-CTnEWuor.js";
|
|
11
|
-
import { a as resolveCodexDynamicToolsLoading, i as normalizeCodexDynamicToolName, n as filterCodexDynamicTools, r as isForcedPrivateQaCodexRuntime, t as createCodexDynamicToolBridge } from "./dynamic-tools-
|
|
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-
|
|
13
|
-
import { t as ensureCodexComputerUse } from "./computer-use-
|
|
11
|
+
import { a as resolveCodexDynamicToolsLoading, i as normalizeCodexDynamicToolName, n as filterCodexDynamicTools, r as isForcedPrivateQaCodexRuntime, t as createCodexDynamicToolBridge } from "./dynamic-tools-DlEefKNQ.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-DqpLmF5H.js";
|
|
13
|
+
import { t as ensureCodexComputerUse } from "./computer-use-DSdj1hJY.js";
|
|
14
14
|
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-N66I-Rd7.js";
|
|
15
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
16
|
-
import
|
|
16
|
+
import fsSync from "node:fs";
|
|
17
17
|
import { asBoolean, asFiniteNumber, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
18
18
|
import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentHarnessAgentEndHook, bootstrapHarnessContextEngine, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, getBeforeToolCallPolicyDiagnosticState, 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";
|
|
19
19
|
import { spawn } from "node:child_process";
|
|
@@ -22,10 +22,10 @@ import { WebSocketServer } from "ws";
|
|
|
22
22
|
import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
23
23
|
import fs from "node:fs/promises";
|
|
24
24
|
import path, { posix } from "node:path";
|
|
25
|
+
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
25
26
|
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
26
27
|
import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
|
|
27
28
|
import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
28
|
-
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, hasPendingInternalDiagnosticEvent, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
29
29
|
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
|
|
30
30
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
31
31
|
import { isIP } from "node:net";
|
|
@@ -108,7 +108,7 @@ function buildSenderLabel(params) {
|
|
|
108
108
|
if (!params.senderId || label.includes(params.senderId)) return label;
|
|
109
109
|
return `${label} (${params.senderId})`;
|
|
110
110
|
}
|
|
111
|
-
function
|
|
111
|
+
function buildCodexUserPromptMessageFromPrepared(params, preparedUserMessage) {
|
|
112
112
|
const senderId = normalizeOptionalString(params.senderId);
|
|
113
113
|
const senderName = normalizeOptionalString(params.senderName);
|
|
114
114
|
const senderUsername = normalizeOptionalString(params.senderUsername);
|
|
@@ -120,6 +120,18 @@ function buildCodexUserPromptMessage(params) {
|
|
|
120
120
|
senderE164
|
|
121
121
|
});
|
|
122
122
|
const sourceChannel = normalizeOptionalString(params.inputProvenance?.sourceChannel ?? params.messageChannel ?? params.messageProvider);
|
|
123
|
+
if (preparedUserMessage) return {
|
|
124
|
+
role: "user",
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
...params.inputProvenance ? { provenance: params.inputProvenance } : {},
|
|
127
|
+
...sourceChannel ? { sourceChannel } : {},
|
|
128
|
+
...senderId ? { senderId } : {},
|
|
129
|
+
...senderName ? { senderName } : {},
|
|
130
|
+
...senderUsername ? { senderUsername } : {},
|
|
131
|
+
...senderE164 ? { senderE164 } : {},
|
|
132
|
+
...senderLabel ? { senderLabel } : {},
|
|
133
|
+
...preparedUserMessage
|
|
134
|
+
};
|
|
123
135
|
return {
|
|
124
136
|
role: "user",
|
|
125
137
|
content: params.prompt,
|
|
@@ -133,6 +145,12 @@ function buildCodexUserPromptMessage(params) {
|
|
|
133
145
|
...senderLabel ? { senderLabel } : {}
|
|
134
146
|
};
|
|
135
147
|
}
|
|
148
|
+
function buildCodexUserPromptMessage(params) {
|
|
149
|
+
return buildCodexUserPromptMessageFromPrepared(params, params.userTurnTranscriptRecorder?.message);
|
|
150
|
+
}
|
|
151
|
+
async function buildResolvedCodexUserPromptMessage(params) {
|
|
152
|
+
return buildCodexUserPromptMessageFromPrepared(params, await params.userTurnTranscriptRecorder?.resolveMessage() ?? params.userTurnTranscriptRecorder?.message);
|
|
153
|
+
}
|
|
136
154
|
/**
|
|
137
155
|
* Tag a message with a stable logical identity for mirror dedupe. Callers
|
|
138
156
|
* should use a value that is invariant for the same logical message across
|
|
@@ -174,24 +192,30 @@ function buildMirrorDedupeIdentity(message) {
|
|
|
174
192
|
}
|
|
175
193
|
async function mirrorCodexAppServerTranscript(params) {
|
|
176
194
|
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant" || message.role === "toolResult");
|
|
177
|
-
if (messages.length === 0) return;
|
|
195
|
+
if (messages.length === 0) return { userMessagesPresent: [] };
|
|
178
196
|
const lock = await acquireSessionWriteLock({
|
|
179
197
|
sessionFile: params.sessionFile,
|
|
180
198
|
...resolveSessionWriteLockOptions(params.config)
|
|
181
199
|
});
|
|
182
200
|
const appendedUpdates = [];
|
|
201
|
+
const userMessagesPresent = [];
|
|
183
202
|
try {
|
|
184
203
|
const mirrorState = await readTranscriptMirrorState(params.sessionFile);
|
|
185
204
|
let nextMessageSeq = mirrorState.messageCount;
|
|
186
205
|
for (const message of messages) {
|
|
187
206
|
const dedupeIdentity = buildMirrorDedupeIdentity(message);
|
|
188
207
|
const idempotencyKey = params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0;
|
|
189
|
-
|
|
208
|
+
const transcriptMessage = {
|
|
209
|
+
...message,
|
|
210
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
211
|
+
};
|
|
212
|
+
if (idempotencyKey && mirrorState.idempotencyKeys.has(idempotencyKey)) {
|
|
213
|
+
const persistedUserMessage = mirrorState.userMessagesByIdempotencyKey.get(idempotencyKey);
|
|
214
|
+
if (persistedUserMessage) userMessagesPresent.push(persistedUserMessage);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
190
217
|
const nextMessage = runAgentHarnessBeforeMessageWriteHook({
|
|
191
|
-
message:
|
|
192
|
-
...message,
|
|
193
|
-
...idempotencyKey ? { idempotencyKey } : {}
|
|
194
|
-
},
|
|
218
|
+
message: transcriptMessage,
|
|
195
219
|
agentId: params.agentId,
|
|
196
220
|
sessionKey: params.sessionKey
|
|
197
221
|
});
|
|
@@ -203,8 +227,13 @@ async function mirrorCodexAppServerTranscript(params) {
|
|
|
203
227
|
const { messageId, message: appendedMessage } = await appendSessionTranscriptMessage({
|
|
204
228
|
transcriptPath: params.sessionFile,
|
|
205
229
|
message: messageToAppend,
|
|
230
|
+
idempotencyLookup: idempotencyKey ? "caller-checked" : "scan",
|
|
206
231
|
config: params.config
|
|
207
232
|
});
|
|
233
|
+
if (appendedMessage.role === "user") {
|
|
234
|
+
userMessagesPresent.push(appendedMessage);
|
|
235
|
+
if (idempotencyKey) mirrorState.userMessagesByIdempotencyKey.set(idempotencyKey, appendedMessage);
|
|
236
|
+
}
|
|
208
237
|
nextMessageSeq += 1;
|
|
209
238
|
appendedUpdates.push({
|
|
210
239
|
messageId,
|
|
@@ -223,9 +252,11 @@ async function mirrorCodexAppServerTranscript(params) {
|
|
|
223
252
|
messageId: update.messageId,
|
|
224
253
|
messageSeq: update.messageSeq
|
|
225
254
|
});
|
|
255
|
+
return { userMessagesPresent };
|
|
226
256
|
}
|
|
227
257
|
async function readTranscriptMirrorState(sessionFile) {
|
|
228
258
|
const idempotencyKeys = /* @__PURE__ */ new Set();
|
|
259
|
+
const userMessagesByIdempotencyKey = /* @__PURE__ */ new Map();
|
|
229
260
|
let messageCount = 0;
|
|
230
261
|
let raw;
|
|
231
262
|
try {
|
|
@@ -234,7 +265,8 @@ async function readTranscriptMirrorState(sessionFile) {
|
|
|
234
265
|
if (error.code !== "ENOENT") throw error;
|
|
235
266
|
return {
|
|
236
267
|
idempotencyKeys,
|
|
237
|
-
messageCount
|
|
268
|
+
messageCount,
|
|
269
|
+
userMessagesByIdempotencyKey
|
|
238
270
|
};
|
|
239
271
|
}
|
|
240
272
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -242,14 +274,18 @@ async function readTranscriptMirrorState(sessionFile) {
|
|
|
242
274
|
try {
|
|
243
275
|
const parsed = JSON.parse(line);
|
|
244
276
|
if (parsed.type === "message") messageCount += 1;
|
|
245
|
-
if (typeof parsed.message?.idempotencyKey === "string")
|
|
277
|
+
if (typeof parsed.message?.idempotencyKey === "string") {
|
|
278
|
+
idempotencyKeys.add(parsed.message.idempotencyKey);
|
|
279
|
+
if (parsed.message.role === "user") userMessagesByIdempotencyKey.set(parsed.message.idempotencyKey, parsed.message);
|
|
280
|
+
}
|
|
246
281
|
} catch {
|
|
247
282
|
continue;
|
|
248
283
|
}
|
|
249
284
|
}
|
|
250
285
|
return {
|
|
251
286
|
idempotencyKeys,
|
|
252
|
-
messageCount
|
|
287
|
+
messageCount,
|
|
288
|
+
userMessagesByIdempotencyKey
|
|
253
289
|
};
|
|
254
290
|
}
|
|
255
291
|
//#endregion
|
|
@@ -3946,7 +3982,7 @@ const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]
|
|
|
3946
3982
|
const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
|
|
3947
3983
|
const TRAJECTORY_RUNTIME_FILE_MAX_BYTES = 50 * 1024 * 1024;
|
|
3948
3984
|
const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
|
|
3949
|
-
function resolveCodexTrajectoryPointerFlags(constants =
|
|
3985
|
+
function resolveCodexTrajectoryPointerFlags(constants = fsSync.constants) {
|
|
3950
3986
|
const noFollow = constants.O_NOFOLLOW;
|
|
3951
3987
|
return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
|
|
3952
3988
|
}
|
|
@@ -3980,23 +4016,23 @@ function writeTrajectoryPointerBestEffort(params) {
|
|
|
3980
4016
|
const pointerPath = resolveTrajectoryPointerFilePath(params.sessionFile);
|
|
3981
4017
|
try {
|
|
3982
4018
|
const pointerDir = path.resolve(path.dirname(pointerPath));
|
|
3983
|
-
if (
|
|
4019
|
+
if (fsSync.lstatSync(pointerDir).isSymbolicLink()) return;
|
|
3984
4020
|
try {
|
|
3985
|
-
if (
|
|
4021
|
+
if (fsSync.lstatSync(pointerPath).isSymbolicLink()) return;
|
|
3986
4022
|
} catch (error) {
|
|
3987
4023
|
if (error.code !== "ENOENT") return;
|
|
3988
4024
|
}
|
|
3989
|
-
const fd =
|
|
4025
|
+
const fd = fsSync.openSync(pointerPath, resolveCodexTrajectoryPointerFlags(), 384);
|
|
3990
4026
|
try {
|
|
3991
|
-
|
|
4027
|
+
fsSync.writeFileSync(fd, `${JSON.stringify({
|
|
3992
4028
|
traceSchema: "openclaw-trajectory-pointer",
|
|
3993
4029
|
schemaVersion: 1,
|
|
3994
4030
|
sessionId: params.sessionId,
|
|
3995
4031
|
runtimeFile: params.filePath
|
|
3996
4032
|
}, null, 2)}\n`, "utf8");
|
|
3997
|
-
|
|
4033
|
+
fsSync.fchmodSync(fd, 384);
|
|
3998
4034
|
} finally {
|
|
3999
|
-
|
|
4035
|
+
fsSync.closeSync(fd);
|
|
4000
4036
|
}
|
|
4001
4037
|
} catch {}
|
|
4002
4038
|
}
|
|
@@ -4312,7 +4348,7 @@ function readRequestId(record) {
|
|
|
4312
4348
|
}
|
|
4313
4349
|
//#endregion
|
|
4314
4350
|
//#region extensions/codex/src/app-server/run-attempt.ts
|
|
4315
|
-
const CODEX_DYNAMIC_TOOL_TIMEOUT_MS =
|
|
4351
|
+
const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 9e4;
|
|
4316
4352
|
const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
|
|
4317
4353
|
const CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS = 12e4;
|
|
4318
4354
|
const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
|
|
@@ -4361,6 +4397,7 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
|
|
|
4361
4397
|
["memory.md", 60],
|
|
4362
4398
|
["heartbeat.md", 70]
|
|
4363
4399
|
]);
|
|
4400
|
+
const ensuredCodexWorkspaceDirs = /* @__PURE__ */ new Set();
|
|
4364
4401
|
const pendingCodexNativeHookRelayUnregisters = /* @__PURE__ */ new Set();
|
|
4365
4402
|
function scheduleCodexNativeHookRelayUnregister(params) {
|
|
4366
4403
|
let pending;
|
|
@@ -4383,6 +4420,19 @@ function resolveCodexNativeHookRelayUnregisterGraceMs(hookTimeoutSec) {
|
|
|
4383
4420
|
const hookTimeoutMs = typeof hookTimeoutSec === "number" && Number.isFinite(hookTimeoutSec) && hookTimeoutSec > 0 ? Math.ceil(hookTimeoutSec) * 1e3 : 0;
|
|
4384
4421
|
return Math.max(CODEX_NATIVE_HOOK_RELAY_UNREGISTER_GRACE_MS, hookTimeoutMs + CODEX_NATIVE_HOOK_RELAY_UNREGISTER_EXTRA_GRACE_MS);
|
|
4385
4422
|
}
|
|
4423
|
+
async function ensureCodexWorkspaceDirOnce(workspaceDir) {
|
|
4424
|
+
const normalized = path.resolve(workspaceDir);
|
|
4425
|
+
if (ensuredCodexWorkspaceDirs.has(normalized)) {
|
|
4426
|
+
try {
|
|
4427
|
+
if ((await fs.stat(normalized)).isDirectory()) return;
|
|
4428
|
+
} catch (error) {
|
|
4429
|
+
if ((typeof error === "object" && error ? error.code : void 0) !== "ENOENT") throw error;
|
|
4430
|
+
}
|
|
4431
|
+
ensuredCodexWorkspaceDirs.delete(normalized);
|
|
4432
|
+
}
|
|
4433
|
+
await fs.mkdir(normalized, { recursive: true });
|
|
4434
|
+
ensuredCodexWorkspaceDirs.add(normalized);
|
|
4435
|
+
}
|
|
4386
4436
|
function emitCodexAppServerEvent(params, event) {
|
|
4387
4437
|
try {
|
|
4388
4438
|
emitAgentEvent({
|
|
@@ -4565,7 +4615,7 @@ function isCodexAppServerPolicyMode(value) {
|
|
|
4565
4615
|
function isCodexAppServerApprovalPolicy(value) {
|
|
4566
4616
|
return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
|
|
4567
4617
|
}
|
|
4568
|
-
const
|
|
4618
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
|
|
4569
4619
|
const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
4570
4620
|
b: 1,
|
|
4571
4621
|
k: 1024,
|
|
@@ -4653,25 +4703,29 @@ async function readCodexSessionRecordForSessionFile(sessionFile) {
|
|
|
4653
4703
|
};
|
|
4654
4704
|
}
|
|
4655
4705
|
}
|
|
4656
|
-
async function
|
|
4706
|
+
async function readCodexAppServerRolloutTokenSnapshot(file) {
|
|
4657
4707
|
let handle;
|
|
4658
4708
|
try {
|
|
4659
4709
|
handle = await fs.open(file, "r");
|
|
4660
4710
|
} catch {
|
|
4661
4711
|
return;
|
|
4662
4712
|
}
|
|
4663
|
-
let
|
|
4713
|
+
let snapshot;
|
|
4664
4714
|
try {
|
|
4665
4715
|
for await (const line of handle.readLines()) {
|
|
4666
|
-
const
|
|
4667
|
-
if (
|
|
4716
|
+
const lineSnapshot = readCodexAppServerRolloutTokenSnapshotLine(line);
|
|
4717
|
+
if (lineSnapshot !== void 0) {
|
|
4718
|
+
snapshot ??= {};
|
|
4719
|
+
if (lineSnapshot.totalTokens !== void 0) snapshot.totalTokens = lineSnapshot.totalTokens;
|
|
4720
|
+
if (lineSnapshot.modelContextWindow !== void 0) snapshot.modelContextWindow = lineSnapshot.modelContextWindow;
|
|
4721
|
+
}
|
|
4668
4722
|
}
|
|
4669
4723
|
} finally {
|
|
4670
4724
|
await handle.close();
|
|
4671
4725
|
}
|
|
4672
|
-
return
|
|
4726
|
+
return snapshot;
|
|
4673
4727
|
}
|
|
4674
|
-
function
|
|
4728
|
+
function readCodexAppServerRolloutTokenSnapshotLine(line) {
|
|
4675
4729
|
if (!line.trim()) return;
|
|
4676
4730
|
try {
|
|
4677
4731
|
const parsed = JSON.parse(line);
|
|
@@ -4680,11 +4734,20 @@ function readCodexAppServerRolloutTokenUsageLine(line) {
|
|
|
4680
4734
|
if (!info) return;
|
|
4681
4735
|
const usage = isJsonObject(info.last_token_usage) ? info.last_token_usage : isJsonObject(info.total_token_usage) ? info.total_token_usage : void 0;
|
|
4682
4736
|
const value = usage?.total_tokens ?? usage?.totalTokens;
|
|
4683
|
-
|
|
4737
|
+
const totalTokens = typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4738
|
+
const windowValue = info.model_context_window ?? info.modelContextWindow;
|
|
4739
|
+
const modelContextWindow = typeof windowValue === "number" && Number.isFinite(windowValue) && windowValue > 0 ? Math.floor(windowValue) : void 0;
|
|
4740
|
+
const snapshot = {};
|
|
4741
|
+
if (totalTokens !== void 0) snapshot.totalTokens = totalTokens;
|
|
4742
|
+
if (modelContextWindow !== void 0) snapshot.modelContextWindow = modelContextWindow;
|
|
4743
|
+
return snapshot.totalTokens !== void 0 || snapshot.modelContextWindow !== void 0 ? snapshot : void 0;
|
|
4684
4744
|
} catch {
|
|
4685
4745
|
return;
|
|
4686
4746
|
}
|
|
4687
4747
|
}
|
|
4748
|
+
function resolveCodexAppServerNativeThreadTokenFuse(modelContextWindow) {
|
|
4749
|
+
return modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
|
|
4750
|
+
}
|
|
4688
4751
|
function utf8JsonByteLength(value) {
|
|
4689
4752
|
try {
|
|
4690
4753
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -4697,10 +4760,22 @@ function maxFiniteNumber(values) {
|
|
|
4697
4760
|
if (nums.length === 0) return;
|
|
4698
4761
|
return Math.max(...nums);
|
|
4699
4762
|
}
|
|
4763
|
+
function hasContextEngineThreadBootstrapProjection(binding) {
|
|
4764
|
+
return binding.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
4765
|
+
}
|
|
4700
4766
|
async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
4701
4767
|
const binding = params.binding;
|
|
4702
4768
|
if (!binding?.threadId) return binding;
|
|
4703
4769
|
if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
|
|
4770
|
+
if (params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) {
|
|
4771
|
+
embeddedAgentLog.debug("codex app-server deferring native transcript size guard for context-engine thread bootstrap", {
|
|
4772
|
+
threadId: binding.threadId,
|
|
4773
|
+
engineId: binding.contextEngine?.engineId,
|
|
4774
|
+
epoch: binding.contextEngine?.projection?.epoch,
|
|
4775
|
+
fingerprint: binding.contextEngine?.projection?.fingerprint
|
|
4776
|
+
});
|
|
4777
|
+
return binding;
|
|
4778
|
+
}
|
|
4704
4779
|
const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
|
|
4705
4780
|
const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
|
|
4706
4781
|
const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
|
|
@@ -4719,16 +4794,20 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
4719
4794
|
return;
|
|
4720
4795
|
}
|
|
4721
4796
|
}
|
|
4722
|
-
const
|
|
4797
|
+
const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
|
|
4798
|
+
const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
|
|
4799
|
+
const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
|
|
4800
|
+
const maxTokens = resolveCodexAppServerNativeThreadTokenFuse(nativeModelContextWindow);
|
|
4723
4801
|
const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
|
|
4724
4802
|
const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
|
|
4725
|
-
if (tokenCount !== void 0 && tokenCount >=
|
|
4803
|
+
if (tokenCount !== void 0 && tokenCount >= maxTokens) {
|
|
4726
4804
|
embeddedAgentLog.warn("codex app-server native transcript exceeded active token limit; starting a fresh thread", {
|
|
4727
4805
|
threadId: binding.threadId,
|
|
4728
|
-
maxTokens
|
|
4806
|
+
maxTokens,
|
|
4729
4807
|
sessionKey: sessionRecord?.sessionKey,
|
|
4730
4808
|
sessionTokens,
|
|
4731
|
-
nativeTokens
|
|
4809
|
+
nativeTokens,
|
|
4810
|
+
nativeModelContextWindow
|
|
4732
4811
|
});
|
|
4733
4812
|
await clearCodexAppServerBinding(params.sessionFile);
|
|
4734
4813
|
return;
|
|
@@ -4747,6 +4826,7 @@ async function runCodexAgentEndHook(params, hookParams) {
|
|
|
4747
4826
|
}
|
|
4748
4827
|
async function runCodexAppServerAttempt(params, options = {}) {
|
|
4749
4828
|
const attemptStartedAt = Date.now();
|
|
4829
|
+
const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
|
|
4750
4830
|
const codexModelCallTrace = freezeDiagnosticTraceContext(createDiagnosticTraceContextFromActiveScope());
|
|
4751
4831
|
const codexModelContentCapture = resolveDiagnosticModelContentCapturePolicy(params.config);
|
|
4752
4832
|
const codexModelCallId = `${params.runId}:codex-model:1`;
|
|
@@ -4754,13 +4834,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4754
4834
|
let codexModelCallStarted = false;
|
|
4755
4835
|
let codexModelCallTerminalEmitted = false;
|
|
4756
4836
|
let codexModelCallRequestPayloadBytes;
|
|
4757
|
-
const
|
|
4837
|
+
const preDynamicStartupStages = createCodexDynamicToolBuildStageTracker({ enabled: profilerEnabled });
|
|
4838
|
+
const attemptClientFactory = options.clientFactory ?? defaultLeasedCodexAppServerClientFactory;
|
|
4758
4839
|
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
|
4759
4840
|
const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
|
|
4760
4841
|
const configuredAppServer = resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
|
4761
4842
|
const beforeToolCallPolicy = getBeforeToolCallPolicyDiagnosticState();
|
|
4843
|
+
preDynamicStartupStages.mark("config");
|
|
4762
4844
|
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
|
4763
|
-
await
|
|
4845
|
+
await ensureCodexWorkspaceDirOnce(resolvedWorkspace);
|
|
4846
|
+
preDynamicStartupStages.mark("workspace");
|
|
4764
4847
|
const sandboxSessionKey = params.sandboxSessionKey?.trim() || params.sessionKey?.trim() || params.sessionId;
|
|
4765
4848
|
const contextSessionKey = params.sessionKey?.trim() || sandboxSessionKey;
|
|
4766
4849
|
const sandbox = await resolveSandboxContext({
|
|
@@ -4768,8 +4851,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4768
4851
|
sessionKey: sandboxSessionKey,
|
|
4769
4852
|
workspaceDir: resolvedWorkspace
|
|
4770
4853
|
});
|
|
4854
|
+
preDynamicStartupStages.mark("sandbox");
|
|
4771
4855
|
const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
|
|
4772
|
-
await
|
|
4856
|
+
await ensureCodexWorkspaceDirOnce(effectiveWorkspace);
|
|
4857
|
+
preDynamicStartupStages.mark("effective-workspace");
|
|
4773
4858
|
const appServer = resolveCodexAppServerForOpenClawToolPolicy({
|
|
4774
4859
|
appServer: configuredAppServer,
|
|
4775
4860
|
pluginConfig,
|
|
@@ -4783,11 +4868,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4783
4868
|
beforeToolCallHook: beforeToolCallPolicy.hasBeforeToolCallHook,
|
|
4784
4869
|
trustedToolPolicies: beforeToolCallPolicy.trustedToolPolicies
|
|
4785
4870
|
});
|
|
4871
|
+
preDynamicStartupStages.mark("app-server-policy");
|
|
4786
4872
|
let pluginAppServer = appServer;
|
|
4787
4873
|
const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
|
|
4788
4874
|
configuredEvents: options.nativeHookRelay?.events,
|
|
4789
4875
|
appServer
|
|
4790
4876
|
});
|
|
4877
|
+
preDynamicStartupStages.mark("native-hook-relay");
|
|
4791
4878
|
const runAbortController = new AbortController();
|
|
4792
4879
|
const abortFromUpstream = () => {
|
|
4793
4880
|
runAbortController.abort(params.abortSignal?.reason ?? "upstream_abort");
|
|
@@ -4800,15 +4887,19 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4800
4887
|
agentId: params.agentId
|
|
4801
4888
|
});
|
|
4802
4889
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
4890
|
+
preDynamicStartupStages.mark("session-agent");
|
|
4803
4891
|
let startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
|
4892
|
+
preDynamicStartupStages.mark("read-binding");
|
|
4804
4893
|
const startupBindingAuthProfileId = startupBinding?.authProfileId;
|
|
4805
4894
|
startupBinding = await rotateOversizedCodexAppServerStartupBinding({
|
|
4806
4895
|
binding: startupBinding,
|
|
4807
4896
|
sessionFile: params.sessionFile,
|
|
4808
4897
|
agentDir,
|
|
4809
4898
|
codexHome: appServer.start.env?.CODEX_HOME,
|
|
4810
|
-
config: params.config
|
|
4899
|
+
config: params.config,
|
|
4900
|
+
contextEngineActive: isActiveHarnessContextEngine(params.contextEngine)
|
|
4811
4901
|
});
|
|
4902
|
+
preDynamicStartupStages.mark("rotate-binding");
|
|
4812
4903
|
const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId ?? startupBindingAuthProfileId;
|
|
4813
4904
|
const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
|
|
4814
4905
|
authProfileId: startupAuthProfileCandidate,
|
|
@@ -4819,6 +4910,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4819
4910
|
agentDir,
|
|
4820
4911
|
config: params.config
|
|
4821
4912
|
});
|
|
4913
|
+
preDynamicStartupStages.mark("auth-profile");
|
|
4822
4914
|
const runtimeParams = {
|
|
4823
4915
|
...params,
|
|
4824
4916
|
sessionKey: contextSessionKey,
|
|
@@ -4837,12 +4929,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4837
4929
|
agentDir,
|
|
4838
4930
|
config: params.config
|
|
4839
4931
|
});
|
|
4840
|
-
const startupEnvApiKeyCacheKey = startupAuthProfileId ? void 0 :
|
|
4932
|
+
const startupEnvApiKeyCacheKey = startupAuthProfileId ? void 0 : resolveCodexAppServerFallbackApiKeyCacheKey({ startOptions: appServer.start });
|
|
4933
|
+
preDynamicStartupStages.mark("auth-cache");
|
|
4841
4934
|
const nodeExecBlocksNativeExecution = isCodexNativeExecutionBlockedByNodeExecHost(params, {
|
|
4842
4935
|
agentId: sessionAgentId,
|
|
4843
4936
|
runtimeSessionKey: sandboxSessionKey,
|
|
4844
4937
|
sandbox
|
|
4845
4938
|
});
|
|
4939
|
+
preDynamicStartupStages.mark("native-exec-policy");
|
|
4846
4940
|
const bundleMcpThreadConfig = await loadCodexBundleMcpThreadConfig({
|
|
4847
4941
|
workspaceDir: effectiveWorkspace,
|
|
4848
4942
|
cfg: params.config,
|
|
@@ -4850,12 +4944,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4850
4944
|
disableTools: params.disableTools,
|
|
4851
4945
|
toolsAllow: nodeExecBlocksNativeExecution ? [] : params.toolsAllow
|
|
4852
4946
|
});
|
|
4947
|
+
preDynamicStartupStages.mark("bundle-mcp");
|
|
4853
4948
|
const sandboxExecServerEnabled = isCodexSandboxExecServerEnabled(pluginConfig);
|
|
4854
4949
|
const nativeToolSurfaceEnabled = shouldEnableCodexAppServerNativeToolSurface(params, sandbox, {
|
|
4855
4950
|
agentId: sessionAgentId,
|
|
4856
4951
|
runtimeSessionKey: sandboxSessionKey,
|
|
4857
4952
|
sandboxExecServerEnabled
|
|
4858
4953
|
});
|
|
4954
|
+
preDynamicStartupStages.mark("native-tool-surface");
|
|
4859
4955
|
for (const diagnostic of bundleMcpThreadConfig.diagnostics) embeddedAgentLog.warn(`bundle-mcp: ${diagnostic.pluginId}: ${diagnostic.message}`);
|
|
4860
4956
|
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
4861
4957
|
if (activeContextEngine) assertContextEngineHostSupport({
|
|
@@ -4864,6 +4960,18 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4864
4960
|
host: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST
|
|
4865
4961
|
});
|
|
4866
4962
|
const hookChannelId = resolveCodexAppServerHookChannelId(params, sandboxSessionKey);
|
|
4963
|
+
preDynamicStartupStages.mark("context-engine-support");
|
|
4964
|
+
const preDynamicSummary = preDynamicStartupStages.snapshot();
|
|
4965
|
+
if (shouldWarnCodexDynamicToolBuildStageSummary(preDynamicSummary)) embeddedAgentLog.warn(`codex app-server pre-dynamic startup timings runId=${params.runId} sessionId=${params.sessionId} totalMs=${preDynamicSummary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(preDynamicSummary)}`, {
|
|
4966
|
+
runId: params.runId,
|
|
4967
|
+
sessionId: params.sessionId,
|
|
4968
|
+
totalMs: preDynamicSummary.totalMs,
|
|
4969
|
+
stages: preDynamicSummary.stages,
|
|
4970
|
+
hasStartupBinding: Boolean(startupBinding?.threadId),
|
|
4971
|
+
startupAuthProfileId: startupAuthProfileId ?? null,
|
|
4972
|
+
bundleMcpDiagnosticCount: bundleMcpThreadConfig.diagnostics.length,
|
|
4973
|
+
nativeToolSurfaceEnabled
|
|
4974
|
+
});
|
|
4867
4975
|
let yieldDetected = false;
|
|
4868
4976
|
const tools = await buildDynamicTools({
|
|
4869
4977
|
params,
|
|
@@ -4875,6 +4983,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4875
4983
|
runAbortController,
|
|
4876
4984
|
sessionAgentId,
|
|
4877
4985
|
pluginConfig,
|
|
4986
|
+
profilerEnabled,
|
|
4878
4987
|
onYieldDetected: () => {
|
|
4879
4988
|
yieldDetected = true;
|
|
4880
4989
|
}
|
|
@@ -4891,6 +5000,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
4891
5000
|
runAbortController,
|
|
4892
5001
|
sessionAgentId,
|
|
4893
5002
|
pluginConfig,
|
|
5003
|
+
profilerEnabled,
|
|
4894
5004
|
forceHeartbeatTool: true,
|
|
4895
5005
|
ignoreRuntimePlan: true,
|
|
4896
5006
|
onYieldDetected: () => {
|
|
@@ -5076,6 +5186,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
5076
5186
|
let thread;
|
|
5077
5187
|
let trajectoryEndRecorded = false;
|
|
5078
5188
|
let nativeHookRelay;
|
|
5189
|
+
let releaseSharedClientLease;
|
|
5079
5190
|
let startupClientForCleanup;
|
|
5080
5191
|
let sandboxExecEnvironmentAcquired = false;
|
|
5081
5192
|
const releaseSandboxExecEnvironment = async () => {
|
|
@@ -5159,106 +5270,120 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
5159
5270
|
operation: async () => {
|
|
5160
5271
|
let attemptedClient;
|
|
5161
5272
|
const startupAttempt = async () => {
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
startupClientForCleanup = startupClient;
|
|
5165
|
-
await ensureCodexComputerUse({
|
|
5166
|
-
client: startupClient,
|
|
5167
|
-
pluginConfig,
|
|
5168
|
-
timeoutMs: appServer.requestTimeoutMs,
|
|
5169
|
-
signal: runAbortController.signal
|
|
5170
|
-
});
|
|
5171
|
-
let startupSandboxEnvironment;
|
|
5172
|
-
let startupSandboxEnvironmentAcquired = false;
|
|
5173
|
-
const releaseStartupSandboxEnvironment = async () => {
|
|
5174
|
-
if (startupSandboxEnvironmentAcquired) {
|
|
5175
|
-
startupSandboxEnvironmentAcquired = false;
|
|
5176
|
-
await releaseCodexSandboxExecServerEnvironment(sandbox);
|
|
5177
|
-
}
|
|
5178
|
-
};
|
|
5179
|
-
releaseStartupResourcesOnTimeout = releaseStartupSandboxEnvironment;
|
|
5273
|
+
let startupClientLease;
|
|
5274
|
+
let startupAttemptSucceeded = false;
|
|
5180
5275
|
try {
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5276
|
+
const startupClient = await attemptClientFactory(appServer.start, startupAuthProfileId, agentDir, params.config);
|
|
5277
|
+
startupClientLease = () => {
|
|
5278
|
+
releaseLeasedSharedCodexAppServerClient(startupClient);
|
|
5279
|
+
};
|
|
5280
|
+
releaseSharedClientLease = startupClientLease;
|
|
5281
|
+
attemptedClient = startupClient;
|
|
5282
|
+
startupClientForCleanup = startupClient;
|
|
5283
|
+
await ensureCodexComputerUse({
|
|
5186
5284
|
client: startupClient,
|
|
5187
|
-
|
|
5188
|
-
appServerStartOptions: appServer.start,
|
|
5285
|
+
pluginConfig,
|
|
5189
5286
|
timeoutMs: appServer.requestTimeoutMs,
|
|
5190
5287
|
signal: runAbortController.signal
|
|
5191
|
-
})
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
nativeCodeModeOnlyEnabled: appServer.codeModeOnly,
|
|
5221
|
-
userMcpServersEnabled: nativeToolSurfaceEnabled,
|
|
5222
|
-
mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
|
|
5223
|
-
mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
|
|
5224
|
-
environmentSelection: startupEnvironmentSelection,
|
|
5225
|
-
contextEngineProjection,
|
|
5226
|
-
pluginThreadConfig: pluginThreadConfigRequired ? {
|
|
5227
|
-
enabled: true,
|
|
5228
|
-
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
5229
|
-
enabledPluginConfigKeys,
|
|
5230
|
-
build: () => buildCodexPluginThreadConfig({
|
|
5231
|
-
pluginConfig: pluginThreadConfigPluginConfig,
|
|
5232
|
-
request: (method, requestParams) => startupClient.request(method, requestParams, {
|
|
5233
|
-
timeoutMs: appServer.requestTimeoutMs,
|
|
5234
|
-
signal: runAbortController.signal
|
|
5235
|
-
}),
|
|
5236
|
-
appCache: defaultCodexAppInventoryCache,
|
|
5237
|
-
appCacheKey: pluginAppCacheKey
|
|
5238
|
-
})
|
|
5239
|
-
} : void 0
|
|
5240
|
-
});
|
|
5241
|
-
try {
|
|
5242
|
-
restartContextEngineCodexThread = () => startOrResumeThread(buildThreadLifecycleParams());
|
|
5243
|
-
const startupThread = await startOrResumeThread(buildThreadLifecycleParams());
|
|
5244
|
-
if (runAbortController.signal.aborted) {
|
|
5288
|
+
});
|
|
5289
|
+
let startupSandboxEnvironment;
|
|
5290
|
+
let startupSandboxEnvironmentAcquired = false;
|
|
5291
|
+
const releaseStartupSandboxEnvironment = async () => {
|
|
5292
|
+
if (startupSandboxEnvironmentAcquired) {
|
|
5293
|
+
startupSandboxEnvironmentAcquired = false;
|
|
5294
|
+
await releaseCodexSandboxExecServerEnvironment(sandbox);
|
|
5295
|
+
}
|
|
5296
|
+
};
|
|
5297
|
+
releaseStartupResourcesOnTimeout = releaseStartupSandboxEnvironment;
|
|
5298
|
+
try {
|
|
5299
|
+
startupSandboxEnvironment = shouldRequireCodexSandboxExecServerEnvironment({
|
|
5300
|
+
sandbox,
|
|
5301
|
+
nativeToolSurfaceEnabled,
|
|
5302
|
+
sandboxExecServerEnabled
|
|
5303
|
+
}) ? await ensureCodexSandboxExecServerEnvironment({
|
|
5304
|
+
client: startupClient,
|
|
5305
|
+
sandbox: sandbox ?? null,
|
|
5306
|
+
appServerStartOptions: appServer.start,
|
|
5307
|
+
timeoutMs: appServer.requestTimeoutMs,
|
|
5308
|
+
signal: runAbortController.signal
|
|
5309
|
+
}) : void 0;
|
|
5310
|
+
startupSandboxEnvironmentAcquired = Boolean(startupSandboxEnvironment);
|
|
5311
|
+
if (runAbortController.signal.aborted) {
|
|
5312
|
+
await releaseStartupSandboxEnvironment();
|
|
5313
|
+
throw new Error("codex app-server startup aborted");
|
|
5314
|
+
}
|
|
5315
|
+
if (sandbox?.enabled && nativeToolSurfaceEnabled && sandboxExecServerEnabled && !startupSandboxEnvironment) throw new Error("Codex app-server did not register an OpenClaw sandbox exec-server environment.");
|
|
5316
|
+
} catch (error) {
|
|
5245
5317
|
await releaseStartupSandboxEnvironment();
|
|
5246
|
-
throw
|
|
5318
|
+
throw error;
|
|
5247
5319
|
}
|
|
5248
|
-
|
|
5249
|
-
|
|
5320
|
+
const startupEnvironmentSelection = resolveCodexSandboxEnvironmentSelection(startupSandboxEnvironment, nativeToolSurfaceEnabled);
|
|
5321
|
+
const startupExecutionCwd = resolveCodexAppServerExecutionCwd({
|
|
5322
|
+
effectiveWorkspace,
|
|
5323
|
+
environment: startupSandboxEnvironment,
|
|
5324
|
+
nativeToolSurfaceEnabled
|
|
5325
|
+
});
|
|
5326
|
+
const startupSandboxPolicy = startupSandboxEnvironment ? resolveCodexExternalSandboxPolicyForOpenClawSandbox(sandbox) : void 0;
|
|
5327
|
+
const buildThreadLifecycleParams = () => ({
|
|
5250
5328
|
client: startupClient,
|
|
5251
|
-
|
|
5252
|
-
|
|
5329
|
+
params: buildActiveRunAttemptParams(),
|
|
5330
|
+
agentId: sessionAgentId,
|
|
5331
|
+
cwd: startupExecutionCwd,
|
|
5332
|
+
dynamicTools: toolBridge.specs,
|
|
5333
|
+
appServer: pluginAppServer,
|
|
5334
|
+
developerInstructions: promptBuild.developerInstructions,
|
|
5335
|
+
config: threadConfig,
|
|
5336
|
+
finalConfigPatch: nativeHookRelayConfig,
|
|
5337
|
+
nativeCodeModeEnabled: nativeToolSurfaceEnabled,
|
|
5338
|
+
nativeCodeModeOnlyEnabled: appServer.codeModeOnly,
|
|
5339
|
+
userMcpServersEnabled: nativeToolSurfaceEnabled,
|
|
5340
|
+
mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
|
|
5341
|
+
mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
|
|
5253
5342
|
environmentSelection: startupEnvironmentSelection,
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5343
|
+
contextEngineProjection,
|
|
5344
|
+
pluginThreadConfig: pluginThreadConfigRequired ? {
|
|
5345
|
+
enabled: true,
|
|
5346
|
+
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
5347
|
+
enabledPluginConfigKeys,
|
|
5348
|
+
build: () => buildCodexPluginThreadConfig({
|
|
5349
|
+
pluginConfig: pluginThreadConfigPluginConfig,
|
|
5350
|
+
request: (method, requestParams) => startupClient.request(method, requestParams, {
|
|
5351
|
+
timeoutMs: appServer.requestTimeoutMs,
|
|
5352
|
+
signal: runAbortController.signal
|
|
5353
|
+
}),
|
|
5354
|
+
appCache: defaultCodexAppInventoryCache,
|
|
5355
|
+
appCacheKey: pluginAppCacheKey
|
|
5356
|
+
})
|
|
5357
|
+
} : void 0
|
|
5358
|
+
});
|
|
5359
|
+
try {
|
|
5360
|
+
restartContextEngineCodexThread = () => startOrResumeThread(buildThreadLifecycleParams());
|
|
5361
|
+
const startupThread = await startOrResumeThread(buildThreadLifecycleParams());
|
|
5362
|
+
if (runAbortController.signal.aborted) {
|
|
5363
|
+
await releaseStartupSandboxEnvironment();
|
|
5364
|
+
throw new Error("codex app-server startup aborted");
|
|
5365
|
+
}
|
|
5366
|
+
startupSandboxEnvironmentAcquired = false;
|
|
5367
|
+
startupAttemptSucceeded = true;
|
|
5368
|
+
return {
|
|
5369
|
+
client: startupClient,
|
|
5370
|
+
thread: startupThread,
|
|
5371
|
+
sandboxEnvironment: startupSandboxEnvironment,
|
|
5372
|
+
environmentSelection: startupEnvironmentSelection,
|
|
5373
|
+
executionCwd: startupExecutionCwd,
|
|
5374
|
+
sandboxPolicy: startupSandboxPolicy
|
|
5375
|
+
};
|
|
5376
|
+
} catch (error) {
|
|
5377
|
+
await releaseStartupSandboxEnvironment();
|
|
5378
|
+
throw error;
|
|
5379
|
+
} finally {
|
|
5380
|
+
if (releaseStartupResourcesOnTimeout === releaseStartupSandboxEnvironment) releaseStartupResourcesOnTimeout = void 0;
|
|
5381
|
+
}
|
|
5260
5382
|
} finally {
|
|
5261
|
-
if (
|
|
5383
|
+
if (!startupAttemptSucceeded) {
|
|
5384
|
+
if (releaseSharedClientLease === startupClientLease) releaseSharedClientLease = void 0;
|
|
5385
|
+
startupClientLease?.();
|
|
5386
|
+
}
|
|
5262
5387
|
}
|
|
5263
5388
|
};
|
|
5264
5389
|
for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS; attempt += 1) try {
|
|
@@ -5465,7 +5590,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
5465
5590
|
runAbortController.abort("turn_progress_idle_timeout");
|
|
5466
5591
|
};
|
|
5467
5592
|
const fireTurnCompletionIdleTimeout = () => {
|
|
5468
|
-
if (completed || runAbortController.signal.aborted || !turnCompletionIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
5593
|
+
if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted || !turnCompletionIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
5469
5594
|
const timeoutMs = turnCompletionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
5470
5595
|
const idleMs = Math.max(0, Date.now() - turnCompletionLastActivityAt);
|
|
5471
5596
|
if (idleMs < timeoutMs) {
|
|
@@ -5495,7 +5620,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
5495
5620
|
runAbortController.abort("turn_completion_idle_timeout");
|
|
5496
5621
|
};
|
|
5497
5622
|
const fireTurnTerminalIdleTimeout = () => {
|
|
5498
|
-
if (completed || runAbortController.signal.aborted || !turnTerminalIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
5623
|
+
if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted || !turnTerminalIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
5499
5624
|
const idleMs = Math.max(0, Date.now() - turnCompletionLastActivityAt);
|
|
5500
5625
|
if (idleMs < turnTerminalIdleTimeoutMs) {
|
|
5501
5626
|
scheduleTurnTerminalIdleWatch();
|
|
@@ -5817,14 +5942,23 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
5817
5942
|
threadId: thread.threadId,
|
|
5818
5943
|
...turnId ? { turnId } : {}
|
|
5819
5944
|
});
|
|
5820
|
-
embeddedAgentLog.
|
|
5821
|
-
if (notification.method === "turn/completed" && correlation.matchesActiveTurn === false) embeddedAgentLog.warn("codex app-server turn/completed did not match active turn", correlation);
|
|
5945
|
+
embeddedAgentLog.trace("codex app-server raw notification received", correlation);
|
|
5946
|
+
if (notification.method === "turn/completed" && correlation.matchesActiveTurn === false) if (correlation.matchesActiveThread) embeddedAgentLog.warn("codex app-server turn/completed did not match active turn", correlation);
|
|
5947
|
+
else embeddedAgentLog.debug("codex app-server turn/completed ignored for other subscribed thread", correlation);
|
|
5948
|
+
if (isCodexNotificationOutsideActiveRun(correlation)) return Promise.resolve();
|
|
5822
5949
|
if (!projector || !turnId) {
|
|
5823
5950
|
userInputBridge?.handleNotification(notification);
|
|
5824
5951
|
pendingNotifications.push(notification);
|
|
5825
5952
|
return Promise.resolve();
|
|
5826
5953
|
}
|
|
5827
5954
|
if (isTerminalTurnNotificationForTurn(notification, turnId)) terminalTurnNotificationQueued = true;
|
|
5955
|
+
if (correlation.matchesActiveTurn !== false) {
|
|
5956
|
+
const now = Date.now();
|
|
5957
|
+
turnCompletionLastActivityAt = now;
|
|
5958
|
+
turnCompletionLastActivityReason = `notification:${notification.method}`;
|
|
5959
|
+
turnAttemptLastProgressAt = now;
|
|
5960
|
+
turnAttemptLastProgressReason = `notification:${notification.method}`;
|
|
5961
|
+
}
|
|
5828
5962
|
notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
|
|
5829
5963
|
return notificationQueue;
|
|
5830
5964
|
};
|
|
@@ -6276,6 +6410,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6276
6410
|
}
|
|
6277
6411
|
});
|
|
6278
6412
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
6413
|
+
releaseSharedClientLease?.();
|
|
6414
|
+
releaseSharedClientLease = void 0;
|
|
6279
6415
|
if (usageLimitError) {
|
|
6280
6416
|
await markCodexAuthProfileBlockedFromRateLimits({
|
|
6281
6417
|
params,
|
|
@@ -6292,7 +6428,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6292
6428
|
throw turnStartError;
|
|
6293
6429
|
}
|
|
6294
6430
|
}
|
|
6295
|
-
if (!turn)
|
|
6431
|
+
if (!turn) {
|
|
6432
|
+
releaseSharedClientLease?.();
|
|
6433
|
+
releaseSharedClientLease = void 0;
|
|
6434
|
+
throw new Error("codex app-server turn/start failed without an error");
|
|
6435
|
+
}
|
|
6296
6436
|
turnId = turn.turn.id;
|
|
6297
6437
|
const activeTurnId = turn.turn.id;
|
|
6298
6438
|
emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
|
|
@@ -6364,9 +6504,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6364
6504
|
abort: () => runAbortController.abort("aborted")
|
|
6365
6505
|
};
|
|
6366
6506
|
setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
|
|
6507
|
+
const notifyUserMessagePersisted = createCodexAppServerUserMessagePersistenceNotifier(params);
|
|
6367
6508
|
mirrorPromptAtTurnStartBestEffort({
|
|
6368
6509
|
params,
|
|
6369
6510
|
agentId: sessionAgentId,
|
|
6511
|
+
notifyUserMessagePersisted,
|
|
6370
6512
|
sessionKey: sandboxSessionKey,
|
|
6371
6513
|
threadId: thread.threadId,
|
|
6372
6514
|
turnId: activeTurnId
|
|
@@ -6375,16 +6517,19 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6375
6517
|
turnTerminalIdleWatchArmed = true;
|
|
6376
6518
|
touchTurnCompletionActivity("turn:start", { attemptProgress: true });
|
|
6377
6519
|
const abortListener = () => {
|
|
6378
|
-
|
|
6520
|
+
if (timedOut) {
|
|
6521
|
+
retireCodexAppServerClientAfterTimedOutTurn(client, {
|
|
6522
|
+
threadId: thread.threadId,
|
|
6523
|
+
turnId: activeTurnId,
|
|
6524
|
+
reason: String(runAbortController.signal.reason ?? "timeout")
|
|
6525
|
+
}).finally(() => {
|
|
6526
|
+
resolveCompletion?.();
|
|
6527
|
+
});
|
|
6528
|
+
return;
|
|
6529
|
+
}
|
|
6379
6530
|
interruptCodexTurnBestEffort(client, {
|
|
6380
6531
|
threadId: thread.threadId,
|
|
6381
|
-
turnId: activeTurnId
|
|
6382
|
-
timeoutMs: shouldRetireClient ? CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS : void 0
|
|
6383
|
-
});
|
|
6384
|
-
if (shouldRetireClient) retireCodexAppServerClientAfterTimedOutTurn(client, {
|
|
6385
|
-
threadId: thread.threadId,
|
|
6386
|
-
turnId: activeTurnId,
|
|
6387
|
-
reason: String(runAbortController.signal.reason ?? "timeout")
|
|
6532
|
+
turnId: activeTurnId
|
|
6388
6533
|
});
|
|
6389
6534
|
resolveCompletion?.();
|
|
6390
6535
|
};
|
|
@@ -6443,6 +6588,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6443
6588
|
await mirrorTranscriptBestEffort({
|
|
6444
6589
|
params,
|
|
6445
6590
|
agentId: sessionAgentId,
|
|
6591
|
+
notifyUserMessagePersisted,
|
|
6446
6592
|
result,
|
|
6447
6593
|
sessionKey: contextSessionKey,
|
|
6448
6594
|
threadId: thread.threadId,
|
|
@@ -6567,6 +6713,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
6567
6713
|
notificationCleanup();
|
|
6568
6714
|
requestCleanup();
|
|
6569
6715
|
closeCleanup?.();
|
|
6716
|
+
releaseSharedClientLease?.();
|
|
6570
6717
|
if (nativeHookRelay) if (shouldDelayNativeHookRelayUnregister) scheduleCodexNativeHookRelayUnregister({
|
|
6571
6718
|
relay: nativeHookRelay,
|
|
6572
6719
|
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
@@ -6799,7 +6946,10 @@ function createCodexNativeHookRelay(params) {
|
|
|
6799
6946
|
turnStartTimeoutMs: params.turnStartTimeoutMs
|
|
6800
6947
|
}),
|
|
6801
6948
|
signal: params.signal,
|
|
6802
|
-
command: {
|
|
6949
|
+
command: {
|
|
6950
|
+
nice: 10,
|
|
6951
|
+
timeoutMs: params.options?.gatewayTimeoutMs
|
|
6952
|
+
}
|
|
6803
6953
|
});
|
|
6804
6954
|
}
|
|
6805
6955
|
function resolveCodexNativeHookRelayEvents(params) {
|
|
@@ -6867,17 +7017,39 @@ async function unsubscribeCodexThreadBestEffort(client, params) {
|
|
|
6867
7017
|
});
|
|
6868
7018
|
}
|
|
6869
7019
|
}
|
|
6870
|
-
function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
|
|
6871
|
-
const
|
|
6872
|
-
|
|
7020
|
+
async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
|
|
7021
|
+
const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
|
|
7022
|
+
const detachedSharedClient = Boolean(retiredSharedClient);
|
|
7023
|
+
interruptCodexTurnBestEffort(client, {
|
|
7024
|
+
threadId: params.threadId,
|
|
7025
|
+
turnId: params.turnId,
|
|
7026
|
+
timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
|
|
7027
|
+
});
|
|
7028
|
+
await unsubscribeCodexThreadBestEffort(client, {
|
|
7029
|
+
threadId: params.threadId,
|
|
7030
|
+
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
7031
|
+
});
|
|
7032
|
+
let closedClient = retiredSharedClient?.closed ?? false;
|
|
7033
|
+
if (!detachedSharedClient) {
|
|
6873
7034
|
const close = client.close;
|
|
6874
|
-
if (typeof close === "function")
|
|
7035
|
+
if (typeof close === "function") try {
|
|
7036
|
+
close.call(client);
|
|
7037
|
+
closedClient = true;
|
|
7038
|
+
} catch (error) {
|
|
7039
|
+
embeddedAgentLog.debug("codex app-server client close failed during timeout cleanup", {
|
|
7040
|
+
threadId: params.threadId,
|
|
7041
|
+
turnId: params.turnId,
|
|
7042
|
+
error
|
|
7043
|
+
});
|
|
7044
|
+
}
|
|
6875
7045
|
}
|
|
6876
7046
|
embeddedAgentLog.warn("codex app-server client retired after timed-out turn", {
|
|
6877
7047
|
threadId: params.threadId,
|
|
6878
7048
|
turnId: params.turnId,
|
|
6879
7049
|
reason: params.reason,
|
|
6880
|
-
|
|
7050
|
+
detachedSharedClient,
|
|
7051
|
+
closedClient,
|
|
7052
|
+
activeSharedClientLeases: retiredSharedClient?.activeLeases ?? 0
|
|
6881
7053
|
});
|
|
6882
7054
|
}
|
|
6883
7055
|
function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
@@ -6895,12 +7067,54 @@ function resolveCodexAppServerHookChannelId(params, sandboxSessionKey) {
|
|
|
6895
7067
|
messageTo: params.messageTo
|
|
6896
7068
|
}).channelId;
|
|
6897
7069
|
}
|
|
7070
|
+
const CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS = 1e3;
|
|
7071
|
+
const CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS = 500;
|
|
7072
|
+
function createCodexDynamicToolBuildStageTracker(options = {}) {
|
|
7073
|
+
if (!options.enabled) return {
|
|
7074
|
+
mark() {},
|
|
7075
|
+
snapshot() {
|
|
7076
|
+
return {
|
|
7077
|
+
totalMs: 0,
|
|
7078
|
+
stages: []
|
|
7079
|
+
};
|
|
7080
|
+
}
|
|
7081
|
+
};
|
|
7082
|
+
const startedAt = Date.now();
|
|
7083
|
+
let previousAt = startedAt;
|
|
7084
|
+
const stages = [];
|
|
7085
|
+
const toMs = (value) => Math.max(0, Math.round(value));
|
|
7086
|
+
return {
|
|
7087
|
+
mark(name) {
|
|
7088
|
+
const currentAt = Date.now();
|
|
7089
|
+
stages.push({
|
|
7090
|
+
name,
|
|
7091
|
+
durationMs: toMs(currentAt - previousAt),
|
|
7092
|
+
elapsedMs: toMs(currentAt - startedAt)
|
|
7093
|
+
});
|
|
7094
|
+
previousAt = currentAt;
|
|
7095
|
+
},
|
|
7096
|
+
snapshot() {
|
|
7097
|
+
return {
|
|
7098
|
+
totalMs: toMs(Date.now() - startedAt),
|
|
7099
|
+
stages: stages.slice()
|
|
7100
|
+
};
|
|
7101
|
+
}
|
|
7102
|
+
};
|
|
7103
|
+
}
|
|
7104
|
+
function shouldWarnCodexDynamicToolBuildStageSummary(summary) {
|
|
7105
|
+
return summary.totalMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_TOTAL_MS || summary.stages.some((stage) => stage.durationMs >= CODEX_DYNAMIC_TOOL_BUILD_WARN_STAGE_MS);
|
|
7106
|
+
}
|
|
7107
|
+
function formatCodexDynamicToolBuildStageSummary(summary) {
|
|
7108
|
+
return summary.stages.length > 0 ? summary.stages.map((stage) => `${stage.name}:${stage.durationMs}ms@${stage.elapsedMs}ms`).join(",") : "none";
|
|
7109
|
+
}
|
|
6898
7110
|
async function buildDynamicTools(input) {
|
|
6899
7111
|
const { params } = input;
|
|
6900
7112
|
if (params.disableTools || !supportsModelTools(params.model)) return [];
|
|
7113
|
+
const toolBuildStages = createCodexDynamicToolBuildStageTracker({ enabled: input.profilerEnabled });
|
|
6901
7114
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
6902
7115
|
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, input.sessionAgentId);
|
|
6903
7116
|
const createOpenClawCodingTools = (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
|
|
7117
|
+
toolBuildStages.mark("load-agent-harness-tools");
|
|
6904
7118
|
const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
|
|
6905
7119
|
const allTools = createOpenClawCodingTools({
|
|
6906
7120
|
agentId: input.sessionAgentId,
|
|
@@ -6941,7 +7155,7 @@ async function buildDynamicTools(input) {
|
|
|
6941
7155
|
modelCompat: params.model.compat && typeof params.model.compat === "object" ? params.model.compat : void 0,
|
|
6942
7156
|
modelApi: params.model.api,
|
|
6943
7157
|
modelContextWindowTokens: params.model.contextWindow,
|
|
6944
|
-
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config,
|
|
7158
|
+
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config, params.toolAuthProfileStore ?? params.authProfileStore, { workspaceDir: input.effectiveWorkspace }),
|
|
6945
7159
|
suppressManagedWebSearch: false,
|
|
6946
7160
|
currentChannelId: params.currentChannelId,
|
|
6947
7161
|
hookChannelId: resolveCodexAppServerHookChannelId(params, input.sandboxSessionKey),
|
|
@@ -6965,13 +7179,22 @@ async function buildDynamicTools(input) {
|
|
|
6965
7179
|
message
|
|
6966
7180
|
}
|
|
6967
7181
|
});
|
|
7182
|
+
},
|
|
7183
|
+
recordToolPrepStage: (name) => {
|
|
7184
|
+
toolBuildStages.mark(name);
|
|
6968
7185
|
}
|
|
6969
7186
|
});
|
|
6970
|
-
|
|
7187
|
+
toolBuildStages.mark("create-openclaw-coding-tools");
|
|
7188
|
+
const codexFilteredTools = addNodeShellDynamicToolsIfNeeded(addSandboxShellDynamicToolsIfAvailable(isCodexMemoryFlushRun(params) ? filterCodexMemoryFlushDynamicTools(allTools) : filterCodexDynamicTools(allTools, input.pluginConfig), allTools, input), allTools, input);
|
|
7189
|
+
toolBuildStages.mark("codex-filtering");
|
|
7190
|
+
const visionFilteredTools = filterToolsForVisionInputs(codexFilteredTools, {
|
|
6971
7191
|
modelHasVision,
|
|
6972
7192
|
hasInboundImages: (params.images?.length ?? 0) > 0
|
|
6973
|
-
})
|
|
6974
|
-
|
|
7193
|
+
});
|
|
7194
|
+
toolBuildStages.mark("vision-filtering");
|
|
7195
|
+
const filteredTools = filterCodexDynamicToolsForAllowlist(visionFilteredTools, includeForcedCodexDynamicToolAllow(params.toolsAllow, params));
|
|
7196
|
+
toolBuildStages.mark("allowlist-filter");
|
|
7197
|
+
const normalizedTools = normalizeAgentRuntimeTools({
|
|
6975
7198
|
runtimePlan: input.ignoreRuntimePlan ? void 0 : params.runtimePlan,
|
|
6976
7199
|
tools: filteredTools,
|
|
6977
7200
|
provider: params.provider,
|
|
@@ -6982,6 +7205,27 @@ async function buildDynamicTools(input) {
|
|
|
6982
7205
|
modelApi: params.model.api,
|
|
6983
7206
|
model: params.model
|
|
6984
7207
|
});
|
|
7208
|
+
toolBuildStages.mark("runtime-normalization");
|
|
7209
|
+
const summary = toolBuildStages.snapshot();
|
|
7210
|
+
if (shouldWarnCodexDynamicToolBuildStageSummary(summary)) {
|
|
7211
|
+
const phase = input.forceHeartbeatTool ? "registered-tools" : "runtime-tools";
|
|
7212
|
+
embeddedAgentLog.warn(`codex app-server dynamic tool build timings runId=${params.runId} sessionId=${params.sessionId} phase=${phase} totalMs=${summary.totalMs} stages=${formatCodexDynamicToolBuildStageSummary(summary)}`, {
|
|
7213
|
+
runId: params.runId,
|
|
7214
|
+
sessionId: params.sessionId,
|
|
7215
|
+
phase,
|
|
7216
|
+
totalMs: summary.totalMs,
|
|
7217
|
+
stages: summary.stages,
|
|
7218
|
+
allToolCount: allTools.length,
|
|
7219
|
+
codexFilteredToolCount: codexFilteredTools.length,
|
|
7220
|
+
visionFilteredToolCount: visionFilteredTools.length,
|
|
7221
|
+
filteredToolCount: filteredTools.length,
|
|
7222
|
+
normalizedToolCount: normalizedTools.length,
|
|
7223
|
+
forceHeartbeatTool: input.forceHeartbeatTool === true,
|
|
7224
|
+
ignoreRuntimePlan: input.ignoreRuntimePlan === true,
|
|
7225
|
+
nativeToolSurfaceEnabled: input.nativeToolSurfaceEnabled === true
|
|
7226
|
+
});
|
|
7227
|
+
}
|
|
7228
|
+
return normalizedTools;
|
|
6985
7229
|
}
|
|
6986
7230
|
function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
|
|
6987
7231
|
if (toolsAllow === void 0 || hasWildcardCodexToolsAllow(toolsAllow)) return toolsAllow;
|
|
@@ -7151,11 +7395,33 @@ function shouldProjectMirroredHistoryForCodexStart(params) {
|
|
|
7151
7395
|
if (!params.historyMessages.some((message) => message.role === "user")) return false;
|
|
7152
7396
|
if (params.forceProject) return true;
|
|
7153
7397
|
if (!params.startupBinding?.threadId) return true;
|
|
7398
|
+
if (hasUserVisibleHistoryAfterCodexBinding({
|
|
7399
|
+
startupBinding: params.startupBinding,
|
|
7400
|
+
historyMessages: params.historyMessages
|
|
7401
|
+
})) return true;
|
|
7154
7402
|
return !areCodexDynamicToolFingerprintsCompatible({
|
|
7155
7403
|
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
7156
7404
|
next: params.dynamicToolsFingerprint
|
|
7157
7405
|
});
|
|
7158
7406
|
}
|
|
7407
|
+
function hasUserVisibleHistoryAfterCodexBinding(params) {
|
|
7408
|
+
const bindingUpdatedAt = Date.parse(params.startupBinding.updatedAt);
|
|
7409
|
+
if (!Number.isFinite(bindingUpdatedAt)) return false;
|
|
7410
|
+
return params.historyMessages.some((message) => {
|
|
7411
|
+
if (message.role !== "user" && message.role !== "assistant") return false;
|
|
7412
|
+
if (isCodexAppServerMirroredTranscriptMessage(message)) return false;
|
|
7413
|
+
const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
7414
|
+
return Number.isFinite(timestamp) && timestamp > bindingUpdatedAt;
|
|
7415
|
+
});
|
|
7416
|
+
}
|
|
7417
|
+
function isCodexAppServerMirroredTranscriptMessage(message) {
|
|
7418
|
+
const record = message;
|
|
7419
|
+
const idempotencyKey = record.idempotencyKey;
|
|
7420
|
+
if (typeof idempotencyKey === "string" && idempotencyKey.startsWith("codex-app-server:")) return true;
|
|
7421
|
+
const meta = record["__openclaw"];
|
|
7422
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
|
|
7423
|
+
return typeof meta.mirrorIdentity === "string";
|
|
7424
|
+
}
|
|
7159
7425
|
function readContextEngineThreadBootstrapProjection(projection) {
|
|
7160
7426
|
if (projection?.mode !== "thread_bootstrap") return;
|
|
7161
7427
|
const epoch = projection.epoch?.trim();
|
|
@@ -7473,6 +7739,11 @@ function readRawAssistantTextPreview(item) {
|
|
|
7473
7739
|
function isTurnNotification(value, threadId, turnId) {
|
|
7474
7740
|
return isCodexNotificationForTurn(value, threadId, turnId);
|
|
7475
7741
|
}
|
|
7742
|
+
function isCodexNotificationOutsideActiveRun(correlation) {
|
|
7743
|
+
if (!Boolean(correlation.threadId || correlation.nestedTurnThreadId)) return false;
|
|
7744
|
+
if (!correlation.matchesActiveThread) return true;
|
|
7745
|
+
return Boolean(correlation.turnId || correlation.nestedTurnId) && correlation.matchesActiveTurn === false;
|
|
7746
|
+
}
|
|
7476
7747
|
function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
|
|
7477
7748
|
if (!isJsonObject(value)) return false;
|
|
7478
7749
|
return readString(value, "threadId") === threadId && readString(value, "turnId") === turnId;
|
|
@@ -7742,6 +8013,16 @@ function readPositiveNumber(value) {
|
|
|
7742
8013
|
function readNonEmptyString(value) {
|
|
7743
8014
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
7744
8015
|
}
|
|
8016
|
+
const CODEX_DELIVERY_HINT_LINES = ["Delivery: to send a message, use the `message` tool.", "Delivery: Final assistant text is not automatically delivered in this run. Use the `message` tool to send user-visible output."];
|
|
8017
|
+
function splitLeadingCodexDeliveryHint(prompt) {
|
|
8018
|
+
const trimmedStart = prompt.trimStart();
|
|
8019
|
+
const matchedHint = CODEX_DELIVERY_HINT_LINES.find((hint) => trimmedStart.startsWith(hint));
|
|
8020
|
+
if (!matchedHint) return { prompt };
|
|
8021
|
+
return {
|
|
8022
|
+
deliveryHint: matchedHint,
|
|
8023
|
+
prompt: trimmedStart.slice(matchedHint.length).replace(/^\s*\n/, "").trimStart()
|
|
8024
|
+
};
|
|
8025
|
+
}
|
|
7745
8026
|
function buildCodexOpenClawPromptContext(params) {
|
|
7746
8027
|
if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
|
|
7747
8028
|
const sections = [params.skillsPrompt?.trim() ? [
|
|
@@ -7766,12 +8047,18 @@ function shouldInjectCodexOpenClawPromptContext(params) {
|
|
|
7766
8047
|
}
|
|
7767
8048
|
function prependCodexOpenClawPromptContext(prompt, context) {
|
|
7768
8049
|
if (!context?.trim()) return prompt;
|
|
7769
|
-
const
|
|
8050
|
+
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
8051
|
+
const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
|
|
8052
|
+
const deliverySection = deliveryHint ? [
|
|
8053
|
+
"OpenClaw delivery metadata:",
|
|
8054
|
+
"This delivery metadata is runtime routing guidance, not the user's request.",
|
|
8055
|
+
deliveryHint
|
|
8056
|
+
].join("\n") : void 0;
|
|
7770
8057
|
return [
|
|
7771
8058
|
context.trim(),
|
|
7772
|
-
|
|
8059
|
+
deliverySection,
|
|
7773
8060
|
promptSection
|
|
7774
|
-
].join("\n");
|
|
8061
|
+
].filter(Boolean).join("\n\n");
|
|
7775
8062
|
}
|
|
7776
8063
|
function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
7777
8064
|
const files = selectCodexWorkspacePromptContextFiles(contextFiles);
|
|
@@ -7882,29 +8169,63 @@ function getCodexContextFileBasename(filePath) {
|
|
|
7882
8169
|
}
|
|
7883
8170
|
async function mirrorTranscriptBestEffort(params) {
|
|
7884
8171
|
try {
|
|
7885
|
-
await
|
|
8172
|
+
const messages = await resolveFinalCodexMirrorMessages({
|
|
8173
|
+
params: params.params,
|
|
8174
|
+
messagesSnapshot: params.result.messagesSnapshot,
|
|
8175
|
+
turnId: params.turnId
|
|
8176
|
+
});
|
|
8177
|
+
const mirrorResult = await mirrorCodexAppServerTranscript({
|
|
7886
8178
|
sessionFile: params.params.sessionFile,
|
|
7887
8179
|
agentId: params.agentId,
|
|
7888
8180
|
sessionKey: params.sessionKey,
|
|
7889
|
-
messages
|
|
8181
|
+
messages,
|
|
7890
8182
|
idempotencyScope: `codex-app-server:${params.threadId}`,
|
|
7891
8183
|
config: params.params.config
|
|
7892
8184
|
});
|
|
8185
|
+
for (const message of mirrorResult.userMessagesPresent) params.notifyUserMessagePersisted(message);
|
|
7893
8186
|
} catch (error) {
|
|
7894
8187
|
embeddedAgentLog.warn("failed to mirror codex app-server transcript", { error });
|
|
7895
8188
|
}
|
|
7896
8189
|
}
|
|
8190
|
+
async function resolveFinalCodexMirrorMessages(params) {
|
|
8191
|
+
if (params.params.suppressNextUserMessagePersistence || !params.params.userTurnTranscriptRecorder) return params.messagesSnapshot;
|
|
8192
|
+
const resolvedPrompt = attachCodexMirrorIdentity(await buildResolvedCodexUserPromptMessage(params.params), `${params.turnId}:prompt`);
|
|
8193
|
+
const firstUserIndex = params.messagesSnapshot.findIndex((message) => message.role === "user");
|
|
8194
|
+
if (firstUserIndex === -1) return [resolvedPrompt, ...params.messagesSnapshot];
|
|
8195
|
+
const messages = params.messagesSnapshot.slice();
|
|
8196
|
+
messages[firstUserIndex] = resolvedPrompt;
|
|
8197
|
+
return messages;
|
|
8198
|
+
}
|
|
8199
|
+
function createCodexAppServerUserMessagePersistenceNotifier(runParams) {
|
|
8200
|
+
let notified = false;
|
|
8201
|
+
return (message) => {
|
|
8202
|
+
if (notified) return;
|
|
8203
|
+
notified = true;
|
|
8204
|
+
runParams.userTurnTranscriptRecorder?.markRuntimePersisted(message);
|
|
8205
|
+
try {
|
|
8206
|
+
runParams.onUserMessagePersisted?.(message);
|
|
8207
|
+
} catch (error) {
|
|
8208
|
+
embeddedAgentLog.warn("codex app-server user persistence notification failed", { error: formatErrorMessage(error) });
|
|
8209
|
+
}
|
|
8210
|
+
};
|
|
8211
|
+
}
|
|
7897
8212
|
async function mirrorPromptAtTurnStartBestEffort(params) {
|
|
7898
8213
|
if (params.params.suppressNextUserMessagePersistence) return;
|
|
7899
8214
|
try {
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
8215
|
+
const mirrorPromise = (async () => {
|
|
8216
|
+
const userPromptMessage = attachCodexMirrorIdentity(await buildResolvedCodexUserPromptMessage(params.params), `${params.turnId}:prompt`);
|
|
8217
|
+
const mirrorResult = await mirrorCodexAppServerTranscript({
|
|
8218
|
+
sessionFile: params.params.sessionFile,
|
|
8219
|
+
agentId: params.agentId,
|
|
8220
|
+
sessionKey: params.sessionKey,
|
|
8221
|
+
messages: [userPromptMessage],
|
|
8222
|
+
idempotencyScope: `codex-app-server:${params.threadId}`,
|
|
8223
|
+
config: params.params.config
|
|
8224
|
+
});
|
|
8225
|
+
for (const message of mirrorResult.userMessagesPresent) params.notifyUserMessagePersisted(message);
|
|
8226
|
+
})();
|
|
8227
|
+
params.params.userTurnTranscriptRecorder?.markRuntimePersistencePending(mirrorPromise);
|
|
8228
|
+
await mirrorPromise;
|
|
7908
8229
|
} catch (error) {
|
|
7909
8230
|
embeddedAgentLog.warn("failed to mirror codex app-server prompt at turn start", { error });
|
|
7910
8231
|
}
|