@openclaw/codex 2026.7.2-beta.3 → 2026.7.2-beta.5
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/{app-server-policy-DUMF2Xyr.js → app-server-policy-BmDgseo_.js} +1 -1
- package/dist/attempt-client-cleanup-Ia52yRWc.js +127 -0
- package/dist/{attempt-notifications-Ecjyzufe.js → attempt-notifications-CMR2_fmR.js} +1 -1
- package/dist/{media-understanding-provider-IPNNQre6.js → bounded-turn-FEbUXoYT.js} +71 -188
- package/dist/capabilities-BHRSI6Cn.js +36 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-NCTL7A2q.js → command-formatters-ico4ZFnk.js} +3 -37
- package/dist/{command-handlers-DtFbZiba.js → command-handlers-CRmnwI2N.js} +1233 -1221
- package/dist/{compact-Kgy26gIM.js → compact-dEN49UH6.js} +8 -7
- package/dist/{computer-use-C7x4ZaqR.js → computer-use-BjGylO-E.js} +16 -6
- package/dist/{conversation-control-B0s3aIjT.js → conversation-control-DE7d9DOj.js} +6 -5
- package/dist/doctor-contract-api.js +24 -86
- package/dist/{dynamic-tools-D_vSVmv9.js → dynamic-tools-LIt9ojep.js} +135 -2696
- package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
- package/dist/event-projector-usage-tvgb1NCX.js +69 -0
- package/dist/harness.js +31 -11
- package/dist/incognito-session-ET_ufDH-.js +2 -0
- package/dist/index.js +250 -275
- package/dist/media-understanding-provider.js +173 -1
- package/dist/{models-DD5zBdX5.js → models-BA01NEez.js} +2 -2
- package/dist/{notification-correlation-C8DVQ_Bq.js → notification-correlation-Bj_Ak_jI.js} +3 -3
- package/dist/{plugin-app-cache-key-DJbhLYSK.js → plugin-app-cache-key-DSXX-rXO.js} +5 -5
- package/dist/{transcript-mirror-D9rTxx2P.js → protocol-validators-Dm4eXZmt.js} +335 -595
- package/dist/{rate-limits-CqhWQ2R9.js → rate-limits-S_PXs0ul.js} +1 -1
- package/dist/realtime-voice-api-BPcA1uN9.js +494 -0
- package/dist/realtime-voice-api.js +2 -0
- package/dist/{request-9yf9pZjf.js → request-CXpPennK.js} +1 -1
- package/dist/{run-attempt-BIoO8ISr.js → run-attempt-C5GTPJOE.js} +3111 -387
- package/dist/{session-binding-Bmt20HfB.js → session-binding-DlVQ-Pxs.js} +957 -890
- package/dist/{session-catalog-CA7R-hX2.js → session-catalog-CP2oCcEb.js} +98 -87
- package/dist/{session-cli-Bxk3-Wqz.js → session-cli-CqZ0Fp2a.js} +2 -2
- package/dist/session-upstream-marker-QE-m5QFG.js +82 -0
- package/dist/settled-turn-finalizer-CA_2QXIE.js +303 -0
- package/dist/{shared-client-CSXLtCLE.js → shared-client-BVKE40c-.js} +1870 -1694
- package/dist/{side-question-DtzquMOb.js → side-question-CO12sHxo.js} +24 -16
- package/dist/{thread-lifecycle-CQ_9mAa1.js → thread-lifecycle-DRg_FdzC.js} +127 -153
- package/dist/transcript-mirror-uKA-A4tB.js +550 -0
- package/dist/upstream-session-fork-_Vrz4WJr.js +320 -0
- package/dist/{usage-CuPpFgTc.js → usage-UpVbdX5G.js} +3 -3
- package/dist/{web-search-provider.runtime-_x5XTeqh.js → web-search-provider.runtime-CaQMYDbp.js} +3 -3
- package/package.json +7 -8
- package/npm-shrinkwrap.json +0 -202
- package/dist/{auth-binding-C1czuHPA.js → auth-binding-B4FfbcCg.js} +1 -1
|
@@ -1,32 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { _ as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { n as
|
|
9
|
-
import {
|
|
10
|
-
import { n as
|
|
11
|
-
import {
|
|
12
|
-
import { a as
|
|
1
|
+
import { $ as withCodexStartupTimeout, A as rememberCodexRateLimitsRead, B as flattenCodexDynamicToolFunctions, D as ensureCodexAppServerClientRuntime, F as resolveCodexAppServerPreparedApiKeyCacheKey, G as CodexAppServerStartupError, I as resolveCodexAppServerPreparedAuthHandoff, J as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, K as isCodexAppServerStartupError, M as resolveCodexAppServerAuthProfileId, N as resolveCodexAppServerAuthProfileIdForAgent, O as readCodexRateLimitsRevision, P as resolveCodexAppServerFallbackApiKeyCacheKey, Q as resolveCodexTurnTerminalIdleTimeoutMs, T as isCodexAppServerRequestTimeoutError, U as resolveCodexAppServerHomeDir, V as isJsonObject, W as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, X as resolveCodexTurnAssistantCompletionIdleTimeoutMs, Y as resolveCodexStartupTimeoutMs, Z as resolveCodexTurnCompletionIdleTimeoutMs, _ as CodexAppServerRpcError, a as getLeasedSharedCodexAppServerClient, b as isCodexAppServerBrokenPipeError, d as retainSharedCodexAppServerClientIfCurrent, f as retireSharedCodexAppServerClientIfCurrent, j as resolveCodexAppServerAuthAccountCacheKey, k as readRecentCodexRateLimits, l as releaseLeasedSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as getSharedCodexAppServerClient, s as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, v as getCodexAppServerClientInstanceId, x as isCodexAppServerConnectionClosedError, y as isCodexAppServerApprovalRequest } from "./shared-client-BVKE40c-.js";
|
|
2
|
+
import { C as isCodexAppServerApprovalPolicyAllowedByRequirements, D as resolveOpenClawExecPolicyForCodexAppServer, E as resolveCodexPluginsPolicy, S as resolveCodexModelBackedReviewerPolicyContext, T as readCodexPluginConfig, c as reclaimCurrentCodexSessionGeneration, h as resolveCodexComputerUseConfig, i as createCodexSessionGenerationSupersededError, l as sessionBindingIdentity, v as shouldAutoApproveCodexAppServerApprovals, w as isCodexSandboxExecServerEnabled, y as withMcpElicitationsApprovalPolicy } from "./session-binding-DlVQ-Pxs.js";
|
|
3
|
+
import { a as closeCodexStartupClientBestEffort, l as retireCodexAppServerClientAfterTimedOutTurn, n as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, r as CodexAppServerUnsafeSubscriptionError, s as interruptCodexTurnBestEffort, t as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, u as unsubscribeCodexThreadBestEffort } from "./attempt-client-cleanup-Ia52yRWc.js";
|
|
4
|
+
import { S as updateActiveTurnItemIds, _ as readCodexNotificationItem, a as isCodexTurnAbortMarkerNotification, b as shouldDisarmAssistantCompletionIdleWatch, c as isPendingOpenClawDynamicToolCompletionNotification, d as isRawReasoningCompletionNotification, f as isRawToolOutputCompletionNotification, g as isTerminalTurnStatus, h as isRetryableErrorNotification, i as isAssistantCompletionReleaseNotification, l as isRawAssistantProgressNotification, m as isReasoningProgressNotification, n as describeNotificationActivity, o as isFileChangePatchUpdatedNotification, p as isReasoningItemCompletionNotification, r as isAssistantCommentaryCompletionNotification, s as isNativeToolProgressNotification, t as codexExecutionToolName, u as isRawFunctionToolOutputCompletionNotification, v as readNotificationItemId, x as updateActiveCompletionBlockerItemIds, y as readRawResponseToolCallId } from "./attempt-notifications-CMR2_fmR.js";
|
|
5
|
+
import { $ as readHookOutputEntries, B as resolveCodexContextEngineProjectionReserveTokens, F as buildContextEngineBinding, G as mergeCodexThreadConfigs, H as buildCodexPluginThreadConfig, I as isContextEngineBindingCompatible, K as shouldBuildCodexPluginThreadConfig, L as fitCodexProjectedContextForTurnStart, M as areCodexDynamicToolFingerprintsCompatible, N as codexDynamicToolsFingerprint, O as isSystemAgentOnlyCodexDynamicToolAllowlist, P as codexLegacyDynamicToolsFingerprint, Q as readCodexErrorNotificationMessage, R as projectContextEngineAssemblyForCodex, T as filterCodexDynamicTools, U as buildCodexPluginThreadConfigInputFingerprint, W as buildCodexPluginThreadConfigTimeoutFallback, X as extractRawAssistantText, Y as resolveRecoverableCodexPluginConfigKeys, Z as normalizeNonEmptyString, a as sanitizeCodexHistoryImagePayloads, at as readNullableString$1, b as resolveCodexAppServerThreadModelSelection, ct as splitPlanText, et as readItem, g as buildDeveloperInstructions, h as resolveCodexWebSearchPlan, it as readNonNegativeInteger, j as resolveCodexDynamicToolsLoadingForRuntime, n as buildTurnStartParams, nt as readNonEmptyString$1, ot as readNumber, r as buildCodexUserInput, rt as readNonEmptyStringArray, s as startOrResumeThread, st as readString$6, t as buildTurnCollaborationMode, tt as readItemString, w as isCodexAppServerProfilerEnabled, z as resolveCodexContextEngineProjectionMaxChars } from "./thread-lifecycle-DRg_FdzC.js";
|
|
6
|
+
import { n as projectCodexThreadUsageUpdate, t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-tvgb1NCX.js";
|
|
7
|
+
import { a as assertCodexTurnStartResponse, l as readCodexTurn, o as readCodexDynamicToolCallParams, u as readCodexTurnCompletedNotification } from "./protocol-validators-Dm4eXZmt.js";
|
|
8
|
+
import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-DSXX-rXO.js";
|
|
9
|
+
import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
|
|
10
|
+
import { d as attachCodexMirrorIdentity, f as readMirrorIdentity, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as promptSnapshot, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence } from "./transcript-mirror-uKA-A4tB.js";
|
|
11
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-BHRSI6Cn.js";
|
|
12
|
+
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-S_PXs0ul.js";
|
|
13
|
+
import { r as formatCodexDisplayText } from "./command-formatters-ico4ZFnk.js";
|
|
14
|
+
import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BmDgseo_.js";
|
|
15
|
+
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-Bj_Ak_jI.js";
|
|
16
|
+
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-B4FfbcCg.js";
|
|
17
|
+
import { i as resolveCodexLocalRuntimeAttribution, n as createAssistantMessage, r as createAssistantMirrorMessage, t as createAssistantCommentaryMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
|
|
18
|
+
import { $ as shouldSynthesizeToolProgressForItem, A as resolveCodexNativeHookRelayEvents, B as shouldReleaseTurnAfterTerminalDynamicTool, C as CodexNativeToolLifecycleProjector, D as buildCodexNativeHookRelayDisabledConfig, E as buildCodexNativeHookRelayConfig, F as isDynamicToolTerminalDiagnosticEvent, G as isNonSuccessItemStatus, H as toCodexDynamicToolProtocolResponse, I as isMatchingDynamicToolTerminalDiagnostic, J as itemName, K as isSideEffectingNativeToolItem, L as resolveDynamicToolCallTimeoutMs, M as scheduleCodexNativeHookRelayUnregister, N as handleDynamicToolCallWithTimeout, O as createCodexNativeHookRelay, P as hasPendingDynamicToolTerminalDiagnostic, Q as shouldRecordNativeToolTranscript, R as resolveTerminalDynamicToolBatchAction, T as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, U as resolveCodexToolAbortTerminalReason, V as toCodexDynamicToolProgressResponse, W as isMutatingNativeToolItem, X as itemTitle, Y as itemStatus, Z as shouldClearTerminalPresentationForNativeItem, _ as resolveCodexMessageToolProvider, a as emitDynamicToolStartedDiagnostic, b as shouldRequireCodexSandboxExecServerEnvironment, d as createCodexDynamicToolBuildStageTracker, et as unknownItemStatus, f as disableCodexPluginThreadConfig, g as resolveCodexExternalSandboxPolicyForOpenClawSandbox, h as resolveCodexAppServerHookChannelId, i as emitDynamicToolErrorDiagnostic, j as resolveCodexNativeHookRelayTtlMs, k as emitCodexNativePreToolUseFailureDiagnostic, l as settleCodexSourceReplyFinality, m as resolveCodexAppServerExecutionCwd, n as handleCodexAppServerApprovalRequest, o as emitDynamicToolTerminalDiagnostic, p as formatCodexDynamicToolBuildStageSummary, q as itemKind, r as handleCodexAppServerElicitationRequest, s as resolveCodexProviderWebSearchSupport, t as createCodexDynamicToolBridge, u as buildDynamicTools, v as resolveCodexSandboxEnvironmentSelection, x as shouldWarnCodexDynamicToolBuildStageSummary, y as shouldEnableCodexAppServerNativeToolSurface, z as shouldBlockTerminalReleaseForNonTerminalDynamicToolResult } from "./dynamic-tools-LIt9ojep.js";
|
|
19
|
+
import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-BjGylO-E.js";
|
|
13
20
|
import fs from "node:fs/promises";
|
|
14
21
|
import path, { posix } from "node:path";
|
|
15
|
-
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
16
|
-
import {
|
|
22
|
+
import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
23
|
+
import { AgentHarnessPreflightError, CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, agentHarnessAttemptTerminal, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, prepareHarnessNativeMcpAppPreview, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
17
24
|
import { createHash, randomUUID } from "node:crypto";
|
|
18
|
-
import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
25
|
+
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
19
26
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
20
27
|
import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
21
|
-
import {
|
|
28
|
+
import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
22
29
|
import { spawn } from "node:child_process";
|
|
30
|
+
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
23
31
|
import { once } from "node:events";
|
|
24
32
|
import { isIP } from "node:net";
|
|
25
33
|
import { WebSocketServer } from "ws";
|
|
26
|
-
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
27
34
|
import { fileURLToPath } from "node:url";
|
|
35
|
+
import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
28
36
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
37
|
+
import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
29
38
|
import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
|
39
|
+
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
40
|
+
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
|
|
41
|
+
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
42
|
+
import { resolveGeneratedMediaMaxBytes } from "openclaw/plugin-sdk/media-generation-runtime";
|
|
43
|
+
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
30
44
|
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
31
45
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
32
46
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
@@ -89,106 +103,2677 @@ function createCodexSteeringQueue(params) {
|
|
|
89
103
|
for (const item of liveItems) rejectItem(item, unavailableError);
|
|
90
104
|
throw unavailableError;
|
|
91
105
|
}
|
|
92
|
-
const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
93
|
-
const batch = { items: liveItems };
|
|
94
|
-
dispatchedBatches.set(clientUserMessageId, batch);
|
|
106
|
+
const clientUserMessageId = `openclaw:${params.turnId}:steer:${++batchSequence}`;
|
|
107
|
+
const batch = { items: liveItems };
|
|
108
|
+
dispatchedBatches.set(clientUserMessageId, batch);
|
|
109
|
+
try {
|
|
110
|
+
await params.client.request("turn/steer", {
|
|
111
|
+
threadId: params.threadId,
|
|
112
|
+
expectedTurnId: params.turnId,
|
|
113
|
+
input: liveItems.flatMap((item) => buildCodexUserInput(item.text, item.images)),
|
|
114
|
+
clientUserMessageId
|
|
115
|
+
});
|
|
116
|
+
} catch (error) {
|
|
117
|
+
dispatchedBatches.delete(clientUserMessageId);
|
|
118
|
+
for (const item of liveItems) rejectItem(item, error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const enqueueSend = (items) => {
|
|
123
|
+
const send = sendChain.then(() => sendBatch(items));
|
|
124
|
+
sendChain = send;
|
|
125
|
+
send.catch((error) => {
|
|
126
|
+
for (const item of items) rejectItem(item, error);
|
|
127
|
+
embeddedAgentLog.debug("codex app-server queued steer failed", { error });
|
|
128
|
+
});
|
|
129
|
+
return send;
|
|
130
|
+
};
|
|
131
|
+
const flushBatch = () => {
|
|
132
|
+
clearBatchTimer();
|
|
133
|
+
const items = batchedMessages;
|
|
134
|
+
batchedMessages = [];
|
|
135
|
+
if (items.length === 0) return sendChain;
|
|
136
|
+
const send = enqueueSend(items);
|
|
137
|
+
send.catch(() => void 0);
|
|
138
|
+
return send;
|
|
139
|
+
};
|
|
140
|
+
const createPendingMessage = (text, images) => {
|
|
141
|
+
let resolveDelivery;
|
|
142
|
+
let rejectDelivery;
|
|
143
|
+
const delivery = new Promise((resolve, reject) => {
|
|
144
|
+
resolveDelivery = resolve;
|
|
145
|
+
rejectDelivery = reject;
|
|
146
|
+
});
|
|
147
|
+
const item = {
|
|
148
|
+
text,
|
|
149
|
+
images,
|
|
150
|
+
resolve: resolveDelivery,
|
|
151
|
+
reject: rejectDelivery,
|
|
152
|
+
settled: false
|
|
153
|
+
};
|
|
154
|
+
pendingMessages.add(item);
|
|
155
|
+
return {
|
|
156
|
+
item,
|
|
157
|
+
delivery
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
params.signal.addEventListener("abort", abortQueue, { once: true });
|
|
161
|
+
if (params.signal.aborted) abortQueue();
|
|
162
|
+
return {
|
|
163
|
+
async queue(text, options) {
|
|
164
|
+
const pendingUserInput = params.claimPendingUserInput();
|
|
165
|
+
if (pendingUserInput) {
|
|
166
|
+
if (!options?.images?.length) {
|
|
167
|
+
pendingUserInput.answer(text);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
flushBatch().catch(() => void 0);
|
|
171
|
+
const { item, delivery } = createPendingMessage(text, options.images);
|
|
172
|
+
await Promise.all([enqueueSend([item]).finally(() => pendingUserInput.cancel()), delivery]);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (closedError) throw closedError;
|
|
176
|
+
if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
|
|
177
|
+
const { item, delivery } = createPendingMessage(text, options?.images);
|
|
178
|
+
batchedMessages.push(item);
|
|
179
|
+
clearBatchTimer();
|
|
180
|
+
const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
|
|
181
|
+
if (debounceMs === 0) flushBatch();
|
|
182
|
+
else batchTimer = setTimeout(() => {
|
|
183
|
+
batchTimer = void 0;
|
|
184
|
+
flushBatch();
|
|
185
|
+
}, debounceMs);
|
|
186
|
+
return await delivery;
|
|
187
|
+
},
|
|
188
|
+
async flushPending() {
|
|
189
|
+
if (closedError) return;
|
|
190
|
+
await flushBatch().catch(() => void 0);
|
|
191
|
+
},
|
|
192
|
+
confirmConsumed(clientUserMessageId) {
|
|
193
|
+
const batch = dispatchedBatches.get(clientUserMessageId);
|
|
194
|
+
if (!batch) return false;
|
|
195
|
+
dispatchedBatches.delete(clientUserMessageId);
|
|
196
|
+
for (const item of batch.items) resolveItem(item);
|
|
197
|
+
return true;
|
|
198
|
+
},
|
|
199
|
+
cancel: cancelQueue
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/** Normalizes steer debounce milliseconds, preserving explicit zero. */
|
|
203
|
+
function normalizeCodexSteerDebounceMs(value) {
|
|
204
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
205
|
+
}
|
|
206
|
+
//#endregion
|
|
207
|
+
//#region extensions/codex/src/app-server/attempt-terminal.ts
|
|
208
|
+
const attemptTerminal = agentHarnessAttemptTerminal;
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region extensions/codex/src/app-server/event-projector-assistant.ts
|
|
211
|
+
var CodexAssistantProjection = class {
|
|
212
|
+
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
|
|
213
|
+
this.params = params;
|
|
214
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
215
|
+
this.matchesToolProgressEcho = matchesToolProgressEcho;
|
|
216
|
+
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
217
|
+
this.assistantTextByItem = /* @__PURE__ */ new Map();
|
|
218
|
+
this.assistantItemOrder = [];
|
|
219
|
+
this.assistantTimestampByItem = /* @__PURE__ */ new Map();
|
|
220
|
+
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
221
|
+
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
222
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
223
|
+
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
224
|
+
this.lastCommentaryProgressTextByItem = /* @__PURE__ */ new Map();
|
|
225
|
+
this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
|
|
226
|
+
this.pendingRawCommentaryEchoes = 0;
|
|
227
|
+
this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
228
|
+
this.assistantStarted = false;
|
|
229
|
+
this.streamedPartialAssistantItemReplaceable = false;
|
|
230
|
+
}
|
|
231
|
+
hasCompletedTerminalAssistantText(completedItemIds) {
|
|
232
|
+
const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
|
|
233
|
+
if (!latestCompletedItemId) return false;
|
|
234
|
+
const finalItem = this.resolveFinalAssistantTextItem();
|
|
235
|
+
return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
|
|
236
|
+
}
|
|
237
|
+
getLatestTerminalAssistantCandidate() {
|
|
238
|
+
const itemId = this.latestTerminalAssistantCandidateItemId;
|
|
239
|
+
if (!itemId) return;
|
|
240
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
241
|
+
return {
|
|
242
|
+
itemId,
|
|
243
|
+
hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
hasLatestTerminalAssistantCandidateText() {
|
|
247
|
+
return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
|
|
248
|
+
}
|
|
249
|
+
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
250
|
+
return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
|
|
251
|
+
}
|
|
252
|
+
async handleAssistantDelta(params) {
|
|
253
|
+
const itemId = readString$6(params, "itemId") ?? "assistant";
|
|
254
|
+
const delta = readString$6(params, "delta") ?? "";
|
|
255
|
+
if (!delta) return;
|
|
256
|
+
if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
257
|
+
const isCommentary = this.isCommentaryAssistantItem(itemId);
|
|
258
|
+
if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
|
|
259
|
+
if (!this.assistantStarted) {
|
|
260
|
+
this.assistantStarted = true;
|
|
261
|
+
await this.params.onAssistantMessageStart?.();
|
|
262
|
+
}
|
|
263
|
+
this.rememberAssistantItem(itemId);
|
|
264
|
+
const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
|
|
265
|
+
this.assistantTextByItem.set(itemId, text);
|
|
266
|
+
if (isCommentary) {
|
|
267
|
+
this.emitCommentaryProgress({
|
|
268
|
+
itemId,
|
|
269
|
+
text
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (this.isFinalAnswerAssistantItem(itemId)) this.emitAnswerCandidate(itemId, "candidate");
|
|
274
|
+
const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
|
|
275
|
+
const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
|
|
276
|
+
if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
|
|
277
|
+
else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
|
|
278
|
+
this.streamedPartialAssistantItemId = itemId;
|
|
279
|
+
const replaceable = this.streamedPartialAssistantItemReplaceable;
|
|
280
|
+
const replacement = replace && replaceable;
|
|
281
|
+
const streamPayload = {
|
|
282
|
+
text,
|
|
283
|
+
delta: replacement ? "" : delta,
|
|
284
|
+
...replacement ? { replace: true } : {}
|
|
285
|
+
};
|
|
286
|
+
this.emitAgentEvent({
|
|
287
|
+
stream: "assistant",
|
|
288
|
+
data: {
|
|
289
|
+
...streamPayload,
|
|
290
|
+
...replaceable ? { replaceable: true } : {}
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
|
|
294
|
+
}
|
|
295
|
+
recordItemStarted(item, itemId) {
|
|
296
|
+
if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
297
|
+
this.rememberAssistantPhase(item);
|
|
298
|
+
if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
|
|
299
|
+
if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
|
|
300
|
+
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
301
|
+
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
recordItemCompleted(item, itemId, activeItemIds) {
|
|
305
|
+
if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
306
|
+
if (itemId) this.latestCompletedItemId = itemId;
|
|
307
|
+
this.rememberAssistantPhase(item);
|
|
308
|
+
if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
|
|
309
|
+
this.latestCompletedTerminalAssistantItemId = item.id;
|
|
310
|
+
this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
|
|
311
|
+
this.pendingRawTerminalAssistantEchoItemId = item.id;
|
|
312
|
+
} else if (itemId) {
|
|
313
|
+
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
314
|
+
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
315
|
+
}
|
|
316
|
+
if (item?.type === "agentMessage" && typeof item.text === "string") {
|
|
317
|
+
this.rememberAssistantItem(item.id);
|
|
318
|
+
this.assistantTextByItem.set(item.id, item.text);
|
|
319
|
+
if (item.text && this.isCommentaryAssistantItem(item.id)) {
|
|
320
|
+
this.emitCommentaryProgress({
|
|
321
|
+
itemId: item.id,
|
|
322
|
+
text: item.text
|
|
323
|
+
});
|
|
324
|
+
this.pendingRawCommentaryEchoes += 1;
|
|
325
|
+
} else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
recordSnapshotItem(item) {
|
|
329
|
+
this.rememberAssistantPhase(item);
|
|
330
|
+
if (item.type === "agentMessage" && typeof item.text === "string") {
|
|
331
|
+
this.rememberAssistantItem(item.id);
|
|
332
|
+
this.assistantTextByItem.set(item.id, item.text);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
handleRawResponseItemCompleted(item, activeItemIds) {
|
|
336
|
+
const role = readString$6(item, "role");
|
|
337
|
+
const phase = readString$6(item, "phase");
|
|
338
|
+
const rawItemId = readString$6(item, "id");
|
|
339
|
+
const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
|
|
340
|
+
const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
|
|
341
|
+
const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
|
|
342
|
+
if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
343
|
+
if (!isPendingTerminalAssistantEcho) {
|
|
344
|
+
this.latestCompletedItemId = void 0;
|
|
345
|
+
this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
346
|
+
}
|
|
347
|
+
if (role !== "assistant") return;
|
|
348
|
+
if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
|
|
349
|
+
this.pendingRawCommentaryEchoes -= 1;
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const text = extractRawAssistantText(item);
|
|
353
|
+
if (isPendingTerminalAssistantEcho) {
|
|
354
|
+
const typedItemId = pendingTerminalAssistantEchoItemId;
|
|
355
|
+
this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
356
|
+
if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
|
|
357
|
+
this.rememberAssistantItem(typedItemId);
|
|
358
|
+
this.assistantTextByItem.set(typedItemId, text);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!text) return;
|
|
362
|
+
const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
|
|
363
|
+
const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
|
|
364
|
+
if (phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
|
|
365
|
+
if (phase) this.assistantPhaseByItem.set(itemId, phase);
|
|
366
|
+
this.rememberAssistantItem(itemId);
|
|
367
|
+
this.assistantTextByItem.set(itemId, text);
|
|
368
|
+
this.rawPromotedAssistantItemIds.add(itemId);
|
|
369
|
+
if (phase === "commentary") this.emitCommentaryProgress({
|
|
370
|
+
itemId,
|
|
371
|
+
text
|
|
372
|
+
});
|
|
373
|
+
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
|
|
374
|
+
}
|
|
375
|
+
collectAssistantTexts() {
|
|
376
|
+
const finalText = this.resolveFinalAssistantTextItem()?.text;
|
|
377
|
+
return finalText ? [finalText] : [];
|
|
378
|
+
}
|
|
379
|
+
collectCommentaryMessages() {
|
|
380
|
+
return this.assistantItemOrder.flatMap((itemId) => {
|
|
381
|
+
if (!this.isCommentaryAssistantItem(itemId)) return [];
|
|
382
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
383
|
+
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
384
|
+
if (!text || timestamp === void 0) return [];
|
|
385
|
+
return [{
|
|
386
|
+
itemId,
|
|
387
|
+
message: createAssistantCommentaryMessage(this.params, text, itemId, timestamp)
|
|
388
|
+
}];
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
finalizeAnswerCandidate(turn) {
|
|
392
|
+
if (turn.status !== "completed") {
|
|
393
|
+
this.supersedeVisibleAnswerCandidate();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const turnItems = turn.items ?? [];
|
|
397
|
+
const authoritativeIndex = turnItems.findLastIndex((item) => item.type === "agentMessage" && readItemString(item, "phase") === "final_answer" && typeof item.text === "string" && item.text.trim().length > 0);
|
|
398
|
+
const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
|
|
399
|
+
if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
|
|
400
|
+
this.supersedeVisibleAnswerCandidate();
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const itemId = authoritative?.id ?? this.visibleAnswerCandidateItemId;
|
|
404
|
+
if (!itemId) return;
|
|
405
|
+
if (itemId !== this.visibleAnswerCandidateItemId) {
|
|
406
|
+
this.supersedeVisibleAnswerCandidate();
|
|
407
|
+
this.visibleAnswerCandidateItemId = itemId;
|
|
408
|
+
}
|
|
409
|
+
this.emitAnswerCandidate(itemId, "selected");
|
|
410
|
+
}
|
|
411
|
+
hasAssistantItemTextForSynthesis() {
|
|
412
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
413
|
+
const itemId = this.assistantItemOrder[i];
|
|
414
|
+
if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
|
|
415
|
+
const text = this.assistantTextByItem.get(itemId);
|
|
416
|
+
if (text && text.length > 0) return true;
|
|
417
|
+
}
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
createCurrentAttemptAssistantMessage(options) {
|
|
421
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
422
|
+
const itemId = this.assistantItemOrder[i];
|
|
423
|
+
if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
|
|
424
|
+
const text = this.assistantTextByItem.get(itemId) ?? "";
|
|
425
|
+
const normalizedText = text.trim();
|
|
426
|
+
if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
|
|
427
|
+
return this.createAssistantMessage(text, options);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
createAssistantMessage(text, options) {
|
|
431
|
+
return createAssistantMessage(this.params, text, options);
|
|
432
|
+
}
|
|
433
|
+
createAssistantMirrorMessage(title, text) {
|
|
434
|
+
return createAssistantMirrorMessage(this.params, title, text);
|
|
435
|
+
}
|
|
436
|
+
rememberAssistantPhase(item) {
|
|
437
|
+
if (item?.type !== "agentMessage") return;
|
|
438
|
+
const phase = readItemString(item, "phase");
|
|
439
|
+
if (phase) this.assistantPhaseByItem.set(item.id, phase);
|
|
440
|
+
}
|
|
441
|
+
isCommentaryAssistantItem(itemId) {
|
|
442
|
+
return this.assistantPhaseByItem.get(itemId) === "commentary";
|
|
443
|
+
}
|
|
444
|
+
isFinalAnswerAssistantItem(itemId) {
|
|
445
|
+
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
446
|
+
}
|
|
447
|
+
shouldStreamAssistantPartial(itemId) {
|
|
448
|
+
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
449
|
+
}
|
|
450
|
+
emitCommentaryProgress(params) {
|
|
451
|
+
const progressText = params.text.replace(/\s+/g, " ").trim();
|
|
452
|
+
if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
|
|
453
|
+
this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
|
|
454
|
+
this.emitAgentEvent({
|
|
455
|
+
stream: "item",
|
|
456
|
+
data: {
|
|
457
|
+
itemId: params.itemId,
|
|
458
|
+
kind: "preamble",
|
|
459
|
+
title: "Preamble",
|
|
460
|
+
phase: "update",
|
|
461
|
+
progressText,
|
|
462
|
+
source: "codex-app-server"
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
emitAnswerCandidate(itemId, status) {
|
|
467
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
468
|
+
if (!text) return;
|
|
469
|
+
if (status === "candidate" && this.visibleAnswerCandidateItemId !== itemId) {
|
|
470
|
+
this.supersedeVisibleAnswerCandidate();
|
|
471
|
+
this.visibleAnswerCandidateItemId = itemId;
|
|
472
|
+
}
|
|
473
|
+
const signature = `${status}\0${text}`;
|
|
474
|
+
if (this.lastAnswerCandidateEventByItem.get(itemId) === signature) return;
|
|
475
|
+
this.lastAnswerCandidateEventByItem.set(itemId, signature);
|
|
476
|
+
this.emitAgentEvent({
|
|
477
|
+
stream: "item",
|
|
478
|
+
data: {
|
|
479
|
+
itemId,
|
|
480
|
+
kind: "answer_candidate",
|
|
481
|
+
title: "Answer candidate",
|
|
482
|
+
phase: "update",
|
|
483
|
+
status,
|
|
484
|
+
progressText: text,
|
|
485
|
+
source: "codex-app-server",
|
|
486
|
+
hideFromChannelProgress: true
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
supersedeVisibleAnswerCandidate() {
|
|
491
|
+
const itemId = this.visibleAnswerCandidateItemId;
|
|
492
|
+
if (!itemId) return;
|
|
493
|
+
this.emitAnswerCandidate(itemId, "superseded");
|
|
494
|
+
this.visibleAnswerCandidateItemId = void 0;
|
|
495
|
+
}
|
|
496
|
+
markLatestTerminalAssistantCandidate(itemId, activeItemIds, options) {
|
|
497
|
+
this.latestTerminalAssistantCandidateItemId = itemId;
|
|
498
|
+
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
499
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
|
|
500
|
+
this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
|
|
501
|
+
}
|
|
502
|
+
markTerminalAssistantCandidateSupersededBy(itemId, options) {
|
|
503
|
+
if (!this.latestTerminalAssistantCandidateItemId) return;
|
|
504
|
+
if (itemId && this.terminalAssistantCandidateEarlierActiveItemIds.has(itemId)) {
|
|
505
|
+
if (!options?.preserveEarlierActiveItem) this.terminalAssistantCandidateEarlierActiveItemIds.delete(itemId);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
this.latestTerminalAssistantCandidateSuperseded = true;
|
|
509
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
510
|
+
this.terminalAssistantCandidateEarlierActiveItemIds.clear();
|
|
511
|
+
this.supersedeVisibleAnswerCandidate();
|
|
512
|
+
}
|
|
513
|
+
resolveFinalAssistantTextItem() {
|
|
514
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
515
|
+
const itemId = this.assistantItemOrder[i];
|
|
516
|
+
if (!itemId) continue;
|
|
517
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
518
|
+
if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
|
|
519
|
+
if (text && !this.isToolProgressEchoText(itemId, text)) return {
|
|
520
|
+
itemId,
|
|
521
|
+
text
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
rememberAssistantItem(itemId) {
|
|
526
|
+
if (!itemId || this.assistantItemOrder.includes(itemId)) return;
|
|
527
|
+
this.assistantItemOrder.push(itemId);
|
|
528
|
+
this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
|
|
529
|
+
}
|
|
530
|
+
isToolProgressEchoText(itemId, text) {
|
|
531
|
+
return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
//#endregion
|
|
535
|
+
//#region extensions/codex/src/app-server/event-projector-diagnostics.ts
|
|
536
|
+
function redactCodexEventKind(method) {
|
|
537
|
+
return redactSensitiveText(sanitizeTerminalText(method));
|
|
538
|
+
}
|
|
539
|
+
var CodexProjectionDiagnostics = class {
|
|
540
|
+
constructor(threadId, turnId) {
|
|
541
|
+
this.threadId = threadId;
|
|
542
|
+
this.turnId = turnId;
|
|
543
|
+
this.warningKeys = /* @__PURE__ */ new Set();
|
|
544
|
+
}
|
|
545
|
+
warnUnknownItemStatus(item) {
|
|
546
|
+
if (!item) return;
|
|
547
|
+
const status = unknownItemStatus(item);
|
|
548
|
+
if (!status) return;
|
|
549
|
+
const safeStatus = redactCodexEventKind(status);
|
|
550
|
+
const safeItemType = redactCodexEventKind(item.type);
|
|
551
|
+
this.warnOnce(JSON.stringify([
|
|
552
|
+
"status",
|
|
553
|
+
item.type,
|
|
554
|
+
status
|
|
555
|
+
]), "codex app-server item reported unknown status; continuing projection", {
|
|
556
|
+
itemId: item.id,
|
|
557
|
+
itemType: safeItemType,
|
|
558
|
+
status: safeStatus
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
warnUnknownEvent(notification, params) {
|
|
562
|
+
const notificationThreadId = readCodexNotificationThreadId(params);
|
|
563
|
+
const notificationTurnId = readCodexNotificationTurnId(params);
|
|
564
|
+
const eventKind = redactCodexEventKind(notification.method);
|
|
565
|
+
this.warnOnce(JSON.stringify(["method", notification.method]), `codex app-server projector received unknown event kind; continuing: ${eventKind}`, {
|
|
566
|
+
eventKind,
|
|
567
|
+
activeThreadId: this.threadId,
|
|
568
|
+
activeTurnId: this.turnId,
|
|
569
|
+
threadId: notificationThreadId,
|
|
570
|
+
turnId: notificationTurnId,
|
|
571
|
+
matchesActiveThread: notificationThreadId === this.threadId,
|
|
572
|
+
matchesActiveTurn: notificationTurnId === this.turnId
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
warnOnce(key, message, context) {
|
|
576
|
+
if (this.warningKeys.has(key)) return;
|
|
577
|
+
this.warningKeys.add(key);
|
|
578
|
+
embeddedAgentLog.warn(message, context);
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region extensions/codex/src/app-server/event-projector-tool-output.ts
|
|
583
|
+
const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 1e4;
|
|
584
|
+
const TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX = "...(OpenClaw truncated Codex native tool output";
|
|
585
|
+
var ToolOutputAccumulator = class {
|
|
586
|
+
constructor() {
|
|
587
|
+
this.prefixByItem = /* @__PURE__ */ new Map();
|
|
588
|
+
this.originalLengthByItem = /* @__PURE__ */ new Map();
|
|
589
|
+
this.normalizedLengthByItem = /* @__PURE__ */ new Map();
|
|
590
|
+
this.trimStateByItem = /* @__PURE__ */ new Map();
|
|
591
|
+
this.truncatedItemIds = /* @__PURE__ */ new Set();
|
|
592
|
+
this.textByItem = /* @__PURE__ */ new Map();
|
|
593
|
+
}
|
|
594
|
+
append(itemId, delta) {
|
|
595
|
+
const originalLength = (this.originalLengthByItem.get(itemId) ?? this.textByItem.get(itemId)?.length ?? 0) + delta.length;
|
|
596
|
+
this.originalLengthByItem.set(itemId, originalLength);
|
|
597
|
+
const normalizedLength = updateToolOutputTrimState(this.trimStateByItem, itemId, delta);
|
|
598
|
+
this.normalizedLengthByItem.set(itemId, normalizedLength);
|
|
599
|
+
if (this.truncatedItemIds.has(itemId)) {
|
|
600
|
+
const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", "", originalLength);
|
|
601
|
+
this.prefixByItem.set(itemId, next.rawPrefix);
|
|
602
|
+
this.textByItem.set(itemId, next.text);
|
|
603
|
+
return {
|
|
604
|
+
text: next.text,
|
|
605
|
+
originalLength,
|
|
606
|
+
normalizedLength,
|
|
607
|
+
rawPrefix: next.rawPrefix
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", delta, originalLength);
|
|
611
|
+
this.prefixByItem.set(itemId, next.rawPrefix);
|
|
612
|
+
this.textByItem.set(itemId, next.text);
|
|
613
|
+
if (originalLength > 1e4) this.truncatedItemIds.add(itemId);
|
|
614
|
+
return {
|
|
615
|
+
text: next.text,
|
|
616
|
+
originalLength,
|
|
617
|
+
normalizedLength,
|
|
618
|
+
rawPrefix: next.rawPrefix
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
function updateToolOutputTrimState(trimStateByItem, itemId, delta) {
|
|
623
|
+
const state = trimStateByItem.get(itemId) ?? {
|
|
624
|
+
totalLength: 0,
|
|
625
|
+
leadingWhitespaceLength: 0,
|
|
626
|
+
trailingWhitespaceLength: 0,
|
|
627
|
+
sawNonWhitespace: false
|
|
628
|
+
};
|
|
629
|
+
state.totalLength += delta.length;
|
|
630
|
+
const firstNonWhitespace = delta.search(/\S/u);
|
|
631
|
+
if (firstNonWhitespace === -1) {
|
|
632
|
+
if (!state.sawNonWhitespace) state.leadingWhitespaceLength += delta.length;
|
|
633
|
+
state.trailingWhitespaceLength += delta.length;
|
|
634
|
+
trimStateByItem.set(itemId, state);
|
|
635
|
+
return state.sawNonWhitespace ? state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength : 0;
|
|
636
|
+
}
|
|
637
|
+
if (!state.sawNonWhitespace) {
|
|
638
|
+
state.leadingWhitespaceLength += firstNonWhitespace;
|
|
639
|
+
state.sawNonWhitespace = true;
|
|
640
|
+
}
|
|
641
|
+
state.trailingWhitespaceLength = delta.match(/\s*$/u)?.[0].length ?? 0;
|
|
642
|
+
trimStateByItem.set(itemId, state);
|
|
643
|
+
return state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength;
|
|
644
|
+
}
|
|
645
|
+
function toolOutputRawEchoSignature(text) {
|
|
646
|
+
const trimmed = text.trim();
|
|
647
|
+
if (!trimmed) return;
|
|
648
|
+
return {
|
|
649
|
+
rawLength: trimmed.length,
|
|
650
|
+
rawPrefix: trimmed.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function normalizeToolTranscriptArguments(value) {
|
|
654
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
655
|
+
return value;
|
|
656
|
+
}
|
|
657
|
+
function collectDynamicToolContentText(contentItems) {
|
|
658
|
+
if (!Array.isArray(contentItems)) return "";
|
|
659
|
+
return contentItems.flatMap((entry) => {
|
|
660
|
+
if (!isJsonObject(entry)) return [];
|
|
661
|
+
const text = readString$6(entry, "text");
|
|
662
|
+
return text ? [text] : [];
|
|
663
|
+
}).join("\n");
|
|
664
|
+
}
|
|
665
|
+
function appendBoundedToolTranscriptText(currentPrefix, delta, originalLength) {
|
|
666
|
+
if (originalLength <= 1e4) {
|
|
667
|
+
const rawPrefix = currentPrefix + delta;
|
|
668
|
+
return {
|
|
669
|
+
text: rawPrefix,
|
|
670
|
+
rawPrefix
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
const notice = toolTranscriptTruncationNotice(originalLength);
|
|
674
|
+
if (notice.length >= 1e4) return {
|
|
675
|
+
text: notice.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS),
|
|
676
|
+
rawPrefix: ""
|
|
677
|
+
};
|
|
678
|
+
const textBudget = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length;
|
|
679
|
+
const remaining = Math.max(0, textBudget - currentPrefix.length);
|
|
680
|
+
const rawPrefix = truncateUtf16Safe(remaining > 0 ? `${currentPrefix}${truncateUtf16Safe(delta, remaining)}` : currentPrefix, textBudget);
|
|
681
|
+
return {
|
|
682
|
+
text: `${rawPrefix}${notice}`,
|
|
683
|
+
rawPrefix
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
function toolTranscriptTruncationNotice(originalLength) {
|
|
687
|
+
return `\n${`${TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX}: original ${originalLength} chars, showing ${TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS}; rerun with narrower args.)`}`;
|
|
688
|
+
}
|
|
689
|
+
function truncateToolTranscriptText(text, originalLength = text.length) {
|
|
690
|
+
if (originalLength <= 1e4 && text.length <= 1e4) return text;
|
|
691
|
+
const notice = toolTranscriptTruncationNotice(originalLength);
|
|
692
|
+
if (notice.length >= 1e4) return notice.slice(1, 10001);
|
|
693
|
+
return `${truncateUtf16Safe(text, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length)}${notice}`;
|
|
694
|
+
}
|
|
695
|
+
function formatToolSummary(toolName, meta) {
|
|
696
|
+
const trimmedMeta = meta?.trim();
|
|
697
|
+
return formatToolAggregate(toolName, trimmedMeta ? [trimmedMeta] : void 0, { markdown: true });
|
|
698
|
+
}
|
|
699
|
+
function formatToolOutput(toolName, meta, output) {
|
|
700
|
+
const formattedOutput = formatToolProgressOutput(output);
|
|
701
|
+
if (!formattedOutput) return formatToolSummary(toolName, meta);
|
|
702
|
+
const fence = markdownFenceForText(formattedOutput);
|
|
703
|
+
return `${formatToolSummary(toolName, meta)}\n${fence}txt\n${formattedOutput}\n${fence}`;
|
|
704
|
+
}
|
|
705
|
+
function markdownFenceForText(text) {
|
|
706
|
+
return "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
|
|
707
|
+
}
|
|
708
|
+
function longestBacktickRun(value) {
|
|
709
|
+
let longest = 0;
|
|
710
|
+
let current = 0;
|
|
711
|
+
for (const char of value) {
|
|
712
|
+
if (char === "`") {
|
|
713
|
+
current += 1;
|
|
714
|
+
longest = Math.max(longest, current);
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
current = 0;
|
|
718
|
+
}
|
|
719
|
+
return longest;
|
|
720
|
+
}
|
|
721
|
+
//#endregion
|
|
722
|
+
//#region extensions/codex/src/app-server/tool-progress-normalization.ts
|
|
723
|
+
/**
|
|
724
|
+
* Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
|
|
725
|
+
* emitted into OpenClaw events or logs.
|
|
726
|
+
*/
|
|
727
|
+
/** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
|
|
728
|
+
function resolveCodexToolProgressDetailMode(value) {
|
|
729
|
+
return value === "raw" ? "raw" : "explain";
|
|
730
|
+
}
|
|
731
|
+
/** Recursively redacts sensitive strings and handles circular values in event payloads. */
|
|
732
|
+
function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
733
|
+
if (typeof value === "string") return redactToolPayloadText(value);
|
|
734
|
+
if (Array.isArray(value)) {
|
|
735
|
+
if (seen.has(value)) return "[Circular]";
|
|
736
|
+
seen.add(value);
|
|
737
|
+
return value.map((entry) => sanitizeCodexAgentEventValue(entry, seen));
|
|
738
|
+
}
|
|
739
|
+
if (value && typeof value === "object") {
|
|
740
|
+
if (seen.has(value)) return "[Circular]";
|
|
741
|
+
seen.add(value);
|
|
742
|
+
const out = {};
|
|
743
|
+
for (const [key, child] of Object.entries(value)) out[key] = typeof child === "string" ? redactSensitiveFieldValue(key, child) : sanitizeCodexAgentEventValue(child, seen);
|
|
744
|
+
return out;
|
|
745
|
+
}
|
|
746
|
+
return value;
|
|
747
|
+
}
|
|
748
|
+
/** Sanitizes a record-shaped Codex agent event payload. */
|
|
749
|
+
function sanitizeCodexAgentEventRecord(value) {
|
|
750
|
+
return sanitizeCodexAgentEventValue(value);
|
|
751
|
+
}
|
|
752
|
+
/** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
|
|
753
|
+
function sanitizeCodexToolArguments(value) {
|
|
754
|
+
if (!isJsonObject(value)) return;
|
|
755
|
+
return sanitizeCodexAgentEventRecord(value);
|
|
756
|
+
}
|
|
757
|
+
/** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
|
|
758
|
+
function sanitizeCodexToolResponse(response) {
|
|
759
|
+
return sanitizeCodexAgentEventRecord(response);
|
|
760
|
+
}
|
|
761
|
+
/** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
|
|
762
|
+
function inferCodexDynamicToolMeta(call, detailMode) {
|
|
763
|
+
return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
|
|
764
|
+
}
|
|
765
|
+
//#endregion
|
|
766
|
+
//#region extensions/codex/src/app-server/event-projector-tool-items.ts
|
|
767
|
+
function nativeToolActionFingerprint(item) {
|
|
768
|
+
if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
|
|
769
|
+
type: item.type,
|
|
770
|
+
command: item.command,
|
|
771
|
+
cwd: typeof item.cwd === "string" ? item.cwd : ""
|
|
772
|
+
});
|
|
773
|
+
if (item.type === "fileChange") return JSON.stringify({
|
|
774
|
+
type: item.type,
|
|
775
|
+
changes: itemFileChanges(item)
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
function isNativePostToolUseRelayItem(item) {
|
|
779
|
+
switch (item.type) {
|
|
780
|
+
case "commandExecution":
|
|
781
|
+
case "fileChange":
|
|
782
|
+
case "mcpToolCall": return true;
|
|
783
|
+
default: return false;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
function shouldSuppressChannelProgressForItem(item) {
|
|
787
|
+
if (shouldSynthesizeToolProgressForItem(item)) return true;
|
|
788
|
+
return item.type === "dynamicToolCall";
|
|
789
|
+
}
|
|
790
|
+
function itemToolArgs(item) {
|
|
791
|
+
if (item.type === "commandExecution") return sanitizeCodexAgentEventRecord({
|
|
792
|
+
command: item.command,
|
|
793
|
+
...typeof item.cwd === "string" ? { cwd: item.cwd } : {}
|
|
794
|
+
});
|
|
795
|
+
if (item.type === "fileChange") return sanitizeCodexAgentEventRecord({ changes: itemFileChangesForTranscript(item) });
|
|
796
|
+
if (item.type === "webSearch") return webSearchToolArgs(item);
|
|
797
|
+
if (item.type === "dynamicToolCall" || item.type === "mcpToolCall") return sanitizeCodexToolArguments(item.arguments);
|
|
798
|
+
}
|
|
799
|
+
function webSearchToolArgs(item) {
|
|
800
|
+
const action = isJsonObject(item.action) ? item.action : void 0;
|
|
801
|
+
const actionType = action ? readNonEmptyString$1(action, "type") : void 0;
|
|
802
|
+
const queries = action && actionType === "search" ? readNonEmptyStringArray(action, "queries") : [];
|
|
803
|
+
const query = normalizeNonEmptyString(item.query) ?? (action && actionType === "search" ? readNonEmptyString$1(action, "query") : void 0) ?? queries[0];
|
|
804
|
+
const url = action ? readNonEmptyString$1(action, "url") : void 0;
|
|
805
|
+
const pattern = action ? readNonEmptyString$1(action, "pattern") : void 0;
|
|
806
|
+
const args = {};
|
|
807
|
+
if (query) args.query = query;
|
|
808
|
+
if (queries.length > 0) args.queries = queries;
|
|
809
|
+
if (actionType && actionType !== "search") args.action = actionType;
|
|
810
|
+
if (url) args.url = url;
|
|
811
|
+
if (pattern) args.pattern = pattern;
|
|
812
|
+
if (!query && !url && !pattern) args.queryUnavailable = true;
|
|
813
|
+
return sanitizeCodexAgentEventRecord(args);
|
|
814
|
+
}
|
|
815
|
+
function itemToolResult(item) {
|
|
816
|
+
if (item.type === "commandExecution") return { result: sanitizeCodexAgentEventRecord({
|
|
817
|
+
status: item.status,
|
|
818
|
+
exitCode: item.exitCode,
|
|
819
|
+
durationMs: item.durationMs
|
|
820
|
+
}) };
|
|
821
|
+
if (item.type === "fileChange") return { result: sanitizeCodexAgentEventRecord({
|
|
822
|
+
status: item.status,
|
|
823
|
+
changes: itemFileChanges(item)
|
|
824
|
+
}) };
|
|
825
|
+
if (item.type === "mcpToolCall") return { result: sanitizeCodexAgentEventRecord({
|
|
826
|
+
status: item.status,
|
|
827
|
+
durationMs: item.durationMs,
|
|
828
|
+
...item.error ? { error: item.error } : {},
|
|
829
|
+
...item.result ? { result: item.result } : {}
|
|
830
|
+
}) };
|
|
831
|
+
if (item.type === "webSearch") return { result: webSearchToolResult(item) };
|
|
832
|
+
return {};
|
|
833
|
+
}
|
|
834
|
+
function webSearchToolResult(item) {
|
|
835
|
+
return sanitizeCodexAgentEventRecord({
|
|
836
|
+
status: itemStatus(item),
|
|
837
|
+
...typeof item.durationMs === "number" ? { durationMs: item.durationMs } : {},
|
|
838
|
+
...webSearchToolArgs(item)
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
function itemFileChangeRecords(item) {
|
|
842
|
+
const changes = item.changes;
|
|
843
|
+
return Array.isArray(changes) ? changes.filter(isJsonObject) : [];
|
|
844
|
+
}
|
|
845
|
+
function itemFileChanges(item) {
|
|
846
|
+
return itemFileChangeRecords(item).flatMap((change) => {
|
|
847
|
+
const path = normalizeNonEmptyString(change.path);
|
|
848
|
+
if (!path || change.kind === void 0) return [];
|
|
849
|
+
return [{
|
|
850
|
+
path,
|
|
851
|
+
kind: change.kind
|
|
852
|
+
}];
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
function fileChangeKindType(kind) {
|
|
856
|
+
if (typeof kind === "string") return kind;
|
|
857
|
+
return isJsonObject(kind) ? normalizeNonEmptyString(kind.type) : void 0;
|
|
858
|
+
}
|
|
859
|
+
function countFileContentLines(content) {
|
|
860
|
+
if (!content) return 0;
|
|
861
|
+
const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
862
|
+
if (lines.length > 1 && lines.at(-1) === "") lines.pop();
|
|
863
|
+
return lines.length;
|
|
864
|
+
}
|
|
865
|
+
function fileChangeDiffStat(diff, kind) {
|
|
866
|
+
const kindType = fileChangeKindType(kind);
|
|
867
|
+
if (kindType === "add") return {
|
|
868
|
+
added: countFileContentLines(diff),
|
|
869
|
+
removed: 0
|
|
870
|
+
};
|
|
871
|
+
if (kindType === "delete") return {
|
|
872
|
+
added: 0,
|
|
873
|
+
removed: countFileContentLines(diff)
|
|
874
|
+
};
|
|
875
|
+
let added = 0;
|
|
876
|
+
let removed = 0;
|
|
877
|
+
let inHunk = false;
|
|
878
|
+
for (const line of diff.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
|
|
879
|
+
if (line.startsWith("@@")) {
|
|
880
|
+
inHunk = true;
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
if (!inHunk) continue;
|
|
884
|
+
if (line.startsWith("+")) added += 1;
|
|
885
|
+
else if (line.startsWith("-")) removed += 1;
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
added,
|
|
889
|
+
removed
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
function truncateFileChangeDiffAtLineBoundary(diff, maxChars) {
|
|
893
|
+
if (diff.length <= maxChars) return { diff };
|
|
894
|
+
if (maxChars <= 0) return { diffTruncated: true };
|
|
895
|
+
const boundary = diff.lastIndexOf("\n", maxChars - 1);
|
|
896
|
+
return boundary >= 0 ? {
|
|
897
|
+
diff: diff.slice(0, boundary + 1),
|
|
898
|
+
diffTruncated: true
|
|
899
|
+
} : { diffTruncated: true };
|
|
900
|
+
}
|
|
901
|
+
function itemFileChangesForTranscript(item) {
|
|
902
|
+
let remainingDiffChars = 1e4;
|
|
903
|
+
return itemFileChangeRecords(item).flatMap((change) => {
|
|
904
|
+
const path = normalizeNonEmptyString(change.path);
|
|
905
|
+
if (!path || change.kind === void 0) return [];
|
|
906
|
+
const result = {
|
|
907
|
+
path,
|
|
908
|
+
kind: change.kind
|
|
909
|
+
};
|
|
910
|
+
if (typeof change.diff !== "string") return [result];
|
|
911
|
+
result.stat = fileChangeDiffStat(change.diff, change.kind);
|
|
912
|
+
const bounded = truncateFileChangeDiffAtLineBoundary(change.diff, remainingDiffChars);
|
|
913
|
+
if (bounded.diff !== void 0) {
|
|
914
|
+
result.diff = bounded.diff;
|
|
915
|
+
remainingDiffChars -= bounded.diff.length;
|
|
916
|
+
}
|
|
917
|
+
if (bounded.diffTruncated) result.diffTruncated = true;
|
|
918
|
+
return [result];
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
function itemToolError(item, status, outputTextByItem) {
|
|
922
|
+
if (status === "blocked") return "codex native tool blocked";
|
|
923
|
+
if (status !== "failed") return;
|
|
924
|
+
return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
|
|
925
|
+
}
|
|
926
|
+
function itemMeta(item, detailMode = "explain") {
|
|
927
|
+
if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
|
|
928
|
+
command: item.command,
|
|
929
|
+
cwd: typeof item.cwd === "string" ? item.cwd : void 0
|
|
930
|
+
}, { detailMode });
|
|
931
|
+
if (item.type === "webSearch") return inferToolMetaFromArgs("web_search", webSearchToolArgs(item), { detailMode });
|
|
932
|
+
const toolName = itemName(item);
|
|
933
|
+
if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
|
|
934
|
+
}
|
|
935
|
+
function itemOutputText(item, outputTextByItem) {
|
|
936
|
+
if (item.type === "commandExecution") {
|
|
937
|
+
const output = item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim();
|
|
938
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
939
|
+
}
|
|
940
|
+
if (item.type === "dynamicToolCall") {
|
|
941
|
+
const output = collectDynamicToolContentText(item.contentItems).trim();
|
|
942
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
943
|
+
}
|
|
944
|
+
if (item.type === "mcpToolCall") {
|
|
945
|
+
const output = item.error ? stringifyJsonValue(item.error) : item.result ? stringifyJsonValue(item.result) : void 0;
|
|
946
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
function itemTranscriptResultText(item, outputTextByItem) {
|
|
950
|
+
const output = itemOutputText(item, outputTextByItem);
|
|
951
|
+
if (output) return output;
|
|
952
|
+
const result = itemToolResult(item).result;
|
|
953
|
+
const resultText = result ? stringifyJsonValue(result) : void 0;
|
|
954
|
+
return resultText ? truncateToolTranscriptText(resultText) : itemStatus(item);
|
|
955
|
+
}
|
|
956
|
+
function stringifyJsonValue(value) {
|
|
957
|
+
try {
|
|
958
|
+
return JSON.stringify(value, null, 2);
|
|
959
|
+
} catch {
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
//#endregion
|
|
964
|
+
//#region extensions/codex/src/app-server/event-projector-tool-progress.ts
|
|
965
|
+
const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
966
|
+
"message",
|
|
967
|
+
"messages",
|
|
968
|
+
"reply",
|
|
969
|
+
"send",
|
|
970
|
+
"reaction",
|
|
971
|
+
"react",
|
|
972
|
+
"typing"
|
|
973
|
+
]);
|
|
974
|
+
function shouldEmitTranscriptToolProgress(toolName, _args) {
|
|
975
|
+
const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
|
|
976
|
+
return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
|
|
977
|
+
}
|
|
978
|
+
var CodexToolProgressProjection = class {
|
|
979
|
+
constructor(params) {
|
|
980
|
+
this.params = params;
|
|
981
|
+
this.echoesByItem = /* @__PURE__ */ new Map();
|
|
982
|
+
this.resultSummaryItemIds = /* @__PURE__ */ new Set();
|
|
983
|
+
this.resultOutputItemIds = /* @__PURE__ */ new Set();
|
|
984
|
+
this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
|
|
985
|
+
this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
|
|
986
|
+
this.transcriptArgumentsById = /* @__PURE__ */ new Map();
|
|
987
|
+
this.resultOutputDeltaState = /* @__PURE__ */ new Map();
|
|
988
|
+
this.output = new ToolOutputAccumulator();
|
|
989
|
+
this.metas = /* @__PURE__ */ new Map();
|
|
990
|
+
this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
|
|
991
|
+
this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
|
|
992
|
+
this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
|
|
993
|
+
}
|
|
994
|
+
get outputTextByItem() {
|
|
995
|
+
return this.output.textByItem;
|
|
996
|
+
}
|
|
997
|
+
get toolMetas() {
|
|
998
|
+
return [...this.metas.values()];
|
|
999
|
+
}
|
|
1000
|
+
getToolMeta(itemId) {
|
|
1001
|
+
return this.metas.get(itemId);
|
|
1002
|
+
}
|
|
1003
|
+
get lastToolError() {
|
|
1004
|
+
return this.lastNativeToolError;
|
|
1005
|
+
}
|
|
1006
|
+
get hasPotentialSideEffects() {
|
|
1007
|
+
return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
|
|
1008
|
+
}
|
|
1009
|
+
setLastToolError(error) {
|
|
1010
|
+
if (!error) {
|
|
1011
|
+
this.lastNativeToolError = void 0;
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
1015
|
+
toolName: error.toolName,
|
|
1016
|
+
...error.meta ? { meta: error.meta } : {},
|
|
1017
|
+
outcome: "failure",
|
|
1018
|
+
failure: {
|
|
1019
|
+
...error.errorCode ? { errorCode: error.errorCode } : {},
|
|
1020
|
+
...error.error ? { error: error.error } : {},
|
|
1021
|
+
...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
|
|
1022
|
+
...error.timedOut ? { timedOut: true } : {},
|
|
1023
|
+
...error.middlewareError ? { middlewareError: true } : {}
|
|
1024
|
+
},
|
|
1025
|
+
nativeMutation: {
|
|
1026
|
+
mutatingAction: error.mutatingAction === true,
|
|
1027
|
+
replaySafe: error.mutatingAction !== true,
|
|
1028
|
+
...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
|
|
1029
|
+
...error.fileTarget ? { fileTarget: error.fileTarget } : {}
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
|
|
1033
|
+
}
|
|
1034
|
+
recordDynamicToolResult(params) {
|
|
1035
|
+
const resultText = collectDynamicToolContentText(params.contentItems);
|
|
1036
|
+
const existing = this.metas.get(params.callId);
|
|
1037
|
+
this.metas.set(params.callId, {
|
|
1038
|
+
toolName: existing?.toolName ?? params.tool,
|
|
1039
|
+
...existing?.meta ? { meta: existing.meta } : {},
|
|
1040
|
+
...params.asyncStarted === true ? { asyncStarted: true } : {},
|
|
1041
|
+
...!params.success ? { isError: true } : {}
|
|
1042
|
+
});
|
|
1043
|
+
if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
|
|
1044
|
+
else if (!params.success) this.lastNativeToolError = {
|
|
1045
|
+
toolName: params.tool,
|
|
1046
|
+
error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
|
|
1047
|
+
};
|
|
1048
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
1049
|
+
if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
|
|
1050
|
+
}
|
|
1051
|
+
handleOutputDelta(params, toolName) {
|
|
1052
|
+
const itemId = readString$6(params, "itemId");
|
|
1053
|
+
const delta = readString$6(params, "delta");
|
|
1054
|
+
if (!itemId || !delta) return;
|
|
1055
|
+
const storedOutput = this.output.append(itemId, delta);
|
|
1056
|
+
this.rememberEcho(itemId, {
|
|
1057
|
+
displayText: storedOutput.text,
|
|
1058
|
+
rawLength: storedOutput.normalizedLength,
|
|
1059
|
+
rawPrefix: storedOutput.rawPrefix,
|
|
1060
|
+
streamedDisplay: true
|
|
1061
|
+
});
|
|
1062
|
+
if (!this.shouldEmitToolOutput()) return;
|
|
1063
|
+
if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
|
|
1064
|
+
const state = this.resultOutputDeltaState.get(itemId) ?? {
|
|
1065
|
+
chars: 0,
|
|
1066
|
+
messages: 0,
|
|
1067
|
+
truncated: false
|
|
1068
|
+
};
|
|
1069
|
+
if (state.truncated) return;
|
|
1070
|
+
const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
|
|
1071
|
+
const remainingMessages = Math.max(0, 20 - state.messages);
|
|
1072
|
+
if (remainingChars === 0 || remainingMessages === 0) {
|
|
1073
|
+
state.truncated = true;
|
|
1074
|
+
this.resultOutputDeltaState.set(itemId, state);
|
|
1075
|
+
this.emitToolResultMessage({
|
|
1076
|
+
itemId,
|
|
1077
|
+
text: formatToolOutput(toolName, void 0, "(output truncated)")
|
|
1078
|
+
});
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
|
|
1082
|
+
state.chars += chunk.length;
|
|
1083
|
+
state.messages += 1;
|
|
1084
|
+
const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
|
|
1085
|
+
if (reachedLimit) state.truncated = true;
|
|
1086
|
+
this.resultOutputDeltaState.set(itemId, state);
|
|
1087
|
+
this.resultOutputStreamedItemIds.add(itemId);
|
|
1088
|
+
this.emitToolResultMessage({
|
|
1089
|
+
itemId,
|
|
1090
|
+
text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
|
|
1091
|
+
});
|
|
1092
|
+
}
|
|
1093
|
+
recordNativeToolError(params) {
|
|
1094
|
+
const executionStarted = params.status !== "blocked";
|
|
1095
|
+
const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
|
|
1096
|
+
const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
|
|
1097
|
+
const isFailure = isNonSuccessItemStatus(params.status);
|
|
1098
|
+
const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
|
|
1099
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
1100
|
+
toolCallId: params.item.id,
|
|
1101
|
+
toolName: params.name,
|
|
1102
|
+
arguments: itemToolArgs(params.item),
|
|
1103
|
+
...params.meta ? { meta: params.meta } : {},
|
|
1104
|
+
executionStarted,
|
|
1105
|
+
outcome: isFailure ? "failure" : "success",
|
|
1106
|
+
...isFailure ? { failure: error ? { error } : {} } : {},
|
|
1107
|
+
nativeMutation: {
|
|
1108
|
+
mutatingAction,
|
|
1109
|
+
replaySafe: !mutatingAction,
|
|
1110
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
if (terminalResolution) {
|
|
1114
|
+
this.lastNativeToolError = terminalResolution.lastToolError;
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
if (isFailure) this.lastNativeToolError = {
|
|
1118
|
+
toolName: params.name,
|
|
1119
|
+
...params.meta ? { meta: params.meta } : {},
|
|
1120
|
+
...error ? { error } : {},
|
|
1121
|
+
...mutatingAction ? { mutatingAction: true } : {},
|
|
1122
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1123
|
+
};
|
|
1124
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
1125
|
+
}
|
|
1126
|
+
emitToolResultSummary(item) {
|
|
1127
|
+
if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
|
|
1128
|
+
if (this.resultSummaryItemIds.has(item.id)) return;
|
|
1129
|
+
const toolName = itemName(item);
|
|
1130
|
+
if (!toolName || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1131
|
+
this.resultSummaryItemIds.add(item.id);
|
|
1132
|
+
this.emitToolResultMessage({
|
|
1133
|
+
itemId: item.id,
|
|
1134
|
+
text: formatToolSummary(toolName, itemMeta(item, this.toolProgressDetailMode()))
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
emitToolResultOutput(item) {
|
|
1138
|
+
if (!item || !this.params.onToolResult || !this.shouldEmitToolOutput()) return;
|
|
1139
|
+
if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
|
|
1140
|
+
const toolName = itemName(item);
|
|
1141
|
+
const output = itemOutputText(item, this.output.textByItem);
|
|
1142
|
+
if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1143
|
+
this.emitToolResultMessage({
|
|
1144
|
+
itemId: item.id,
|
|
1145
|
+
text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
|
|
1146
|
+
finalOutput: true,
|
|
1147
|
+
isError: isNonSuccessItemStatus(itemStatus(item))
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
recordToolMeta(item) {
|
|
1151
|
+
if (!item) return;
|
|
1152
|
+
if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
|
|
1153
|
+
else this.sideEffectingNativeIds.delete(item.id);
|
|
1154
|
+
const toolName = itemName(item);
|
|
1155
|
+
if (!toolName) return;
|
|
1156
|
+
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1157
|
+
const status = itemStatus(item);
|
|
1158
|
+
const existing = this.metas.get(item.id);
|
|
1159
|
+
this.metas.set(item.id, {
|
|
1160
|
+
toolName,
|
|
1161
|
+
...meta ? { meta } : {},
|
|
1162
|
+
...existing?.asyncStarted ? { asyncStarted: true } : {},
|
|
1163
|
+
...status !== "running" && isNonSuccessItemStatus(status) ? { isError: true } : {}
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
recordTranscriptCall(params) {
|
|
1167
|
+
this.transcriptArgumentsById.set(params.id, params.arguments);
|
|
1168
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
|
|
1169
|
+
else this.transcriptProgressSuppressedIds.delete(params.id);
|
|
1170
|
+
this.emitTranscriptToolCallProgress(params);
|
|
1171
|
+
}
|
|
1172
|
+
recordTranscriptResult(params) {
|
|
1173
|
+
this.emitTranscriptToolResultProgress(params);
|
|
1174
|
+
}
|
|
1175
|
+
matchesEcho(text) {
|
|
1176
|
+
for (const state of this.echoesByItem.values()) {
|
|
1177
|
+
if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
|
|
1178
|
+
if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
|
|
1179
|
+
for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
|
|
1180
|
+
}
|
|
1181
|
+
return false;
|
|
1182
|
+
}
|
|
1183
|
+
rememberCommandAggregateOutputEcho(item) {
|
|
1184
|
+
if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
|
|
1185
|
+
const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
|
|
1186
|
+
if (signature) this.rememberEcho(item.id, signature);
|
|
1187
|
+
}
|
|
1188
|
+
toolProgressDetailMode() {
|
|
1189
|
+
return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
|
|
1190
|
+
}
|
|
1191
|
+
emitToolResultMessage(params) {
|
|
1192
|
+
const rawText = params.text.trim();
|
|
1193
|
+
const text = truncateToolTranscriptText(rawText);
|
|
1194
|
+
if (!text) return;
|
|
1195
|
+
this.rememberEcho(params.itemId, {
|
|
1196
|
+
displayText: text,
|
|
1197
|
+
rawText
|
|
1198
|
+
});
|
|
1199
|
+
if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
|
|
1200
|
+
try {
|
|
1201
|
+
Promise.resolve(this.params.onToolResult?.({
|
|
1202
|
+
text,
|
|
1203
|
+
...params.isError === true ? { isError: true } : {}
|
|
1204
|
+
})).catch(() => {});
|
|
1205
|
+
} catch {}
|
|
1206
|
+
}
|
|
1207
|
+
shouldEmitToolResult() {
|
|
1208
|
+
return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
|
|
1209
|
+
}
|
|
1210
|
+
shouldEmitToolOutput() {
|
|
1211
|
+
return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
|
|
1212
|
+
}
|
|
1213
|
+
emitTranscriptToolCallProgress(params) {
|
|
1214
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
|
|
1215
|
+
this.transcriptProgressCallIds.add(params.id);
|
|
1216
|
+
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1217
|
+
const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
|
|
1218
|
+
if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
|
|
1219
|
+
this.resultSummaryItemIds.add(params.id);
|
|
1220
|
+
this.emitToolResultMessage({
|
|
1221
|
+
itemId: params.id,
|
|
1222
|
+
text: formatToolSummary(params.name, meta)
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
emitTranscriptToolResultProgress(params) {
|
|
1226
|
+
if (this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
|
|
1227
|
+
if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
|
|
1228
|
+
id: params.id,
|
|
1229
|
+
name: params.name,
|
|
1230
|
+
arguments: {}
|
|
1231
|
+
});
|
|
1232
|
+
if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
|
|
1233
|
+
const text = params.text?.trim();
|
|
1234
|
+
if (text) this.emitToolResultMessage({
|
|
1235
|
+
itemId: params.id,
|
|
1236
|
+
text: formatToolOutput(params.name, void 0, text),
|
|
1237
|
+
finalOutput: true,
|
|
1238
|
+
isError: params.isError
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
rememberEcho(itemId, signature) {
|
|
1242
|
+
if (!itemId) return;
|
|
1243
|
+
const existing = this.echoesByItem.get(itemId) ?? {
|
|
1244
|
+
displayTexts: [],
|
|
1245
|
+
rawSignatures: []
|
|
1246
|
+
};
|
|
1247
|
+
const displayText = signature.displayText?.trim();
|
|
1248
|
+
if (displayText) {
|
|
1249
|
+
if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
|
|
1250
|
+
else if (!existing.displayTexts.includes(displayText)) {
|
|
1251
|
+
if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
|
|
1252
|
+
existing.displayTexts.push(displayText);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
const rawText = signature.rawText?.trim();
|
|
1256
|
+
const rawLength = signature.rawLength ?? rawText?.length;
|
|
1257
|
+
const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
|
|
1258
|
+
if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
|
|
1259
|
+
const next = {
|
|
1260
|
+
length: rawLength,
|
|
1261
|
+
prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
|
|
1262
|
+
};
|
|
1263
|
+
if (signature.streamedDisplay) existing.streamedRawSignature = next;
|
|
1264
|
+
else {
|
|
1265
|
+
const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
|
|
1266
|
+
if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
|
|
1267
|
+
else {
|
|
1268
|
+
if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
|
|
1269
|
+
existing.rawSignatures.push(next);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
this.echoesByItem.set(itemId, existing);
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
//#endregion
|
|
1277
|
+
//#region extensions/codex/src/app-server/session-history.ts
|
|
1278
|
+
/**
|
|
1279
|
+
* Reads OpenClaw session history for Codex transcript mirroring and sanitizes
|
|
1280
|
+
* image payloads before replaying messages into the app-server projector.
|
|
1281
|
+
*/
|
|
1282
|
+
function isMissingFileError(error) {
|
|
1283
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
1284
|
+
}
|
|
1285
|
+
function selectPreferredSessionKey(matches, sessionId) {
|
|
1286
|
+
const structural = matches.filter(({ sessionKey }) => sessionKey === sessionId || sessionKey.endsWith(`:${sessionId}`));
|
|
1287
|
+
const candidates = structural.length > 0 ? structural : matches;
|
|
1288
|
+
if (candidates.length === 1) return candidates[0]?.sessionKey;
|
|
1289
|
+
const sorted = candidates.toSorted((left, right) => (right.entry.updatedAt ?? 0) - (left.entry.updatedAt ?? 0));
|
|
1290
|
+
return (sorted[0]?.entry.updatedAt ?? 0) > (sorted[1]?.entry.updatedAt ?? 0) ? sorted[0]?.sessionKey : void 0;
|
|
1291
|
+
}
|
|
1292
|
+
/** Returns sanitized session-context messages for a Codex mirrored session file. */
|
|
1293
|
+
async function readCodexMirroredSessionHistoryMessages(target) {
|
|
1294
|
+
try {
|
|
1295
|
+
const entries = await readCodexMirroredSessionEntries(target);
|
|
1296
|
+
if (entries.length === 0) return [];
|
|
1297
|
+
const firstEntry = entries[0];
|
|
1298
|
+
if (firstEntry?.type !== "session") return [];
|
|
1299
|
+
if (typeof firstEntry.id !== "string") return;
|
|
1300
|
+
migrateSessionEntries(entries);
|
|
1301
|
+
return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
|
|
1302
|
+
return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
|
|
1303
|
+
})).messages, "codex mirrored history");
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
if (isMissingFileError(error)) return [];
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
async function readCodexMirroredSessionEntries(target) {
|
|
1310
|
+
const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
|
|
1311
|
+
if (sqliteMarker) {
|
|
1312
|
+
if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return [];
|
|
1313
|
+
const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
|
|
1314
|
+
if (!sessionKey) return [];
|
|
1315
|
+
return await readSessionTranscriptEvents({
|
|
1316
|
+
agentId: sqliteMarker.agentId,
|
|
1317
|
+
sessionId: sqliteMarker.sessionId,
|
|
1318
|
+
sessionKey,
|
|
1319
|
+
storePath: sqliteMarker.storePath
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
return parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
|
|
1323
|
+
}
|
|
1324
|
+
function resolveSqliteMarkerSessionKey(target, marker) {
|
|
1325
|
+
const explicitSessionKey = target.sessionKey?.trim();
|
|
1326
|
+
const entries = listSessionEntries({
|
|
1327
|
+
agentId: marker.agentId,
|
|
1328
|
+
readOnly: true,
|
|
1329
|
+
storePath: marker.storePath
|
|
1330
|
+
});
|
|
1331
|
+
if (explicitSessionKey) {
|
|
1332
|
+
const explicitEntry = entries.find(({ sessionKey }) => sessionKey === explicitSessionKey);
|
|
1333
|
+
if (explicitEntry) return explicitEntry.entry.sessionId === marker.sessionId ? explicitSessionKey : void 0;
|
|
1334
|
+
}
|
|
1335
|
+
return selectPreferredSessionKey(entries.filter(({ entry }) => entry.sessionId === marker.sessionId), marker.sessionId);
|
|
1336
|
+
}
|
|
1337
|
+
//#endregion
|
|
1338
|
+
//#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
|
|
1339
|
+
const ZERO_USAGE = {
|
|
1340
|
+
input: 0,
|
|
1341
|
+
output: 0,
|
|
1342
|
+
cacheRead: 0,
|
|
1343
|
+
cacheWrite: 0,
|
|
1344
|
+
totalTokens: 0,
|
|
1345
|
+
cost: {
|
|
1346
|
+
input: 0,
|
|
1347
|
+
output: 0,
|
|
1348
|
+
cacheRead: 0,
|
|
1349
|
+
cacheWrite: 0,
|
|
1350
|
+
total: 0
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
|
|
1354
|
+
var CodexToolTranscriptProjection = class {
|
|
1355
|
+
constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
|
|
1356
|
+
this.params = params;
|
|
1357
|
+
this.threadId = threadId;
|
|
1358
|
+
this.turnId = turnId;
|
|
1359
|
+
this.progress = progress;
|
|
1360
|
+
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
1361
|
+
this.options = options;
|
|
1362
|
+
this.messages = [];
|
|
1363
|
+
this.callIds = /* @__PURE__ */ new Set();
|
|
1364
|
+
this.resultIds = /* @__PURE__ */ new Set();
|
|
1365
|
+
this.namesById = /* @__PURE__ */ new Map();
|
|
1366
|
+
this.trajectoryCallIds = /* @__PURE__ */ new Set();
|
|
1367
|
+
this.trajectoryResultIds = /* @__PURE__ */ new Set();
|
|
1368
|
+
this.trajectoryNamesById = /* @__PURE__ */ new Map();
|
|
1369
|
+
this.trajectoryItemsById = /* @__PURE__ */ new Map();
|
|
1370
|
+
this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
|
|
1371
|
+
this.nativeMcpAppResultDetails = /* @__PURE__ */ new Map();
|
|
1372
|
+
this.nativeMcpAppResultDetailsAttempted = /* @__PURE__ */ new Set();
|
|
1373
|
+
}
|
|
1374
|
+
get transcriptMessages() {
|
|
1375
|
+
return this.messages;
|
|
1376
|
+
}
|
|
1377
|
+
recordDynamicToolCall(params) {
|
|
1378
|
+
this.recordToolCall({
|
|
1379
|
+
id: params.callId,
|
|
1380
|
+
name: params.tool,
|
|
1381
|
+
arguments: sanitizeCodexToolArguments(params.arguments)
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
recordDynamicToolResult(params) {
|
|
1385
|
+
this.recordToolResult({
|
|
1386
|
+
id: params.callId,
|
|
1387
|
+
name: params.tool,
|
|
1388
|
+
text: collectDynamicToolContentText(params.contentItems),
|
|
1389
|
+
isError: !params.success,
|
|
1390
|
+
details: params.details
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
recordNativeToolCall(item) {
|
|
1394
|
+
if (!item || !shouldRecordNativeToolTranscript(item)) return;
|
|
1395
|
+
const name = itemName(item);
|
|
1396
|
+
if (name) this.recordToolCall({
|
|
1397
|
+
id: item.id,
|
|
1398
|
+
name,
|
|
1399
|
+
arguments: itemToolArgs(item)
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
recordNativeToolResult(item, details) {
|
|
1403
|
+
if (!item || !shouldRecordNativeToolTranscript(item)) return;
|
|
1404
|
+
const name = itemName(item);
|
|
1405
|
+
if (name) this.recordToolResult({
|
|
1406
|
+
id: item.id,
|
|
1407
|
+
name,
|
|
1408
|
+
text: itemTranscriptResultText(item, this.progress.outputTextByItem),
|
|
1409
|
+
isError: isNonSuccessItemStatus(itemStatus(item)),
|
|
1410
|
+
details
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
async recordNativeToolResultWithDetails(item) {
|
|
1414
|
+
this.recordNativeToolResult(item, await this.prepareNativeMcpAppResultDetails(item));
|
|
1415
|
+
}
|
|
1416
|
+
async prepareNativeMcpAppResultDetails(item) {
|
|
1417
|
+
if (!item || item.type !== "mcpToolCall" || itemStatus(item) === "running") return;
|
|
1418
|
+
if (this.nativeMcpAppResultDetails.has(item.id)) return this.nativeMcpAppResultDetails.get(item.id);
|
|
1419
|
+
if (this.nativeMcpAppResultDetailsAttempted.has(item.id) || !this.options.prepareNativeMcpAppResultDetails) return;
|
|
1420
|
+
this.nativeMcpAppResultDetailsAttempted.add(item.id);
|
|
1421
|
+
try {
|
|
1422
|
+
const details = await this.options.prepareNativeMcpAppResultDetails(item);
|
|
1423
|
+
if (details !== void 0) this.nativeMcpAppResultDetails.set(item.id, details);
|
|
1424
|
+
return details;
|
|
1425
|
+
} catch (error) {
|
|
1426
|
+
embeddedAgentLog.debug("codex native MCP App preview preparation failed", {
|
|
1427
|
+
itemId: item.id,
|
|
1428
|
+
error
|
|
1429
|
+
});
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
recordTrajectoryEvent(params) {
|
|
1434
|
+
if (params.phase === "start") {
|
|
1435
|
+
this.trajectoryCallIds.add(params.item.id);
|
|
1436
|
+
this.trajectoryNamesById.set(params.item.id, params.name);
|
|
1437
|
+
this.trajectoryItemsById.set(params.item.id, params.item);
|
|
1438
|
+
this.options.trajectoryRecorder?.recordEvent("tool.call", {
|
|
1439
|
+
threadId: this.threadId,
|
|
1440
|
+
turnId: this.turnId,
|
|
1441
|
+
itemId: params.item.id,
|
|
1442
|
+
toolCallId: params.item.id,
|
|
1443
|
+
name: params.name,
|
|
1444
|
+
arguments: params.args
|
|
1445
|
+
});
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
this.trajectoryResultIds.add(params.item.id);
|
|
1449
|
+
const toolResult = itemToolResult(params.item).result;
|
|
1450
|
+
const output = itemOutputText(params.item, this.progress.outputTextByItem);
|
|
1451
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1452
|
+
threadId: this.threadId,
|
|
1453
|
+
turnId: this.turnId,
|
|
1454
|
+
itemId: params.item.id,
|
|
1455
|
+
toolCallId: params.item.id,
|
|
1456
|
+
name: params.name,
|
|
1457
|
+
status: params.status,
|
|
1458
|
+
isError: isNonSuccessItemStatus(params.status),
|
|
1459
|
+
...toolResult ? { result: toolResult } : {},
|
|
1460
|
+
...output ? { output } : {}
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
emitAfterToolCallObservation(item) {
|
|
1464
|
+
if (!this.shouldEmitAfterToolCallObservation(item)) return;
|
|
1465
|
+
const name = itemName(item);
|
|
1466
|
+
const status = itemStatus(item);
|
|
1467
|
+
if (!name || status === "running") return;
|
|
1468
|
+
this.afterToolCallObservedItemIds.add(item.id);
|
|
1469
|
+
const result = itemToolResult(item).result;
|
|
1470
|
+
const error = itemToolError(item, status, this.progress.outputTextByItem);
|
|
1471
|
+
const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
|
|
1472
|
+
const hookParams = {
|
|
1473
|
+
toolName: name,
|
|
1474
|
+
toolCallId: item.id,
|
|
1475
|
+
runId: this.params.runId,
|
|
1476
|
+
agentId: this.params.agentId,
|
|
1477
|
+
sessionId: this.params.sessionId,
|
|
1478
|
+
sessionKey: this.params.sessionKey,
|
|
1479
|
+
startArgs: itemToolArgs(item) ?? {},
|
|
1480
|
+
...result !== void 0 ? { result } : {},
|
|
1481
|
+
...error ? { error } : {},
|
|
1482
|
+
...startedAt !== void 0 ? { startedAt } : {}
|
|
1483
|
+
};
|
|
1484
|
+
setImmediate(() => {
|
|
1485
|
+
runAgentHarnessAfterToolCallHook(hookParams);
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
synthesizeMissingToolResults(params) {
|
|
1489
|
+
if (!params.synthesize) return;
|
|
1490
|
+
const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
|
|
1491
|
+
const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
|
|
1492
|
+
if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
|
|
1493
|
+
for (const id of missingTranscriptIds) {
|
|
1494
|
+
const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
|
|
1495
|
+
if (name) this.recordToolResult({
|
|
1496
|
+
id,
|
|
1497
|
+
name,
|
|
1498
|
+
text: formatMissingToolResultError({
|
|
1499
|
+
id,
|
|
1500
|
+
name
|
|
1501
|
+
}),
|
|
1502
|
+
isError: true
|
|
1503
|
+
});
|
|
1504
|
+
}
|
|
1505
|
+
for (const id of missingTrajectoryIds) {
|
|
1506
|
+
const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
|
|
1507
|
+
if (!name) continue;
|
|
1508
|
+
this.trajectoryResultIds.add(id);
|
|
1509
|
+
const text = formatMissingToolResultError({
|
|
1510
|
+
id,
|
|
1511
|
+
name
|
|
1512
|
+
});
|
|
1513
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1514
|
+
threadId: this.threadId,
|
|
1515
|
+
turnId: this.turnId,
|
|
1516
|
+
itemId: id,
|
|
1517
|
+
toolCallId: id,
|
|
1518
|
+
name,
|
|
1519
|
+
status: "failed",
|
|
1520
|
+
isError: true,
|
|
1521
|
+
result: {
|
|
1522
|
+
status: "failed",
|
|
1523
|
+
reason: "missing_tool_result"
|
|
1524
|
+
},
|
|
1525
|
+
output: text
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
if (!params.recordPromptError) {
|
|
1529
|
+
this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
|
|
1533
|
+
return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
|
|
1534
|
+
}
|
|
1535
|
+
async readMirroredSessionMessages() {
|
|
1536
|
+
return await readCodexMirroredSessionHistoryMessages({
|
|
1537
|
+
agentId: this.params.agentId,
|
|
1538
|
+
sessionFile: this.params.sessionFile,
|
|
1539
|
+
sessionId: this.params.sessionId,
|
|
1540
|
+
sessionKey: this.params.sessionKey
|
|
1541
|
+
}) ?? [];
|
|
1542
|
+
}
|
|
1543
|
+
recordToolCall(params) {
|
|
1544
|
+
if (!params.id || !params.name || this.callIds.has(params.id)) return;
|
|
1545
|
+
this.callIds.add(params.id);
|
|
1546
|
+
this.namesById.set(params.id, params.name);
|
|
1547
|
+
this.progress.recordTranscriptCall(params);
|
|
1548
|
+
this.messages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
|
|
1549
|
+
}
|
|
1550
|
+
recordToolResult(params) {
|
|
1551
|
+
if (!params.id || !params.name || this.resultIds.has(params.id)) return;
|
|
1552
|
+
this.resultIds.add(params.id);
|
|
1553
|
+
this.progress.recordTranscriptResult(params);
|
|
1554
|
+
this.messages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
|
|
1555
|
+
}
|
|
1556
|
+
recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
|
|
1557
|
+
const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
|
|
1558
|
+
if (!firstMissingId) return;
|
|
1559
|
+
const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
|
|
1560
|
+
if (!name) return;
|
|
1561
|
+
const item = this.trajectoryItemsById.get(firstMissingId);
|
|
1562
|
+
const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
|
|
1563
|
+
const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
|
|
1564
|
+
this.progress.setLastToolError({
|
|
1565
|
+
toolName: name,
|
|
1566
|
+
...meta ? { meta } : {},
|
|
1567
|
+
error: formatMissingToolResultError({
|
|
1568
|
+
id: firstMissingId,
|
|
1569
|
+
name
|
|
1570
|
+
}),
|
|
1571
|
+
...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
|
|
1572
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1575
|
+
shouldEmitAfterToolCallObservation(item) {
|
|
1576
|
+
if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
|
|
1577
|
+
return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
|
|
1578
|
+
}
|
|
1579
|
+
createToolCallMessage(params) {
|
|
1580
|
+
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1581
|
+
const attribution = resolveCodexLocalRuntimeAttribution(this.params);
|
|
1582
|
+
return {
|
|
1583
|
+
role: "assistant",
|
|
1584
|
+
content: [{
|
|
1585
|
+
type: "toolCall",
|
|
1586
|
+
id: params.id,
|
|
1587
|
+
name: params.name,
|
|
1588
|
+
arguments: args,
|
|
1589
|
+
input: args
|
|
1590
|
+
}],
|
|
1591
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
1592
|
+
provider: attribution.provider,
|
|
1593
|
+
model: this.params.modelId,
|
|
1594
|
+
usage: ZERO_USAGE,
|
|
1595
|
+
stopReason: "toolUse",
|
|
1596
|
+
timestamp: this.nextTranscriptTimestamp()
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
createToolResultMessage(params) {
|
|
1600
|
+
const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
|
|
1601
|
+
return {
|
|
1602
|
+
role: "toolResult",
|
|
1603
|
+
toolCallId: params.id,
|
|
1604
|
+
toolName: params.name,
|
|
1605
|
+
isError: params.isError,
|
|
1606
|
+
content: [{
|
|
1607
|
+
type: "toolResult",
|
|
1608
|
+
id: params.id,
|
|
1609
|
+
name: params.name,
|
|
1610
|
+
toolName: params.name,
|
|
1611
|
+
toolCallId: params.id,
|
|
1612
|
+
toolUseId: params.id,
|
|
1613
|
+
tool_use_id: params.id,
|
|
1614
|
+
content: text,
|
|
1615
|
+
text
|
|
1616
|
+
}],
|
|
1617
|
+
...params.details !== void 0 ? { details: params.details } : {},
|
|
1618
|
+
timestamp: this.nextTranscriptTimestamp()
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
function formatMissingToolResultError(params) {
|
|
1623
|
+
return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
|
|
1624
|
+
}
|
|
1625
|
+
function toolResultStatusText(params) {
|
|
1626
|
+
return params.isError ? `${params.name} failed` : `${params.name} completed`;
|
|
1627
|
+
}
|
|
1628
|
+
function resolveStartedAtFromDurationMs(durationMs) {
|
|
1629
|
+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
|
|
1630
|
+
return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
|
|
1631
|
+
}
|
|
1632
|
+
//#endregion
|
|
1633
|
+
//#region extensions/codex/src/app-server/event-projector-events.ts
|
|
1634
|
+
var CodexEventProjection = class {
|
|
1635
|
+
constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
|
|
1636
|
+
this.threadId = threadId;
|
|
1637
|
+
this.turnId = turnId;
|
|
1638
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
1639
|
+
this.toolProgress = toolProgress;
|
|
1640
|
+
this.toolTranscript = toolTranscript;
|
|
1641
|
+
this.onNativeToolResultRecorded = onNativeToolResultRecorded;
|
|
1642
|
+
this.reviewCount = 0;
|
|
1643
|
+
}
|
|
1644
|
+
get guardianReviewCount() {
|
|
1645
|
+
return this.reviewCount;
|
|
1646
|
+
}
|
|
1647
|
+
handleGuardianReview(method, params) {
|
|
1648
|
+
this.reviewCount += 1;
|
|
1649
|
+
const review = isJsonObject(params.review) ? params.review : void 0;
|
|
1650
|
+
const action = isJsonObject(params.action) ? params.action : void 0;
|
|
1651
|
+
this.emitAgentEvent({
|
|
1652
|
+
stream: "codex_app_server.guardian",
|
|
1653
|
+
data: {
|
|
1654
|
+
method,
|
|
1655
|
+
phase: method.endsWith("/started") ? "started" : "completed",
|
|
1656
|
+
reviewId: readString$6(params, "reviewId"),
|
|
1657
|
+
targetItemId: readNullableString$1(params, "targetItemId"),
|
|
1658
|
+
decisionSource: readString$6(params, "decisionSource"),
|
|
1659
|
+
status: review ? readString$6(review, "status") : void 0,
|
|
1660
|
+
riskLevel: review ? readString$6(review, "riskLevel") : void 0,
|
|
1661
|
+
userAuthorization: review ? readString$6(review, "userAuthorization") : void 0,
|
|
1662
|
+
rationale: review ? readNullableString$1(review, "rationale") : void 0,
|
|
1663
|
+
actionType: action ? readString$6(action, "type") : void 0
|
|
1664
|
+
}
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
handleGuardianWarning(params) {
|
|
1668
|
+
this.emitAgentEvent({
|
|
1669
|
+
stream: "codex_app_server.guardian",
|
|
1670
|
+
data: {
|
|
1671
|
+
phase: "warning",
|
|
1672
|
+
message: readString$6(params, "message")
|
|
1673
|
+
}
|
|
1674
|
+
});
|
|
1675
|
+
}
|
|
1676
|
+
handleHook(method, params) {
|
|
1677
|
+
const run = isJsonObject(params.run) ? params.run : void 0;
|
|
1678
|
+
if (!run) return;
|
|
1679
|
+
const durationMs = readNumber(run, "durationMs");
|
|
1680
|
+
const entries = readHookOutputEntries(run.entries);
|
|
1681
|
+
const hookTurnId = readNullableString$1(params, "turnId");
|
|
1682
|
+
this.emitAgentEvent({
|
|
1683
|
+
stream: "codex_app_server.hook",
|
|
1684
|
+
data: {
|
|
1685
|
+
phase: method === "hook/started" ? "started" : "completed",
|
|
1686
|
+
threadId: this.threadId,
|
|
1687
|
+
turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
|
|
1688
|
+
hookRunId: readString$6(run, "id"),
|
|
1689
|
+
eventName: readString$6(run, "eventName"),
|
|
1690
|
+
handlerType: readString$6(run, "handlerType"),
|
|
1691
|
+
executionMode: readString$6(run, "executionMode"),
|
|
1692
|
+
scope: readString$6(run, "scope"),
|
|
1693
|
+
source: readString$6(run, "source"),
|
|
1694
|
+
sourcePath: readString$6(run, "sourcePath"),
|
|
1695
|
+
status: readString$6(run, "status"),
|
|
1696
|
+
statusMessage: readNullableString$1(run, "statusMessage"),
|
|
1697
|
+
...durationMs !== void 0 ? { durationMs } : {},
|
|
1698
|
+
...entries.length > 0 ? { entries } : {}
|
|
1699
|
+
}
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
emitStandardItemEvent(params) {
|
|
1703
|
+
const { item } = params;
|
|
1704
|
+
if (!item) return;
|
|
1705
|
+
const kind = itemKind(item);
|
|
1706
|
+
if (!kind) return;
|
|
1707
|
+
const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
|
|
1708
|
+
const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
|
|
1709
|
+
this.emitAgentEvent({
|
|
1710
|
+
stream: "item",
|
|
1711
|
+
data: {
|
|
1712
|
+
itemId: item.id,
|
|
1713
|
+
phase: params.phase,
|
|
1714
|
+
kind,
|
|
1715
|
+
title: itemTitle(item),
|
|
1716
|
+
status: params.phase === "start" ? "running" : itemStatus(item),
|
|
1717
|
+
...itemName(item) ? { name: itemName(item) } : {},
|
|
1718
|
+
...meta ? { meta } : {},
|
|
1719
|
+
...suppressChannelProgress ? { suppressChannelProgress: true } : {}
|
|
1720
|
+
}
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
async emitNormalizedToolItemEvent(params) {
|
|
1724
|
+
const { item } = params;
|
|
1725
|
+
if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
|
|
1726
|
+
const name = itemName(item);
|
|
1727
|
+
if (!name) return;
|
|
1728
|
+
const status = params.phase === "result" ? itemStatus(item) : "running";
|
|
1729
|
+
const args = itemToolArgs(item);
|
|
1730
|
+
const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
|
|
1731
|
+
this.toolTranscript.recordTrajectoryEvent({
|
|
1732
|
+
phase: params.phase,
|
|
1733
|
+
item,
|
|
1734
|
+
name,
|
|
1735
|
+
args,
|
|
1736
|
+
status
|
|
1737
|
+
});
|
|
1738
|
+
if (params.phase === "result") this.toolProgress.recordNativeToolError({
|
|
1739
|
+
item,
|
|
1740
|
+
name,
|
|
1741
|
+
meta,
|
|
1742
|
+
status
|
|
1743
|
+
});
|
|
1744
|
+
if (!shouldEmitTranscriptToolProgress(name, args)) {
|
|
1745
|
+
if (params.phase === "result") {
|
|
1746
|
+
this.toolTranscript.emitAfterToolCallObservation(item);
|
|
1747
|
+
await this.onNativeToolResultRecorded?.();
|
|
1748
|
+
}
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
this.emitAgentEvent({
|
|
1752
|
+
stream: "tool",
|
|
1753
|
+
data: {
|
|
1754
|
+
phase: params.phase,
|
|
1755
|
+
name,
|
|
1756
|
+
itemId: item.id,
|
|
1757
|
+
toolCallId: item.id,
|
|
1758
|
+
...meta ? { meta } : {},
|
|
1759
|
+
...params.phase === "start" && args ? { args } : {},
|
|
1760
|
+
...params.phase === "result" ? {
|
|
1761
|
+
status,
|
|
1762
|
+
isError: isNonSuccessItemStatus(status),
|
|
1763
|
+
...itemToolResult(item)
|
|
1764
|
+
} : {}
|
|
1765
|
+
}
|
|
1766
|
+
});
|
|
1767
|
+
if (params.phase === "result") {
|
|
1768
|
+
this.toolTranscript.emitAfterToolCallObservation(item);
|
|
1769
|
+
await this.onNativeToolResultRecorded?.();
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
//#endregion
|
|
1774
|
+
//#region extensions/codex/src/app-server/event-projector-media.ts
|
|
1775
|
+
const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
|
|
1776
|
+
var CodexGeneratedMediaProjection = class {
|
|
1777
|
+
constructor(config) {
|
|
1778
|
+
this.config = config;
|
|
1779
|
+
this.itemIds = /* @__PURE__ */ new Set();
|
|
1780
|
+
this.urlsByItemId = /* @__PURE__ */ new Map();
|
|
1781
|
+
}
|
|
1782
|
+
hasGeneratedMedia() {
|
|
1783
|
+
return this.itemIds.size > 0;
|
|
1784
|
+
}
|
|
1785
|
+
recordNative(item) {
|
|
1786
|
+
if (item?.type !== "imageGeneration") return;
|
|
1787
|
+
const savedPath = readItemString(item, "savedPath")?.trim();
|
|
1788
|
+
if (savedPath) this.recordUrl({
|
|
1789
|
+
itemId: item.id,
|
|
1790
|
+
mediaUrl: savedPath
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
async recordRaw(item) {
|
|
1794
|
+
if (readString$6(item, "type") !== "image_generation_call") return;
|
|
1795
|
+
const result = readString$6(item, "result");
|
|
1796
|
+
if (!result) return;
|
|
1797
|
+
const itemId = readString$6(item, "id") ?? `raw-image-${this.itemIds.size}`;
|
|
1798
|
+
this.itemIds.add(itemId);
|
|
1799
|
+
const maxBytes = resolveGeneratedMediaMaxBytes(this.config, "image");
|
|
1800
|
+
const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
|
|
1801
|
+
if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
|
|
1802
|
+
embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
|
|
1803
|
+
itemId,
|
|
1804
|
+
estimatedDecodedBytes,
|
|
1805
|
+
maxBytes
|
|
1806
|
+
});
|
|
1807
|
+
return;
|
|
1808
|
+
}
|
|
1809
|
+
const asset = generatedImageAssetFromBase64({
|
|
1810
|
+
base64: result,
|
|
1811
|
+
index: this.itemIds.size,
|
|
1812
|
+
revisedPrompt: readString$6(item, "revised_prompt") ?? readString$6(item, "revisedPrompt"),
|
|
1813
|
+
fileNamePrefix: "codex-image-generation",
|
|
1814
|
+
sniffMimeType: true
|
|
1815
|
+
});
|
|
1816
|
+
if (!asset) return;
|
|
1817
|
+
try {
|
|
1818
|
+
const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
|
|
1819
|
+
this.recordUrl({
|
|
1820
|
+
itemId,
|
|
1821
|
+
mediaUrl: saved.path,
|
|
1822
|
+
replaceExisting: true
|
|
1823
|
+
});
|
|
1824
|
+
} catch (error) {
|
|
1825
|
+
embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
|
|
1826
|
+
itemId,
|
|
1827
|
+
error
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
buildToolMediaUrls(params) {
|
|
1832
|
+
const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
|
|
1833
|
+
if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
|
|
1834
|
+
return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
|
|
1835
|
+
}
|
|
1836
|
+
buildHostOwnedMediaUrls(params) {
|
|
1837
|
+
if ((params.messagingToolSentMediaUrls?.length ?? 0) > 0) return;
|
|
1838
|
+
const mediaUrls = [...this.urlsByItemId.values()];
|
|
1839
|
+
return mediaUrls.length > 0 ? mediaUrls : void 0;
|
|
1840
|
+
}
|
|
1841
|
+
recordUrl(params) {
|
|
1842
|
+
if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
|
|
1843
|
+
this.itemIds.add(params.itemId);
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
this.urlsByItemId.set(params.itemId, params.mediaUrl);
|
|
1847
|
+
this.itemIds.add(params.itemId);
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
function estimateBase64DecodedBytes(base64) {
|
|
1851
|
+
let nonWhitespaceLength = 0;
|
|
1852
|
+
let previousCode = -1;
|
|
1853
|
+
let lastCode = -1;
|
|
1854
|
+
for (let i = 0; i < base64.length; i += 1) {
|
|
1855
|
+
const code = base64.charCodeAt(i);
|
|
1856
|
+
if (isBase64WhitespaceCode(code)) continue;
|
|
1857
|
+
nonWhitespaceLength += 1;
|
|
1858
|
+
previousCode = lastCode;
|
|
1859
|
+
lastCode = code;
|
|
1860
|
+
}
|
|
1861
|
+
if (nonWhitespaceLength === 0) return;
|
|
1862
|
+
const equalsCode = "=".charCodeAt(0);
|
|
1863
|
+
const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
|
|
1864
|
+
return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
|
|
1865
|
+
}
|
|
1866
|
+
function isBase64WhitespaceCode(code) {
|
|
1867
|
+
return code === 32 || code === 9 || code === 10 || code === 13;
|
|
1868
|
+
}
|
|
1869
|
+
//#endregion
|
|
1870
|
+
//#region extensions/codex/src/app-server/event-projector-reasoning.ts
|
|
1871
|
+
var CodexReasoningProjection = class {
|
|
1872
|
+
constructor(params, emitAgentEvent) {
|
|
1873
|
+
this.params = params;
|
|
1874
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
1875
|
+
this.reasoningTextByGroup = /* @__PURE__ */ new Map();
|
|
1876
|
+
this.reasoningItemOrder = /* @__PURE__ */ new Map();
|
|
1877
|
+
this.planTextByItem = /* @__PURE__ */ new Map();
|
|
1878
|
+
this.reasoningStarted = false;
|
|
1879
|
+
this.reasoningEnded = false;
|
|
1880
|
+
}
|
|
1881
|
+
async handleReasoningDelta(method, params) {
|
|
1882
|
+
const itemId = readString$6(params, "itemId") ?? "reasoning";
|
|
1883
|
+
const delta = readString$6(params, "delta") ?? "";
|
|
1884
|
+
if (!delta) return;
|
|
1885
|
+
this.reasoningStarted = true;
|
|
1886
|
+
if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
|
|
1887
|
+
const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
|
|
1888
|
+
const groupKey = `${method}\0${itemId}\0${groupIndex}`;
|
|
1889
|
+
const current = this.reasoningTextByGroup.get(groupKey);
|
|
1890
|
+
this.reasoningTextByGroup.set(groupKey, {
|
|
1891
|
+
itemId,
|
|
1892
|
+
method,
|
|
1893
|
+
index: groupIndex,
|
|
1894
|
+
text: `${current?.text ?? ""}${delta}`
|
|
1895
|
+
});
|
|
1896
|
+
await this.params.onReasoningStream?.({
|
|
1897
|
+
text: this.reasoningText(),
|
|
1898
|
+
isReasoningSnapshot: true
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
handlePlanDelta(params) {
|
|
1902
|
+
const itemId = readString$6(params, "itemId") ?? "plan";
|
|
1903
|
+
const delta = readString$6(params, "delta") ?? "";
|
|
1904
|
+
if (!delta) return;
|
|
1905
|
+
const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
|
|
1906
|
+
this.planTextByItem.set(itemId, text);
|
|
1907
|
+
this.emitPlanUpdate({
|
|
1908
|
+
explanation: void 0,
|
|
1909
|
+
steps: splitPlanText(text).map((step) => ({
|
|
1910
|
+
step,
|
|
1911
|
+
status: "pending"
|
|
1912
|
+
}))
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
handleTurnPlanUpdated(params) {
|
|
1916
|
+
const explanation = readNullableString$1(params, "explanation");
|
|
1917
|
+
const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
|
|
1918
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
|
|
1919
|
+
const record = entry;
|
|
1920
|
+
const step = readString$6(record, "step");
|
|
1921
|
+
if (!step) return [];
|
|
1922
|
+
return [{
|
|
1923
|
+
step,
|
|
1924
|
+
status: normalizePlanStepStatus(readString$6(record, "status"))
|
|
1925
|
+
}];
|
|
1926
|
+
}) : void 0;
|
|
1927
|
+
const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
|
|
1928
|
+
if (planText) this.turnPlanText = planText;
|
|
1929
|
+
this.emitPlanUpdate({
|
|
1930
|
+
explanation,
|
|
1931
|
+
steps: plan
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
recordItem(item) {
|
|
1935
|
+
if (item?.type === "plan" && typeof item.text === "string" && item.text) {
|
|
1936
|
+
this.planTextByItem.set(item.id, item.text);
|
|
1937
|
+
this.emitPlanUpdate({
|
|
1938
|
+
explanation: void 0,
|
|
1939
|
+
steps: splitPlanText(item.text).map((step) => ({
|
|
1940
|
+
step,
|
|
1941
|
+
status: "pending"
|
|
1942
|
+
}))
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
async maybeEndReasoning() {
|
|
1947
|
+
if (!this.reasoningStarted || this.reasoningEnded) return;
|
|
1948
|
+
this.reasoningEnded = true;
|
|
1949
|
+
await this.params.onReasoningEnd?.();
|
|
1950
|
+
}
|
|
1951
|
+
reasoningText() {
|
|
1952
|
+
return collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
|
|
1953
|
+
}
|
|
1954
|
+
planText() {
|
|
1955
|
+
return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
|
|
1956
|
+
}
|
|
1957
|
+
emitPlanUpdate(params) {
|
|
1958
|
+
if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
|
|
1959
|
+
this.emitAgentEvent({
|
|
1960
|
+
stream: "plan",
|
|
1961
|
+
data: {
|
|
1962
|
+
phase: "update",
|
|
1963
|
+
title: "Plan updated",
|
|
1964
|
+
source: "codex-app-server",
|
|
1965
|
+
...params.explanation ? { explanation: params.explanation } : {},
|
|
1966
|
+
...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
function normalizePlanStepStatus(status) {
|
|
1972
|
+
if (status === "inProgress" || status === "in_progress") return "in_progress";
|
|
1973
|
+
return status === "completed" ? "completed" : "pending";
|
|
1974
|
+
}
|
|
1975
|
+
function collectReasoningTextValues(groups, itemOrder) {
|
|
1976
|
+
return [...groups.values()].toSorted((left, right) => {
|
|
1977
|
+
const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
|
|
1978
|
+
if (itemDelta !== 0) return itemDelta;
|
|
1979
|
+
const methodDelta = reasoningMethodOrder(left.method) - reasoningMethodOrder(right.method);
|
|
1980
|
+
return methodDelta !== 0 ? methodDelta : left.index - right.index;
|
|
1981
|
+
}).map((group) => group.text).filter((text) => text.trim().length > 0);
|
|
1982
|
+
}
|
|
1983
|
+
function reasoningMethodOrder(method) {
|
|
1984
|
+
return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
|
|
1985
|
+
}
|
|
1986
|
+
//#endregion
|
|
1987
|
+
//#region extensions/codex/src/app-server/event-projector-snapshot.ts
|
|
1988
|
+
function buildCodexMessagesSnapshot(params) {
|
|
1989
|
+
const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
|
|
1990
|
+
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
|
|
1991
|
+
if (params.planText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex plan", params.planText), `${params.turnId}:plan`));
|
|
1992
|
+
const visibleWorkMessages = [...params.runParams.config?.ui?.prefs?.chatPersistCommentary === false ? [] : params.commentaryMessages.map(({ itemId, message }) => attachCodexMirrorIdentity(message, `${params.turnId}:commentary:${itemId}`)), ...params.toolMessages].toSorted((left, right) => (asDateTimestampMs(left.timestamp) ?? 0) - (asDateTimestampMs(right.timestamp) ?? 0));
|
|
1993
|
+
messages.push(...visibleWorkMessages);
|
|
1994
|
+
if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
|
|
1995
|
+
return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
|
|
1996
|
+
hidden: params.runParams.trigger === "memory",
|
|
1997
|
+
message
|
|
1998
|
+
}));
|
|
1999
|
+
}
|
|
2000
|
+
//#endregion
|
|
2001
|
+
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
2002
|
+
/**
|
|
2003
|
+
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
2004
|
+
* marks blocked auth profiles when Codex exposes a reset time.
|
|
2005
|
+
*/
|
|
2006
|
+
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
2007
|
+
function createCodexUsageLimitPromptError(message) {
|
|
2008
|
+
return Object.assign(new Error(message), { status: 429 });
|
|
2009
|
+
}
|
|
2010
|
+
function isCodexUsageLimitPromptError(error) {
|
|
2011
|
+
return error instanceof Error && "status" in error && error.status === 429;
|
|
2012
|
+
}
|
|
2013
|
+
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
2014
|
+
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
2015
|
+
const authProfileId = params.authProfileId?.trim();
|
|
2016
|
+
if (!authProfileId || !params.params.authProfileStore) return;
|
|
2017
|
+
const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
|
|
2018
|
+
if (!blockedUntil) return;
|
|
2019
|
+
try {
|
|
2020
|
+
await markAuthProfileBlockedUntil({
|
|
2021
|
+
store: params.params.authProfileStore,
|
|
2022
|
+
profileId: authProfileId,
|
|
2023
|
+
blockedUntil,
|
|
2024
|
+
source: "codex_rate_limits",
|
|
2025
|
+
agentDir: params.params.agentDir,
|
|
2026
|
+
runId: params.params.runId,
|
|
2027
|
+
modelId: params.params.modelId
|
|
2028
|
+
});
|
|
2029
|
+
} catch (error) {
|
|
2030
|
+
embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
|
|
2031
|
+
authProfileId,
|
|
2032
|
+
error: formatErrorMessage(error)
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
2037
|
+
async function formatCodexTurnStartUsageLimitError(params) {
|
|
2038
|
+
return refreshCodexUsageLimitError({
|
|
2039
|
+
client: params.client,
|
|
2040
|
+
source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
|
|
2041
|
+
timeoutMs: params.timeoutMs,
|
|
2042
|
+
signal: params.signal
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
2046
|
+
async function refreshCodexUsageLimitPromptError(params) {
|
|
2047
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
2048
|
+
return refreshCodexUsageLimitError({
|
|
2049
|
+
client: params.client,
|
|
2050
|
+
source: {
|
|
2051
|
+
message: params.message,
|
|
2052
|
+
codexErrorInfo: "usageLimitExceeded",
|
|
2053
|
+
rateLimits: readRecentCodexRateLimits(params.client)
|
|
2054
|
+
},
|
|
2055
|
+
timeoutMs: params.timeoutMs,
|
|
2056
|
+
signal: params.signal
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
async function refreshCodexUsageLimitError(params) {
|
|
2060
|
+
const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
|
|
2061
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
|
|
2062
|
+
message: initialMessage,
|
|
2063
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2064
|
+
} : void 0;
|
|
2065
|
+
const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
|
|
2066
|
+
client: params.client,
|
|
2067
|
+
timeoutMs: params.timeoutMs,
|
|
2068
|
+
signal: params.signal
|
|
2069
|
+
});
|
|
2070
|
+
if (!rateLimits) return initialMessage ? {
|
|
2071
|
+
message: initialMessage,
|
|
2072
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2073
|
+
} : void 0;
|
|
2074
|
+
const message = formatCodexUsageLimitErrorMessage({
|
|
2075
|
+
message: params.source.message,
|
|
2076
|
+
codexErrorInfo: params.source.codexErrorInfo,
|
|
2077
|
+
rateLimits,
|
|
2078
|
+
rateLimitsAuthoritative: true
|
|
2079
|
+
}) ?? initialMessage;
|
|
2080
|
+
return message ? {
|
|
2081
|
+
message,
|
|
2082
|
+
rateLimitsForProfile: rateLimits
|
|
2083
|
+
} : void 0;
|
|
2084
|
+
}
|
|
2085
|
+
async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
|
|
2086
|
+
if (params.signal?.aborted) return;
|
|
2087
|
+
try {
|
|
2088
|
+
const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
2089
|
+
timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
|
|
2090
|
+
signal: params.signal
|
|
2091
|
+
});
|
|
2092
|
+
rememberCodexRateLimitsRead(params.client, rateLimits);
|
|
2093
|
+
return rateLimits;
|
|
2094
|
+
} catch (error) {
|
|
2095
|
+
embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
|
|
2096
|
+
return;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
|
|
2100
|
+
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
|
|
2101
|
+
return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
|
|
2102
|
+
}
|
|
2103
|
+
function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
|
|
2104
|
+
const notificationError = readCodexErrorNotification(errorNotification);
|
|
2105
|
+
const errorPayload = readCodexErrorPayload(error);
|
|
2106
|
+
const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
|
|
2107
|
+
const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
|
|
2108
|
+
return {
|
|
2109
|
+
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
2110
|
+
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
2111
|
+
rateLimits,
|
|
2112
|
+
rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
function readCodexErrorNotification(notification) {
|
|
2116
|
+
if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
|
|
2117
|
+
const error = notification.params.error;
|
|
2118
|
+
return isJsonObject(error) ? {
|
|
2119
|
+
message: readString$5(error, "message"),
|
|
2120
|
+
codexErrorInfo: error.codexErrorInfo
|
|
2121
|
+
} : void 0;
|
|
2122
|
+
}
|
|
2123
|
+
function readCodexErrorPayload(error) {
|
|
2124
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
2125
|
+
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
2126
|
+
const data = error.data;
|
|
2127
|
+
if (!isJsonObject(data)) return { message };
|
|
2128
|
+
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
2129
|
+
const rateLimits = nestedError.rateLimits ?? data.rateLimits;
|
|
2130
|
+
return {
|
|
2131
|
+
message: readString$5(nestedError, "message") ?? message,
|
|
2132
|
+
codexErrorInfo: nestedError.codexErrorInfo,
|
|
2133
|
+
rateLimits
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function readString$5(record, key) {
|
|
2137
|
+
const value = record[key];
|
|
2138
|
+
return typeof value === "string" ? value : void 0;
|
|
2139
|
+
}
|
|
2140
|
+
//#endregion
|
|
2141
|
+
//#region extensions/codex/src/app-server/event-projector.ts
|
|
2142
|
+
var CodexAppServerEventProjector = class {
|
|
2143
|
+
constructor(params, threadId, turnId, options = {}) {
|
|
2144
|
+
this.params = params;
|
|
2145
|
+
this.threadId = threadId;
|
|
2146
|
+
this.turnId = turnId;
|
|
2147
|
+
this.options = options;
|
|
2148
|
+
this.activeItemIds = /* @__PURE__ */ new Set();
|
|
2149
|
+
this.completedItemIds = /* @__PURE__ */ new Set();
|
|
2150
|
+
this.activeCompactionItemIds = /* @__PURE__ */ new Set();
|
|
2151
|
+
this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
|
|
2152
|
+
this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
|
|
2153
|
+
this.promptErrorSource = null;
|
|
2154
|
+
this.synthesizedMissingToolResultError = null;
|
|
2155
|
+
this.aborted = false;
|
|
2156
|
+
this.completedCompactionCount = 0;
|
|
2157
|
+
this.lastTranscriptTimestamp = 0;
|
|
2158
|
+
this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
|
|
2159
|
+
this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
|
|
2160
|
+
this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
|
|
2161
|
+
this.toolProgressProjection = new CodexToolProgressProjection(params);
|
|
2162
|
+
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, () => this.nextTranscriptTimestamp(), {
|
|
2163
|
+
nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
|
|
2164
|
+
prepareNativeMcpAppResultDetails: options.prepareNativeMcpAppResultDetails,
|
|
2165
|
+
trajectoryRecorder: options.trajectoryRecorder
|
|
2166
|
+
});
|
|
2167
|
+
this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
2168
|
+
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), () => this.nextTranscriptTimestamp());
|
|
2169
|
+
this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
|
|
2170
|
+
}
|
|
2171
|
+
nextTranscriptTimestamp() {
|
|
2172
|
+
this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
|
|
2173
|
+
return this.lastTranscriptTimestamp;
|
|
2174
|
+
}
|
|
2175
|
+
getCompletedTurnStatus() {
|
|
2176
|
+
return this.completedTurn?.status;
|
|
2177
|
+
}
|
|
2178
|
+
hasCompletedTerminalAssistantText() {
|
|
2179
|
+
return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
|
|
2180
|
+
}
|
|
2181
|
+
getLatestTerminalAssistantCandidate() {
|
|
2182
|
+
return this.assistantProjection.getLatestTerminalAssistantCandidate();
|
|
2183
|
+
}
|
|
2184
|
+
hasLatestTerminalAssistantCandidateText() {
|
|
2185
|
+
return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
|
|
2186
|
+
}
|
|
2187
|
+
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
2188
|
+
return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
|
|
2189
|
+
}
|
|
2190
|
+
/** Restores a completed final item after only the enclosing turn timeout fired. */
|
|
2191
|
+
recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
|
|
2192
|
+
if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
|
|
2193
|
+
this.aborted = false;
|
|
2194
|
+
this.promptError = void 0;
|
|
2195
|
+
this.promptErrorSource = null;
|
|
2196
|
+
return true;
|
|
2197
|
+
}
|
|
2198
|
+
/** Resolves the shared model-order position for a native tool item. */
|
|
2199
|
+
recordNativeToolOutcome(item) {
|
|
2200
|
+
if (!item || this.nativeToolOutcomeOrdinals.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
|
|
2201
|
+
const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
|
|
2202
|
+
if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
|
|
2203
|
+
}
|
|
2204
|
+
recordNativeToolApprovalFailure(toolCallId, disposition) {
|
|
2205
|
+
this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
|
|
2206
|
+
}
|
|
2207
|
+
recordNativeToolPreToolUseFailure(failure) {
|
|
2208
|
+
this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
|
|
2209
|
+
}
|
|
2210
|
+
async handleNotification(notification) {
|
|
2211
|
+
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
2212
|
+
if (!params) return;
|
|
2213
|
+
if (isHookNotificationMethod(notification.method)) {
|
|
2214
|
+
if (!this.isHookNotificationForCurrentThread(params)) return;
|
|
2215
|
+
} else if (notification.method === "guardianWarning") {
|
|
2216
|
+
if (readCodexNotificationThreadId(params) !== this.threadId) return;
|
|
2217
|
+
} else if (!this.isNotificationForTurn(params)) return;
|
|
2218
|
+
this.nativeToolLifecycleProjector.handleNotification(notification);
|
|
2219
|
+
switch (notification.method) {
|
|
2220
|
+
case "item/agentMessage/delta":
|
|
2221
|
+
await this.assistantProjection.handleAssistantDelta(params);
|
|
2222
|
+
break;
|
|
2223
|
+
case "item/reasoning/summaryTextDelta":
|
|
2224
|
+
case "item/reasoning/textDelta":
|
|
2225
|
+
await this.reasoningProjection.handleReasoningDelta(notification.method, params);
|
|
2226
|
+
break;
|
|
2227
|
+
case "item/plan/delta":
|
|
2228
|
+
this.reasoningProjection.handlePlanDelta(params);
|
|
2229
|
+
break;
|
|
2230
|
+
case "turn/plan/updated":
|
|
2231
|
+
this.reasoningProjection.handleTurnPlanUpdated(params);
|
|
2232
|
+
break;
|
|
2233
|
+
case "item/started":
|
|
2234
|
+
await this.handleItemStarted(params);
|
|
2235
|
+
break;
|
|
2236
|
+
case "item/completed":
|
|
2237
|
+
await this.handleItemCompleted(params);
|
|
2238
|
+
break;
|
|
2239
|
+
case "item/commandExecution/outputDelta":
|
|
2240
|
+
this.toolProgressProjection.handleOutputDelta(params, "bash");
|
|
2241
|
+
break;
|
|
2242
|
+
case "item/autoApprovalReview/started":
|
|
2243
|
+
case "item/autoApprovalReview/completed":
|
|
2244
|
+
this.eventProjection.handleGuardianReview(notification.method, params);
|
|
2245
|
+
break;
|
|
2246
|
+
case "guardianWarning":
|
|
2247
|
+
this.eventProjection.handleGuardianWarning(params);
|
|
2248
|
+
break;
|
|
2249
|
+
case "hook/started":
|
|
2250
|
+
case "hook/completed":
|
|
2251
|
+
this.eventProjection.handleHook(notification.method, params);
|
|
2252
|
+
break;
|
|
2253
|
+
case "thread/tokenUsage/updated":
|
|
2254
|
+
projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => this.emitAgentEvent({
|
|
2255
|
+
stream: "codex_app_server.usage",
|
|
2256
|
+
data
|
|
2257
|
+
}));
|
|
2258
|
+
break;
|
|
2259
|
+
case "turn/completed":
|
|
2260
|
+
await this.handleTurnCompleted(params);
|
|
2261
|
+
break;
|
|
2262
|
+
case "rawResponse/completed":
|
|
2263
|
+
this.handleRawResponseCompleted(params);
|
|
2264
|
+
break;
|
|
2265
|
+
case "rawResponseItem/completed":
|
|
2266
|
+
await this.handleRawResponseItemCompleted(params);
|
|
2267
|
+
break;
|
|
2268
|
+
case "error":
|
|
2269
|
+
this.responseUsage = void 0;
|
|
2270
|
+
if (params.willRetry === true) break;
|
|
2271
|
+
this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
|
|
2272
|
+
this.promptErrorSource = "prompt";
|
|
2273
|
+
break;
|
|
2274
|
+
case "thread/compacted":
|
|
2275
|
+
case "turn/started":
|
|
2276
|
+
case "turn/diff/updated":
|
|
2277
|
+
case "item/reasoning/summaryPartAdded":
|
|
2278
|
+
case "item/commandExecution/terminalInteraction":
|
|
2279
|
+
case "item/fileChange/outputDelta":
|
|
2280
|
+
case "item/fileChange/patchUpdated":
|
|
2281
|
+
case "item/mcpToolCall/progress":
|
|
2282
|
+
case "model/rerouted":
|
|
2283
|
+
case "model/verification":
|
|
2284
|
+
case "turn/moderationMetadata":
|
|
2285
|
+
case "model/safetyBuffering/updated": break;
|
|
2286
|
+
default:
|
|
2287
|
+
this.diagnostics.warnUnknownEvent(notification, params);
|
|
2288
|
+
break;
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
buildResult(toolTelemetry, options) {
|
|
2292
|
+
this.nativeToolLifecycleProjector.finalizeActive();
|
|
2293
|
+
const assistantTexts = this.assistantProjection.collectAssistantTexts();
|
|
2294
|
+
const commentaryMessages = this.assistantProjection.collectCommentaryMessages();
|
|
2295
|
+
const reasoningText = this.reasoningProjection.reasoningText();
|
|
2296
|
+
const planText = this.reasoningProjection.planText();
|
|
2297
|
+
const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
|
|
2298
|
+
const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
|
|
2299
|
+
const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
|
|
2300
|
+
const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
|
|
2301
|
+
const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
|
|
2302
|
+
synthesize: legacyFailClosed,
|
|
2303
|
+
recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
|
|
2304
|
+
});
|
|
2305
|
+
if (synthesizedMissingToolResultError) {
|
|
2306
|
+
this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
|
|
2307
|
+
this.promptErrorSource = this.promptErrorSource ?? "prompt";
|
|
2308
|
+
}
|
|
2309
|
+
const assistantMessageOptions = {
|
|
2310
|
+
tokenUsage: projectedUsage,
|
|
2311
|
+
aborted: this.aborted,
|
|
2312
|
+
promptError: this.promptError
|
|
2313
|
+
};
|
|
2314
|
+
const lastAssistant = assistantTexts.length ? this.assistantProjection.createAssistantMessage(assistantTexts.join("\n\n"), assistantMessageOptions) : void 0;
|
|
2315
|
+
const currentAttemptAssistant = this.assistantProjection.createCurrentAttemptAssistantMessage(assistantMessageOptions);
|
|
2316
|
+
const messagesSnapshot = buildCodexMessagesSnapshot({
|
|
2317
|
+
runParams: this.params,
|
|
2318
|
+
turnId: this.turnId,
|
|
2319
|
+
upstreamUserText: this.options.upstreamUserText,
|
|
2320
|
+
reasoningText,
|
|
2321
|
+
planText,
|
|
2322
|
+
commentaryMessages,
|
|
2323
|
+
toolMessages: this.toolTranscriptProjection.transcriptMessages,
|
|
2324
|
+
lastAssistant,
|
|
2325
|
+
createAssistantMirrorMessage: (title, text) => this.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
2326
|
+
});
|
|
2327
|
+
const turnFailed = this.completedTurn?.status === "failed";
|
|
2328
|
+
const promptError = this.promptError ?? this.synthesizedMissingToolResultError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
|
|
2329
|
+
const agentHarnessResultClassification = classifyAgentHarnessTerminalOutcome({
|
|
2330
|
+
assistantTexts,
|
|
2331
|
+
reasoningText,
|
|
2332
|
+
planText,
|
|
2333
|
+
promptError,
|
|
2334
|
+
turnCompleted: Boolean(this.completedTurn)
|
|
2335
|
+
});
|
|
2336
|
+
const toolMetas = this.toolProgressProjection.toolMetas;
|
|
2337
|
+
const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
|
|
2338
|
+
return {
|
|
2339
|
+
terminal: attemptTerminal.normalize({
|
|
2340
|
+
aborted: this.aborted,
|
|
2341
|
+
promptError,
|
|
2342
|
+
promptErrorSource: promptError ? this.promptErrorSource || "prompt" : null
|
|
2343
|
+
}),
|
|
2344
|
+
sessionIdUsed: this.params.sessionId,
|
|
2345
|
+
...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
|
|
2346
|
+
bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
|
|
2347
|
+
bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
|
|
2348
|
+
messagesSnapshot,
|
|
2349
|
+
assistantTexts,
|
|
2350
|
+
toolMetas,
|
|
2351
|
+
lastAssistant,
|
|
2352
|
+
currentAttemptAssistant,
|
|
2353
|
+
...this.toolProgressProjection.lastToolError ? { lastToolError: this.toolProgressProjection.lastToolError } : {},
|
|
2354
|
+
didSendViaMessagingTool: toolTelemetry.didSendViaMessagingTool,
|
|
2355
|
+
didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
|
|
2356
|
+
messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
|
|
2357
|
+
messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
|
|
2358
|
+
messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
|
|
2359
|
+
messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
|
|
2360
|
+
heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
|
|
2361
|
+
toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
|
|
2362
|
+
hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
|
|
2363
|
+
toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
|
|
2364
|
+
successfulCronAdds: toolTelemetry.successfulCronAdds,
|
|
2365
|
+
cloudCodeAssistFormatError: false,
|
|
2366
|
+
attemptUsage: projectedUsage,
|
|
2367
|
+
...this.completedCompactionCount > 0 ? { compactionCount: this.completedCompactionCount } : {},
|
|
2368
|
+
replayMetadata: {
|
|
2369
|
+
hadPotentialSideEffects,
|
|
2370
|
+
replaySafe: !hadPotentialSideEffects
|
|
2371
|
+
},
|
|
2372
|
+
itemLifecycle: {
|
|
2373
|
+
startedCount: this.activeItemIds.size + this.completedItemIds.size,
|
|
2374
|
+
completedCount: this.completedItemIds.size,
|
|
2375
|
+
activeCount: this.activeItemIds.size
|
|
2376
|
+
},
|
|
2377
|
+
yieldDetected: options?.yieldDetected || false,
|
|
2378
|
+
didSendDeterministicApprovalPrompt: this.eventProjection.guardianReviewCount > 0 ? false : void 0
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2381
|
+
recordDynamicToolCall(params) {
|
|
2382
|
+
this.toolTranscriptProjection.recordDynamicToolCall(params);
|
|
2383
|
+
}
|
|
2384
|
+
recordDynamicToolResult(params) {
|
|
2385
|
+
this.toolProgressProjection.recordDynamicToolResult(params);
|
|
2386
|
+
this.toolTranscriptProjection.recordDynamicToolResult(params);
|
|
2387
|
+
}
|
|
2388
|
+
markTimedOut() {
|
|
2389
|
+
this.aborted = true;
|
|
2390
|
+
this.promptError = "codex app-server attempt timed out";
|
|
2391
|
+
this.promptErrorSource = "prompt";
|
|
2392
|
+
}
|
|
2393
|
+
markAborted() {
|
|
2394
|
+
this.aborted = true;
|
|
2395
|
+
this.responseUsage = void 0;
|
|
2396
|
+
}
|
|
2397
|
+
isCompacting() {
|
|
2398
|
+
return this.activeCompactionItemIds.size > 0;
|
|
2399
|
+
}
|
|
2400
|
+
async handleItemStarted(params) {
|
|
2401
|
+
const item = readItem(params.item);
|
|
2402
|
+
const itemId = item?.id ?? readString$6(params, "itemId");
|
|
2403
|
+
this.assistantProjection.recordItemStarted(item, itemId);
|
|
2404
|
+
if (itemId) this.activeItemIds.add(itemId);
|
|
2405
|
+
this.recordNativeToolOutcome(item);
|
|
2406
|
+
if (item?.type === "contextCompaction" && itemId) {
|
|
2407
|
+
this.activeCompactionItemIds.add(itemId);
|
|
2408
|
+
await runAgentHarnessBeforeCompactionHook({
|
|
2409
|
+
sessionFile: this.params.sessionFile,
|
|
2410
|
+
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
2411
|
+
ctx: {
|
|
2412
|
+
runId: this.params.runId,
|
|
2413
|
+
agentId: this.params.agentId,
|
|
2414
|
+
sessionKey: this.params.sessionKey,
|
|
2415
|
+
sessionId: this.params.sessionId,
|
|
2416
|
+
workspaceDir: this.params.workspaceDir,
|
|
2417
|
+
messageProvider: this.params.messageProvider ?? void 0,
|
|
2418
|
+
trigger: this.params.trigger,
|
|
2419
|
+
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
this.emitAgentEvent({
|
|
2423
|
+
stream: "compaction",
|
|
2424
|
+
data: {
|
|
2425
|
+
phase: "start",
|
|
2426
|
+
backend: "codex-app-server",
|
|
2427
|
+
threadId: this.threadId,
|
|
2428
|
+
turnId: this.turnId,
|
|
2429
|
+
itemId
|
|
2430
|
+
}
|
|
2431
|
+
});
|
|
2432
|
+
}
|
|
2433
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2434
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2435
|
+
phase: "start",
|
|
2436
|
+
item
|
|
2437
|
+
});
|
|
2438
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2439
|
+
phase: "start",
|
|
2440
|
+
item
|
|
2441
|
+
});
|
|
2442
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2443
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2444
|
+
this.emitAgentEvent({
|
|
2445
|
+
stream: "codex_app_server.item",
|
|
2446
|
+
data: {
|
|
2447
|
+
phase: "started",
|
|
2448
|
+
itemId,
|
|
2449
|
+
type: item?.type
|
|
2450
|
+
}
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
async handleItemCompleted(params) {
|
|
2454
|
+
const item = readItem(params.item);
|
|
2455
|
+
this.diagnostics.warnUnknownItemStatus(item);
|
|
2456
|
+
this.recordNativeToolOutcome(item);
|
|
2457
|
+
this.clearTerminalPresentationForNativeItem(item);
|
|
2458
|
+
const itemId = item?.id ?? readString$6(params, "itemId");
|
|
2459
|
+
if (itemId) {
|
|
2460
|
+
this.activeItemIds.delete(itemId);
|
|
2461
|
+
this.completedItemIds.add(itemId);
|
|
2462
|
+
}
|
|
2463
|
+
this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
2464
|
+
this.reasoningProjection.recordItem(item);
|
|
2465
|
+
this.generatedMediaProjection.recordNative(item);
|
|
2466
|
+
if (item?.type === "contextCompaction" && itemId) {
|
|
2467
|
+
this.activeCompactionItemIds.delete(itemId);
|
|
2468
|
+
this.completedCompactionCount += 1;
|
|
2469
|
+
this.options.onContextCompacted?.();
|
|
2470
|
+
await runAgentHarnessAfterCompactionHook({
|
|
2471
|
+
sessionFile: this.params.sessionFile,
|
|
2472
|
+
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
2473
|
+
compactedCount: -1,
|
|
2474
|
+
ctx: {
|
|
2475
|
+
runId: this.params.runId,
|
|
2476
|
+
agentId: this.params.agentId,
|
|
2477
|
+
sessionKey: this.params.sessionKey,
|
|
2478
|
+
sessionId: this.params.sessionId,
|
|
2479
|
+
workspaceDir: this.params.workspaceDir,
|
|
2480
|
+
messageProvider: this.params.messageProvider ?? void 0,
|
|
2481
|
+
trigger: this.params.trigger,
|
|
2482
|
+
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
2483
|
+
}
|
|
2484
|
+
});
|
|
2485
|
+
this.emitAgentEvent({
|
|
2486
|
+
stream: "compaction",
|
|
2487
|
+
data: {
|
|
2488
|
+
phase: "end",
|
|
2489
|
+
backend: "codex-app-server",
|
|
2490
|
+
completed: true,
|
|
2491
|
+
threadId: this.threadId,
|
|
2492
|
+
turnId: this.turnId,
|
|
2493
|
+
itemId
|
|
2494
|
+
}
|
|
2495
|
+
});
|
|
2496
|
+
}
|
|
2497
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2498
|
+
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
2499
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2500
|
+
phase: "end",
|
|
2501
|
+
item
|
|
2502
|
+
});
|
|
2503
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2504
|
+
phase: "result",
|
|
2505
|
+
item
|
|
2506
|
+
});
|
|
2507
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2508
|
+
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
2509
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2510
|
+
this.toolProgressProjection.emitToolResultOutput(item);
|
|
2511
|
+
this.emitAgentEvent({
|
|
2512
|
+
stream: "codex_app_server.item",
|
|
2513
|
+
data: {
|
|
2514
|
+
phase: "completed",
|
|
2515
|
+
itemId,
|
|
2516
|
+
type: item?.type
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
handleRawResponseCompleted(params) {
|
|
2521
|
+
const usage = isJsonObject(params.usage) ? params.usage : void 0;
|
|
2522
|
+
this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
|
|
2523
|
+
}
|
|
2524
|
+
async handleTurnCompleted(params) {
|
|
2525
|
+
const turn = readCodexTurn(params.turn);
|
|
2526
|
+
if (!turn || turn.id !== this.turnId) return;
|
|
2527
|
+
this.completedTurn = turn;
|
|
2528
|
+
if (turn.status !== "completed") this.responseUsage = void 0;
|
|
2529
|
+
if (turn.status === "failed") {
|
|
2530
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
2531
|
+
message: turn.error?.message,
|
|
2532
|
+
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
2533
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
2534
|
+
});
|
|
2535
|
+
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
2536
|
+
this.promptErrorSource = "prompt";
|
|
2537
|
+
}
|
|
2538
|
+
const turnItems = turn.items ?? [];
|
|
2539
|
+
for (let index = turnItems.length - 1; index >= 0; index -= 1) {
|
|
2540
|
+
const item = turnItems[index];
|
|
2541
|
+
if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
|
|
2542
|
+
if (item?.type === "dynamicToolCall") break;
|
|
2543
|
+
if (shouldClearTerminalPresentationForNativeItem(item)) {
|
|
2544
|
+
this.clearTerminalPresentationForNativeItem(item);
|
|
2545
|
+
break;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
for (const item of turnItems) {
|
|
2549
|
+
this.diagnostics.warnUnknownItemStatus(item);
|
|
2550
|
+
this.assistantProjection.recordSnapshotItem(item);
|
|
2551
|
+
this.reasoningProjection.recordItem(item);
|
|
2552
|
+
this.generatedMediaProjection.recordNative(item);
|
|
2553
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2554
|
+
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
2555
|
+
await this.emitSnapshotOnlyNativeToolProgress(item);
|
|
2556
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2557
|
+
await this.toolTranscriptProjection.recordNativeToolResultWithDetails(item);
|
|
2558
|
+
this.toolTranscriptProjection.emitAfterToolCallObservation(item);
|
|
2559
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2560
|
+
this.toolProgressProjection.emitToolResultOutput(item);
|
|
2561
|
+
}
|
|
2562
|
+
this.assistantProjection.finalizeAnswerCandidate(turn);
|
|
2563
|
+
this.activeCompactionItemIds.clear();
|
|
2564
|
+
await this.reasoningProjection.maybeEndReasoning();
|
|
2565
|
+
}
|
|
2566
|
+
async emitSnapshotOnlyNativeToolProgress(item) {
|
|
2567
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
2568
|
+
if (!this.activeItemIds.has(item.id)) {
|
|
2569
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2570
|
+
phase: "start",
|
|
2571
|
+
item
|
|
2572
|
+
});
|
|
2573
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2574
|
+
phase: "start",
|
|
2575
|
+
item
|
|
2576
|
+
});
|
|
2577
|
+
}
|
|
2578
|
+
this.activeItemIds.delete(item.id);
|
|
2579
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2580
|
+
phase: "end",
|
|
2581
|
+
item
|
|
2582
|
+
});
|
|
2583
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2584
|
+
phase: "result",
|
|
2585
|
+
item
|
|
2586
|
+
});
|
|
2587
|
+
this.completedItemIds.add(item.id);
|
|
2588
|
+
}
|
|
2589
|
+
isCurrentTurnSnapshotItem(item) {
|
|
2590
|
+
const itemTurnId = readItemString(item, "turnId");
|
|
2591
|
+
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
2592
|
+
}
|
|
2593
|
+
async handleRawResponseItemCompleted(params) {
|
|
2594
|
+
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
2595
|
+
if (!item) return;
|
|
2596
|
+
this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
|
|
2597
|
+
await this.generatedMediaProjection.recordRaw(item);
|
|
2598
|
+
}
|
|
2599
|
+
clearTerminalPresentationForNativeItem(item) {
|
|
2600
|
+
if (!item || this.terminalPresentationClearedItemIds.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
|
|
2601
|
+
const toolCallOrdinal = this.nativeToolOutcomeOrdinals.get(item.id);
|
|
2602
|
+
this.terminalPresentationClearedItemIds.add(item.id);
|
|
2603
|
+
this.params.onToolOutcome?.({
|
|
2604
|
+
toolName: itemName(item) ?? item.type,
|
|
2605
|
+
argsHash: "",
|
|
2606
|
+
resultHash: "",
|
|
2607
|
+
...toolCallOrdinal !== void 0 ? { toolCallOrdinal } : {},
|
|
2608
|
+
terminalPresentation: void 0,
|
|
2609
|
+
presentationOnly: true
|
|
2610
|
+
});
|
|
2611
|
+
}
|
|
2612
|
+
formatCodexErrorMessage(params) {
|
|
2613
|
+
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
2614
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
2615
|
+
message: error ? readString$6(error, "message") : void 0,
|
|
2616
|
+
codexErrorInfo: error?.codexErrorInfo,
|
|
2617
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
2618
|
+
});
|
|
2619
|
+
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
2620
|
+
}
|
|
2621
|
+
emitAgentEvent(event) {
|
|
95
2622
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
2623
|
+
emitAgentEvent({
|
|
2624
|
+
runId: this.params.runId,
|
|
2625
|
+
stream: event.stream,
|
|
2626
|
+
data: event.data,
|
|
2627
|
+
...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
|
|
101
2628
|
});
|
|
102
2629
|
} catch (error) {
|
|
103
|
-
|
|
104
|
-
for (const item of liveItems) rejectItem(item, error);
|
|
105
|
-
throw error;
|
|
2630
|
+
embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
|
|
106
2631
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
embeddedAgentLog.debug("codex app-server
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
return
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
2632
|
+
try {
|
|
2633
|
+
const maybePromise = this.params.onAgentEvent?.(event);
|
|
2634
|
+
Promise.resolve(maybePromise).catch((error) => {
|
|
2635
|
+
embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
|
|
2636
|
+
});
|
|
2637
|
+
} catch (error) {
|
|
2638
|
+
embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
isNotificationForTurn(params) {
|
|
2642
|
+
const threadId = readCodexNotificationThreadId(params);
|
|
2643
|
+
const turnId = readCodexNotificationTurnId(params);
|
|
2644
|
+
return threadId === this.threadId && turnId === this.turnId;
|
|
2645
|
+
}
|
|
2646
|
+
isHookNotificationForCurrentThread(params) {
|
|
2647
|
+
const threadId = readString$6(params, "threadId");
|
|
2648
|
+
const turnId = params.turnId;
|
|
2649
|
+
return threadId === this.threadId && (turnId === this.turnId || turnId === null);
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
function isHookNotificationMethod(method) {
|
|
2653
|
+
return method === "hook/started" || method === "hook/completed";
|
|
2654
|
+
}
|
|
2655
|
+
//#endregion
|
|
2656
|
+
//#region extensions/codex/src/app-server/native-mcp-app.ts
|
|
2657
|
+
function asRecord(value) {
|
|
2658
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
2659
|
+
}
|
|
2660
|
+
function readString$4(value) {
|
|
2661
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
2662
|
+
}
|
|
2663
|
+
function readMcpAppResourceUri(item) {
|
|
2664
|
+
const uri = readString$4(asRecord(item.appContext)?.resourceUri) ?? readString$4(item.mcpAppResourceUri);
|
|
2665
|
+
return uri?.startsWith("ui://") ? uri : void 0;
|
|
2666
|
+
}
|
|
2667
|
+
function readMcpToolResult(item) {
|
|
2668
|
+
const result = asRecord(item.result);
|
|
2669
|
+
if (!result || !Array.isArray(result.content)) return;
|
|
2670
|
+
const resultMeta = asRecord(result["_meta"]);
|
|
2671
|
+
return {
|
|
2672
|
+
content: result.content,
|
|
2673
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
|
|
2674
|
+
...result.isError === true ? { isError: true } : {},
|
|
2675
|
+
...resultMeta ? { _meta: resultMeta } : {}
|
|
2676
|
+
};
|
|
2677
|
+
}
|
|
2678
|
+
function statusTools(status) {
|
|
2679
|
+
return Object.entries(status.tools).map(([name, value]) => Object.assign({}, asRecord(value), { name }));
|
|
2680
|
+
}
|
|
2681
|
+
function createNativeMcpRuntime(params) {
|
|
2682
|
+
let catalog = null;
|
|
2683
|
+
let statuses;
|
|
2684
|
+
const createdAt = Date.now();
|
|
2685
|
+
const loadStatuses = async () => {
|
|
2686
|
+
if (statuses) return statuses;
|
|
2687
|
+
statuses = (await params.client.request("mcpServerStatus/list", {
|
|
2688
|
+
threadId: params.threadId,
|
|
2689
|
+
detail: "full"
|
|
2690
|
+
})).data;
|
|
2691
|
+
return statuses;
|
|
2692
|
+
};
|
|
2693
|
+
const getCatalog = async () => {
|
|
2694
|
+
if (catalog) return catalog;
|
|
2695
|
+
const loaded = await loadStatuses();
|
|
2696
|
+
catalog = {
|
|
2697
|
+
version: 1,
|
|
2698
|
+
generatedAt: Date.now(),
|
|
2699
|
+
servers: Object.fromEntries(loaded.map((status) => [status.name, {
|
|
2700
|
+
serverName: status.name,
|
|
2701
|
+
launchSummary: "Codex native MCP connection",
|
|
2702
|
+
toolCount: Object.keys(status.tools).length
|
|
2703
|
+
}])),
|
|
2704
|
+
tools: loaded.flatMap((status) => statusTools(status).map((tool) => ({
|
|
2705
|
+
serverName: status.name,
|
|
2706
|
+
safeServerName: status.name,
|
|
2707
|
+
toolName: String(tool.name),
|
|
2708
|
+
inputSchema: asRecord(tool.inputSchema) ?? { type: "object" },
|
|
2709
|
+
fallbackDescription: readString$4(tool.description) ?? String(tool.name)
|
|
2710
|
+
})))
|
|
144
2711
|
};
|
|
2712
|
+
return catalog;
|
|
145
2713
|
};
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (closedError) throw closedError;
|
|
162
|
-
if (params.signal.aborted) throw new Error("codex app-server steering queue aborted");
|
|
163
|
-
const { item, delivery } = createPendingMessage(text, options?.images);
|
|
164
|
-
batchedMessages.push(item);
|
|
165
|
-
clearBatchTimer();
|
|
166
|
-
const debounceMs = normalizeCodexSteerDebounceMs(options?.debounceMs);
|
|
167
|
-
if (debounceMs === 0) flushBatch();
|
|
168
|
-
else batchTimer = setTimeout(() => {
|
|
169
|
-
batchTimer = void 0;
|
|
170
|
-
flushBatch();
|
|
171
|
-
}, debounceMs);
|
|
172
|
-
return await delivery;
|
|
2714
|
+
const runtime = {
|
|
2715
|
+
sessionId: params.attempt.sessionId,
|
|
2716
|
+
sessionKey: params.attempt.sessionKey,
|
|
2717
|
+
workspaceDir: params.attempt.workspaceDir,
|
|
2718
|
+
configFingerprint: `${getCodexAppServerClientInstanceId(params.client)}:${params.threadId}`,
|
|
2719
|
+
mcpAppsEnabled: true,
|
|
2720
|
+
createdAt,
|
|
2721
|
+
lastUsedAt: createdAt,
|
|
2722
|
+
acquireLease: () => retainSharedCodexAppServerClientIfCurrent(params.client) ?? (() => {}),
|
|
2723
|
+
getCatalog,
|
|
2724
|
+
peekCatalog: () => catalog,
|
|
2725
|
+
markUsed: () => {
|
|
2726
|
+
runtime.lastUsedAt = Date.now();
|
|
173
2727
|
},
|
|
174
|
-
async
|
|
175
|
-
|
|
176
|
-
|
|
2728
|
+
callTool: async (serverName, toolName, input) => await params.client.request("mcpServer/tool/call", {
|
|
2729
|
+
threadId: params.threadId,
|
|
2730
|
+
server: serverName,
|
|
2731
|
+
tool: toolName,
|
|
2732
|
+
arguments: asRecord(input) ?? {}
|
|
2733
|
+
}),
|
|
2734
|
+
listTools: async (serverName) => {
|
|
2735
|
+
const status = (await loadStatuses()).find((entry) => entry.name === serverName);
|
|
2736
|
+
return { tools: status ? statusTools(status) : [] };
|
|
177
2737
|
},
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
2738
|
+
readResource: async (serverName, uri) => await params.client.request("mcpServer/resource/read", {
|
|
2739
|
+
threadId: params.threadId,
|
|
2740
|
+
server: serverName,
|
|
2741
|
+
uri
|
|
2742
|
+
}),
|
|
2743
|
+
listResources: async (serverName) => {
|
|
2744
|
+
return { resources: (await loadStatuses()).find((entry) => entry.name === serverName)?.resources ?? [] };
|
|
184
2745
|
},
|
|
185
|
-
|
|
2746
|
+
listResourceTemplates: async (serverName) => {
|
|
2747
|
+
return { resourceTemplates: (await loadStatuses()).find((entry) => entry.name === serverName)?.resourceTemplates ?? [] };
|
|
2748
|
+
},
|
|
2749
|
+
dispose: async () => {}
|
|
2750
|
+
};
|
|
2751
|
+
return runtime;
|
|
2752
|
+
}
|
|
2753
|
+
function createCodexNativeMcpAppResultDetailsPreparer(params) {
|
|
2754
|
+
if (params.attempt.config?.mcp?.apps?.enabled !== true) return;
|
|
2755
|
+
const runtime = createNativeMcpRuntime(params);
|
|
2756
|
+
return async (item) => {
|
|
2757
|
+
const serverName = readString$4(item.server);
|
|
2758
|
+
const toolName = readString$4(item.tool);
|
|
2759
|
+
const uiResourceUri = readMcpAppResourceUri(item);
|
|
2760
|
+
const toolResult = readMcpToolResult(item);
|
|
2761
|
+
if (!serverName || !toolName || !uiResourceUri || !toolResult) return;
|
|
2762
|
+
const allowedAppToolNames = new Set((await runtime.getCatalog()).tools.filter((tool) => tool.serverName === serverName).map((tool) => tool.toolName));
|
|
2763
|
+
if (allowedAppToolNames.size === 0) return;
|
|
2764
|
+
return await prepareHarnessNativeMcpAppPreview({
|
|
2765
|
+
runtime,
|
|
2766
|
+
serverName,
|
|
2767
|
+
toolName,
|
|
2768
|
+
uiResourceUri,
|
|
2769
|
+
toolCallId: item.id,
|
|
2770
|
+
toolInput: item.arguments ?? {},
|
|
2771
|
+
toolResult,
|
|
2772
|
+
allowedAppToolNames,
|
|
2773
|
+
...toolResult["_meta"] !== void 0 ? { resultMetaState: "unavailable" } : {}
|
|
2774
|
+
});
|
|
186
2775
|
};
|
|
187
2776
|
}
|
|
188
|
-
/** Normalizes steer debounce milliseconds, preserving explicit zero. */
|
|
189
|
-
function normalizeCodexSteerDebounceMs(value) {
|
|
190
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
191
|
-
}
|
|
192
2777
|
//#endregion
|
|
193
2778
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
194
2779
|
/** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
|
|
@@ -258,6 +2843,7 @@ function createCodexUserInputBridge(params) {
|
|
|
258
2843
|
questions: requestParams.questions,
|
|
259
2844
|
sessionKey: params.paramsForRun.sessionKey ?? params.paramsForRun.sessionId,
|
|
260
2845
|
agentId: params.paramsForRun.agentId,
|
|
2846
|
+
runId: params.paramsForRun.runId,
|
|
261
2847
|
timeoutMs: requestParams.autoResolutionMs ?? params.paramsForRun.timeoutMs ?? DEFAULT_USER_INPUT_TIMEOUT_MS,
|
|
262
2848
|
gatewayCall,
|
|
263
2849
|
delivery: params.paramsForRun,
|
|
@@ -267,7 +2853,7 @@ function createCodexUserInputBridge(params) {
|
|
|
267
2853
|
},
|
|
268
2854
|
signal: abort.signal
|
|
269
2855
|
});
|
|
270
|
-
return result.status === "answered" ? result.answers : emptyUserInputResponse();
|
|
2856
|
+
return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
|
|
271
2857
|
} catch (error) {
|
|
272
2858
|
embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
|
|
273
2859
|
return emptyUserInputResponse();
|
|
@@ -350,6 +2936,9 @@ function readOption(value) {
|
|
|
350
2936
|
function buildUserInputResponse(questions, inputText) {
|
|
351
2937
|
return buildAgentHarnessUserInputAnswers(questions, inputText);
|
|
352
2938
|
}
|
|
2939
|
+
function gatewayAnswersToCodexResponse(answers) {
|
|
2940
|
+
return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
|
|
2941
|
+
}
|
|
353
2942
|
function emptyUserInputResponse() {
|
|
354
2943
|
return emptyAgentHarnessUserInputAnswers();
|
|
355
2944
|
}
|
|
@@ -374,6 +2963,11 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
374
2963
|
const { emitExecutionPhaseOnce, emitLifecycleStart, maybeAnnounceFastModeAutoOff } = lifecycle;
|
|
375
2964
|
const { enqueueNotification } = notifications;
|
|
376
2965
|
const activeTurnId = turn.turn.id;
|
|
2966
|
+
const prepareNativeMcpAppResultDetails = createCodexNativeMcpAppResultDetailsPreparer({
|
|
2967
|
+
client: resourceState.client,
|
|
2968
|
+
threadId: resourceState.thread.threadId,
|
|
2969
|
+
attempt: dynamicToolParams
|
|
2970
|
+
});
|
|
377
2971
|
const streamState = {
|
|
378
2972
|
eventEmitted: false,
|
|
379
2973
|
needsTerminalSnapshot: false
|
|
@@ -406,6 +3000,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
406
3000
|
runAbortSignal: runAbortController.signal,
|
|
407
3001
|
trajectoryRecorder,
|
|
408
3002
|
onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff,
|
|
3003
|
+
...prepareNativeMcpAppResultDetails ? { prepareNativeMcpAppResultDetails } : {},
|
|
409
3004
|
upstreamUserText: turnState.codexTurnPromptText,
|
|
410
3005
|
onContextCompacted: () => {
|
|
411
3006
|
computerContextEpoch.value += 1;
|
|
@@ -471,9 +3066,11 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
471
3066
|
await activeSteeringQueue.queue(text, optionsLocal);
|
|
472
3067
|
},
|
|
473
3068
|
isStreaming: () => !state.completed && !runAbortController.signal.aborted,
|
|
3069
|
+
isAborted: () => runAbortController.signal.aborted,
|
|
474
3070
|
isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
|
|
475
3071
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
476
3072
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
3073
|
+
supportsTranscriptCommitWait: true,
|
|
477
3074
|
supportsQueueMessageImages: true,
|
|
478
3075
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
479
3076
|
cancel: () => abortExplicitly("cancelled"),
|
|
@@ -536,7 +3133,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
536
3133
|
async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
|
|
537
3134
|
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment } = resources;
|
|
538
3135
|
const { connection } = prompt.context.runtime;
|
|
539
|
-
const { params, options, runAbortController } = connection;
|
|
3136
|
+
const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
|
|
540
3137
|
const { state, steeringQueueRef, userInputBridgeRef, turnWatches } = turnRuntime;
|
|
541
3138
|
const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
542
3139
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
@@ -566,10 +3163,17 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
566
3163
|
cleanup: async () => trajectoryRecorder?.flush()
|
|
567
3164
|
});
|
|
568
3165
|
if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueueRef.current?.flushPending();
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
3166
|
+
const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
|
|
3167
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
|
|
3168
|
+
kind: "clear",
|
|
3169
|
+
threadId: resourceState.thread.threadId
|
|
3170
|
+
}) : true;
|
|
3171
|
+
if (!state.timedOut && !retainLiveIncognitoThread) {
|
|
3172
|
+
if (bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
3173
|
+
threadId: resourceState.thread.threadId,
|
|
3174
|
+
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
3175
|
+
});
|
|
3176
|
+
}
|
|
573
3177
|
userInputBridgeRef.current?.cancelPending();
|
|
574
3178
|
turnWatches.clearAllTimers();
|
|
575
3179
|
releaseCurrentRoute();
|
|
@@ -603,7 +3207,8 @@ const codexWorkspaceDirCache = /* @__PURE__ */ new Set();
|
|
|
603
3207
|
//#region extensions/codex/src/app-server/run-attempt-lifecycle.ts
|
|
604
3208
|
const CODEX_APP_SERVER_PROJECTED_CHARS_PER_TOKEN = 4;
|
|
605
3209
|
function shouldKeepCodexSharedAbortOpen(params) {
|
|
606
|
-
|
|
3210
|
+
const terminal = attemptTerminal.project(params.result.terminal);
|
|
3211
|
+
if (params.explicitCancellationObserved || terminal.aborted || terminal.externalAbort) return false;
|
|
607
3212
|
return params.trigger === "memory" || !params.attemptSucceeded;
|
|
608
3213
|
}
|
|
609
3214
|
function withCodexAppServerFastModeServiceTier(appServer, params) {
|
|
@@ -830,19 +3435,11 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
|
|
|
830
3435
|
return;
|
|
831
3436
|
}
|
|
832
3437
|
}
|
|
833
|
-
function toNonNegativeInt(value) {
|
|
834
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
|
|
835
|
-
return Math.floor(value);
|
|
836
|
-
}
|
|
837
3438
|
function readCompactionConfig(config) {
|
|
838
3439
|
return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
|
|
839
3440
|
}
|
|
840
|
-
function resolveCodexAppServerNativeThreadReserveTokens(
|
|
841
|
-
|
|
842
|
-
const reserveTokens = toNonNegativeInt(compaction?.reserveTokens);
|
|
843
|
-
const reserveTokensFloor = toNonNegativeInt(compaction?.reserveTokensFloor);
|
|
844
|
-
if (reserveTokens !== void 0) return Math.max(reserveTokens, reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS);
|
|
845
|
-
return reserveTokensFloor ?? CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
3441
|
+
function resolveCodexAppServerNativeThreadReserveTokens(_config) {
|
|
3442
|
+
return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
846
3443
|
}
|
|
847
3444
|
function resolveCodexAppServerNativeThreadTokenFuse(params) {
|
|
848
3445
|
const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
|
|
@@ -938,6 +3535,14 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
938
3535
|
}
|
|
939
3536
|
//#endregion
|
|
940
3537
|
//#region extensions/codex/src/app-server/run-attempt-connection.ts
|
|
3538
|
+
function applyStoredBindingPermissions(params) {
|
|
3539
|
+
if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
|
|
3540
|
+
return {
|
|
3541
|
+
...params.appServer,
|
|
3542
|
+
approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
|
|
3543
|
+
sandbox: params.binding?.sandbox ?? params.appServer.sandbox
|
|
3544
|
+
};
|
|
3545
|
+
}
|
|
941
3546
|
async function prepareCodexAttemptConnection({ params, options }) {
|
|
942
3547
|
const attemptStartedAt = Date.now();
|
|
943
3548
|
const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
|
|
@@ -954,7 +3559,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
954
3559
|
const runtimeArtifactRequest = params.captureRuntimeArtifact || params.expectedRuntimeArtifact ? params.expectedRuntimeArtifact ? { expected: params.expectedRuntimeArtifact } : {} : void 0;
|
|
955
3560
|
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
|
956
3561
|
const computerUseConfig = resolveCodexComputerUseConfig({ pluginConfig });
|
|
957
|
-
const { sessionAgentId } = resolveSessionAgentIds
|
|
3562
|
+
const { sessionAgentId } = resolveSessionAgentIds({
|
|
958
3563
|
sessionKey: params.sessionKey,
|
|
959
3564
|
config: params.config,
|
|
960
3565
|
agentId: params.agentId
|
|
@@ -978,7 +3583,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
978
3583
|
config: params.config,
|
|
979
3584
|
agentId: sessionAgentId
|
|
980
3585
|
});
|
|
981
|
-
const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId);
|
|
3586
|
+
const agentDir = params.agentDir ?? resolveAgentDir$1(params.config ?? {}, sessionAgentId);
|
|
982
3587
|
const bindingIdentity = sessionBindingIdentity({
|
|
983
3588
|
sessionId: params.sessionId,
|
|
984
3589
|
sessionKey: params.sessionKey,
|
|
@@ -995,23 +3600,27 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
995
3600
|
bindingStore,
|
|
996
3601
|
identity: bindingIdentity,
|
|
997
3602
|
config: params.config
|
|
998
|
-
})) throw
|
|
3603
|
+
})) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
|
|
999
3604
|
startupBinding = await bindingStore.read(bindingIdentity);
|
|
1000
3605
|
}
|
|
1001
3606
|
preDynamicStartupStages.mark("read-binding");
|
|
1002
3607
|
const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
|
|
1003
3608
|
if (usesSupervisionConnection) activeContextEngine = void 0;
|
|
1004
3609
|
if (usesSupervisionConnection && pluginConfig.supervision?.enabled !== true) throw new Error("Codex supervision is disabled; refusing to open a native user-home supervised session");
|
|
1005
|
-
const resolveRuntimeOptionsForBinding = (selection) =>
|
|
3610
|
+
const resolveRuntimeOptionsForBinding = (selection) => applyStoredBindingPermissions({
|
|
3611
|
+
appServer: resolveCodexBindingAppServerConnection({
|
|
3612
|
+
binding: startupBinding,
|
|
3613
|
+
pluginConfig,
|
|
3614
|
+
execPolicy,
|
|
3615
|
+
modelProvider: selection.modelProvider,
|
|
3616
|
+
model: selection.model,
|
|
3617
|
+
config: params.config,
|
|
3618
|
+
agentDir,
|
|
3619
|
+
openClawSandboxActive: sandbox?.enabled === true
|
|
3620
|
+
}).appServer,
|
|
1006
3621
|
binding: startupBinding,
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
modelProvider: selection.modelProvider,
|
|
1010
|
-
model: selection.model,
|
|
1011
|
-
config: params.config,
|
|
1012
|
-
agentDir,
|
|
1013
|
-
openClawSandboxActive: sandbox?.enabled === true
|
|
1014
|
-
}).appServer;
|
|
3622
|
+
execPolicyTouched: execPolicy.touched
|
|
3623
|
+
});
|
|
1015
3624
|
const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
|
|
1016
3625
|
const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
|
|
1017
3626
|
const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
|
|
@@ -1034,6 +3643,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1034
3643
|
authProfileId: resolvedStartupAuthProfileId,
|
|
1035
3644
|
authProfileStore: params.authProfileStore,
|
|
1036
3645
|
agentDir,
|
|
3646
|
+
...pluginConfig.appServer?.homeScope ? { homeScope: pluginConfig.appServer.homeScope } : {},
|
|
1037
3647
|
config: params.config,
|
|
1038
3648
|
subscriptionProfileRequiredError: "Prepared Codex subscription route requires a forwarded OpenAI OAuth or token profile.",
|
|
1039
3649
|
subscriptionProfileUnusableError: "Prepared Codex subscription auth profile is unusable."
|
|
@@ -1087,6 +3697,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1087
3697
|
preDynamicStartupStages.mark("app-server-policy");
|
|
1088
3698
|
preDynamicStartupStages.mark("native-hook-relay");
|
|
1089
3699
|
const terminalState = {
|
|
3700
|
+
turnSucceeded: false,
|
|
1090
3701
|
explicitCancellationObserved: false,
|
|
1091
3702
|
explicitCancellationReason: void 0,
|
|
1092
3703
|
terminalOutcomeFrozen: false,
|
|
@@ -1148,16 +3759,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1148
3759
|
startupBinding,
|
|
1149
3760
|
pluginAppServer: appServer
|
|
1150
3761
|
};
|
|
1151
|
-
const resolveRuntimeOptionsForCurrentBinding = (selection) =>
|
|
3762
|
+
const resolveRuntimeOptionsForCurrentBinding = (selection) => applyStoredBindingPermissions({
|
|
3763
|
+
appServer: resolveCodexBindingAppServerConnection({
|
|
3764
|
+
binding: mutable.startupBinding,
|
|
3765
|
+
pluginConfig,
|
|
3766
|
+
execPolicy,
|
|
3767
|
+
modelProvider: selection.modelProvider,
|
|
3768
|
+
model: selection.model,
|
|
3769
|
+
config: params.config,
|
|
3770
|
+
agentDir,
|
|
3771
|
+
openClawSandboxActive: sandbox?.enabled === true
|
|
3772
|
+
}).appServer,
|
|
1152
3773
|
binding: mutable.startupBinding,
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
modelProvider: selection.modelProvider,
|
|
1156
|
-
model: selection.model,
|
|
1157
|
-
config: params.config,
|
|
1158
|
-
agentDir,
|
|
1159
|
-
openClawSandboxActive: sandbox?.enabled === true
|
|
1160
|
-
}).appServer;
|
|
3774
|
+
execPolicyTouched: execPolicy.touched
|
|
3775
|
+
});
|
|
1161
3776
|
return {
|
|
1162
3777
|
params,
|
|
1163
3778
|
options,
|
|
@@ -1210,24 +3825,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1210
3825
|
* system-prompt reports, and context-engine projection decisions.
|
|
1211
3826
|
*/
|
|
1212
3827
|
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = /* @__PURE__ */ new Set(["agents.md"]);
|
|
1213
|
-
const CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set(["tools.md"]);
|
|
1214
3828
|
const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([
|
|
1215
3829
|
"identity.md",
|
|
1216
3830
|
"soul.md",
|
|
1217
3831
|
"user.md"
|
|
1218
3832
|
]);
|
|
1219
|
-
const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES =
|
|
1220
|
-
const CODEX_HEARTBEAT_CONTEXT_BASENAME = "heartbeat.md";
|
|
3833
|
+
const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = new Set(CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
1221
3834
|
const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
|
|
1222
3835
|
const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
|
|
1223
3836
|
const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
|
|
1224
3837
|
["soul.md", 10],
|
|
1225
3838
|
["identity.md", 20],
|
|
1226
3839
|
["user.md", 30],
|
|
1227
|
-
["tools.md", 40],
|
|
1228
3840
|
["bootstrap.md", 50],
|
|
1229
|
-
["memory.md", 60]
|
|
1230
|
-
["heartbeat.md", 70]
|
|
3841
|
+
["memory.md", 60]
|
|
1231
3842
|
]);
|
|
1232
3843
|
/** Reads mirrored Codex session history for harness hooks. */
|
|
1233
3844
|
async function readMirroredSessionHistoryMessages(params) {
|
|
@@ -1326,22 +3937,17 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
1326
3937
|
excludeMemory: memoryToolsAvailable,
|
|
1327
3938
|
memoryWorkspaceDir: params.effectiveWorkspace
|
|
1328
3939
|
});
|
|
1329
|
-
const developerInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) : [];
|
|
1330
3940
|
const turnScopedDeveloperInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
|
|
1331
|
-
const heartbeatReferenceFiles = selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles);
|
|
1332
3941
|
return {
|
|
1333
3942
|
bootstrapFiles,
|
|
1334
3943
|
contextFiles,
|
|
1335
3944
|
promptContextFiles,
|
|
1336
|
-
developerInstructionFiles,
|
|
1337
3945
|
turnScopedDeveloperInstructionFiles,
|
|
1338
|
-
heartbeatReferenceFiles,
|
|
1339
3946
|
memoryReferenceFiles,
|
|
1340
3947
|
memoryToolRoutedBootstrapFiles,
|
|
1341
3948
|
memoryToolNames: [...params.memoryToolNames],
|
|
1342
3949
|
memoryToolRouted: memoryToolsAvailable,
|
|
1343
3950
|
promptContext: renderCodexWorkspaceBootstrapPromptContext(promptContextFiles),
|
|
1344
|
-
developerInstructions: renderCodexWorkspaceThreadDeveloperInstructions(developerInstructionFiles),
|
|
1345
3951
|
turnScopedDeveloperInstructions: renderCodexWorkspaceCollaborationDeveloperInstructions(turnScopedDeveloperInstructionFiles),
|
|
1346
3952
|
memoryCollaborationInstructions: shouldInjectCodexOpenClawPromptContext(params.params) ? await renderCodexWorkspaceMemoryCollaborationInstructions({
|
|
1347
3953
|
files: memoryReferenceFiles,
|
|
@@ -1351,8 +3957,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
1351
3957
|
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
1352
3958
|
agentSessionKey: params.sessionKey,
|
|
1353
3959
|
sandboxed: params.sandboxed
|
|
1354
|
-
}) : void 0
|
|
1355
|
-
heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
|
|
3960
|
+
}) : void 0
|
|
1356
3961
|
};
|
|
1357
3962
|
} catch (error) {
|
|
1358
3963
|
embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
|
|
@@ -1391,7 +3996,7 @@ function buildCodexSystemPromptReport(params) {
|
|
|
1391
3996
|
injectedWorkspaceFiles: buildCodexBootstrapInjectionStats({
|
|
1392
3997
|
bootstrapFiles: params.workspaceBootstrapContext.bootstrapFiles,
|
|
1393
3998
|
injectedFiles: params.workspaceBootstrapContext.promptContextFiles ?? [],
|
|
1394
|
-
developerInstructionFiles:
|
|
3999
|
+
developerInstructionFiles: params.workspaceBootstrapContext.turnScopedDeveloperInstructionFiles ?? [],
|
|
1395
4000
|
memoryToolRoutedBootstrapFiles: params.workspaceBootstrapContext.memoryToolRoutedBootstrapFiles ?? [],
|
|
1396
4001
|
memoryToolRouted: params.workspaceBootstrapContext.memoryToolRouted === true
|
|
1397
4002
|
}),
|
|
@@ -1474,14 +4079,9 @@ function buildCodexBootstrapInjectionStats(params) {
|
|
|
1474
4079
|
const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
|
|
1475
4080
|
let injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
|
|
1476
4081
|
let truncated = memoryToolRoutedFile ? false : !file.missing && injectedChars < rawChars;
|
|
1477
|
-
if (injected === void 0) {
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
truncated = false;
|
|
1481
|
-
} else if (baseName === CODEX_HEARTBEAT_CONTEXT_BASENAME) {
|
|
1482
|
-
injectedChars = 0;
|
|
1483
|
-
truncated = false;
|
|
1484
|
-
}
|
|
4082
|
+
if (injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
|
|
4083
|
+
injectedChars = rawChars;
|
|
4084
|
+
truncated = false;
|
|
1485
4085
|
}
|
|
1486
4086
|
return {
|
|
1487
4087
|
name: displayName,
|
|
@@ -1605,7 +4205,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
|
1605
4205
|
const files = contextFiles;
|
|
1606
4206
|
if (files.length === 0) return;
|
|
1607
4207
|
const lines = [
|
|
1608
|
-
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively.
|
|
4208
|
+
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. SOUL.md, IDENTITY.md, and USER.md are provided as turn-scoped collaboration instructions so native Codex subagents do not inherit them. Those files are not repeated here.",
|
|
1609
4209
|
"",
|
|
1610
4210
|
"# Project Context",
|
|
1611
4211
|
"",
|
|
@@ -1619,15 +4219,12 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
|
|
|
1619
4219
|
const excludeMemory = options.excludeMemory ?? true;
|
|
1620
4220
|
return contextFiles.filter((file) => {
|
|
1621
4221
|
const baseName = getCodexContextFileBasename(file.path);
|
|
1622
|
-
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) &&
|
|
4222
|
+
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
|
|
1623
4223
|
file,
|
|
1624
4224
|
workspaceDir: options.memoryWorkspaceDir
|
|
1625
4225
|
})) && !isMissingCodexBootstrapContextFile(file);
|
|
1626
4226
|
}).toSorted(compareCodexContextFiles);
|
|
1627
4227
|
}
|
|
1628
|
-
function selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) {
|
|
1629
|
-
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
1630
|
-
}
|
|
1631
4228
|
function selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) {
|
|
1632
4229
|
return selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES);
|
|
1633
4230
|
}
|
|
@@ -1637,13 +4234,6 @@ function selectCodexWorkspaceDeveloperInstructionFiles(contextFiles, basenames)
|
|
|
1637
4234
|
return baseName && basenames.has(baseName) && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
|
|
1638
4235
|
}).toSorted(compareCodexContextFiles);
|
|
1639
4236
|
}
|
|
1640
|
-
function renderCodexWorkspaceThreadDeveloperInstructions(files) {
|
|
1641
|
-
return renderCodexWorkspaceDeveloperInstructions({
|
|
1642
|
-
files,
|
|
1643
|
-
header: "## OpenClaw Workspace Instructions",
|
|
1644
|
-
preamble: "OpenClaw loaded these workspace instruction files from the active agent workspace. Internalize and follow them accordingly."
|
|
1645
|
-
});
|
|
1646
|
-
}
|
|
1647
4237
|
function renderCodexWorkspaceCollaborationDeveloperInstructions(files) {
|
|
1648
4238
|
return renderCodexWorkspaceDeveloperInstructions({
|
|
1649
4239
|
files,
|
|
@@ -1666,22 +4256,6 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
|
1666
4256
|
if (wrapperTag) lines.push(`</${wrapperTag}>`);
|
|
1667
4257
|
return lines.join("\n").trim();
|
|
1668
4258
|
}
|
|
1669
|
-
function selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles) {
|
|
1670
|
-
return contextFiles.filter((file) => {
|
|
1671
|
-
return getCodexContextFileBasename(file.path) === CODEX_HEARTBEAT_CONTEXT_BASENAME && !isMissingCodexBootstrapContextFile(file) && file.content.trim().length > 0;
|
|
1672
|
-
}).toSorted(compareCodexContextFiles);
|
|
1673
|
-
}
|
|
1674
|
-
function renderCodexWorkspaceHeartbeatReference(files) {
|
|
1675
|
-
if (files.length === 0) return;
|
|
1676
|
-
const lines = [
|
|
1677
|
-
"## OpenClaw Heartbeat Workspace",
|
|
1678
|
-
"",
|
|
1679
|
-
"HEARTBEAT.md exists in the active agent workspace. Read it before proceeding with this heartbeat, then decide what action is appropriate.",
|
|
1680
|
-
""
|
|
1681
|
-
];
|
|
1682
|
-
for (const file of files) lines.push(`- ${file.path}`);
|
|
1683
|
-
return lines.join("\n").trim();
|
|
1684
|
-
}
|
|
1685
4259
|
function selectCodexWorkspaceMemoryReferenceFiles(params) {
|
|
1686
4260
|
return params.bootstrapFiles.filter((file) => {
|
|
1687
4261
|
return isCodexWorkspaceRootMemoryBootstrapFile({
|
|
@@ -1771,151 +4345,50 @@ function isCodexWorkspaceRootMemoryPath(params) {
|
|
|
1771
4345
|
return (path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(params.workspaceDir, filePath)) === path.join(path.resolve(params.workspaceDir), "MEMORY.md");
|
|
1772
4346
|
}
|
|
1773
4347
|
function isSameCodexWorkspacePath(left, right) {
|
|
1774
|
-
return path.resolve(left) === path.resolve(right);
|
|
1775
|
-
}
|
|
1776
|
-
/**
|
|
1777
|
-
* Remaps bootstrap file paths from the resolved workspace to the effective Codex
|
|
1778
|
-
* workspace while preserving platform path separators.
|
|
1779
|
-
*/
|
|
1780
|
-
function remapCodexContextFilePath(params) {
|
|
1781
|
-
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
1782
|
-
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
1783
|
-
const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
|
|
1784
|
-
const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
|
|
1785
|
-
return {
|
|
1786
|
-
...params.file,
|
|
1787
|
-
path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
|
|
1788
|
-
};
|
|
1789
|
-
}
|
|
1790
|
-
function compareCodexContextFiles(left, right) {
|
|
1791
|
-
const leftPath = normalizeCodexContextFilePath(left.path);
|
|
1792
|
-
const rightPath = normalizeCodexContextFilePath(right.path);
|
|
1793
|
-
const leftBase = getCodexContextFileBasename(left.path);
|
|
1794
|
-
const rightBase = getCodexContextFileBasename(right.path);
|
|
1795
|
-
const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
|
|
1796
|
-
const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
|
|
1797
|
-
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
1798
|
-
if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
|
|
1799
|
-
return leftPath.localeCompare(rightPath);
|
|
1800
|
-
}
|
|
1801
|
-
function compareCodexBootstrapFiles(left, right) {
|
|
1802
|
-
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
1803
|
-
}
|
|
1804
|
-
function normalizeCodexContextFilePath(filePath) {
|
|
1805
|
-
return filePath.trim().replaceAll("\\", "/").toLowerCase();
|
|
1806
|
-
}
|
|
1807
|
-
function getCodexContextFileDisplayBasename(filePath) {
|
|
1808
|
-
return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
|
|
1809
|
-
}
|
|
1810
|
-
function getCodexContextFileBasename(filePath) {
|
|
1811
|
-
return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
|
|
1812
|
-
}
|
|
1813
|
-
function normalizeCodexDynamicToolName(name) {
|
|
1814
|
-
return name.trim().toLowerCase();
|
|
1815
|
-
}
|
|
1816
|
-
function isNonEmptyString$1(value) {
|
|
1817
|
-
return typeof value === "string" && value.length > 0;
|
|
1818
|
-
}
|
|
1819
|
-
//#endregion
|
|
1820
|
-
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
1821
|
-
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
1822
|
-
const currentBinding = await bindingStore.read(identity);
|
|
1823
|
-
const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
|
|
1824
|
-
if (!expectedThreadId) return;
|
|
1825
|
-
if (currentBinding && currentBinding.threadId !== expectedThreadId) {
|
|
1826
|
-
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
1827
|
-
...fields,
|
|
1828
|
-
boundThreadId: currentBinding.threadId
|
|
1829
|
-
});
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
if (currentBinding?.connectionScope === "supervision") {
|
|
1833
|
-
embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
|
|
1834
|
-
return;
|
|
1835
|
-
}
|
|
1836
|
-
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
1837
|
-
await bindingStore.mutate(identity, {
|
|
1838
|
-
kind: "clear",
|
|
1839
|
-
threadId: expectedThreadId
|
|
1840
|
-
});
|
|
1841
|
-
}
|
|
1842
|
-
async function markCodexAppServerBindingCoveredThroughTurn(params) {
|
|
1843
|
-
await params.bindingStore.mutate(params.identity, {
|
|
1844
|
-
kind: "patch",
|
|
1845
|
-
threadId: params.threadId,
|
|
1846
|
-
patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
1849
|
-
function isNonEmptyString(value) {
|
|
1850
|
-
return typeof value === "string" && value.length > 0;
|
|
1851
|
-
}
|
|
1852
|
-
function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
|
|
1853
|
-
if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
|
|
1854
|
-
const message = formatErrorMessage(params.error);
|
|
1855
|
-
return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
|
|
1856
|
-
}
|
|
1857
|
-
function isCodexActiveCompactTurnError(error) {
|
|
1858
|
-
if (!(error instanceof CodexAppServerRpcError)) return false;
|
|
1859
|
-
const data = isJsonObject(error.data) ? error.data : void 0;
|
|
1860
|
-
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
1861
|
-
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
4348
|
+
return path.resolve(left) === path.resolve(right);
|
|
1862
4349
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
4350
|
+
/**
|
|
4351
|
+
* Remaps bootstrap file paths from the resolved workspace to the effective Codex
|
|
4352
|
+
* workspace while preserving platform path separators.
|
|
4353
|
+
*/
|
|
4354
|
+
function remapCodexContextFilePath(params) {
|
|
4355
|
+
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
4356
|
+
if (!relativePath || relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
4357
|
+
const targetUsesPosixSeparators = params.targetWorkspaceDir.includes("/") && !params.targetWorkspaceDir.includes("\\");
|
|
4358
|
+
const normalizedRelativePath = targetUsesPosixSeparators ? relativePath.replaceAll("\\", "/") : relativePath.replaceAll("/", "\\");
|
|
1872
4359
|
return {
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
status: typeof run.status === "string" ? run.status : void 0
|
|
4360
|
+
...params.file,
|
|
4361
|
+
path: targetUsesPosixSeparators ? path.posix.join(params.targetWorkspaceDir, normalizedRelativePath) : path.win32.join(params.targetWorkspaceDir, normalizedRelativePath)
|
|
1876
4362
|
};
|
|
1877
4363
|
}
|
|
1878
|
-
function
|
|
1879
|
-
|
|
4364
|
+
function compareCodexContextFiles(left, right) {
|
|
4365
|
+
const leftPath = normalizeCodexContextFilePath(left.path);
|
|
4366
|
+
const rightPath = normalizeCodexContextFilePath(right.path);
|
|
4367
|
+
const leftBase = getCodexContextFileBasename(left.path);
|
|
4368
|
+
const rightBase = getCodexContextFileBasename(right.path);
|
|
4369
|
+
const leftOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(leftBase) ?? Number.MAX_SAFE_INTEGER;
|
|
4370
|
+
const rightOrder = CODEX_BOOTSTRAP_CONTEXT_ORDER.get(rightBase) ?? Number.MAX_SAFE_INTEGER;
|
|
4371
|
+
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
|
4372
|
+
if (leftBase !== rightBase) return leftBase.localeCompare(rightBase);
|
|
4373
|
+
return leftPath.localeCompare(rightPath);
|
|
1880
4374
|
}
|
|
1881
|
-
function
|
|
1882
|
-
|
|
1883
|
-
return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4375
|
+
function compareCodexBootstrapFiles(left, right) {
|
|
4376
|
+
return compareCodexContextFiles(toCodexEmbeddedContextFile(left), toCodexEmbeddedContextFile(right));
|
|
1884
4377
|
}
|
|
1885
|
-
function
|
|
1886
|
-
return
|
|
1887
|
-
setImmediate(resolve);
|
|
1888
|
-
});
|
|
4378
|
+
function normalizeCodexContextFilePath(filePath) {
|
|
4379
|
+
return filePath.trim().replaceAll("\\", "/").toLowerCase();
|
|
1889
4380
|
}
|
|
1890
|
-
function
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
return typeof value === "boolean" ? value : void 0;
|
|
1902
|
-
};
|
|
1903
|
-
return {
|
|
1904
|
-
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
1905
|
-
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
1906
|
-
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
1907
|
-
...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
|
|
1908
|
-
...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
|
|
1909
|
-
...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
|
|
1910
|
-
...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
|
|
1911
|
-
...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
|
|
1912
|
-
...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
|
|
1913
|
-
...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
|
|
1914
|
-
...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
|
|
1915
|
-
...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
|
|
1916
|
-
...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
|
|
1917
|
-
...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
|
|
1918
|
-
};
|
|
4381
|
+
function getCodexContextFileDisplayBasename(filePath) {
|
|
4382
|
+
return filePath.trim().replaceAll("\\", "/").split("/").pop()?.trim() ?? "";
|
|
4383
|
+
}
|
|
4384
|
+
function getCodexContextFileBasename(filePath) {
|
|
4385
|
+
return normalizeCodexContextFilePath(filePath).split("/").pop() ?? "";
|
|
4386
|
+
}
|
|
4387
|
+
function normalizeCodexDynamicToolName(name) {
|
|
4388
|
+
return name.trim().toLowerCase();
|
|
4389
|
+
}
|
|
4390
|
+
function isNonEmptyString$1(value) {
|
|
4391
|
+
return typeof value === "string" && value.length > 0;
|
|
1919
4392
|
}
|
|
1920
4393
|
//#endregion
|
|
1921
4394
|
//#region extensions/codex/src/app-server/run-attempt-context.ts
|
|
@@ -1988,7 +4461,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
1988
4461
|
memoryToolNames: getCodexWorkspaceMemoryToolNames(toolBridge.availableSpecs),
|
|
1989
4462
|
sandboxed: sandbox?.enabled === true
|
|
1990
4463
|
});
|
|
1991
|
-
const baseDeveloperInstructions =
|
|
4464
|
+
const baseDeveloperInstructions = buildDeveloperInstructions(runtimeParams, { dynamicTools: toolBridge.availableSpecs });
|
|
1992
4465
|
return {
|
|
1993
4466
|
runtime,
|
|
1994
4467
|
attemptTools,
|
|
@@ -2020,7 +4493,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
2020
4493
|
},
|
|
2021
4494
|
codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
|
|
2022
4495
|
contextTokenBudget: effectiveContextTokenBudget,
|
|
2023
|
-
reserveTokens: resolveCodexContextEngineProjectionReserveTokens(
|
|
4496
|
+
reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
|
|
2024
4497
|
})
|
|
2025
4498
|
};
|
|
2026
4499
|
}
|
|
@@ -2196,14 +4669,10 @@ function resolveCodexAppServerReplayBlockedReason(result) {
|
|
|
2196
4669
|
/** Builds an attempt result for failures before the app-server turn starts. */
|
|
2197
4670
|
function buildCodexTurnStartFailureResult(params) {
|
|
2198
4671
|
return {
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
timedOutDuringCompaction: false,
|
|
2204
|
-
timedOutDuringToolExecution: false,
|
|
2205
|
-
promptError: params.promptError ?? params.message,
|
|
2206
|
-
promptErrorSource: "prompt",
|
|
4672
|
+
terminal: attemptTerminal.normalize({
|
|
4673
|
+
promptError: params.promptError ?? params.message,
|
|
4674
|
+
promptErrorSource: "prompt"
|
|
4675
|
+
}),
|
|
2207
4676
|
sessionIdUsed: params.params.sessionId,
|
|
2208
4677
|
messagesSnapshot: params.messagesSnapshot,
|
|
2209
4678
|
assistantTexts: [],
|
|
@@ -2235,6 +4704,168 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
2235
4704
|
return /\b(?:invalid|malformed)\b[\s\S]{0,120}\b(?:image|image url|base64)\b/iu.test(normalizedMessage) || /\b(?:image|image url|base64)\b[\s\S]{0,120}\b(?:invalid|malformed)\b/iu.test(normalizedMessage);
|
|
2236
4705
|
}
|
|
2237
4706
|
//#endregion
|
|
4707
|
+
//#region extensions/codex/src/app-server/run-attempt-state.ts
|
|
4708
|
+
async function clearCodexBindingAfterInvalidImagePayload(bindingStore, identity, fields) {
|
|
4709
|
+
const currentBinding = await bindingStore.read(identity);
|
|
4710
|
+
const expectedThreadId = fields.threadId ?? currentBinding?.threadId;
|
|
4711
|
+
if (!expectedThreadId) return;
|
|
4712
|
+
if (currentBinding && currentBinding.threadId !== expectedThreadId) {
|
|
4713
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for unbound thread; preserving thread binding", {
|
|
4714
|
+
...fields,
|
|
4715
|
+
boundThreadId: currentBinding.threadId
|
|
4716
|
+
});
|
|
4717
|
+
return;
|
|
4718
|
+
}
|
|
4719
|
+
if (currentBinding?.connectionScope === "supervision") {
|
|
4720
|
+
embeddedAgentLog.warn("codex app-server image payload error detected for supervised thread; preserving native binding", fields);
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
embeddedAgentLog.warn("codex app-server image payload error detected; clearing thread binding", fields);
|
|
4724
|
+
await bindingStore.mutate(identity, {
|
|
4725
|
+
kind: "clear",
|
|
4726
|
+
threadId: expectedThreadId
|
|
4727
|
+
});
|
|
4728
|
+
}
|
|
4729
|
+
async function markCodexAppServerBindingCoveredThroughTurn(params) {
|
|
4730
|
+
await params.bindingStore.mutate(params.identity, {
|
|
4731
|
+
kind: "patch",
|
|
4732
|
+
threadId: params.threadId,
|
|
4733
|
+
patch: { historyCoveredThrough: (/* @__PURE__ */ new Date()).toISOString() }
|
|
4734
|
+
});
|
|
4735
|
+
}
|
|
4736
|
+
function isNonEmptyString(value) {
|
|
4737
|
+
return typeof value === "string" && value.length > 0;
|
|
4738
|
+
}
|
|
4739
|
+
function shouldUseFreshCodexThreadAfterContextEngineOverflow(params) {
|
|
4740
|
+
if (!params.contextEngineActive || params.thread.lifecycle.action !== "resumed") return false;
|
|
4741
|
+
const message = formatErrorMessage(params.error);
|
|
4742
|
+
return /ran out of room in the model'?s context window/iu.test(message) || /context window/iu.test(message) || /context length/iu.test(message) || /maximum context/iu.test(message) || /too many tokens/iu.test(message);
|
|
4743
|
+
}
|
|
4744
|
+
function isCodexActiveCompactTurnError(error) {
|
|
4745
|
+
if (!(error instanceof CodexAppServerRpcError)) return false;
|
|
4746
|
+
const data = isJsonObject(error.data) ? error.data : void 0;
|
|
4747
|
+
const codexErrorInfo = isJsonObject(data?.codexErrorInfo) ? data.codexErrorInfo : void 0;
|
|
4748
|
+
return (isJsonObject(codexErrorInfo?.activeTurnNotSteerable) ? codexErrorInfo.activeTurnNotSteerable : void 0)?.turnKind === "compact";
|
|
4749
|
+
}
|
|
4750
|
+
function readCodexFinalizationHookNotification(notification, threadId, turnId) {
|
|
4751
|
+
if (notification.method !== "hook/started" && notification.method !== "hook/completed") return;
|
|
4752
|
+
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
4753
|
+
const run = params && isJsonObject(params.run) ? params.run : void 0;
|
|
4754
|
+
if (params?.threadId !== threadId || params.turnId !== turnId || run?.eventName !== "stop" && run?.eventName !== "subagentStop" || typeof run.id !== "string" || !run.id) return;
|
|
4755
|
+
if (notification.method === "hook/started") return {
|
|
4756
|
+
phase: "started",
|
|
4757
|
+
runId: run.id
|
|
4758
|
+
};
|
|
4759
|
+
return {
|
|
4760
|
+
phase: "completed",
|
|
4761
|
+
runId: run.id,
|
|
4762
|
+
status: typeof run.status === "string" ? run.status : void 0
|
|
4763
|
+
};
|
|
4764
|
+
}
|
|
4765
|
+
function joinPresentSections(...sections) {
|
|
4766
|
+
return sections.filter((section) => Boolean(section?.trim())).join("\n\n");
|
|
4767
|
+
}
|
|
4768
|
+
function prependCurrentInboundContext(prompt, context) {
|
|
4769
|
+
const text = context?.text.trim();
|
|
4770
|
+
return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4771
|
+
}
|
|
4772
|
+
function waitForCodexNotificationDispatchTurn() {
|
|
4773
|
+
return new Promise((resolve) => {
|
|
4774
|
+
setImmediate(resolve);
|
|
4775
|
+
});
|
|
4776
|
+
}
|
|
4777
|
+
function buildCodexAppServerTimeoutDiagnostics(params) {
|
|
4778
|
+
const readString = (key) => {
|
|
4779
|
+
const value = params.details?.[key];
|
|
4780
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
4781
|
+
};
|
|
4782
|
+
const readNumber = (key) => {
|
|
4783
|
+
const value = params.details?.[key];
|
|
4784
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4785
|
+
};
|
|
4786
|
+
const readBoolean = (key) => {
|
|
4787
|
+
const value = params.details?.[key];
|
|
4788
|
+
return typeof value === "boolean" ? value : void 0;
|
|
4789
|
+
};
|
|
4790
|
+
return {
|
|
4791
|
+
...params.idleMs !== void 0 ? { idleMs: params.idleMs } : {},
|
|
4792
|
+
...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {},
|
|
4793
|
+
...params.lastActivityReason ? { lastActivityReason: params.lastActivityReason } : {},
|
|
4794
|
+
...readString("lastNotificationMethod") ? { lastNotificationMethod: readString("lastNotificationMethod") } : {},
|
|
4795
|
+
...readString("lastNotificationItemId") ? { lastNotificationItemId: readString("lastNotificationItemId") } : {},
|
|
4796
|
+
...readString("lastNotificationItemType") ? { lastNotificationItemType: readString("lastNotificationItemType") } : {},
|
|
4797
|
+
...readString("lastNotificationItemRole") ? { lastNotificationItemRole: readString("lastNotificationItemRole") } : {},
|
|
4798
|
+
...readString("lastAssistantTextPreview") ? { lastAssistantTextPreview: readString("lastAssistantTextPreview") } : {},
|
|
4799
|
+
...readNumber("activeAppServerTurnRequests") !== void 0 ? { activeAppServerTurnRequests: readNumber("activeAppServerTurnRequests") } : {},
|
|
4800
|
+
...readNumber("activeTurnItemCount") !== void 0 ? { activeTurnItemCount: readNumber("activeTurnItemCount") } : {},
|
|
4801
|
+
...readBoolean("terminalTurnNotificationQueued") !== void 0 ? { terminalTurnNotificationQueued: readBoolean("terminalTurnNotificationQueued") } : {},
|
|
4802
|
+
...readBoolean("completionIdleWatchArmed") !== void 0 ? { completionIdleWatchArmed: readBoolean("completionIdleWatchArmed") } : {},
|
|
4803
|
+
...readBoolean("assistantCompletionIdleWatchArmed") !== void 0 ? { assistantCompletionIdleWatchArmed: readBoolean("assistantCompletionIdleWatchArmed") } : {},
|
|
4804
|
+
...readBoolean("terminalIdleWatchArmed") !== void 0 ? { terminalIdleWatchArmed: readBoolean("terminalIdleWatchArmed") } : {}
|
|
4805
|
+
};
|
|
4806
|
+
}
|
|
4807
|
+
//#endregion
|
|
4808
|
+
//#region extensions/codex/src/app-server/settled-turn-context.ts
|
|
4809
|
+
function collectUniqueMessageIdentities(messages) {
|
|
4810
|
+
const identities = /* @__PURE__ */ new Map();
|
|
4811
|
+
for (const [index, message] of messages.entries()) {
|
|
4812
|
+
const identity = readMirrorIdentity(message);
|
|
4813
|
+
if (!identity) continue;
|
|
4814
|
+
if (identities.has(identity)) return;
|
|
4815
|
+
identities.set(identity, index);
|
|
4816
|
+
}
|
|
4817
|
+
return identities;
|
|
4818
|
+
}
|
|
4819
|
+
/** Freezes one complete active transcript branch through the settled tool-result boundary. */
|
|
4820
|
+
function buildCodexSettledTurnFinalizationContext(params) {
|
|
4821
|
+
const boundaryMessage = params.settledMessages.findLast((message) => message.role === "toolResult");
|
|
4822
|
+
const boundaryIdentity = boundaryMessage ? readMirrorIdentity(boundaryMessage) : void 0;
|
|
4823
|
+
if (!boundaryMessage || !boundaryIdentity || !boundaryIdentity.startsWith(`${params.turnId}:tool:`)) return;
|
|
4824
|
+
const settledBoundaryIndex = params.settledMessages.indexOf(boundaryMessage);
|
|
4825
|
+
const requiredIdentities = params.settledMessages.slice(0, settledBoundaryIndex + 1).map(readMirrorIdentity);
|
|
4826
|
+
if (requiredIdentities.length === 0 || requiredIdentities.some((identity) => !identity) || new Set(requiredIdentities).size !== requiredIdentities.length || !requiredIdentities.includes(`${params.turnId}:prompt`)) return;
|
|
4827
|
+
const historyIdentities = collectUniqueMessageIdentities(params.historyMessages);
|
|
4828
|
+
const mirroredIdentities = collectUniqueMessageIdentities(params.mirroredMessages);
|
|
4829
|
+
if (!historyIdentities || !mirroredIdentities) return;
|
|
4830
|
+
const mirroredBoundaryIndex = mirroredIdentities.get(boundaryIdentity);
|
|
4831
|
+
if (mirroredBoundaryIndex === void 0) return;
|
|
4832
|
+
const mirroredThroughBoundary = params.mirroredMessages.slice(0, mirroredBoundaryIndex + 1);
|
|
4833
|
+
if (mirroredThroughBoundary.length !== requiredIdentities.length || mirroredThroughBoundary.some((message, index) => readMirrorIdentity(message) !== requiredIdentities[index])) return;
|
|
4834
|
+
const historyBoundaryIndex = historyIdentities.get(boundaryIdentity);
|
|
4835
|
+
if (historyBoundaryIndex === void 0) return;
|
|
4836
|
+
let previousHistoryIndex = -1;
|
|
4837
|
+
for (const mirroredMessage of mirroredThroughBoundary) {
|
|
4838
|
+
const identity = readMirrorIdentity(mirroredMessage);
|
|
4839
|
+
const historyIndex = identity ? historyIdentities.get(identity) : void 0;
|
|
4840
|
+
const historyMessage = historyIndex === void 0 ? void 0 : params.historyMessages[historyIndex];
|
|
4841
|
+
if (historyIndex === void 0 || historyIndex <= previousHistoryIndex || historyIndex > historyBoundaryIndex || !historyMessage || serializeCodexMirrorSourceEvidence(historyMessage) !== serializeCodexMirrorSourceEvidence(mirroredMessage)) return;
|
|
4842
|
+
previousHistoryIndex = historyIndex;
|
|
4843
|
+
}
|
|
4844
|
+
return {
|
|
4845
|
+
source: "openclaw-transcript",
|
|
4846
|
+
messages: Object.freeze(structuredClone(params.historyMessages.slice(0, historyBoundaryIndex + 1)))
|
|
4847
|
+
};
|
|
4848
|
+
}
|
|
4849
|
+
/** Reads and freezes the current active transcript branch after mirroring has settled. */
|
|
4850
|
+
async function captureCodexSettledTurnFinalizationContext(params) {
|
|
4851
|
+
try {
|
|
4852
|
+
const historyMessages = await readCodexMirroredSessionHistoryMessages(params);
|
|
4853
|
+
if (!historyMessages) return;
|
|
4854
|
+
return buildCodexSettledTurnFinalizationContext({
|
|
4855
|
+
historyMessages,
|
|
4856
|
+
mirroredMessages: params.mirroredMessages,
|
|
4857
|
+
settledMessages: params.settledMessages,
|
|
4858
|
+
turnId: params.turnId
|
|
4859
|
+
});
|
|
4860
|
+
} catch (error) {
|
|
4861
|
+
embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
|
|
4862
|
+
error: formatErrorMessage(error),
|
|
4863
|
+
turnId: params.turnId
|
|
4864
|
+
});
|
|
4865
|
+
return;
|
|
4866
|
+
}
|
|
4867
|
+
}
|
|
4868
|
+
//#endregion
|
|
2238
4869
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
2239
4870
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
2240
4871
|
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
@@ -2353,13 +4984,14 @@ function recordCodexTrajectoryContext(recorder, params) {
|
|
|
2353
4984
|
/** Records final Codex model completion metadata and assistant snapshots. */
|
|
2354
4985
|
function recordCodexTrajectoryCompletion(recorder, params) {
|
|
2355
4986
|
if (!recorder) return;
|
|
4987
|
+
const terminal = attemptTerminal.project(params.result.terminal);
|
|
2356
4988
|
recorder.recordEvent("model.completed", {
|
|
2357
4989
|
threadId: params.threadId,
|
|
2358
4990
|
turnId: params.turnId,
|
|
2359
4991
|
timedOut: params.timedOut,
|
|
2360
4992
|
yieldDetected: params.yieldDetected ?? false,
|
|
2361
|
-
aborted:
|
|
2362
|
-
promptError: normalizeCodexTrajectoryError(
|
|
4993
|
+
aborted: terminal.aborted,
|
|
4994
|
+
promptError: normalizeCodexTrajectoryError(terminal.promptError),
|
|
2363
4995
|
usage: params.result.attemptUsage,
|
|
2364
4996
|
assistantTexts: params.result.assistantTexts,
|
|
2365
4997
|
messagesSnapshot: params.result.messagesSnapshot
|
|
@@ -2453,11 +5085,12 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2453
5085
|
});
|
|
2454
5086
|
}
|
|
2455
5087
|
const result = activeProjector.buildResult(toolBridge.telemetry, { yieldDetected: toolState.yieldDetected });
|
|
5088
|
+
const projectedTerminal = attemptTerminal.project(result.terminal);
|
|
2456
5089
|
const effectiveTimedOut = state.timedOut && !recoveredTurnWatchTimeout;
|
|
2457
5090
|
const effectiveTurnCompletionIdleTimedOut = state.turnCompletionIdleTimedOut && !recoveredTurnWatchTimeout;
|
|
2458
|
-
const isFinalAborted = () =>
|
|
5091
|
+
const isFinalAborted = () => projectedTerminal.aborted || terminalState.explicitCancellationObserved || runAbortController.signal.aborted && !state.clientClosedAbort && !recoveredTurnWatchTimeout;
|
|
2459
5092
|
const clientClosedPromptErrorForFinal = state.clientClosedPromptError && hasRecoverableCompletedAssistant ? void 0 : state.clientClosedPromptError;
|
|
2460
|
-
let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" :
|
|
5093
|
+
let finalPromptError = clientClosedPromptErrorForFinal ?? (effectiveTurnCompletionIdleTimedOut ? state.turnCompletionIdleTimeoutMessage : effectiveTimedOut ? "codex app-server attempt timed out" : projectedTerminal.promptError);
|
|
2461
5094
|
const finalPromptErrorMessage = typeof finalPromptError === "string" ? finalPromptError : finalPromptError instanceof Error ? finalPromptError.message : finalPromptError ? formatErrorMessage(finalPromptError) : void 0;
|
|
2462
5095
|
if (isInvalidCodexImagePayloadError(finalPromptErrorMessage)) await clearCodexBindingAfterInvalidImagePayload(bindingStore, bindingIdentity, {
|
|
2463
5096
|
phase: "turn_completed",
|
|
@@ -2498,7 +5131,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2498
5131
|
authProfileId: startupAuthProfileId,
|
|
2499
5132
|
rateLimits: readRecentCodexRateLimits(resourceState.client)
|
|
2500
5133
|
});
|
|
2501
|
-
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" :
|
|
5134
|
+
const finalPromptErrorSource = effectiveTimedOut || clientClosedPromptErrorForFinal ? "prompt" : projectedTerminal.promptErrorSource;
|
|
2502
5135
|
const codexAppServerFailureKind = clientClosedPromptErrorForFinal ? "client_closed_before_turn_completed" : effectiveTurnCompletionIdleTimedOut ? "turn_completion_idle_timeout" : void 0;
|
|
2503
5136
|
const replayBlockedReason = codexAppServerFailureKind ? resolveCodexAppServerReplayBlockedReason(result) : void 0;
|
|
2504
5137
|
const promptTimeoutOutcome = buildCodexAppServerPromptTimeoutOutcome({
|
|
@@ -2528,6 +5161,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2528
5161
|
const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
|
|
2529
5162
|
if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
|
|
2530
5163
|
const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
|
|
5164
|
+
terminalState.turnSucceeded = turnSucceeded;
|
|
2531
5165
|
terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
|
|
2532
5166
|
trigger: params.trigger,
|
|
2533
5167
|
result,
|
|
@@ -2547,7 +5181,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2547
5181
|
if (modelCallFailureKind) codexModelCallDiagnostics.emitError(finalPromptError ?? "codex app-server attempt interrupted", { failureKind: modelCallFailureKind });
|
|
2548
5182
|
else if (finalPromptError) codexModelCallDiagnostics.emitError(finalPromptError);
|
|
2549
5183
|
else codexModelCallDiagnostics.emitCompleted(result);
|
|
2550
|
-
const
|
|
5184
|
+
const mirrorOutcome = await codexTranscriptMirrorRuntime.mirrorBestEffort({
|
|
2551
5185
|
params,
|
|
2552
5186
|
agentId: sessionAgentId,
|
|
2553
5187
|
notifyUserMessagePersisted,
|
|
@@ -2557,6 +5191,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2557
5191
|
threadId: resourceState.thread.threadId,
|
|
2558
5192
|
turnId: activeTurnId
|
|
2559
5193
|
});
|
|
5194
|
+
const { assistantTranscriptOwned, assistantTranscriptIdempotencyKey } = mirrorOutcome;
|
|
5195
|
+
const shouldCaptureSettledTurnFinalizationContext = turnSucceeded && result.assistantTexts.every((text) => !text.trim()) && result.messagesSnapshot.some((message) => message.role === "toolResult");
|
|
5196
|
+
const settledTurnFinalizationContext = shouldCaptureSettledTurnFinalizationContext ? await captureCodexSettledTurnFinalizationContext({
|
|
5197
|
+
...activeTranscriptTarget,
|
|
5198
|
+
mirroredMessages: mirrorOutcome.mirroredMessages,
|
|
5199
|
+
settledMessages: result.messagesSnapshot,
|
|
5200
|
+
turnId: activeTurnId
|
|
5201
|
+
}) : void 0;
|
|
5202
|
+
if (shouldCaptureSettledTurnFinalizationContext && !settledTurnFinalizationContext) embeddedAgentLog.warn("codex settled-turn finalization context is unavailable", {
|
|
5203
|
+
threadId: resourceState.thread.threadId,
|
|
5204
|
+
turnId: activeTurnId
|
|
5205
|
+
});
|
|
2560
5206
|
if (activeContextEngine) {
|
|
2561
5207
|
const contextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
|
|
2562
5208
|
const isHeartbeat = params.bootstrapContextRunKind === "heartbeat" || params.bootstrapContextRunKind === "commitment-only";
|
|
@@ -2680,13 +5326,17 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2680
5326
|
});
|
|
2681
5327
|
return {
|
|
2682
5328
|
...result,
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
5329
|
+
terminal: attemptTerminal.normalize({
|
|
5330
|
+
timedOut: effectiveTimedOut,
|
|
5331
|
+
aborted: finalAborted,
|
|
5332
|
+
promptError: finalPromptError,
|
|
5333
|
+
promptErrorSource: finalPromptErrorSource
|
|
5334
|
+
}),
|
|
2687
5335
|
...codexAppServerFailure ? { codexAppServerFailure } : {},
|
|
2688
5336
|
...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
|
|
2689
5337
|
...assistantTranscriptOwned ? { assistantTranscriptOwned: true } : {},
|
|
5338
|
+
...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
|
|
5339
|
+
...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
|
|
2690
5340
|
...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
|
|
2691
5341
|
...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
|
|
2692
5342
|
systemPromptReport
|
|
@@ -3011,7 +5661,7 @@ var ClientTurnRouter = class {
|
|
|
3011
5661
|
this.nativeTurnCompletionWatchers = /* @__PURE__ */ new Map();
|
|
3012
5662
|
this.disposed = false;
|
|
3013
5663
|
client.addNotificationHandler((notification) => this.routeNotification(notification));
|
|
3014
|
-
client.addRequestHandler((request) => this.routeRequest(request));
|
|
5664
|
+
client.addRequestHandler((request, signal) => this.routeRequest(request, signal));
|
|
3015
5665
|
client.addCloseHandler(() => this.dispose());
|
|
3016
5666
|
}
|
|
3017
5667
|
reserveThread(options) {
|
|
@@ -3172,34 +5822,35 @@ var ClientTurnRouter = class {
|
|
|
3172
5822
|
this.enqueueNotification(route, handler, notification, routeScope);
|
|
3173
5823
|
return route.notificationTail;
|
|
3174
5824
|
}
|
|
3175
|
-
async routeRequest(request) {
|
|
3176
|
-
if (this.disposed) return;
|
|
5825
|
+
async routeRequest(request, signal = new AbortController().signal) {
|
|
5826
|
+
if (this.disposed || signal.aborted) return;
|
|
3177
5827
|
const scope = readScope(request.params);
|
|
3178
5828
|
if (!scope.threadId) return;
|
|
3179
5829
|
const route = this.routes.get(scope.threadId);
|
|
3180
5830
|
if (!route || route.released) return;
|
|
3181
|
-
if (!route.handlers
|
|
3182
|
-
if (route.released || !route.handlers) return;
|
|
5831
|
+
if (!route.handlers && !await waitForPromiseOrAbort(route.activated.promise, signal)) return;
|
|
5832
|
+
if (signal.aborted || route.released || !route.handlers) return;
|
|
3183
5833
|
const handler = route.handlers.onRequest;
|
|
3184
5834
|
if (!handler) return;
|
|
3185
5835
|
while (route.gate === "armed") {
|
|
3186
|
-
|
|
3187
|
-
if (
|
|
5836
|
+
const binding = route.binding?.promise;
|
|
5837
|
+
if (!binding || !await waitForPromiseOrAbort(binding, signal)) return;
|
|
5838
|
+
if (signal.aborted || route.released) return;
|
|
3188
5839
|
}
|
|
3189
5840
|
if (route.gate === "bound") {
|
|
3190
5841
|
if (scope.turnId && scope.turnId !== route.turnId) return;
|
|
3191
5842
|
if (route.released) return;
|
|
3192
5843
|
}
|
|
3193
|
-
await this.waitForNotifications(route);
|
|
3194
|
-
if (route.released) return;
|
|
5844
|
+
if (!await waitForPromiseOrAbort(this.waitForNotifications(route), signal)) return;
|
|
5845
|
+
if (signal.aborted || route.released) return;
|
|
3195
5846
|
try {
|
|
3196
5847
|
const result = await handler(request, {
|
|
3197
5848
|
threadId: scope.threadId,
|
|
3198
5849
|
...scope.turnId ? { turnId: scope.turnId } : {}
|
|
3199
|
-
});
|
|
3200
|
-
return route.released ? void 0 : result;
|
|
5850
|
+
}, signal);
|
|
5851
|
+
return signal.aborted || route.released ? void 0 : result;
|
|
3201
5852
|
} catch (error) {
|
|
3202
|
-
if (route.released) return;
|
|
5853
|
+
if (signal.aborted || route.released) return;
|
|
3203
5854
|
throw error;
|
|
3204
5855
|
}
|
|
3205
5856
|
}
|
|
@@ -3319,6 +5970,20 @@ function isCodexTerminalTurnNotification(notification) {
|
|
|
3319
5970
|
if (notification.method === "turn/completed") return true;
|
|
3320
5971
|
return notification.method === "error" && isJsonObject(notification.params) && notification.params.willRetry === false;
|
|
3321
5972
|
}
|
|
5973
|
+
async function waitForPromiseOrAbort(promise, signal) {
|
|
5974
|
+
if (signal.aborted) return false;
|
|
5975
|
+
let removeAbort;
|
|
5976
|
+
try {
|
|
5977
|
+
return await Promise.race([promise.then(() => true), new Promise((resolve) => {
|
|
5978
|
+
const onAbort = () => resolve(false);
|
|
5979
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5980
|
+
removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
5981
|
+
if (signal.aborted) onAbort();
|
|
5982
|
+
})]);
|
|
5983
|
+
} finally {
|
|
5984
|
+
removeAbort?.();
|
|
5985
|
+
}
|
|
5986
|
+
}
|
|
3322
5987
|
function deferred() {
|
|
3323
5988
|
let resolve;
|
|
3324
5989
|
return {
|
|
@@ -3579,8 +6244,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
3579
6244
|
developerInstructions: promptState.developerInstructions,
|
|
3580
6245
|
messages: structuredClone(historyState.messages),
|
|
3581
6246
|
ctx: hookContext,
|
|
3582
|
-
bootstrapContextRunKind: params.bootstrapContextRunKind
|
|
3583
|
-
..."beforeAgentStartResult" in params ? { beforeAgentStartResult: params.beforeAgentStartResult } : {}
|
|
6247
|
+
bootstrapContextRunKind: params.bootstrapContextRunKind
|
|
3584
6248
|
});
|
|
3585
6249
|
const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
|
|
3586
6250
|
if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
|
|
@@ -3631,8 +6295,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
3631
6295
|
const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(turnState.promptBuild.developerInstructions, buildTurnCollaborationMode(params, {
|
|
3632
6296
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
3633
6297
|
skillsCollaborationInstructions,
|
|
3634
|
-
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
|
|
3635
|
-
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
|
|
6298
|
+
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
|
|
3636
6299
|
}).settings.developer_instructions ?? void 0);
|
|
3637
6300
|
const rebuildCodexPromptBuildFromCurrentProjection = async () => {
|
|
3638
6301
|
turnState.promptBuild = await buildPromptFromCurrentInputs();
|
|
@@ -5595,7 +8258,7 @@ async function readFile(execServer, params) {
|
|
|
5595
8258
|
const fsBridge = requireFsBridge(execServer);
|
|
5596
8259
|
const stat = await fsBridge.stat({ filePath });
|
|
5597
8260
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
5598
|
-
|
|
8261
|
+
assertSandboxFileReadWithinLimit(stat);
|
|
5599
8262
|
return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
|
|
5600
8263
|
}
|
|
5601
8264
|
/** Writes base64 data to an existing sandbox directory after write-policy checks. */
|
|
@@ -5736,6 +8399,15 @@ async function copySandboxPath(execServer, params) {
|
|
|
5736
8399
|
}
|
|
5737
8400
|
return;
|
|
5738
8401
|
}
|
|
8402
|
+
if (sourceStat.type === "file" && fsBridge.copyFile) {
|
|
8403
|
+
await fsBridge.copyFile({
|
|
8404
|
+
sourcePath: params.sourcePath,
|
|
8405
|
+
destinationPath: params.destinationPath,
|
|
8406
|
+
mkdir: true
|
|
8407
|
+
});
|
|
8408
|
+
return;
|
|
8409
|
+
}
|
|
8410
|
+
assertSandboxFileReadWithinLimit(sourceStat);
|
|
5739
8411
|
const data = await fsBridge.readFile({ filePath: params.sourcePath });
|
|
5740
8412
|
await fsBridge.writeFile({
|
|
5741
8413
|
filePath: params.destinationPath,
|
|
@@ -5743,6 +8415,9 @@ async function copySandboxPath(execServer, params) {
|
|
|
5743
8415
|
mkdir: true
|
|
5744
8416
|
});
|
|
5745
8417
|
}
|
|
8418
|
+
function assertSandboxFileReadWithinLimit(stat) {
|
|
8419
|
+
if (stat.type === "file" && stat.size > CODEX_SANDBOX_EXEC_SERVER_MAX_READ_FILE_BYTES) throw new Error(`file is too large to read through Codex sandbox exec-server: ${stat.size} bytes`);
|
|
8420
|
+
}
|
|
5746
8421
|
function metadataResponse(stat) {
|
|
5747
8422
|
return {
|
|
5748
8423
|
isDirectory: stat?.type === "directory",
|
|
@@ -6792,6 +9467,15 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6792
9467
|
timeoutMs: params.timeoutMs,
|
|
6793
9468
|
timeoutFloorMs: options.startupTimeoutFloorMs
|
|
6794
9469
|
});
|
|
9470
|
+
const requesterChannel = params.messageChannel ?? params.messageProvider;
|
|
9471
|
+
const requester = {
|
|
9472
|
+
...requesterChannel ? { channel: requesterChannel } : {},
|
|
9473
|
+
...params.agentAccountId ? { accountId: params.agentAccountId } : {},
|
|
9474
|
+
...params.senderId ? { senderId: params.senderId } : {},
|
|
9475
|
+
...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
|
|
9476
|
+
...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
|
|
9477
|
+
};
|
|
9478
|
+
const hasRequester = Object.keys(requester).length > 0;
|
|
6795
9479
|
const buildNativeHookRelayFinalConfigPatch = (decision) => {
|
|
6796
9480
|
state.nativeHookRelay?.unregister();
|
|
6797
9481
|
state.nativeHookRelay = createCodexNativeHookRelay({
|
|
@@ -6805,6 +9489,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6805
9489
|
config: params.config,
|
|
6806
9490
|
runId: params.runId,
|
|
6807
9491
|
channelId: hookChannelId,
|
|
9492
|
+
...hasRequester ? { requester } : {},
|
|
6808
9493
|
attemptTimeoutMs: params.timeoutMs,
|
|
6809
9494
|
startupTimeoutMs,
|
|
6810
9495
|
turnStartTimeoutMs: params.timeoutMs,
|
|
@@ -6914,6 +9599,28 @@ async function prepareCodexAttemptRoute(resources, turnRuntime, notifications, h
|
|
|
6914
9599
|
return { ensureCurrentThreadRoute };
|
|
6915
9600
|
}
|
|
6916
9601
|
//#endregion
|
|
9602
|
+
//#region extensions/codex/src/app-server/run-attempt-client-prewarm.ts
|
|
9603
|
+
/** Starts the shared process while tools and prompt context are still being prepared. */
|
|
9604
|
+
function prewarmCodexAttemptClient(params) {
|
|
9605
|
+
const { connection, authProfileStore, authBindingFingerprint } = params;
|
|
9606
|
+
const { appServer, attemptClientFactory, options, pluginConfig, runtimeArtifactRequest, startupAuthRequirement, startupClientAuthProfileId, startupPreparedAuth, agentDir, params: runParams, runAbortController } = connection;
|
|
9607
|
+
if (options.clientFactory || attemptClientFactory !== getLeasedSharedCodexAppServerClient || runtimeArtifactRequest) return;
|
|
9608
|
+
getSharedCodexAppServerClient({
|
|
9609
|
+
startOptions: appServer.start,
|
|
9610
|
+
pluginConfig,
|
|
9611
|
+
...startupPreparedAuth ? { preparedAuth: startupPreparedAuth } : { authProfileId: startupClientAuthProfileId },
|
|
9612
|
+
authRequirement: startupAuthRequirement,
|
|
9613
|
+
authProfileStore,
|
|
9614
|
+
authBindingFingerprint,
|
|
9615
|
+
agentDir,
|
|
9616
|
+
config: runParams.config,
|
|
9617
|
+
timeoutMs: appServer.requestTimeoutMs,
|
|
9618
|
+
abandonSignal: runAbortController.signal
|
|
9619
|
+
}).catch((error) => {
|
|
9620
|
+
embeddedAgentLog.debug("codex app-server client prewarm failed", { error });
|
|
9621
|
+
});
|
|
9622
|
+
}
|
|
9623
|
+
//#endregion
|
|
6917
9624
|
//#region extensions/codex/src/app-server/run-attempt-runtime.ts
|
|
6918
9625
|
async function prepareCodexAttemptRuntime(connection) {
|
|
6919
9626
|
const { params, pluginConfig, usesSupervisionConnection, appServer, startupAuthProfileId, startupPreparedAuth, startupClientAuthProfileId, agentDir, preDynamicStartupStages, effectiveWorkspace, contextSessionKey, sandboxSessionKey, sessionAgentId, sandbox, attemptClientFactory, runAbortController, activeContextEngine, mutable } = connection;
|
|
@@ -6924,6 +9631,11 @@ async function prepareCodexAttemptRuntime(connection) {
|
|
|
6924
9631
|
config: params.config
|
|
6925
9632
|
}) : void 0;
|
|
6926
9633
|
const attemptAuthProfileStore = preparedAuthBinding?.authProfileStore ?? params.authProfileStore;
|
|
9634
|
+
prewarmCodexAttemptClient({
|
|
9635
|
+
connection,
|
|
9636
|
+
authProfileStore: attemptAuthProfileStore,
|
|
9637
|
+
authBindingFingerprint: preparedAuthBinding?.fingerprint
|
|
9638
|
+
});
|
|
6927
9639
|
const effectiveContextWindowInfo = usesSupervisionConnection ? void 0 : params.contextWindowInfo;
|
|
6928
9640
|
const effectiveContextTokenBudget = usesSupervisionConnection ? void 0 : params.contextTokenBudget;
|
|
6929
9641
|
const effectiveRuntimeProviderId = usesSupervisionConnection ? mutable.startupBinding?.modelProvider ?? "codex" : params.provider;
|
|
@@ -7052,7 +9764,8 @@ function recordCodexDynamicToolResult(projector, call, response, protocolRespons
|
|
|
7052
9764
|
success: protocolResponse.success,
|
|
7053
9765
|
terminalType: response.diagnosticTerminalType ?? (protocolResponse.success ? "completed" : "error"),
|
|
7054
9766
|
sideEffectEvidence: response.sideEffectEvidence === true || response.terminalResolution?.sideEffectEvidence === true,
|
|
7055
|
-
contentItems: protocolResponse.contentItems
|
|
9767
|
+
contentItems: protocolResponse.contentItems,
|
|
9768
|
+
details: response.transcriptDetails
|
|
7056
9769
|
});
|
|
7057
9770
|
}
|
|
7058
9771
|
//#endregion
|
|
@@ -7150,7 +9863,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7150
9863
|
const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
7151
9864
|
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
|
|
7152
9865
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
7153
|
-
const handleServerRequest = async (request, scope) => {
|
|
9866
|
+
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
|
|
9867
|
+
const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
|
|
7154
9868
|
const turnId = turnIdRef.current;
|
|
7155
9869
|
const projector = projectorRef.current;
|
|
7156
9870
|
let armCompletionWatchOnResponse = false;
|
|
@@ -7176,7 +9890,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7176
9890
|
turnId,
|
|
7177
9891
|
pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
|
|
7178
9892
|
...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
|
|
7179
|
-
signal
|
|
9893
|
+
signal
|
|
7180
9894
|
});
|
|
7181
9895
|
}
|
|
7182
9896
|
if (request.method === "item/tool/requestUserInput") {
|
|
@@ -7203,7 +9917,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7203
9917
|
turnId,
|
|
7204
9918
|
nativeHookRelay: resourceState.nativeHookRelay,
|
|
7205
9919
|
autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
|
|
7206
|
-
signal
|
|
9920
|
+
signal,
|
|
7207
9921
|
onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
|
|
7208
9922
|
});
|
|
7209
9923
|
}
|
|
@@ -7279,7 +9993,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7279
9993
|
const { execution } = openClawDynamicToolExecutions.claim(call, () => handleDynamicToolCallWithTimeout({
|
|
7280
9994
|
call,
|
|
7281
9995
|
toolBridge,
|
|
7282
|
-
signal
|
|
9996
|
+
signal,
|
|
7283
9997
|
timeoutMs: dynamicToolTimeoutMs,
|
|
7284
9998
|
toolMeta,
|
|
7285
9999
|
toolCallOrdinal,
|
|
@@ -7576,7 +10290,7 @@ function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
|
|
|
7576
10290
|
//#endregion
|
|
7577
10291
|
//#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
|
|
7578
10292
|
/** Enforces one bounded startup budget across Codex plugin config discovery. */
|
|
7579
|
-
const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS =
|
|
10293
|
+
const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 6e4;
|
|
7580
10294
|
const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
|
|
7581
10295
|
const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
|
|
7582
10296
|
var CodexPluginThreadConfigDeadlineError = class extends Error {
|
|
@@ -7743,6 +10457,7 @@ async function startCodexAttemptThread(params) {
|
|
|
7743
10457
|
const attemptParams = params.buildAttemptParams();
|
|
7744
10458
|
startupClient = await params.attemptClientFactory({
|
|
7745
10459
|
startOptions: params.appServer.start,
|
|
10460
|
+
pluginConfig: params.pluginConfig,
|
|
7746
10461
|
...params.startupPreparedAuth ? { preparedAuth: params.startupPreparedAuth } : { authProfileId: params.startupAuthProfileId },
|
|
7747
10462
|
authRequirement: params.startupAuthRequirement,
|
|
7748
10463
|
authProfileStore: attemptParams.authProfileStore,
|
|
@@ -7791,14 +10506,19 @@ async function startCodexAttemptThread(params) {
|
|
|
7791
10506
|
config: params.config
|
|
7792
10507
|
});
|
|
7793
10508
|
const turnRouter = getCodexAppServerTurnRouter(activeStartupClient);
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
10509
|
+
try {
|
|
10510
|
+
await ensureCodexComputerUse({
|
|
10511
|
+
client: activeStartupClient,
|
|
10512
|
+
pluginConfig: params.pluginConfig,
|
|
10513
|
+
config: params.config,
|
|
10514
|
+
agentDir: params.agentDir,
|
|
10515
|
+
timeoutMs: params.appServer.requestTimeoutMs,
|
|
10516
|
+
signal: startupAbandonController.signal
|
|
10517
|
+
});
|
|
10518
|
+
} catch (error) {
|
|
10519
|
+
if (startupAbandonController.signal.aborted) throw error;
|
|
10520
|
+
throw new AgentHarnessPreflightError(`Codex Computer Use readiness failed: ${formatErrorMessage(error)}`, { cause: error });
|
|
10521
|
+
}
|
|
7802
10522
|
const startupRuntimeIdentity = activeStartupClient.getRuntimeIdentity();
|
|
7803
10523
|
const pluginAppCacheKey = buildCodexPluginAppCacheKey({
|
|
7804
10524
|
appServer: params.appServer,
|
|
@@ -8266,7 +10986,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
8266
10986
|
sessionId: params.sessionId,
|
|
8267
10987
|
sessionKey: params.sessionKey,
|
|
8268
10988
|
workspaceDir: effectiveWorkspace,
|
|
8269
|
-
agentDir: agentDir ?? resolveAgentDir
|
|
10989
|
+
agentDir: agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId),
|
|
8270
10990
|
cfg: params.config,
|
|
8271
10991
|
requesterSenderId: params.senderId,
|
|
8272
10992
|
agentAccountId: params.agentAccountId,
|
|
@@ -8280,7 +11000,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
8280
11000
|
sessionId: params.sessionId,
|
|
8281
11001
|
runId: params.runId,
|
|
8282
11002
|
agentId: sessionAgentId,
|
|
8283
|
-
agentDir: agentDir ?? resolveAgentDir
|
|
11003
|
+
agentDir: agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId),
|
|
8284
11004
|
agentAccountId: params.agentAccountId,
|
|
8285
11005
|
messageProvider: params.messageProvider ?? params.messageChannel,
|
|
8286
11006
|
messageChannel: params.messageChannel,
|
|
@@ -8332,6 +11052,7 @@ async function prepareCodexAttemptTools(runtime) {
|
|
|
8332
11052
|
hookContext: {
|
|
8333
11053
|
agentId: sessionAgentId,
|
|
8334
11054
|
config: params.config,
|
|
11055
|
+
contextWindowTokens: params.contextTokenBudget ?? params.model.contextWindow,
|
|
8335
11056
|
workspaceDir: effectiveWorkspace,
|
|
8336
11057
|
sessionId: params.sessionId,
|
|
8337
11058
|
sessionKey: sandboxSessionKey,
|
|
@@ -8418,7 +11139,6 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
8418
11139
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
8419
11140
|
skillsCollaborationInstructions: context.skillsCollaborationInstructions,
|
|
8420
11141
|
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
8421
|
-
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions,
|
|
8422
11142
|
preserveNativeTurnSettings: usesSupervisionConnection
|
|
8423
11143
|
});
|
|
8424
11144
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
@@ -8643,7 +11363,11 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8643
11363
|
ctx: hookContext,
|
|
8644
11364
|
hookRunner
|
|
8645
11365
|
});
|
|
8646
|
-
|
|
11366
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
|
|
11367
|
+
kind: "clear",
|
|
11368
|
+
threadId: resourceState.thread.threadId
|
|
11369
|
+
}) : true;
|
|
11370
|
+
if (!state.timedOut && bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
8647
11371
|
threadId: resourceState.thread.threadId,
|
|
8648
11372
|
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
8649
11373
|
});
|