@openclaw/codex 2026.5.28 → 2026.5.31-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-DMXvboVu.js → client-BnOmn0y-.js} +20 -6
- package/dist/client-factory-B8dh39UW.js +20 -0
- package/dist/{command-handlers-C2t6-ChO.js → command-handlers-BsK6kZJi.js} +265 -16
- package/dist/{compact-Dlnt5G3v.js → compact-BXLjhUHX.js} +4 -4
- package/dist/{computer-use-Ba4vW9fO.js → computer-use-D-0EFJBJ.js} +3 -4
- package/dist/{config--tW89bHH.js → config-AlzuNKCY.js} +14 -5
- package/dist/{conversation-binding-CC9XMAwn.js → conversation-binding-KUDxop-C.js} +69 -92
- package/dist/doctor-contract-api.js +1 -1
- package/dist/harness.js +6 -10
- package/dist/index.js +23 -60
- package/dist/media-understanding-provider.js +8 -9
- package/dist/{models-QT-XOhE7.js → models-mbjSisZL.js} +2 -2
- package/dist/{native-hook-relay-B8qM8ZwR.js → native-hook-relay-DCxPRaBN.js} +77 -9
- package/dist/{notification-correlation-BDakP_d3.js → notification-correlation-BykOI_jh.js} +3 -3
- package/dist/{protocol-validators-DtjYmUw_.js → protocol-validators-DIt7cXIp.js} +2 -2
- package/dist/provider-catalog.js +2 -2
- package/dist/provider.js +2 -2
- package/dist/{request-CF4f5hWY.js → request-DuFgTwRU.js} +4 -4
- package/dist/{run-attempt-CuhGEh0u.js → run-attempt-CgaY9r5u.js} +579 -288
- package/dist/{sandbox-guard-mXE4_vE_.js → sandbox-guard-DMCJlzmz.js} +4 -1
- package/dist/{session-binding-ueMCn4om.js → session-binding-BXJAV_xy.js} +27 -10
- package/dist/{shared-client-Duh1bHaP.js → shared-client-DBlR-rV2.js} +33 -4
- package/dist/{side-question-B-Cjb9wm.js → side-question-SjBLGANT.js} +10 -10
- package/dist/{thread-lifecycle-Dv9Npl7a.js → thread-lifecycle-Bnlv_Q8u.js} +78 -120
- package/npm-shrinkwrap.json +34 -34
- package/openclaw.plugin.json +5 -4
- package/package.json +6 -6
- package/dist/client-factory-qZvhyyXr.js +0 -15
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { a as
|
|
4
|
-
import { a as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { n as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { _ as normalizeCodexDynamicToolName$1, a as createCodexNativeHookRelay, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as isForcedPrivateQaCodexRuntime, h as filterCodexDynamicTools, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexDynamicToolsLoading, y as handleCodexAppServerApprovalRequest } from "./native-hook-relay-
|
|
12
|
-
import { t as ensureCodexComputerUse } from "./computer-use-
|
|
1
|
+
import { a as isCodexAppServerApprovalPolicyAllowedByRequirements, c as isCodexSandboxExecServerEnabled, d as resolveCodexAppServerRuntimeOptions, f as resolveCodexComputerUseConfig, g as withMcpElicitationsApprovalPolicy, h as shouldAutoApproveCodexAppServerApprovals, m as resolveOpenClawExecPolicyForCodexAppServer, p as resolveCodexPluginsPolicy, u as readCodexPluginConfig } from "./config-AlzuNKCY.js";
|
|
2
|
+
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-DIt7cXIp.js";
|
|
3
|
+
import { a as isCodexAppServerConnectionClosedError, i as isCodexAppServerApprovalRequest, l as isJsonObject, r as compareCodexAppServerVersions, s as MIN_CODEX_SANDBOX_EXEC_SERVER_APP_SERVER_VERSION } from "./client-BnOmn0y-.js";
|
|
4
|
+
import { C as sanitizeCodexHistoryImagePayloads, D as resolveCodexContextEngineProjectionReserveTokens, E as resolveCodexContextEngineProjectionMaxChars, T as projectContextEngineAssemblyForCodex, _ as shouldBuildCodexPluginThreadConfig, a as buildDeveloperInstructions, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as mergeCodexThreadConfigs, h as buildCodexPluginThreadConfigInputFingerprint, i as buildContextEngineBinding, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfig, n as areCodexDynamicToolFingerprintsCompatible, o as buildTurnCollaborationMode, p as isCodexAppServerProfilerEnabled, s as buildTurnStartParams, x as defaultCodexAppInventoryCache } from "./thread-lifecycle-Bnlv_Q8u.js";
|
|
5
|
+
import { a as readCodexAppServerBinding, n as clearCodexAppServerBindingForThread, s as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-BXJAV_xy.js";
|
|
6
|
+
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-DuFgTwRU.js";
|
|
7
|
+
import { _ as shouldRefreshCodexRateLimitsForUsageLimitMessage, g as resolveCodexUsageLimitResetAtMs, h as formatCodexUsageLimitErrorMessage, i as readCodexNotificationTurnId, n as isCodexNotificationForTurn, r as readCodexNotificationThreadId, s as formatCodexDisplayText, t as describeCodexNotificationCorrelation } from "./notification-correlation-BykOI_jh.js";
|
|
8
|
+
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-DBlR-rV2.js";
|
|
9
|
+
import { i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-DMCJlzmz.js";
|
|
10
|
+
import { n as defaultLeasedCodexAppServerClientFactory } from "./client-factory-B8dh39UW.js";
|
|
11
|
+
import { C as resolveCodexTurnAssistantCompletionIdleTimeoutMs, E as withCodexStartupTimeout, S as resolveCodexStartupTimeoutMs, T as resolveCodexTurnTerminalIdleTimeoutMs, _ as normalizeCodexDynamicToolName$1, a as createCodexNativeHookRelay, b as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, c as scheduleCodexNativeHookRelayUnregister, d as emitDynamicToolErrorDiagnostic, f as emitDynamicToolStartedDiagnostic, g as isForcedPrivateQaCodexRuntime, h as filterCodexDynamicTools, i as buildCodexNativeHookRelayDisabledConfig, l as handleCodexAppServerElicitationRequest, m as filterToolsForVisionInputs, n as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, o as resolveCodexNativeHookRelayEvents, p as emitDynamicToolTerminalDiagnostic, r as buildCodexNativeHookRelayConfig, s as resolveCodexNativeHookRelayTtlMs, u as createCodexDynamicToolBridge, v as resolveCodexDynamicToolsLoading, w as resolveCodexTurnCompletionIdleTimeoutMs, x as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, y as handleCodexAppServerApprovalRequest } from "./native-hook-relay-DCxPRaBN.js";
|
|
12
|
+
import { t as ensureCodexComputerUse } from "./computer-use-D-0EFJBJ.js";
|
|
13
13
|
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-N66I-Rd7.js";
|
|
14
|
+
import { asDateTimestampMs, parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
14
15
|
import { createHash, randomUUID } from "node:crypto";
|
|
15
16
|
import fsSync from "node:fs";
|
|
16
17
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
@@ -26,9 +27,10 @@ import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent
|
|
|
26
27
|
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
27
28
|
import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
|
|
28
29
|
import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
29
|
-
import { parseStrictNonNegativeInteger, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
30
30
|
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
|
|
31
31
|
import { isIP } from "node:net";
|
|
32
|
+
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
33
|
+
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
32
34
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
33
35
|
//#region extensions/codex/src/app-server/app-server-policy.ts
|
|
34
36
|
function resolveCodexAppServerForOpenClawToolPolicy(params) {
|
|
@@ -155,37 +157,6 @@ async function readMirroredSessionHistoryMessages(sessionFile) {
|
|
|
155
157
|
if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
|
|
156
158
|
return messages;
|
|
157
159
|
}
|
|
158
|
-
function shouldProjectMirroredHistoryForCodexStart(params) {
|
|
159
|
-
if (!params.historyMessages.some((message) => message.role === "user")) return false;
|
|
160
|
-
if (params.forceProject) return true;
|
|
161
|
-
if (!params.startupBinding?.threadId) return true;
|
|
162
|
-
if (hasUserVisibleHistoryAfterCodexBinding({
|
|
163
|
-
startupBinding: params.startupBinding,
|
|
164
|
-
historyMessages: params.historyMessages
|
|
165
|
-
})) return true;
|
|
166
|
-
return !areCodexDynamicToolFingerprintsCompatible({
|
|
167
|
-
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
168
|
-
next: params.dynamicToolsFingerprint
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
function hasUserVisibleHistoryAfterCodexBinding(params) {
|
|
172
|
-
const bindingUpdatedAt = Date.parse(params.startupBinding.updatedAt);
|
|
173
|
-
if (!Number.isFinite(bindingUpdatedAt)) return false;
|
|
174
|
-
return params.historyMessages.some((message) => {
|
|
175
|
-
if (message.role !== "user" && message.role !== "assistant") return false;
|
|
176
|
-
if (isCodexAppServerMirroredTranscriptMessage(message)) return false;
|
|
177
|
-
const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
178
|
-
return Number.isFinite(timestamp) && timestamp > bindingUpdatedAt;
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
function isCodexAppServerMirroredTranscriptMessage(message) {
|
|
182
|
-
const record = message;
|
|
183
|
-
const idempotencyKey = record.idempotencyKey;
|
|
184
|
-
if (typeof idempotencyKey === "string" && idempotencyKey.startsWith("codex-app-server:")) return true;
|
|
185
|
-
const meta = record["__openclaw"];
|
|
186
|
-
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return false;
|
|
187
|
-
return typeof meta.mirrorIdentity === "string";
|
|
188
|
-
}
|
|
189
160
|
function readContextEngineThreadBootstrapProjection(projection) {
|
|
190
161
|
if (projection?.mode !== "thread_bootstrap") return;
|
|
191
162
|
const epoch = projection.epoch?.trim();
|
|
@@ -284,6 +255,10 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
284
255
|
promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
|
|
285
256
|
developerInstructions: renderCodexWorkspaceThreadDeveloperInstructions(developerInstructionFiles),
|
|
286
257
|
turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
|
|
258
|
+
memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? renderCodexWorkspaceMemoryReference({
|
|
259
|
+
files: memoryReferenceFiles,
|
|
260
|
+
toolNames: params.memoryToolNames
|
|
261
|
+
}) : void 0,
|
|
287
262
|
heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
|
|
288
263
|
};
|
|
289
264
|
} catch (error) {
|
|
@@ -454,19 +429,11 @@ function readNonEmptyString$1(value) {
|
|
|
454
429
|
}
|
|
455
430
|
function buildCodexOpenClawPromptContext(params) {
|
|
456
431
|
if (!shouldInjectCodexOpenClawPromptContext(params.params)) return;
|
|
457
|
-
const sections = [
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
].join("\n") : void 0,
|
|
463
|
-
params.workspaceMemoryReference?.trim() ? params.workspaceMemoryReference.trim() : void 0,
|
|
464
|
-
params.workspacePromptContext?.trim() ? [
|
|
465
|
-
"## OpenClaw Workspace Context",
|
|
466
|
-
"",
|
|
467
|
-
params.workspacePromptContext.trim()
|
|
468
|
-
].join("\n") : void 0
|
|
469
|
-
].filter(isNonEmptyString$2);
|
|
432
|
+
const sections = [params.workspacePromptContext?.trim() ? [
|
|
433
|
+
"## OpenClaw Workspace Context",
|
|
434
|
+
"",
|
|
435
|
+
params.workspacePromptContext.trim()
|
|
436
|
+
].join("\n") : void 0].filter(isNonEmptyString$2);
|
|
470
437
|
if (sections.length === 0) return;
|
|
471
438
|
return [
|
|
472
439
|
"OpenClaw runtime context for this turn:",
|
|
@@ -478,9 +445,17 @@ function buildCodexOpenClawPromptContext(params) {
|
|
|
478
445
|
function shouldInjectCodexOpenClawPromptContext(params) {
|
|
479
446
|
return !(params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron");
|
|
480
447
|
}
|
|
481
|
-
function
|
|
482
|
-
if (!
|
|
448
|
+
function renderCodexSkillsCollaborationInstructions(params) {
|
|
449
|
+
if (!shouldInjectCodexOpenClawPromptContext(params.attempt)) return;
|
|
450
|
+
return params.skillsPrompt?.trim() ? [
|
|
451
|
+
"## OpenClaw Skills",
|
|
452
|
+
"",
|
|
453
|
+
params.skillsPrompt.trim()
|
|
454
|
+
].join("\n") : void 0;
|
|
455
|
+
}
|
|
456
|
+
function prependCodexOpenClawPromptContext(prompt, context, options = {}) {
|
|
483
457
|
const { deliveryHint, prompt: promptWithoutDeliveryHint } = splitLeadingCodexDeliveryHint(prompt);
|
|
458
|
+
if (!context?.trim() && (!deliveryHint || options.preservePromptWithoutContext)) return prompt;
|
|
484
459
|
const promptSection = promptWithoutDeliveryHint.startsWith("OpenClaw assembled context for this turn:") ? promptWithoutDeliveryHint : ["Current user request:", promptWithoutDeliveryHint].join("\n");
|
|
485
460
|
const deliverySection = deliveryHint ? [
|
|
486
461
|
"OpenClaw delivery metadata:",
|
|
@@ -488,7 +463,7 @@ function prependCodexOpenClawPromptContext(prompt, context) {
|
|
|
488
463
|
deliveryHint
|
|
489
464
|
].join("\n") : void 0;
|
|
490
465
|
return [
|
|
491
|
-
context
|
|
466
|
+
context?.trim(),
|
|
492
467
|
deliverySection,
|
|
493
468
|
promptSection
|
|
494
469
|
].filter(Boolean).join("\n\n");
|
|
@@ -550,11 +525,12 @@ function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
|
|
|
550
525
|
return renderCodexWorkspaceDeveloperInstructions({
|
|
551
526
|
files,
|
|
552
527
|
header: "## OpenClaw Agent Soul",
|
|
553
|
-
preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. They are the canonical definitions of who you are, how you think and work, and the human you work alongside. Internalize and follow them accordingly."
|
|
528
|
+
preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. They are the canonical definitions of who you are, how you think and work, and the human you work alongside. Internalize and follow them accordingly.",
|
|
529
|
+
wrapperTag: "AGENT_SOUL"
|
|
554
530
|
});
|
|
555
531
|
}
|
|
556
532
|
function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
557
|
-
const { files, header, preamble } = params;
|
|
533
|
+
const { files, header, preamble, wrapperTag } = params;
|
|
558
534
|
if (files.length === 0) return;
|
|
559
535
|
const lines = [
|
|
560
536
|
header,
|
|
@@ -562,7 +538,9 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
|
562
538
|
preamble,
|
|
563
539
|
""
|
|
564
540
|
];
|
|
541
|
+
if (wrapperTag) lines.push(`<${wrapperTag}>`, "");
|
|
565
542
|
for (const file of files) lines.push(`### ${file.path}`, "", file.content, "");
|
|
543
|
+
if (wrapperTag) lines.push(`</${wrapperTag}>`);
|
|
566
544
|
return lines.join("\n").trim();
|
|
567
545
|
}
|
|
568
546
|
function selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles) {
|
|
@@ -594,7 +572,7 @@ function renderCodexWorkspaceMemoryReference(params) {
|
|
|
594
572
|
const lines = [
|
|
595
573
|
"## OpenClaw Workspace Memory",
|
|
596
574
|
"",
|
|
597
|
-
`MEMORY.md exists in the active agent workspace. OpenClaw does not paste its contents into native Codex turns; use ${(params.toolNames?.length ? params.toolNames : Array.from(CODEX_MEMORY_TOOL_NAMES)).join(" or ")} when durable memory is relevant and the tools are available.`,
|
|
575
|
+
`MEMORY.md exists in the active agent workspace as a memory file, not an instruction file. OpenClaw does not paste its contents into native Codex turns; use ${(params.toolNames?.length ? params.toolNames : Array.from(CODEX_MEMORY_TOOL_NAMES)).join(" or ")} when durable memory is relevant and the tools are available.`,
|
|
598
576
|
""
|
|
599
577
|
];
|
|
600
578
|
for (const file of params.files) lines.push(`- ${file.path}`);
|
|
@@ -825,6 +803,11 @@ function isReasoningItemCompletionNotification(notification) {
|
|
|
825
803
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
826
804
|
return item ? readString$6(item, "type") === "reasoning" : false;
|
|
827
805
|
}
|
|
806
|
+
function isAssistantCommentaryCompletionNotification(notification) {
|
|
807
|
+
if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
|
|
808
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
809
|
+
return Boolean(item && readString$6(item, "type") === "agentMessage" && readString$6(item, "phase") === "commentary");
|
|
810
|
+
}
|
|
828
811
|
function isRawReasoningCompletionNotification(notification) {
|
|
829
812
|
if (!isJsonObject(notification.params) || notification.method !== "rawResponseItem/completed") return false;
|
|
830
813
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
@@ -870,10 +853,21 @@ function isNativeToolProgressNotification(notification) {
|
|
|
870
853
|
default: return false;
|
|
871
854
|
}
|
|
872
855
|
}
|
|
873
|
-
function
|
|
856
|
+
function isNativeResponseStreamDeltaNotification(notification) {
|
|
857
|
+
return notification.method.startsWith("response.") && notification.method.endsWith(".delta");
|
|
858
|
+
}
|
|
859
|
+
function isFileChangePatchUpdatedNotification(notification) {
|
|
860
|
+
return notification.method === "item/fileChange/patchUpdated" && isJsonObject(notification.params);
|
|
861
|
+
}
|
|
862
|
+
function isRawAssistantProgressNotification(notification) {
|
|
874
863
|
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
875
864
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
876
|
-
return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" &&
|
|
865
|
+
return Boolean(item && readString$6(item, "type") === "message" && readString$6(item, "role") === "assistant" && readRawAssistantTextPreview(item));
|
|
866
|
+
}
|
|
867
|
+
function isRawAssistantCompletionNotification(notification) {
|
|
868
|
+
if (!isRawAssistantProgressNotification(notification) || !isJsonObject(notification.params)) return false;
|
|
869
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
870
|
+
return Boolean(item && readString$6(item, "phase") !== "commentary");
|
|
877
871
|
}
|
|
878
872
|
function readRawAssistantTextPreview(item) {
|
|
879
873
|
if (readString$6(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
|
|
@@ -964,67 +958,6 @@ function codexExecutionToolName(item) {
|
|
|
964
958
|
function isNonEmptyString$1(value) {
|
|
965
959
|
return typeof value === "string" && value.length > 0;
|
|
966
960
|
}
|
|
967
|
-
const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
|
|
968
|
-
const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
|
|
969
|
-
const CODEX_POST_REASONING_SOURCE_REPLY_IDLE_TIMEOUT_MS = 5 * 6e4;
|
|
970
|
-
const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
971
|
-
function resolvePositiveIntegerTimeoutMs(value, fallbackMs) {
|
|
972
|
-
return resolveTimerTimeoutMs(value, resolveTimerTimeoutMs(fallbackMs, 1));
|
|
973
|
-
}
|
|
974
|
-
async function withCodexStartupTimeout(params) {
|
|
975
|
-
if (params.signal.aborted) throw new Error("codex app-server startup aborted");
|
|
976
|
-
let timeout;
|
|
977
|
-
let abortCleanup;
|
|
978
|
-
let timeoutError;
|
|
979
|
-
let timeoutCleanup;
|
|
980
|
-
try {
|
|
981
|
-
return await Promise.race([params.operation(), new Promise((_, reject) => {
|
|
982
|
-
const rejectOnce = (error) => {
|
|
983
|
-
if (timeout) {
|
|
984
|
-
clearTimeout(timeout);
|
|
985
|
-
timeout = void 0;
|
|
986
|
-
}
|
|
987
|
-
reject(error);
|
|
988
|
-
};
|
|
989
|
-
timeout = setTimeout(() => {
|
|
990
|
-
timeoutError = /* @__PURE__ */ new Error("codex app-server startup timed out");
|
|
991
|
-
timeoutCleanup = Promise.resolve(params.onTimeout?.()).then(() => void 0, () => void 0);
|
|
992
|
-
timeoutCleanup.finally(() => {
|
|
993
|
-
rejectOnce(timeoutError);
|
|
994
|
-
});
|
|
995
|
-
}, params.timeoutMs);
|
|
996
|
-
const abortListener = () => rejectOnce(/* @__PURE__ */ new Error("codex app-server startup aborted"));
|
|
997
|
-
params.signal.addEventListener("abort", abortListener, { once: true });
|
|
998
|
-
abortCleanup = () => params.signal.removeEventListener("abort", abortListener);
|
|
999
|
-
})]);
|
|
1000
|
-
} catch (error) {
|
|
1001
|
-
if (timeoutError) {
|
|
1002
|
-
await timeoutCleanup;
|
|
1003
|
-
throw timeoutError;
|
|
1004
|
-
}
|
|
1005
|
-
throw error;
|
|
1006
|
-
} finally {
|
|
1007
|
-
if (timeout) clearTimeout(timeout);
|
|
1008
|
-
abortCleanup?.();
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
function resolveCodexStartupTimeoutMs(params) {
|
|
1012
|
-
const timeoutFloorMs = resolvePositiveIntegerTimeoutMs(params.timeoutFloorMs, 100);
|
|
1013
|
-
const timeoutMs = resolvePositiveIntegerTimeoutMs(params.timeoutMs, timeoutFloorMs);
|
|
1014
|
-
return Math.max(timeoutFloorMs, timeoutMs);
|
|
1015
|
-
}
|
|
1016
|
-
function resolveCodexTurnCompletionIdleTimeoutMs(value) {
|
|
1017
|
-
return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS);
|
|
1018
|
-
}
|
|
1019
|
-
function resolveCodexTurnAssistantCompletionIdleTimeoutMs(value) {
|
|
1020
|
-
return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS);
|
|
1021
|
-
}
|
|
1022
|
-
function resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs(value, fallbackMs) {
|
|
1023
|
-
return resolvePositiveIntegerTimeoutMs(value, fallbackMs);
|
|
1024
|
-
}
|
|
1025
|
-
function resolveCodexTurnTerminalIdleTimeoutMs(value) {
|
|
1026
|
-
return resolvePositiveIntegerTimeoutMs(value, CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS);
|
|
1027
|
-
}
|
|
1028
961
|
//#endregion
|
|
1029
962
|
//#region extensions/codex/src/app-server/attempt-notification-state.ts
|
|
1030
963
|
function reportCodexExecutionNotification(params) {
|
|
@@ -1055,8 +988,9 @@ function applyCodexTurnNotificationState(params) {
|
|
|
1055
988
|
const { notification, turnWatches } = params;
|
|
1056
989
|
const isCurrentTurnNotification = isTurnNotification(notification.params, params.threadId, params.turnId);
|
|
1057
990
|
const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
|
|
991
|
+
const isNativeResponseStreamDelta = isNativeResponseStreamDeltaNotification(notification);
|
|
1058
992
|
let turnCrossedToolHandoff = params.turnCrossedToolHandoff;
|
|
1059
|
-
if (isCurrentTurnNotification) {
|
|
993
|
+
if (isCurrentTurnNotification && !isNativeResponseStreamDelta) {
|
|
1060
994
|
turnWatches.touchActivity(`notification:${notification.method}`, {
|
|
1061
995
|
details: describeNotificationActivity(notification),
|
|
1062
996
|
attemptProgress: true
|
|
@@ -1070,25 +1004,37 @@ function applyCodexTurnNotificationState(params) {
|
|
|
1070
1004
|
const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
|
|
1071
1005
|
if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
|
|
1072
1006
|
const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
|
|
1073
|
-
const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff &&
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1076
|
-
const
|
|
1077
|
-
const
|
|
1007
|
+
const postToolRawAssistantCompletionNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isRawAssistantProgressNotification(notification) && params.activeTurnItemIds.size === 0;
|
|
1008
|
+
const postToolPatchUpdateNeedsTerminalGuard = isCurrentTurnNotification && turnCrossedToolHandoff && isFileChangePatchUpdatedNotification(notification);
|
|
1009
|
+
const rawResponseItemCompletedWithNoActiveItems = isCurrentTurnNotification && notification.method === "rawResponseItem/completed" && params.activeTurnItemIds.size === 0 && params.activeAppServerTurnRequests === 0 && !assistantCompletionCanRelease && !postToolRawAssistantCompletionNeedsTerminalGuard && !rawToolOutputCompletion;
|
|
1010
|
+
const shouldArmNoToolPostProgressReplyWatch = isCurrentTurnNotification && !turnCrossedToolHandoff && params.activeTurnItemIds.size === 0 && (isReasoningItemCompletionNotification(notification) || isAssistantCommentaryCompletionNotification(notification));
|
|
1011
|
+
const shouldArmNoToolPostRawProgressReplyWatch = !turnCrossedToolHandoff && rawResponseItemCompletedWithNoActiveItems && (isRawReasoningCompletionNotification(notification) || isRawAssistantProgressNotification(notification));
|
|
1012
|
+
const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && params.activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease && !shouldArmNoToolPostProgressReplyWatch;
|
|
1013
|
+
const shouldUsePostToolContinuationWatch = turnCrossedToolHandoff && (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard || rawToolOutputCompletion || trackedDynamicToolCompletion || shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem);
|
|
1014
|
+
const armPostToolContinuationWatch = () => {
|
|
1015
|
+
turnWatches.armCompletionIdleWatch({ timeoutMs: params.postToolRawAssistantCompletionIdleTimeoutMs });
|
|
1016
|
+
turnWatches.extendAttemptIdleWatch(params.postToolRawAssistantCompletionIdleTimeoutMs);
|
|
1017
|
+
};
|
|
1018
|
+
const armPostProgressReplyWatch = () => {
|
|
1019
|
+
turnWatches.armCompletionIdleWatch({ timeoutMs: CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS });
|
|
1020
|
+
turnWatches.extendAttemptIdleWatch(CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS);
|
|
1021
|
+
};
|
|
1078
1022
|
if (isCurrentTurnNotification && notification.method === "error") {
|
|
1079
1023
|
if (isRetryableErrorNotification(notification.params)) turnWatches.disarmCompletionIdleWatch();
|
|
1080
1024
|
else turnWatches.armCompletionIdleWatch({ pinnedByTerminalError: true });
|
|
1081
1025
|
turnWatches.disarmAssistantCompletionIdleWatch();
|
|
1082
1026
|
} else if (isTurnCompletion) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
1083
1027
|
else if (isCurrentTurnNotification && assistantCompletionCanRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
1084
|
-
else if (postToolRawAssistantCompletionNeedsTerminalGuard)
|
|
1085
|
-
else if (
|
|
1028
|
+
else if (postToolRawAssistantCompletionNeedsTerminalGuard || postToolPatchUpdateNeedsTerminalGuard) armPostToolContinuationWatch();
|
|
1029
|
+
else if (shouldArmNoToolPostProgressReplyWatch || shouldArmNoToolPostRawProgressReplyWatch) armPostProgressReplyWatch();
|
|
1030
|
+
else if (trackedDynamicToolCompletion) armPostToolContinuationWatch();
|
|
1086
1031
|
else if (unblockedAssistantCompletionRelease) turnWatches.armAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
1087
|
-
else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem)
|
|
1032
|
+
else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) if (shouldUsePostToolContinuationWatch) armPostToolContinuationWatch();
|
|
1033
|
+
else turnWatches.armCompletionIdleWatch();
|
|
1088
1034
|
else if (rawResponseItemCompletedWithNoActiveItems) turnWatches.armCompletionIdleWatch();
|
|
1089
|
-
else if (isCurrentTurnNotification && rawToolOutputCompletion)
|
|
1035
|
+
else if (isCurrentTurnNotification && rawToolOutputCompletion) armPostToolContinuationWatch();
|
|
1090
1036
|
else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) turnWatches.disarmAssistantCompletionIdleWatch();
|
|
1091
|
-
if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !
|
|
1037
|
+
if (turnWatches.isCompletionIdleWatchArmed() && !turnWatches.isCompletionIdleWatchPinnedByTerminalError() && notification.method !== "turn/completed" && isCurrentTurnNotification && !isNativeResponseStreamDelta && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !postToolRawAssistantCompletionNeedsTerminalGuard && !postToolPatchUpdateNeedsTerminalGuard && !rawResponseItemCompletedWithNoActiveItems && !shouldArmNoToolPostProgressReplyWatch && !shouldArmNoToolPostRawProgressReplyWatch && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) turnWatches.disarmCompletionIdleWatch();
|
|
1092
1038
|
if (trackedDynamicToolCompletion) {
|
|
1093
1039
|
const itemId = readNotificationItemId(notification);
|
|
1094
1040
|
if (itemId) {
|
|
@@ -1120,7 +1066,8 @@ function hasCodexAppServerPotentialSideEffectEvidence(result) {
|
|
|
1120
1066
|
}
|
|
1121
1067
|
function buildCodexAppServerPromptTimeoutOutcome(params) {
|
|
1122
1068
|
const completionIdleTimeoutHadPotentialSideEffects = hasCodexAppServerPotentialSideEffectEvidence(params.result);
|
|
1123
|
-
|
|
1069
|
+
const replayBlockedReason = resolveCodexAppServerReplayBlockedReason(params.result);
|
|
1070
|
+
if (!params.turnCompletionIdleTimedOut || params.result.itemLifecycle.completedCount === 0 && !completionIdleTimeoutHadPotentialSideEffects && replayBlockedReason === void 0) return;
|
|
1124
1071
|
return {
|
|
1125
1072
|
message: completionIdleTimeoutHadPotentialSideEffects ? CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_SIDE_EFFECT_USER_MESSAGE : CODEX_APP_SERVER_MISSING_TERMINAL_EVENT_USER_MESSAGE,
|
|
1126
1073
|
...completionIdleTimeoutHadPotentialSideEffects ? {
|
|
@@ -3013,9 +2960,16 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3013
2960
|
let completionLastActivityAt = Date.now();
|
|
3014
2961
|
let completionLastActivityReason = "startup";
|
|
3015
2962
|
let completionLastActivityDetails;
|
|
2963
|
+
let attemptIdleTimeoutOverrideMs;
|
|
3016
2964
|
let attemptLastProgressAt = Date.now();
|
|
3017
2965
|
let attemptLastProgressReason = "startup";
|
|
3018
2966
|
let attemptLastProgressDetails;
|
|
2967
|
+
const turnCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnCompletionIdleTimeoutMs, 1);
|
|
2968
|
+
const turnAssistantCompletionIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAssistantCompletionIdleTimeoutMs, 1);
|
|
2969
|
+
const turnAttemptIdleTimeoutMs = resolveTimerTimeoutMs(params.turnAttemptIdleTimeoutMs, 1);
|
|
2970
|
+
const turnTerminalIdleTimeoutMs = resolveTimerTimeoutMs(params.turnTerminalIdleTimeoutMs, 1);
|
|
2971
|
+
const interruptTimeoutMs = resolveTimerTimeoutMs(params.interruptTimeoutMs, 1);
|
|
2972
|
+
const resolveWatchTimeoutMs = (timeoutMs) => resolveTimerTimeoutMs(timeoutMs, 1);
|
|
3019
2973
|
const clearCompletionIdleTimer = () => {
|
|
3020
2974
|
if (completionIdleTimer) {
|
|
3021
2975
|
clearTimeout(completionIdleTimer);
|
|
@@ -3050,8 +3004,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3050
3004
|
clearCompletionIdleTimer();
|
|
3051
3005
|
if (params.isCompleted() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0) return;
|
|
3052
3006
|
const elapsedMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
3053
|
-
const
|
|
3054
|
-
const delayMs = Math.max(1, timeoutMs - elapsedMs);
|
|
3007
|
+
const delayMs = Math.max(1, (completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs) - elapsedMs);
|
|
3055
3008
|
completionIdleTimer = setTimeout(fireCompletionIdleTimeout, delayMs);
|
|
3056
3009
|
completionIdleTimer.unref?.();
|
|
3057
3010
|
}
|
|
@@ -3059,7 +3012,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3059
3012
|
clearAssistantCompletionIdleTimer();
|
|
3060
3013
|
if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
|
|
3061
3014
|
const elapsedMs = Math.max(0, Date.now() - assistantCompletionLastActivityAt);
|
|
3062
|
-
const delayMs = Math.max(1,
|
|
3015
|
+
const delayMs = Math.max(1, turnAssistantCompletionIdleTimeoutMs - elapsedMs);
|
|
3063
3016
|
assistantCompletionIdleTimer = setTimeout(fireAssistantCompletionIdleRelease, delayMs);
|
|
3064
3017
|
assistantCompletionIdleTimer.unref?.();
|
|
3065
3018
|
}
|
|
@@ -3067,7 +3020,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3067
3020
|
clearAttemptIdleTimer();
|
|
3068
3021
|
if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
|
|
3069
3022
|
const elapsedMs = Math.max(0, Date.now() - attemptLastProgressAt);
|
|
3070
|
-
const delayMs = Math.max(1,
|
|
3023
|
+
const delayMs = Math.max(1, (attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs) - elapsedMs);
|
|
3071
3024
|
attemptIdleTimer = setTimeout(fireAttemptIdleTimeout, delayMs);
|
|
3072
3025
|
attemptIdleTimer.unref?.();
|
|
3073
3026
|
}
|
|
@@ -3075,7 +3028,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3075
3028
|
clearTerminalIdleTimer();
|
|
3076
3029
|
if (params.isCompleted() || params.signal.aborted || !terminalIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0) return;
|
|
3077
3030
|
const elapsedMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
3078
|
-
const delayMs = Math.max(1,
|
|
3031
|
+
const delayMs = Math.max(1, turnTerminalIdleTimeoutMs - elapsedMs);
|
|
3079
3032
|
terminalIdleTimer = setTimeout(fireTerminalIdleTimeout, delayMs);
|
|
3080
3033
|
terminalIdleTimer.unref?.();
|
|
3081
3034
|
}
|
|
@@ -3084,6 +3037,14 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3084
3037
|
scheduleCompletionIdleWatch();
|
|
3085
3038
|
scheduleTerminalIdleWatch();
|
|
3086
3039
|
}
|
|
3040
|
+
function recordAttemptProgress(reason, options) {
|
|
3041
|
+
attemptIdleTimeoutOverrideMs = options?.attemptTimeoutMs !== void 0 ? resolveWatchTimeoutMs(options.attemptTimeoutMs) : void 0;
|
|
3042
|
+
attemptLastProgressAt = completionLastActivityAt;
|
|
3043
|
+
attemptLastProgressReason = reason;
|
|
3044
|
+
attemptLastProgressDetails = options?.details;
|
|
3045
|
+
params.onAttemptProgress(reason, options?.details);
|
|
3046
|
+
scheduleAttemptIdleWatch();
|
|
3047
|
+
}
|
|
3087
3048
|
function fireAssistantCompletionIdleRelease() {
|
|
3088
3049
|
if (params.isCompleted() || params.signal.aborted || !assistantCompletionIdleWatchArmed) return;
|
|
3089
3050
|
if (params.getActiveAppServerTurnRequests() > 0 || params.getActiveTurnItemCount() > 0) {
|
|
@@ -3091,7 +3052,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3091
3052
|
return;
|
|
3092
3053
|
}
|
|
3093
3054
|
const idleMs = Math.max(0, Date.now() - assistantCompletionLastActivityAt);
|
|
3094
|
-
if (idleMs <
|
|
3055
|
+
if (idleMs < turnAssistantCompletionIdleTimeoutMs) {
|
|
3095
3056
|
scheduleAssistantCompletionIdleWatch();
|
|
3096
3057
|
return;
|
|
3097
3058
|
}
|
|
@@ -3103,20 +3064,20 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3103
3064
|
threadId: params.threadId,
|
|
3104
3065
|
turnId,
|
|
3105
3066
|
idleMs,
|
|
3106
|
-
timeoutMs:
|
|
3067
|
+
timeoutMs: turnAssistantCompletionIdleTimeoutMs,
|
|
3107
3068
|
...assistantCompletionLastActivityDetails
|
|
3108
3069
|
});
|
|
3109
3070
|
embeddedAgentLog.warn("codex app-server turn released after completed assistant item without terminal event", {
|
|
3110
3071
|
threadId: params.threadId,
|
|
3111
3072
|
turnId,
|
|
3112
3073
|
idleMs,
|
|
3113
|
-
timeoutMs:
|
|
3074
|
+
timeoutMs: turnAssistantCompletionIdleTimeoutMs,
|
|
3114
3075
|
...assistantCompletionLastActivityDetails
|
|
3115
3076
|
});
|
|
3116
3077
|
if (turnId) params.onInterruptTurn({
|
|
3117
3078
|
threadId: params.threadId,
|
|
3118
3079
|
turnId,
|
|
3119
|
-
timeoutMs:
|
|
3080
|
+
timeoutMs: interruptTimeoutMs
|
|
3120
3081
|
});
|
|
3121
3082
|
params.onCompleted();
|
|
3122
3083
|
params.onResolveCompletion();
|
|
@@ -3124,14 +3085,15 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3124
3085
|
function fireAttemptIdleTimeout() {
|
|
3125
3086
|
if (params.isCompleted() || params.signal.aborted || !attemptIdleWatchArmed) return;
|
|
3126
3087
|
const idleMs = Math.max(0, Date.now() - attemptLastProgressAt);
|
|
3127
|
-
|
|
3088
|
+
const timeoutMs = attemptIdleTimeoutOverrideMs ?? turnAttemptIdleTimeoutMs;
|
|
3089
|
+
if (idleMs < timeoutMs) {
|
|
3128
3090
|
scheduleAttemptIdleWatch();
|
|
3129
3091
|
return;
|
|
3130
3092
|
}
|
|
3131
3093
|
const timeout = {
|
|
3132
3094
|
kind: "progress",
|
|
3133
3095
|
idleMs,
|
|
3134
|
-
timeoutMs
|
|
3096
|
+
timeoutMs,
|
|
3135
3097
|
lastActivityReason: attemptLastProgressReason,
|
|
3136
3098
|
details: attemptLastProgressDetails
|
|
3137
3099
|
};
|
|
@@ -3157,7 +3119,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3157
3119
|
}
|
|
3158
3120
|
function fireCompletionIdleTimeout() {
|
|
3159
3121
|
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !completionIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0) return;
|
|
3160
|
-
const timeoutMs = completionIdleTimeoutOverrideMs ??
|
|
3122
|
+
const timeoutMs = completionIdleTimeoutOverrideMs ?? turnCompletionIdleTimeoutMs;
|
|
3161
3123
|
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
3162
3124
|
if (idleMs < timeoutMs) {
|
|
3163
3125
|
scheduleCompletionIdleWatch();
|
|
@@ -3193,14 +3155,14 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3193
3155
|
function fireTerminalIdleTimeout() {
|
|
3194
3156
|
if (params.isCompleted() || params.isTerminalTurnNotificationQueued() || params.signal.aborted || !terminalIdleWatchArmed || params.getActiveAppServerTurnRequests() > 0) return;
|
|
3195
3157
|
const idleMs = Math.max(0, Date.now() - completionLastActivityAt);
|
|
3196
|
-
if (idleMs <
|
|
3158
|
+
if (idleMs < turnTerminalIdleTimeoutMs) {
|
|
3197
3159
|
scheduleTerminalIdleWatch();
|
|
3198
3160
|
return;
|
|
3199
3161
|
}
|
|
3200
3162
|
const timeout = {
|
|
3201
3163
|
kind: "terminal",
|
|
3202
3164
|
idleMs,
|
|
3203
|
-
timeoutMs:
|
|
3165
|
+
timeoutMs: turnTerminalIdleTimeoutMs,
|
|
3204
3166
|
lastActivityReason: completionLastActivityReason,
|
|
3205
3167
|
details: completionLastActivityDetails
|
|
3206
3168
|
};
|
|
@@ -3239,7 +3201,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3239
3201
|
armCompletionIdleWatch: (options) => {
|
|
3240
3202
|
completionIdleWatchArmed = true;
|
|
3241
3203
|
completionIdleWatchPinnedByTerminalError = options?.pinnedByTerminalError === true;
|
|
3242
|
-
completionIdleTimeoutOverrideMs = options?.timeoutMs !== void 0 ?
|
|
3204
|
+
completionIdleTimeoutOverrideMs = options?.timeoutMs !== void 0 ? resolveWatchTimeoutMs(options.timeoutMs) : void 0;
|
|
3243
3205
|
scheduleCompletionIdleWatch();
|
|
3244
3206
|
},
|
|
3245
3207
|
disarmCompletionIdleWatch: () => {
|
|
@@ -3264,12 +3226,7 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3264
3226
|
completionLastActivityReason = reason;
|
|
3265
3227
|
completionLastActivityDetails = options?.details;
|
|
3266
3228
|
completionIdleTimeoutOverrideMs = void 0;
|
|
3267
|
-
if (options?.attemptProgress)
|
|
3268
|
-
attemptLastProgressAt = completionLastActivityAt;
|
|
3269
|
-
attemptLastProgressReason = reason;
|
|
3270
|
-
attemptLastProgressDetails = options.details;
|
|
3271
|
-
params.onAttemptProgress(reason, options.details);
|
|
3272
|
-
}
|
|
3229
|
+
if (options?.attemptProgress) recordAttemptProgress(reason, options);
|
|
3273
3230
|
params.onProgressDiagnostic(reason);
|
|
3274
3231
|
if (options?.arm) {
|
|
3275
3232
|
completionIdleWatchArmed = true;
|
|
@@ -3277,9 +3234,15 @@ function createCodexAttemptTurnWatchController(params) {
|
|
|
3277
3234
|
}
|
|
3278
3235
|
scheduleProgressWatches();
|
|
3279
3236
|
},
|
|
3280
|
-
noteNotificationReceived: (method) => {
|
|
3237
|
+
noteNotificationReceived: (method, options) => {
|
|
3281
3238
|
completionLastActivityAt = Date.now();
|
|
3282
3239
|
completionLastActivityReason = `notification:${method}`;
|
|
3240
|
+
if (options?.details !== void 0) completionLastActivityDetails = options.details;
|
|
3241
|
+
if (options?.attemptProgress) recordAttemptProgress(completionLastActivityReason, options);
|
|
3242
|
+
},
|
|
3243
|
+
extendAttemptIdleWatch: (timeoutMs) => {
|
|
3244
|
+
attemptIdleTimeoutOverrideMs = resolveWatchTimeoutMs(timeoutMs);
|
|
3245
|
+
scheduleAttemptIdleWatch();
|
|
3283
3246
|
},
|
|
3284
3247
|
scheduleProgressWatches,
|
|
3285
3248
|
clearCompletionIdleTimer,
|
|
@@ -3348,7 +3311,7 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
3348
3311
|
let resolveAbort;
|
|
3349
3312
|
const abortFromRun = () => {
|
|
3350
3313
|
const message = "OpenClaw dynamic tool call aborted.";
|
|
3351
|
-
controller.abort(params.signal.reason ?? new Error(message));
|
|
3314
|
+
controller.abort(params.signal.reason ?? /* @__PURE__ */ new Error(message));
|
|
3352
3315
|
resolveAbort?.(failedDynamicToolResponse(message, { sideEffectEvidence: true }));
|
|
3353
3316
|
};
|
|
3354
3317
|
const abortPromise = new Promise((resolve) => {
|
|
@@ -3428,6 +3391,9 @@ function toCodexDynamicToolProgressResponse(response, protocolResponse) {
|
|
|
3428
3391
|
function shouldReleaseTurnAfterTerminalDynamicTool(state) {
|
|
3429
3392
|
return !state.completed && !state.aborted && state.responseSuccess && !state.currentTurnHadNonTerminalDynamicToolResult && state.activeAppServerTurnRequests === 0 && state.activeTurnItemIdsCount === 0 && state.pendingOpenClawDynamicToolCompletionIdsCount === 0;
|
|
3430
3393
|
}
|
|
3394
|
+
function shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response) {
|
|
3395
|
+
return response.asyncStarted !== true;
|
|
3396
|
+
}
|
|
3431
3397
|
function resolveTerminalDynamicToolBatchAction(state) {
|
|
3432
3398
|
if (state.activeAppServerTurnRequests > 0 || state.activeTurnItemIdsCount > 0 || state.pendingOpenClawDynamicToolCompletionIdsCount > 0) return "wait";
|
|
3433
3399
|
if (state.currentTurnHadNonTerminalDynamicToolResult) return "clear-nonterminal-batch";
|
|
@@ -3486,15 +3452,14 @@ function clampDynamicToolTimeoutMs(timeoutMs) {
|
|
|
3486
3452
|
//#region extensions/codex/src/app-server/local-runtime-attribution.ts
|
|
3487
3453
|
const OPENAI_PROVIDER_ID = "openai";
|
|
3488
3454
|
const OPENAI_RESPONSES_API = "openai-responses";
|
|
3489
|
-
const
|
|
3490
|
-
const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
|
|
3455
|
+
const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
|
|
3491
3456
|
function normalizeRuntimeId(value) {
|
|
3492
3457
|
return value?.trim().toLowerCase() ?? "";
|
|
3493
3458
|
}
|
|
3494
3459
|
function resolveCodexLocalRuntimeAttribution(params) {
|
|
3495
3460
|
const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
|
|
3496
3461
|
if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
|
|
3497
|
-
provider:
|
|
3462
|
+
provider: OPENAI_PROVIDER_ID,
|
|
3498
3463
|
api: OPENAI_CODEX_RESPONSES_API
|
|
3499
3464
|
};
|
|
3500
3465
|
return {
|
|
@@ -3754,6 +3719,7 @@ async function mirrorCodexAppServerTranscript(params) {
|
|
|
3754
3719
|
for (const update of appendedUpdates) emitSessionTranscriptUpdate({
|
|
3755
3720
|
sessionFile: params.sessionFile,
|
|
3756
3721
|
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3722
|
+
...params.agentId ? { agentId: params.agentId } : {},
|
|
3757
3723
|
message: update.message,
|
|
3758
3724
|
messageId: update.messageId,
|
|
3759
3725
|
messageSeq: update.messageSeq
|
|
@@ -3826,6 +3792,9 @@ const CODEX_PROMPT_TOTAL_INPUT_KEYS = [
|
|
|
3826
3792
|
];
|
|
3827
3793
|
const MAX_TOOL_OUTPUT_DELTA_MESSAGES_PER_ITEM = 20;
|
|
3828
3794
|
const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3;
|
|
3795
|
+
const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
|
|
3796
|
+
const BYTES_PER_MB = 1024 * 1024;
|
|
3797
|
+
const DEFAULT_GENERATED_IMAGE_MAX_BYTES = 6 * BYTES_PER_MB;
|
|
3829
3798
|
const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = new Set([
|
|
3830
3799
|
"message",
|
|
3831
3800
|
"messages",
|
|
@@ -3871,6 +3840,8 @@ var CodexAppServerEventProjector = class {
|
|
|
3871
3840
|
this.toolTranscriptResultIds = /* @__PURE__ */ new Set();
|
|
3872
3841
|
this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
|
|
3873
3842
|
this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
|
|
3843
|
+
this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
|
|
3844
|
+
this.nativeGeneratedMediaUrlsByItemId = /* @__PURE__ */ new Map();
|
|
3874
3845
|
this.diagnosticToolStartedAtByItem = /* @__PURE__ */ new Map();
|
|
3875
3846
|
this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
|
|
3876
3847
|
this.assistantStarted = false;
|
|
@@ -3936,7 +3907,7 @@ var CodexAppServerEventProjector = class {
|
|
|
3936
3907
|
await this.handleTurnCompleted(params);
|
|
3937
3908
|
break;
|
|
3938
3909
|
case "rawResponseItem/completed":
|
|
3939
|
-
this.handleRawResponseItemCompleted(params);
|
|
3910
|
+
await this.handleRawResponseItemCompleted(params);
|
|
3940
3911
|
break;
|
|
3941
3912
|
case "error":
|
|
3942
3913
|
if (readBooleanAlias(params, ["willRetry", "will_retry"]) === true) break;
|
|
@@ -3967,7 +3938,7 @@ var CodexAppServerEventProjector = class {
|
|
|
3967
3938
|
turnCompleted: Boolean(this.completedTurn)
|
|
3968
3939
|
});
|
|
3969
3940
|
const toolMetas = [...this.toolMetas.values()];
|
|
3970
|
-
const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.sideEffectingToolItemIds.size > 0 || this.sideEffectingDynamicToolCallIds.size > 0;
|
|
3941
|
+
const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.nativeGeneratedMediaItemIds.size > 0 || this.sideEffectingToolItemIds.size > 0 || this.sideEffectingDynamicToolCallIds.size > 0;
|
|
3971
3942
|
return {
|
|
3972
3943
|
aborted: this.aborted,
|
|
3973
3944
|
externalAbort: false,
|
|
@@ -4388,9 +4359,11 @@ var CodexAppServerEventProjector = class {
|
|
|
4388
4359
|
text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
|
|
4389
4360
|
});
|
|
4390
4361
|
}
|
|
4391
|
-
handleRawResponseItemCompleted(params) {
|
|
4362
|
+
async handleRawResponseItemCompleted(params) {
|
|
4392
4363
|
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
4393
|
-
if (!item
|
|
4364
|
+
if (!item) return;
|
|
4365
|
+
await this.recordRawGeneratedImageMedia(item);
|
|
4366
|
+
if (readString$5(item, "role") !== "assistant") return;
|
|
4394
4367
|
const text = extractRawAssistantText(item);
|
|
4395
4368
|
if (!text) return;
|
|
4396
4369
|
const itemId = readString$5(item, "id") ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
|
|
@@ -4406,7 +4379,56 @@ var CodexAppServerEventProjector = class {
|
|
|
4406
4379
|
recordNativeGeneratedMedia(item) {
|
|
4407
4380
|
if (item?.type !== "imageGeneration") return;
|
|
4408
4381
|
const savedPath = readItemString(item, "savedPath")?.trim();
|
|
4409
|
-
if (savedPath) this.
|
|
4382
|
+
if (savedPath) this.recordNativeGeneratedMediaUrl({
|
|
4383
|
+
itemId: item.id,
|
|
4384
|
+
mediaUrl: savedPath
|
|
4385
|
+
});
|
|
4386
|
+
}
|
|
4387
|
+
async recordRawGeneratedImageMedia(item) {
|
|
4388
|
+
if (readString$5(item, "type") !== "image_generation_call") return;
|
|
4389
|
+
const result = readString$5(item, "result");
|
|
4390
|
+
if (!result) return;
|
|
4391
|
+
const itemId = readString$5(item, "id") ?? `raw-image-${this.nativeGeneratedMediaItemIds.size}`;
|
|
4392
|
+
this.nativeGeneratedMediaItemIds.add(itemId);
|
|
4393
|
+
const maxBytes = resolveGeneratedImageMaxBytes(this.params.config);
|
|
4394
|
+
const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
|
|
4395
|
+
if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
|
|
4396
|
+
embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
|
|
4397
|
+
itemId,
|
|
4398
|
+
estimatedDecodedBytes,
|
|
4399
|
+
maxBytes
|
|
4400
|
+
});
|
|
4401
|
+
return;
|
|
4402
|
+
}
|
|
4403
|
+
const asset = generatedImageAssetFromBase64({
|
|
4404
|
+
base64: result,
|
|
4405
|
+
index: this.nativeGeneratedMediaItemIds.size,
|
|
4406
|
+
revisedPrompt: readString$5(item, "revised_prompt") ?? readString$5(item, "revisedPrompt"),
|
|
4407
|
+
fileNamePrefix: "codex-image-generation",
|
|
4408
|
+
sniffMimeType: true
|
|
4409
|
+
});
|
|
4410
|
+
if (!asset) return;
|
|
4411
|
+
try {
|
|
4412
|
+
const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
|
|
4413
|
+
this.recordNativeGeneratedMediaUrl({
|
|
4414
|
+
itemId,
|
|
4415
|
+
mediaUrl: saved.path
|
|
4416
|
+
});
|
|
4417
|
+
} catch (error) {
|
|
4418
|
+
embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
|
|
4419
|
+
itemId,
|
|
4420
|
+
error
|
|
4421
|
+
});
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
recordNativeGeneratedMediaUrl(params) {
|
|
4425
|
+
if (this.nativeGeneratedMediaUrlsByItemId.has(params.itemId)) {
|
|
4426
|
+
this.nativeGeneratedMediaItemIds.add(params.itemId);
|
|
4427
|
+
return;
|
|
4428
|
+
}
|
|
4429
|
+
this.nativeGeneratedMediaUrlsByItemId.set(params.itemId, params.mediaUrl);
|
|
4430
|
+
this.nativeGeneratedMediaUrls.add(params.mediaUrl);
|
|
4431
|
+
this.nativeGeneratedMediaItemIds.add(params.itemId);
|
|
4410
4432
|
}
|
|
4411
4433
|
buildToolMediaUrls(toolTelemetry) {
|
|
4412
4434
|
const mediaUrls = new Set(toolTelemetry.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
|
|
@@ -4617,7 +4639,7 @@ var CodexAppServerEventProjector = class {
|
|
|
4617
4639
|
this.afterToolCallObservedItemIds.add(item.id);
|
|
4618
4640
|
const result = itemToolResult(item).result;
|
|
4619
4641
|
const error = itemToolError(item, status, this.toolResultOutputTextByItem);
|
|
4620
|
-
const startedAt =
|
|
4642
|
+
const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
|
|
4621
4643
|
const hookParams = {
|
|
4622
4644
|
toolName: name,
|
|
4623
4645
|
toolCallId: item.id,
|
|
@@ -4833,7 +4855,7 @@ var CodexAppServerEventProjector = class {
|
|
|
4833
4855
|
type: "text",
|
|
4834
4856
|
text
|
|
4835
4857
|
}],
|
|
4836
|
-
api: attribution.api ?? "openai-
|
|
4858
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
4837
4859
|
provider: attribution.provider,
|
|
4838
4860
|
model: this.params.modelId,
|
|
4839
4861
|
usage,
|
|
@@ -4850,7 +4872,7 @@ var CodexAppServerEventProjector = class {
|
|
|
4850
4872
|
type: "text",
|
|
4851
4873
|
text: `${title}:\n${text}`
|
|
4852
4874
|
}],
|
|
4853
|
-
api: attribution.api ?? "openai-
|
|
4875
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
4854
4876
|
provider: attribution.provider,
|
|
4855
4877
|
model: this.params.modelId,
|
|
4856
4878
|
usage: ZERO_USAGE,
|
|
@@ -4870,7 +4892,7 @@ var CodexAppServerEventProjector = class {
|
|
|
4870
4892
|
arguments: args,
|
|
4871
4893
|
input: args
|
|
4872
4894
|
}],
|
|
4873
|
-
api: attribution.api ?? "openai-
|
|
4895
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
4874
4896
|
provider: attribution.provider,
|
|
4875
4897
|
model: this.params.modelId,
|
|
4876
4898
|
usage: ZERO_USAGE,
|
|
@@ -4920,6 +4942,30 @@ function readString$5(record, key) {
|
|
|
4920
4942
|
const value = record[key];
|
|
4921
4943
|
return typeof value === "string" ? value : void 0;
|
|
4922
4944
|
}
|
|
4945
|
+
function estimateBase64DecodedBytes(base64) {
|
|
4946
|
+
let nonWhitespaceLength = 0;
|
|
4947
|
+
let previousCode = -1;
|
|
4948
|
+
let lastCode = -1;
|
|
4949
|
+
for (let i = 0; i < base64.length; i += 1) {
|
|
4950
|
+
const code = base64.charCodeAt(i);
|
|
4951
|
+
if (isBase64WhitespaceCode(code)) continue;
|
|
4952
|
+
nonWhitespaceLength += 1;
|
|
4953
|
+
previousCode = lastCode;
|
|
4954
|
+
lastCode = code;
|
|
4955
|
+
}
|
|
4956
|
+
if (nonWhitespaceLength === 0) return;
|
|
4957
|
+
const equalsCode = "=".charCodeAt(0);
|
|
4958
|
+
const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
|
|
4959
|
+
return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
|
|
4960
|
+
}
|
|
4961
|
+
function isBase64WhitespaceCode(code) {
|
|
4962
|
+
return code === 32 || code === 9 || code === 10 || code === 13;
|
|
4963
|
+
}
|
|
4964
|
+
function resolveGeneratedImageMaxBytes(config) {
|
|
4965
|
+
const configured = config?.agents?.defaults?.mediaMaxMb;
|
|
4966
|
+
if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * BYTES_PER_MB);
|
|
4967
|
+
return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
|
|
4968
|
+
}
|
|
4923
4969
|
function normalizeNonEmptyString(value) {
|
|
4924
4970
|
if (typeof value !== "string") return;
|
|
4925
4971
|
return value.trim() || void 0;
|
|
@@ -4946,6 +4992,10 @@ function readNumber$1(record, key) {
|
|
|
4946
4992
|
const value = record[key];
|
|
4947
4993
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4948
4994
|
}
|
|
4995
|
+
function resolveStartedAtFromDurationMs(durationMs) {
|
|
4996
|
+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
|
|
4997
|
+
return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
|
|
4998
|
+
}
|
|
4949
4999
|
function readNonNegativeInteger(record, key) {
|
|
4950
5000
|
const value = readNumber$1(record, key);
|
|
4951
5001
|
return value !== void 0 && Number.isInteger(value) && value >= 0 ? value : void 0;
|
|
@@ -6349,6 +6399,9 @@ function unrefTimer(timer) {
|
|
|
6349
6399
|
//#endregion
|
|
6350
6400
|
//#region extensions/codex/src/app-server/startup-binding.ts
|
|
6351
6401
|
const CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS = 3e5;
|
|
6402
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS = 2e4;
|
|
6403
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS = 8e3;
|
|
6404
|
+
const CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO = .5;
|
|
6352
6405
|
const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
6353
6406
|
b: 1,
|
|
6354
6407
|
k: 1024,
|
|
@@ -6364,6 +6417,7 @@ const CODEX_APP_SERVER_BYTE_UNITS = {
|
|
|
6364
6417
|
tb: 1024 * 1024 * 1024 * 1024,
|
|
6365
6418
|
tib: 1024 * 1024 * 1024 * 1024
|
|
6366
6419
|
};
|
|
6420
|
+
const codexSessionRecordCache = /* @__PURE__ */ new Map();
|
|
6367
6421
|
function parseCodexAppServerByteLimit(value) {
|
|
6368
6422
|
if (typeof value === "number" && Number.isFinite(value) && value > 0) return Math.floor(value);
|
|
6369
6423
|
if (typeof value !== "string") return;
|
|
@@ -6419,22 +6473,44 @@ async function listCodexAppServerRolloutFilesForThread(agentDir, threadId, codex
|
|
|
6419
6473
|
}
|
|
6420
6474
|
async function readCodexSessionRecordForSessionFile(sessionFile) {
|
|
6421
6475
|
const sessionsFile = path.join(path.dirname(sessionFile), "sessions.json");
|
|
6476
|
+
const resolvedSessionFile = path.resolve(sessionFile);
|
|
6477
|
+
let stat;
|
|
6478
|
+
try {
|
|
6479
|
+
stat = await fs.stat(sessionsFile);
|
|
6480
|
+
} catch {
|
|
6481
|
+
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
const cached = codexSessionRecordCache.get(resolvedSessionFile);
|
|
6485
|
+
if (cached?.sessionsFile === sessionsFile && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.record;
|
|
6422
6486
|
let store;
|
|
6423
6487
|
try {
|
|
6424
6488
|
store = JSON.parse(await fs.readFile(sessionsFile, "utf8"));
|
|
6425
6489
|
} catch {
|
|
6490
|
+
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
6426
6491
|
return;
|
|
6427
6492
|
}
|
|
6428
|
-
if (!isJsonObject(store))
|
|
6429
|
-
|
|
6493
|
+
if (!isJsonObject(store)) {
|
|
6494
|
+
codexSessionRecordCache.delete(resolvedSessionFile);
|
|
6495
|
+
return;
|
|
6496
|
+
}
|
|
6497
|
+
let found;
|
|
6430
6498
|
for (const [sessionKey, record] of Object.entries(store)) {
|
|
6431
6499
|
if (!isJsonObject(record) || typeof record.sessionFile !== "string") continue;
|
|
6432
6500
|
if (path.resolve(record.sessionFile) !== resolvedSessionFile) continue;
|
|
6433
|
-
|
|
6501
|
+
found = {
|
|
6434
6502
|
sessionKey,
|
|
6435
6503
|
...record
|
|
6436
6504
|
};
|
|
6505
|
+
break;
|
|
6437
6506
|
}
|
|
6507
|
+
codexSessionRecordCache.set(resolvedSessionFile, {
|
|
6508
|
+
sessionsFile,
|
|
6509
|
+
mtimeMs: stat.mtimeMs,
|
|
6510
|
+
size: stat.size,
|
|
6511
|
+
record: found
|
|
6512
|
+
});
|
|
6513
|
+
return found;
|
|
6438
6514
|
}
|
|
6439
6515
|
async function readCodexAppServerRolloutTokenSnapshot(file) {
|
|
6440
6516
|
let handle;
|
|
@@ -6478,52 +6554,75 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
|
|
|
6478
6554
|
return;
|
|
6479
6555
|
}
|
|
6480
6556
|
}
|
|
6481
|
-
function
|
|
6482
|
-
|
|
6557
|
+
function toNonNegativeInt(value) {
|
|
6558
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
|
|
6559
|
+
return Math.floor(value);
|
|
6560
|
+
}
|
|
6561
|
+
function readCompactionConfig(config) {
|
|
6562
|
+
return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
|
|
6563
|
+
}
|
|
6564
|
+
function resolveCodexAppServerNativeThreadReserveTokens(config) {
|
|
6565
|
+
const compaction = readCompactionConfig(config);
|
|
6566
|
+
const reserveTokens = toNonNegativeInt(compaction?.reserveTokens);
|
|
6567
|
+
const reserveTokensFloor = toNonNegativeInt(compaction?.reserveTokensFloor);
|
|
6568
|
+
if (reserveTokens !== void 0) return Math.max(reserveTokens, reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS);
|
|
6569
|
+
return reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
6570
|
+
}
|
|
6571
|
+
function resolveCodexAppServerNativeThreadTokenFuse(params) {
|
|
6572
|
+
const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
|
|
6573
|
+
const contextWindow = params.modelContextWindow ?? CODEX_APP_SERVER_NATIVE_THREAD_FALLBACK_MAX_TOKENS;
|
|
6574
|
+
const minPromptBudget = Math.min(CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_TOKENS, Math.max(1, Math.floor(contextWindow * CODEX_APP_SERVER_NATIVE_THREAD_MIN_PROMPT_BUDGET_RATIO)));
|
|
6575
|
+
const effectiveReserveTokens = Math.min(params.reserveTokens, Math.max(0, contextWindow - minPromptBudget));
|
|
6576
|
+
return Math.max(1, contextWindow - effectiveReserveTokens - projectedTurnTokens);
|
|
6483
6577
|
}
|
|
6484
6578
|
function maxFiniteNumber(values) {
|
|
6485
6579
|
const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
6486
6580
|
if (nums.length === 0) return;
|
|
6487
6581
|
return Math.max(...nums);
|
|
6488
6582
|
}
|
|
6583
|
+
function minFiniteNumber(values) {
|
|
6584
|
+
const nums = values.filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
6585
|
+
if (nums.length === 0) return;
|
|
6586
|
+
return Math.min(...nums);
|
|
6587
|
+
}
|
|
6489
6588
|
function hasContextEngineThreadBootstrapProjection(binding) {
|
|
6490
6589
|
return binding.contextEngine?.projection?.mode === "thread_bootstrap";
|
|
6491
6590
|
}
|
|
6492
6591
|
async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
6493
6592
|
const binding = params.binding;
|
|
6494
6593
|
if (!binding?.threadId) return binding;
|
|
6495
|
-
if (params.config?.agents?.defaults?.compaction?.truncateAfterCompaction !== true) return binding;
|
|
6496
|
-
if (params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding)) {
|
|
6497
|
-
embeddedAgentLog.debug("codex app-server deferring native transcript size guard for context-engine thread bootstrap", {
|
|
6498
|
-
threadId: binding.threadId,
|
|
6499
|
-
engineId: binding.contextEngine?.engineId,
|
|
6500
|
-
epoch: binding.contextEngine?.projection?.epoch,
|
|
6501
|
-
fingerprint: binding.contextEngine?.projection?.fingerprint
|
|
6502
|
-
});
|
|
6503
|
-
return binding;
|
|
6504
|
-
}
|
|
6505
6594
|
const sessionRecord = await readCodexSessionRecordForSessionFile(params.sessionFile);
|
|
6506
|
-
const maxBytes = parseCodexAppServerByteLimit(params.config?.agents?.defaults?.compaction?.maxActiveTranscriptBytes);
|
|
6507
6595
|
const rolloutFiles = await listCodexAppServerRolloutFilesForThread(params.agentDir, binding.threadId, params.codexHome);
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6596
|
+
const compaction = readCompactionConfig(params.config);
|
|
6597
|
+
const shouldDeferByteGuard = compaction?.truncateAfterCompaction === true && params.contextEngineActive === true && hasContextEngineThreadBootstrapProjection(binding);
|
|
6598
|
+
if (compaction?.truncateAfterCompaction === true && !shouldDeferByteGuard) {
|
|
6599
|
+
const maxBytes = parseCodexAppServerByteLimit(compaction.maxActiveTranscriptBytes);
|
|
6600
|
+
if (maxBytes !== void 0) {
|
|
6601
|
+
const oversizedFiles = rolloutFiles.filter((file) => file.bytes >= maxBytes);
|
|
6602
|
+
if (oversizedFiles.length > 0) {
|
|
6603
|
+
embeddedAgentLog.warn("codex app-server native transcript exceeded active byte limit; starting a fresh thread", {
|
|
6604
|
+
threadId: binding.threadId,
|
|
6605
|
+
maxBytes,
|
|
6606
|
+
files: oversizedFiles.map((file) => ({
|
|
6607
|
+
path: file.path,
|
|
6608
|
+
bytes: file.bytes
|
|
6609
|
+
}))
|
|
6610
|
+
});
|
|
6611
|
+
await clearCodexAppServerBinding(params.sessionFile);
|
|
6612
|
+
return;
|
|
6613
|
+
}
|
|
6521
6614
|
}
|
|
6522
6615
|
}
|
|
6523
6616
|
const nativeTokenSnapshots = await Promise.all(rolloutFiles.map(async (file) => readCodexAppServerRolloutTokenSnapshot(file.path)));
|
|
6524
6617
|
const nativeTokens = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.totalTokens));
|
|
6525
6618
|
const nativeModelContextWindow = maxFiniteNumber(nativeTokenSnapshots.map((snapshot) => snapshot?.modelContextWindow));
|
|
6526
|
-
const
|
|
6619
|
+
const sessionModelContextWindow = typeof sessionRecord?.contextTokens === "number" && Number.isFinite(sessionRecord.contextTokens) && sessionRecord.contextTokens > 0 ? Math.floor(sessionRecord.contextTokens) : void 0;
|
|
6620
|
+
const reserveTokens = resolveCodexAppServerNativeThreadReserveTokens(params.config);
|
|
6621
|
+
const maxTokens = resolveCodexAppServerNativeThreadTokenFuse({
|
|
6622
|
+
modelContextWindow: minFiniteNumber([nativeModelContextWindow, sessionModelContextWindow]),
|
|
6623
|
+
reserveTokens,
|
|
6624
|
+
projectedTurnTokens: params.projectedTurnTokens
|
|
6625
|
+
});
|
|
6527
6626
|
const sessionTokens = sessionRecord?.totalTokensFresh !== false && typeof sessionRecord?.totalTokens === "number" && Number.isFinite(sessionRecord.totalTokens) ? sessionRecord.totalTokens : void 0;
|
|
6528
6627
|
const tokenCount = maxFiniteNumber([sessionTokens, nativeTokens]);
|
|
6529
6628
|
if (tokenCount !== void 0 && tokenCount >= maxTokens) {
|
|
@@ -6533,11 +6632,24 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
6533
6632
|
sessionKey: sessionRecord?.sessionKey,
|
|
6534
6633
|
sessionTokens,
|
|
6535
6634
|
nativeTokens,
|
|
6536
|
-
nativeModelContextWindow
|
|
6635
|
+
nativeModelContextWindow,
|
|
6636
|
+
sessionModelContextWindow,
|
|
6637
|
+
reserveTokens,
|
|
6638
|
+
projectedTurnTokens: params.projectedTurnTokens
|
|
6537
6639
|
});
|
|
6538
6640
|
await clearCodexAppServerBinding(params.sessionFile);
|
|
6539
6641
|
return;
|
|
6540
6642
|
}
|
|
6643
|
+
if (compaction?.truncateAfterCompaction !== true) return binding;
|
|
6644
|
+
if (shouldDeferByteGuard) {
|
|
6645
|
+
embeddedAgentLog.debug("codex app-server deferring native transcript byte guard for context-engine thread bootstrap", {
|
|
6646
|
+
threadId: binding.threadId,
|
|
6647
|
+
engineId: binding.contextEngine?.engineId,
|
|
6648
|
+
epoch: binding.contextEngine?.projection?.epoch,
|
|
6649
|
+
fingerprint: binding.contextEngine?.projection?.fingerprint
|
|
6650
|
+
});
|
|
6651
|
+
return binding;
|
|
6652
|
+
}
|
|
6541
6653
|
return binding;
|
|
6542
6654
|
}
|
|
6543
6655
|
//#endregion
|
|
@@ -7056,7 +7168,12 @@ function readRequestId(record) {
|
|
|
7056
7168
|
//#endregion
|
|
7057
7169
|
//#region extensions/codex/src/app-server/run-attempt.ts
|
|
7058
7170
|
const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
|
|
7171
|
+
const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
|
|
7059
7172
|
const ensuredCodexWorkspaceDirs = /* @__PURE__ */ new Set();
|
|
7173
|
+
function estimateCodexAppServerProjectedTurnTokens(params) {
|
|
7174
|
+
const inputChars = params.prompt.length + (params.developerInstructions?.length ?? 0);
|
|
7175
|
+
return Math.max(1, Math.ceil(inputChars / CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN));
|
|
7176
|
+
}
|
|
7060
7177
|
async function ensureCodexWorkspaceDirOnce(workspaceDir) {
|
|
7061
7178
|
const normalized = path.resolve(workspaceDir);
|
|
7062
7179
|
if (ensuredCodexWorkspaceDirs.has(normalized)) {
|
|
@@ -7202,8 +7319,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7202
7319
|
sessionKey: contextSessionKey,
|
|
7203
7320
|
...startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}
|
|
7204
7321
|
};
|
|
7205
|
-
|
|
7206
|
-
|
|
7322
|
+
const activeSessionId = params.sessionId;
|
|
7323
|
+
const activeSessionFile = params.sessionFile;
|
|
7207
7324
|
const buildActiveRunAttemptParams = () => ({
|
|
7208
7325
|
...runtimeParams,
|
|
7209
7326
|
sessionId: activeSessionId,
|
|
@@ -7363,17 +7480,27 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7363
7480
|
const baseDeveloperInstructions = joinPresentSections(buildDeveloperInstructions(params, { dynamicTools: toolBridge.availableSpecs }), workspaceBootstrapContext.developerInstructions);
|
|
7364
7481
|
const openClawPromptContext = buildCodexOpenClawPromptContext({
|
|
7365
7482
|
params,
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
7371
|
-
})
|
|
7483
|
+
workspacePromptContext: workspaceBootstrapContext.promptContext
|
|
7484
|
+
});
|
|
7485
|
+
const skillsCollaborationInstructions = renderCodexSkillsCollaborationInstructions({
|
|
7486
|
+
attempt: params,
|
|
7487
|
+
skillsPrompt: params.skillsSnapshot?.prompt
|
|
7372
7488
|
});
|
|
7373
7489
|
let promptText = params.prompt;
|
|
7374
7490
|
let developerInstructions = baseDeveloperInstructions;
|
|
7375
7491
|
let prePromptMessageCount = historyMessages.length;
|
|
7376
7492
|
let contextEngineProjection;
|
|
7493
|
+
let precomputedStaleBindingContinuityProjectionApplied = false;
|
|
7494
|
+
let staleBindingContinuityForcedFreshStart = false;
|
|
7495
|
+
const applyFreshThreadContinuityProjection = () => {
|
|
7496
|
+
const projection = projectContextEngineAssemblyForCodex({
|
|
7497
|
+
assembledMessages: historyMessages,
|
|
7498
|
+
originalHistoryMessages: historyMessages,
|
|
7499
|
+
prompt: params.prompt
|
|
7500
|
+
});
|
|
7501
|
+
promptText = projection.promptText;
|
|
7502
|
+
prePromptMessageCount = projection.prePromptMessageCount;
|
|
7503
|
+
};
|
|
7377
7504
|
const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
|
|
7378
7505
|
if (!activeContextEngine) return;
|
|
7379
7506
|
const assembled = await assembleHarnessContextEngine({
|
|
@@ -7435,41 +7562,125 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7435
7562
|
} catch (assembleErr) {
|
|
7436
7563
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
7437
7564
|
}
|
|
7438
|
-
|
|
7439
|
-
startupBinding,
|
|
7440
|
-
dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs),
|
|
7441
|
-
historyMessages,
|
|
7442
|
-
forceProject: !nativeToolSurfaceEnabled
|
|
7443
|
-
})) {
|
|
7444
|
-
const projection = projectContextEngineAssemblyForCodex({
|
|
7445
|
-
assembledMessages: historyMessages,
|
|
7446
|
-
originalHistoryMessages: historyMessages,
|
|
7447
|
-
prompt: params.prompt
|
|
7448
|
-
});
|
|
7449
|
-
promptText = projection.promptText;
|
|
7450
|
-
prePromptMessageCount = projection.prePromptMessageCount;
|
|
7451
|
-
}
|
|
7565
|
+
const codexModelInputHistoryMessages = [];
|
|
7452
7566
|
const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
|
|
7453
7567
|
prompt: prependCurrentInboundContext(promptText, params.currentInboundContext),
|
|
7454
7568
|
developerInstructions,
|
|
7455
|
-
messages:
|
|
7569
|
+
messages: codexModelInputHistoryMessages,
|
|
7456
7570
|
ctx: hookContext
|
|
7457
7571
|
});
|
|
7458
7572
|
let promptBuild = await buildPromptFromCurrentInputs();
|
|
7459
|
-
const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext);
|
|
7573
|
+
const decorateCodexTurnPromptText = (prompt) => prependCodexOpenClawPromptContext(prompt, openClawPromptContext, { preservePromptWithoutContext: params.bootstrapContextMode === "lightweight" && params.bootstrapContextRunKind === "cron" });
|
|
7460
7574
|
let codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
|
|
7461
7575
|
const buildCodexTurnCollaborationDeveloperInstructions = () => buildTurnCollaborationMode(params, {
|
|
7462
7576
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
7577
|
+
skillsCollaborationInstructions,
|
|
7578
|
+
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
7463
7579
|
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
|
|
7464
7580
|
}).settings.developer_instructions ?? void 0;
|
|
7465
7581
|
const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(promptBuild.developerInstructions, buildCodexTurnCollaborationDeveloperInstructions());
|
|
7582
|
+
const rebuildCodexPromptBuildFromCurrentProjection = async () => {
|
|
7583
|
+
promptBuild = await buildPromptFromCurrentInputs();
|
|
7584
|
+
codexTurnPromptText = decorateCodexTurnPromptText(promptBuild.prompt);
|
|
7585
|
+
};
|
|
7586
|
+
const rebuildCodexTurnPromptTextFromCurrentProjection = async () => {
|
|
7587
|
+
const nextPromptBuild = await buildPromptFromCurrentInputs();
|
|
7588
|
+
promptBuild = {
|
|
7589
|
+
...promptBuild,
|
|
7590
|
+
prompt: nextPromptBuild.prompt
|
|
7591
|
+
};
|
|
7592
|
+
codexTurnPromptText = decorateCodexTurnPromptText(nextPromptBuild.prompt);
|
|
7593
|
+
};
|
|
7594
|
+
const selectNewerVisibleHistoryAfterBinding = (binding) => {
|
|
7595
|
+
const bindingUpdatedAt = Date.parse(binding.updatedAt);
|
|
7596
|
+
if (!Number.isFinite(bindingUpdatedAt)) return [];
|
|
7597
|
+
return historyMessages.filter((message) => {
|
|
7598
|
+
if (message.role !== "user" && message.role !== "assistant") return false;
|
|
7599
|
+
const record = message;
|
|
7600
|
+
const idempotencyKey = record.idempotencyKey;
|
|
7601
|
+
if (typeof idempotencyKey === "string" && idempotencyKey.startsWith("codex-app-server:")) return false;
|
|
7602
|
+
const meta = record["__openclaw"];
|
|
7603
|
+
const mirrorIdentity = meta && typeof meta === "object" && !Array.isArray(meta) ? meta.mirrorIdentity : void 0;
|
|
7604
|
+
if (typeof mirrorIdentity === "string" && mirrorIdentity.startsWith("codex-app-server:")) return false;
|
|
7605
|
+
const timestamp = typeof message.timestamp === "number" ? message.timestamp : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
7606
|
+
return Number.isFinite(timestamp) && timestamp > bindingUpdatedAt;
|
|
7607
|
+
});
|
|
7608
|
+
};
|
|
7609
|
+
const applyResumeStaleBindingContinuityProjection = (binding) => {
|
|
7610
|
+
const newerVisibleMessages = selectNewerVisibleHistoryAfterBinding(binding);
|
|
7611
|
+
if (newerVisibleMessages.length === 0) return false;
|
|
7612
|
+
const projection = projectContextEngineAssemblyForCodex({
|
|
7613
|
+
assembledMessages: newerVisibleMessages,
|
|
7614
|
+
originalHistoryMessages: historyMessages,
|
|
7615
|
+
prompt: params.prompt
|
|
7616
|
+
});
|
|
7617
|
+
promptText = projection.promptText;
|
|
7618
|
+
prePromptMessageCount = projection.prePromptMessageCount;
|
|
7619
|
+
return true;
|
|
7620
|
+
};
|
|
7621
|
+
const precomputeNoContextEngineStaleBindingProjection = (binding) => {
|
|
7622
|
+
precomputedStaleBindingContinuityProjectionApplied = false;
|
|
7623
|
+
staleBindingContinuityForcedFreshStart = false;
|
|
7624
|
+
if (activeContextEngine || !binding?.threadId) return false;
|
|
7625
|
+
const projected = applyResumeStaleBindingContinuityProjection(binding);
|
|
7626
|
+
precomputedStaleBindingContinuityProjectionApplied = projected;
|
|
7627
|
+
return projected;
|
|
7628
|
+
};
|
|
7629
|
+
const applyNoContextEngineContinuityProjection = (action, binding) => {
|
|
7630
|
+
if (activeContextEngine || !historyMessages.some((message) => message.role === "user")) return false;
|
|
7631
|
+
if (action === "resumed" && precomputedStaleBindingContinuityProjectionApplied) return true;
|
|
7632
|
+
if (action === "started" && staleBindingContinuityForcedFreshStart) return true;
|
|
7633
|
+
if (action === "resumed" && binding) return applyResumeStaleBindingContinuityProjection(binding);
|
|
7634
|
+
if (action === "started") {
|
|
7635
|
+
applyFreshThreadContinuityProjection();
|
|
7636
|
+
return true;
|
|
7637
|
+
}
|
|
7638
|
+
return false;
|
|
7639
|
+
};
|
|
7640
|
+
if (precomputeNoContextEngineStaleBindingProjection(startupBinding)) await rebuildCodexPromptBuildFromCurrentProjection();
|
|
7641
|
+
const rotateStartupBindingForProjectedTurn = async () => {
|
|
7642
|
+
if (!startupBinding?.threadId) return;
|
|
7643
|
+
const previousThreadId = startupBinding.threadId;
|
|
7644
|
+
const projectedTurnTokens = estimateCodexAppServerProjectedTurnTokens({
|
|
7645
|
+
prompt: codexTurnPromptText,
|
|
7646
|
+
developerInstructions: buildRenderedCodexDeveloperInstructions()
|
|
7647
|
+
});
|
|
7648
|
+
startupBinding = await rotateOversizedCodexAppServerStartupBinding({
|
|
7649
|
+
binding: startupBinding,
|
|
7650
|
+
sessionFile: params.sessionFile,
|
|
7651
|
+
agentDir,
|
|
7652
|
+
codexHome: appServer.start.env?.CODEX_HOME,
|
|
7653
|
+
config: params.config,
|
|
7654
|
+
contextEngineActive: Boolean(activeContextEngine),
|
|
7655
|
+
projectedTurnTokens
|
|
7656
|
+
});
|
|
7657
|
+
if (startupBinding?.threadId) return;
|
|
7658
|
+
staleBindingContinuityForcedFreshStart = precomputedStaleBindingContinuityProjectionApplied;
|
|
7659
|
+
if (activeContextEngine) {
|
|
7660
|
+
contextEngineProjection = void 0;
|
|
7661
|
+
try {
|
|
7662
|
+
await applyActiveContextEngineProjection(void 0);
|
|
7663
|
+
} catch (assembleErr) {
|
|
7664
|
+
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
await rebuildCodexPromptBuildFromCurrentProjection();
|
|
7668
|
+
embeddedAgentLog.info("codex app-server rebuilt turn prompt after native thread rotation", {
|
|
7669
|
+
sessionId: params.sessionId,
|
|
7670
|
+
sessionKey: contextSessionKey,
|
|
7671
|
+
previousThreadId,
|
|
7672
|
+
promptChars: codexTurnPromptText.length,
|
|
7673
|
+
developerInstructionChars: buildRenderedCodexDeveloperInstructions()?.length ?? 0
|
|
7674
|
+
});
|
|
7675
|
+
};
|
|
7676
|
+
await rotateStartupBindingForProjectedTurn();
|
|
7466
7677
|
const systemPromptReport = buildCodexSystemPromptReport({
|
|
7467
7678
|
attempt: params,
|
|
7468
7679
|
sessionKey: contextSessionKey,
|
|
7469
7680
|
workspaceDir: effectiveWorkspace,
|
|
7470
7681
|
developerInstructions: buildRenderedCodexDeveloperInstructions(),
|
|
7471
7682
|
workspaceBootstrapContext,
|
|
7472
|
-
skillsPrompt:
|
|
7683
|
+
skillsPrompt: skillsCollaborationInstructions ? params.skillsSnapshot?.prompt ?? "" : "",
|
|
7473
7684
|
tools: toolBridge.availableSpecs
|
|
7474
7685
|
});
|
|
7475
7686
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
@@ -7582,6 +7793,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7582
7793
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
7583
7794
|
throw error;
|
|
7584
7795
|
}
|
|
7796
|
+
if (applyNoContextEngineContinuityProjection(thread.lifecycle.action, thread)) await rebuildCodexTurnPromptTextFromCurrentProjection();
|
|
7585
7797
|
trajectoryRecorder?.recordEvent("session.started", {
|
|
7586
7798
|
sessionFile: params.sessionFile,
|
|
7587
7799
|
threadId: thread.threadId,
|
|
@@ -7592,19 +7804,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7592
7804
|
recordCodexTrajectoryContext(trajectoryRecorder, {
|
|
7593
7805
|
attempt: params,
|
|
7594
7806
|
cwd: effectiveCwd,
|
|
7595
|
-
developerInstructions:
|
|
7807
|
+
developerInstructions: buildRenderedCodexDeveloperInstructions(),
|
|
7596
7808
|
prompt: codexTurnPromptText,
|
|
7597
7809
|
tools: toolBridge.availableSpecs
|
|
7598
7810
|
});
|
|
7599
|
-
let projector;
|
|
7600
|
-
let turnId;
|
|
7601
7811
|
const pendingNotifications = [];
|
|
7602
|
-
let userInputBridge;
|
|
7603
|
-
let steeringQueue;
|
|
7604
7812
|
let completed = false;
|
|
7605
7813
|
let terminalTurnNotificationQueued = false;
|
|
7606
7814
|
let timedOut = false;
|
|
7607
7815
|
let turnCompletionIdleTimedOut = false;
|
|
7816
|
+
let turnWatchTimeoutKind;
|
|
7608
7817
|
let turnCompletionIdleTimeoutMessage;
|
|
7609
7818
|
let clientClosedPromptError;
|
|
7610
7819
|
let clientClosedAbort = false;
|
|
@@ -7629,6 +7838,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7629
7838
|
let pendingTerminalDynamicToolRelease;
|
|
7630
7839
|
let terminalDynamicToolReleaseCheckScheduled = false;
|
|
7631
7840
|
let currentTurnHadNonTerminalDynamicToolResult = false;
|
|
7841
|
+
const turnIdRef = {};
|
|
7842
|
+
const projectorRef = {};
|
|
7843
|
+
const userInputBridgeRef = {};
|
|
7844
|
+
const steeringQueueRef = {};
|
|
7632
7845
|
const renewNativeHookRelayForTurnProgress = () => {
|
|
7633
7846
|
if (!nativeHookRelay || options.nativeHookRelay?.ttlMs !== void 0) return;
|
|
7634
7847
|
const now = Date.now();
|
|
@@ -7646,7 +7859,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7646
7859
|
const turnWatches = createCodexAttemptTurnWatchController({
|
|
7647
7860
|
threadId: thread.threadId,
|
|
7648
7861
|
signal: runAbortController.signal,
|
|
7649
|
-
getTurnId: () =>
|
|
7862
|
+
getTurnId: () => turnIdRef.current,
|
|
7650
7863
|
isCompleted: () => completed,
|
|
7651
7864
|
isTerminalTurnNotificationQueued: () => terminalTurnNotificationQueued,
|
|
7652
7865
|
getActiveAppServerTurnRequests: () => activeAppServerTurnRequests,
|
|
@@ -7657,12 +7870,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7657
7870
|
turnTerminalIdleTimeoutMs,
|
|
7658
7871
|
interruptTimeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS,
|
|
7659
7872
|
onInterruptTurn: (input) => interruptCodexTurnBestEffort(client, input),
|
|
7660
|
-
onTimeout: () => {
|
|
7873
|
+
onTimeout: (timeout) => {
|
|
7661
7874
|
timedOut = true;
|
|
7662
7875
|
turnCompletionIdleTimedOut = true;
|
|
7876
|
+
turnWatchTimeoutKind = timeout.kind;
|
|
7663
7877
|
turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
|
|
7664
7878
|
},
|
|
7665
|
-
onMarkTimedOut: () =>
|
|
7879
|
+
onMarkTimedOut: () => projectorRef.current?.markTimedOut(),
|
|
7666
7880
|
onAbort: (reason) => runAbortController.abort(reason),
|
|
7667
7881
|
onCompleted: () => {
|
|
7668
7882
|
completed = true;
|
|
@@ -7793,6 +8007,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7793
8007
|
currentPromptTexts: [codexTurnPromptText]
|
|
7794
8008
|
});
|
|
7795
8009
|
const handleNotification = async (notification) => {
|
|
8010
|
+
const projector = projectorRef.current;
|
|
8011
|
+
const turnId = turnIdRef.current;
|
|
8012
|
+
const userInputBridge = userInputBridgeRef.current;
|
|
8013
|
+
const steeringQueue = steeringQueueRef.current;
|
|
7796
8014
|
userInputBridge?.handleNotification(notification);
|
|
7797
8015
|
if (!projector || !turnId) {
|
|
7798
8016
|
pendingNotifications.push(notification);
|
|
@@ -7803,7 +8021,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7803
8021
|
threadId: thread.threadId,
|
|
7804
8022
|
turnId,
|
|
7805
8023
|
currentPromptTexts: [codexTurnPromptText],
|
|
7806
|
-
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
7807
8024
|
turnWatches,
|
|
7808
8025
|
activeTurnItemIds,
|
|
7809
8026
|
activeAppServerTurnRequests,
|
|
@@ -7836,6 +8053,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7836
8053
|
}
|
|
7837
8054
|
};
|
|
7838
8055
|
const enqueueNotification = (notification) => {
|
|
8056
|
+
const projector = projectorRef.current;
|
|
8057
|
+
const turnId = turnIdRef.current;
|
|
8058
|
+
const userInputBridge = userInputBridgeRef.current;
|
|
7839
8059
|
const correlation = describeCodexNotificationCorrelation(notification, {
|
|
7840
8060
|
threadId: thread.threadId,
|
|
7841
8061
|
...turnId ? { turnId } : {}
|
|
@@ -7850,7 +8070,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7850
8070
|
return Promise.resolve();
|
|
7851
8071
|
}
|
|
7852
8072
|
if (isTerminalTurnNotificationForTurn(notification, turnId)) terminalTurnNotificationQueued = true;
|
|
7853
|
-
|
|
8073
|
+
const isNativeResponseStreamDelta = isNativeResponseStreamDeltaNotification(notification);
|
|
8074
|
+
const nativeResponseStreamDeltaMatchesActiveTurn = isNativeResponseStreamDelta && (correlation.matchesActiveTurn === true || isUnscopedCodexNotification(correlation) && canAttributeUnscopedNativeResponseDeltaToThisTurn(client));
|
|
8075
|
+
if (correlation.matchesActiveTurn === true || !isNativeResponseStreamDelta && correlation.matchesActiveTurn !== false || nativeResponseStreamDeltaMatchesActiveTurn) turnWatches.noteNotificationReceived(notification.method, isNativeResponseStreamDelta ? {
|
|
8076
|
+
attemptProgress: true,
|
|
8077
|
+
...turnCrossedToolHandoff ? { attemptTimeoutMs: postToolRawAssistantCompletionIdleTimeoutMs } : {},
|
|
8078
|
+
details: { lastNotificationMethod: notification.method }
|
|
8079
|
+
} : void 0);
|
|
7854
8080
|
notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
|
|
7855
8081
|
return notificationQueue;
|
|
7856
8082
|
};
|
|
@@ -7864,6 +8090,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
7864
8090
|
});
|
|
7865
8091
|
const notificationCleanup = client.addNotificationHandler(enqueueNotification);
|
|
7866
8092
|
const requestCleanup = client.addRequestHandler(async (request) => {
|
|
8093
|
+
const turnId = turnIdRef.current;
|
|
8094
|
+
const userInputBridge = userInputBridgeRef.current;
|
|
8095
|
+
const projector = projectorRef.current;
|
|
7867
8096
|
let armCompletionWatchOnResponse = false;
|
|
7868
8097
|
let requestCountsAsTurnActivity = false;
|
|
7869
8098
|
const markCurrentTurnRequestProgress = () => {
|
|
@@ -8045,19 +8274,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8045
8274
|
sessionKey: params.sessionKey,
|
|
8046
8275
|
durationMs: toolDurationMs
|
|
8047
8276
|
});
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8052
|
-
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
8277
|
+
pendingOpenClawDynamicToolCompletionIds.delete(call.callId);
|
|
8278
|
+
if (response.terminate === true) scheduleTurnReleaseAfterTerminalDynamicTool({
|
|
8279
|
+
call,
|
|
8280
|
+
response,
|
|
8281
|
+
durationMs: toolDurationMs
|
|
8282
|
+
});
|
|
8283
|
+
else if (!shouldBlockTerminalReleaseForNonTerminalDynamicToolResult(response)) scheduleTerminalDynamicToolReleaseCheck();
|
|
8284
|
+
else {
|
|
8056
8285
|
currentTurnHadNonTerminalDynamicToolResult = true;
|
|
8057
8286
|
pendingTerminalDynamicToolRelease = void 0;
|
|
8058
8287
|
}
|
|
8059
8288
|
return protocolResponse;
|
|
8060
8289
|
} catch (error) {
|
|
8290
|
+
pendingOpenClawDynamicToolCompletionIds.delete(call.callId);
|
|
8061
8291
|
if (!terminalDiagnosticObserved && !hasPendingDynamicToolTerminalDiagnostic({
|
|
8062
8292
|
call,
|
|
8063
8293
|
runId: params.runId,
|
|
@@ -8077,15 +8307,17 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8077
8307
|
} finally {
|
|
8078
8308
|
if (requestCountsAsTurnActivity) {
|
|
8079
8309
|
activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
|
|
8310
|
+
const postToolContinuationTimeoutMs = request.method === "item/tool/call" && turnCrossedToolHandoff ? postToolRawAssistantCompletionIdleTimeoutMs : void 0;
|
|
8080
8311
|
turnWatches.touchActivity(`request:${request.method}:response`, {
|
|
8081
8312
|
arm: armCompletionWatchOnResponse,
|
|
8082
|
-
attemptProgress: true
|
|
8313
|
+
attemptProgress: true,
|
|
8314
|
+
...postToolContinuationTimeoutMs !== void 0 ? { attemptTimeoutMs: postToolContinuationTimeoutMs } : {}
|
|
8083
8315
|
});
|
|
8316
|
+
if (armCompletionWatchOnResponse && postToolContinuationTimeoutMs !== void 0) turnWatches.armCompletionIdleWatch({ timeoutMs: postToolContinuationTimeoutMs });
|
|
8084
8317
|
scheduleTerminalDynamicToolReleaseCheck();
|
|
8085
8318
|
} else turnWatches.scheduleProgressWatches();
|
|
8086
8319
|
}
|
|
8087
8320
|
});
|
|
8088
|
-
let closeCleanup;
|
|
8089
8321
|
const buildLlmInputEvent = () => ({
|
|
8090
8322
|
runId: params.runId,
|
|
8091
8323
|
sessionId: params.sessionId,
|
|
@@ -8093,11 +8325,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8093
8325
|
model: params.modelId,
|
|
8094
8326
|
systemPrompt: buildRenderedCodexDeveloperInstructions(),
|
|
8095
8327
|
prompt: codexTurnPromptText,
|
|
8096
|
-
historyMessages,
|
|
8328
|
+
historyMessages: codexModelInputHistoryMessages,
|
|
8097
8329
|
imagesCount: params.images?.length ?? 0,
|
|
8098
8330
|
tools
|
|
8099
8331
|
});
|
|
8100
|
-
const
|
|
8332
|
+
const buildCodexModelInputMessages = () => [...codexModelInputHistoryMessages, buildCodexUserPromptMessage({
|
|
8101
8333
|
...params,
|
|
8102
8334
|
prompt: codexTurnPromptText
|
|
8103
8335
|
})];
|
|
@@ -8116,7 +8348,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8116
8348
|
},
|
|
8117
8349
|
capture: codexModelContentCapture,
|
|
8118
8350
|
tools,
|
|
8119
|
-
buildInputMessages:
|
|
8351
|
+
buildInputMessages: buildCodexModelInputMessages,
|
|
8120
8352
|
buildSystemPrompt: buildRenderedCodexDeveloperInstructions,
|
|
8121
8353
|
onErrorDiagnostic: (error) => {
|
|
8122
8354
|
embeddedAgentLog.debug("codex app-server model call diagnostic ended with error", { error: formatErrorMessage(error) });
|
|
@@ -8132,6 +8364,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8132
8364
|
sandboxPolicy: codexSandboxPolicy,
|
|
8133
8365
|
environmentSelection: codexEnvironmentSelection,
|
|
8134
8366
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
8367
|
+
skillsCollaborationInstructions,
|
|
8368
|
+
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
8135
8369
|
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
|
|
8136
8370
|
});
|
|
8137
8371
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
@@ -8157,7 +8391,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8157
8391
|
turn = await startCodexTurn();
|
|
8158
8392
|
} catch (error) {
|
|
8159
8393
|
let turnStartError = error;
|
|
8160
|
-
if (
|
|
8394
|
+
if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
|
|
8161
8395
|
error: turnStartError,
|
|
8162
8396
|
contextEngineActive: Boolean(activeContextEngine),
|
|
8163
8397
|
thread
|
|
@@ -8168,20 +8402,26 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8168
8402
|
});
|
|
8169
8403
|
try {
|
|
8170
8404
|
const preRetrySessionFile = activeSessionFile;
|
|
8171
|
-
await
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
data: {
|
|
8177
|
-
phase: "thread_ready_retry",
|
|
8178
|
-
threadId: thread.threadId
|
|
8179
|
-
}
|
|
8405
|
+
const clearedPreRetryBinding = await clearCodexAppServerBindingForThread(preRetrySessionFile, thread.threadId);
|
|
8406
|
+
const clearedActiveBinding = activeSessionFile !== preRetrySessionFile ? await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId) : false;
|
|
8407
|
+
if (!clearedPreRetryBinding && !clearedActiveBinding) embeddedAgentLog.warn("codex app-server preserved newer context-engine binding after resume overflow; skipping fresh retry", {
|
|
8408
|
+
threadId: thread.threadId,
|
|
8409
|
+
error: formatErrorMessage(turnStartError)
|
|
8180
8410
|
});
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8411
|
+
else {
|
|
8412
|
+
thread = await restartContextEngineCodexThread();
|
|
8413
|
+
emitCodexAppServerEvent(params, {
|
|
8414
|
+
stream: "codex_app_server.lifecycle",
|
|
8415
|
+
data: {
|
|
8416
|
+
phase: "thread_ready_retry",
|
|
8417
|
+
threadId: thread.threadId
|
|
8418
|
+
}
|
|
8419
|
+
});
|
|
8420
|
+
try {
|
|
8421
|
+
turn = await startCodexTurn();
|
|
8422
|
+
} catch (retryError) {
|
|
8423
|
+
turnStartError = retryError;
|
|
8424
|
+
}
|
|
8185
8425
|
}
|
|
8186
8426
|
} catch (retrySetupError) {
|
|
8187
8427
|
turnStartError = retrySetupError;
|
|
@@ -8240,9 +8480,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8240
8480
|
formatError: formatErrorMessage
|
|
8241
8481
|
});
|
|
8242
8482
|
codexModelCallDiagnostics.emitError(turnStartErrorMessage, turnStartFailureKind ? { failureKind: turnStartFailureKind } : {});
|
|
8483
|
+
const turnStartFailureMessages = [...historyMessages, buildCodexUserPromptMessage({
|
|
8484
|
+
...params,
|
|
8485
|
+
prompt: codexTurnPromptText
|
|
8486
|
+
})];
|
|
8243
8487
|
await runCodexAgentEndHook(params, {
|
|
8244
8488
|
event: {
|
|
8245
|
-
messages:
|
|
8489
|
+
messages: turnStartFailureMessages,
|
|
8246
8490
|
success: false,
|
|
8247
8491
|
error: turnStartErrorMessage,
|
|
8248
8492
|
durationMs: Date.now() - attemptStartedAt
|
|
@@ -8279,7 +8523,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8279
8523
|
return { ...buildCodexTurnStartFailureResult({
|
|
8280
8524
|
params,
|
|
8281
8525
|
message: usageLimitError.message,
|
|
8282
|
-
messagesSnapshot:
|
|
8526
|
+
messagesSnapshot: turnStartFailureMessages,
|
|
8283
8527
|
systemPromptReport
|
|
8284
8528
|
}) };
|
|
8285
8529
|
}
|
|
@@ -8291,10 +8535,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8291
8535
|
releaseSharedClientLease = void 0;
|
|
8292
8536
|
throw new Error("codex app-server turn/start failed without an error");
|
|
8293
8537
|
}
|
|
8294
|
-
|
|
8538
|
+
turnIdRef.current = turn.turn.id;
|
|
8295
8539
|
const activeTurnId = turn.turn.id;
|
|
8296
8540
|
emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
|
|
8297
|
-
|
|
8541
|
+
userInputBridgeRef.current = createCodexUserInputBridge({
|
|
8298
8542
|
paramsForRun: params,
|
|
8299
8543
|
threadId: thread.threadId,
|
|
8300
8544
|
turnId: activeTurnId,
|
|
@@ -8306,12 +8550,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8306
8550
|
prompt: codexTurnPromptText,
|
|
8307
8551
|
imagesCount: params.images?.length ?? 0
|
|
8308
8552
|
});
|
|
8309
|
-
|
|
8553
|
+
projectorRef.current = new CodexAppServerEventProjector(params, thread.threadId, activeTurnId, {
|
|
8310
8554
|
nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && nativeHookRelay.shouldRelayEvent("post_tool_use"),
|
|
8311
8555
|
trajectoryRecorder
|
|
8312
8556
|
});
|
|
8313
8557
|
if (isTerminalTurnStatus(turn.turn.status) || pendingNotifications.some((notification) => isTerminalTurnNotificationForTurn(notification, activeTurnId))) terminalTurnNotificationQueued = true;
|
|
8314
|
-
closeCleanup = client.addCloseHandler?.(() => {
|
|
8558
|
+
const closeCleanup = client.addCloseHandler?.(() => {
|
|
8315
8559
|
if (completed || terminalTurnNotificationQueued || runAbortController.signal.aborted) return;
|
|
8316
8560
|
clientClosedPromptError = "codex app-server client closed before turn completed";
|
|
8317
8561
|
trajectoryRecorder?.recordEvent("turn.client_closed", {
|
|
@@ -8329,9 +8573,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8329
8573
|
resolveCompletion?.();
|
|
8330
8574
|
});
|
|
8331
8575
|
emitLifecycleStart();
|
|
8332
|
-
const activeProjector =
|
|
8576
|
+
const activeProjector = projectorRef.current;
|
|
8577
|
+
if (!activeProjector) throw new Error("codex app-server projector was not initialized");
|
|
8333
8578
|
turnWatches.armTerminalIdleWatch();
|
|
8334
8579
|
turnWatches.touchActivity("turn:start", { arm: true });
|
|
8580
|
+
turnWatches.armAttemptIdleWatch();
|
|
8581
|
+
turnWatches.touchActivity("turn:start", { attemptProgress: true });
|
|
8335
8582
|
for (const notification of pendingNotifications.splice(0)) await enqueueNotification(notification);
|
|
8336
8583
|
if (!completed && isTerminalTurnStatus(turn.turn.status)) await enqueueNotification({
|
|
8337
8584
|
method: "turn/completed",
|
|
@@ -8345,15 +8592,15 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8345
8592
|
client,
|
|
8346
8593
|
threadId: thread.threadId,
|
|
8347
8594
|
turnId: activeTurnId,
|
|
8348
|
-
answerPendingUserInput: (text) =>
|
|
8595
|
+
answerPendingUserInput: (text) => userInputBridgeRef.current?.handleQueuedMessage(text) ?? false,
|
|
8349
8596
|
signal: runAbortController.signal
|
|
8350
8597
|
});
|
|
8351
|
-
|
|
8598
|
+
steeringQueueRef.current = activeSteeringQueue;
|
|
8352
8599
|
const handle = {
|
|
8353
8600
|
kind: "embedded",
|
|
8354
8601
|
queueMessage: async (text, options) => activeSteeringQueue.queue(text, options),
|
|
8355
8602
|
isStreaming: () => !completed,
|
|
8356
|
-
isCompacting: () =>
|
|
8603
|
+
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
8357
8604
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
8358
8605
|
cancel: () => runAbortController.abort("cancelled"),
|
|
8359
8606
|
abort: () => runAbortController.abort("aborted")
|
|
@@ -8369,16 +8616,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8369
8616
|
threadId: thread.threadId,
|
|
8370
8617
|
turnId: activeTurnId
|
|
8371
8618
|
});
|
|
8372
|
-
turnWatches.armAttemptIdleWatch();
|
|
8373
|
-
turnWatches.armTerminalIdleWatch();
|
|
8374
|
-
turnWatches.touchActivity("turn:start", { attemptProgress: true });
|
|
8375
8619
|
const abortListener = () => {
|
|
8376
8620
|
if (timedOut) {
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8621
|
+
(async () => {
|
|
8622
|
+
await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId);
|
|
8623
|
+
await retireCodexAppServerClientAfterTimedOutTurn(client, {
|
|
8624
|
+
threadId: thread.threadId,
|
|
8625
|
+
turnId: activeTurnId,
|
|
8626
|
+
reason: String(runAbortController.signal.reason ?? "timeout")
|
|
8627
|
+
});
|
|
8628
|
+
})().finally(() => {
|
|
8382
8629
|
resolveCompletion?.();
|
|
8383
8630
|
});
|
|
8384
8631
|
return;
|
|
@@ -8393,6 +8640,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8393
8640
|
if (runAbortController.signal.aborted) abortListener();
|
|
8394
8641
|
try {
|
|
8395
8642
|
await completion;
|
|
8643
|
+
await notificationQueue;
|
|
8396
8644
|
const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected });
|
|
8397
8645
|
const finalAborted = result.aborted || runAbortController.signal.aborted && !clientClosedAbort;
|
|
8398
8646
|
let finalPromptError = clientClosedPromptError ?? (turnCompletionIdleTimedOut ? turnCompletionIdleTimeoutMessage : timedOut ? "codex app-server attempt timed out" : result.promptError);
|
|
@@ -8403,6 +8651,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8403
8651
|
turnId: activeTurnId,
|
|
8404
8652
|
error: finalPromptErrorMessage
|
|
8405
8653
|
});
|
|
8654
|
+
if (shouldUseFreshCodexThreadAfterContextEngineOverflow({
|
|
8655
|
+
error: finalPromptError,
|
|
8656
|
+
contextEngineActive: Boolean(activeContextEngine),
|
|
8657
|
+
thread
|
|
8658
|
+
})) {
|
|
8659
|
+
embeddedAgentLog.warn("codex app-server context-engine turn overflowed after resume; clearing thread binding for recovery", {
|
|
8660
|
+
threadId: thread.threadId,
|
|
8661
|
+
turnId: activeTurnId,
|
|
8662
|
+
error: finalPromptErrorMessage
|
|
8663
|
+
});
|
|
8664
|
+
const preClearSessionFile = activeSessionFile;
|
|
8665
|
+
await clearCodexAppServerBindingForThread(preClearSessionFile, thread.threadId);
|
|
8666
|
+
if (activeSessionFile !== preClearSessionFile) await clearCodexAppServerBindingForThread(activeSessionFile, thread.threadId);
|
|
8667
|
+
}
|
|
8406
8668
|
const refreshedUsageLimitPromptError = await refreshCodexUsageLimitPromptError({
|
|
8407
8669
|
client,
|
|
8408
8670
|
message: finalPromptErrorMessage,
|
|
@@ -8526,6 +8788,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8526
8788
|
hookRunner
|
|
8527
8789
|
});
|
|
8528
8790
|
shouldDelayNativeHookRelayUnregister = activeProjector.getCompletedTurnStatus() === "completed" && !timedOut && !runAbortController.signal.aborted && !finalAborted && !finalPromptError;
|
|
8791
|
+
if (shouldDelayNativeHookRelayUnregister) await markCodexAppServerBindingCoveredThroughTurn({
|
|
8792
|
+
sessionFile: params.sessionFile,
|
|
8793
|
+
threadId: thread.threadId,
|
|
8794
|
+
authProfileStore: params.authProfileStore,
|
|
8795
|
+
agentDir: params.agentDir,
|
|
8796
|
+
config: params.config
|
|
8797
|
+
});
|
|
8529
8798
|
return {
|
|
8530
8799
|
...result,
|
|
8531
8800
|
timedOut,
|
|
@@ -8534,6 +8803,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8534
8803
|
promptErrorSource: finalPromptErrorSource,
|
|
8535
8804
|
...codexAppServerFailureKind ? { codexAppServerFailure: {
|
|
8536
8805
|
kind: codexAppServerFailureKind,
|
|
8806
|
+
...codexAppServerFailureKind === "turn_completion_idle_timeout" && turnWatchTimeoutKind ? { turnWatchTimeoutKind } : {},
|
|
8537
8807
|
transport: appServer.start.transport,
|
|
8538
8808
|
threadId: thread.threadId,
|
|
8539
8809
|
turnId: activeTurnId,
|
|
@@ -8565,12 +8835,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8565
8835
|
await trajectoryRecorder?.flush();
|
|
8566
8836
|
}
|
|
8567
8837
|
});
|
|
8568
|
-
if (!timedOut && !runAbortController.signal.aborted) await
|
|
8838
|
+
if (!timedOut && !runAbortController.signal.aborted) await steeringQueueRef.current?.flushPending();
|
|
8569
8839
|
if (!timedOut) await unsubscribeCodexThreadBestEffort(client, {
|
|
8570
8840
|
threadId: thread.threadId,
|
|
8571
8841
|
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
8572
8842
|
});
|
|
8573
|
-
|
|
8843
|
+
userInputBridgeRef.current?.cancelPending();
|
|
8574
8844
|
turnWatches.clearAllTimers();
|
|
8575
8845
|
notificationCleanup();
|
|
8576
8846
|
requestCleanup();
|
|
@@ -8584,7 +8854,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
8584
8854
|
await releaseSandboxExecEnvironment();
|
|
8585
8855
|
runAbortController.signal.removeEventListener("abort", abortListener);
|
|
8586
8856
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
8587
|
-
|
|
8857
|
+
steeringQueueRef.current?.cancel();
|
|
8588
8858
|
clearActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
|
|
8589
8859
|
}
|
|
8590
8860
|
}
|
|
@@ -8603,10 +8873,31 @@ async function clearCodexBindingAfterInvalidImagePayload(sessionFile, fields) {
|
|
|
8603
8873
|
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
8604
8874
|
await clearCodexAppServerBinding(sessionFile);
|
|
8605
8875
|
}
|
|
8876
|
+
async function markCodexAppServerBindingCoveredThroughTurn(params) {
|
|
8877
|
+
const currentBinding = await readCodexAppServerBinding(params.sessionFile, {
|
|
8878
|
+
authProfileStore: params.authProfileStore,
|
|
8879
|
+
agentDir: params.agentDir,
|
|
8880
|
+
config: params.config
|
|
8881
|
+
});
|
|
8882
|
+
if (!currentBinding || currentBinding.threadId !== params.threadId) return;
|
|
8883
|
+
const { schemaVersion: _schemaVersion, sessionFile: _boundSessionFile, updatedAt: _updatedAt, ...bindingForWrite } = currentBinding;
|
|
8884
|
+
await writeCodexAppServerBinding(params.sessionFile, bindingForWrite, {
|
|
8885
|
+
authProfileStore: params.authProfileStore,
|
|
8886
|
+
agentDir: params.agentDir,
|
|
8887
|
+
config: params.config
|
|
8888
|
+
});
|
|
8889
|
+
}
|
|
8606
8890
|
function isNonEmptyString(value) {
|
|
8607
8891
|
return typeof value === "string" && value.length > 0;
|
|
8608
8892
|
}
|
|
8609
|
-
function
|
|
8893
|
+
function canAttributeUnscopedNativeResponseDeltaToThisTurn(client) {
|
|
8894
|
+
const activeLeases = client.getActiveSharedLeaseCountForUnscopedNotifications?.();
|
|
8895
|
+
return activeLeases === void 0 || activeLeases <= 1;
|
|
8896
|
+
}
|
|
8897
|
+
function isUnscopedCodexNotification(correlation) {
|
|
8898
|
+
return !correlation.threadId && !correlation.turnId && !correlation.nestedTurnThreadId && !correlation.nestedTurnId;
|
|
8899
|
+
}
|
|
8900
|
+
function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
|
|
8610
8901
|
if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
|
|
8611
8902
|
return isCodexContextWindowError(params.error);
|
|
8612
8903
|
}
|