@openclaw/codex 2026.7.2-beta.3 → 2026.7.2-beta.4
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-BO3jYBkv.js} +1 -1
- package/dist/{attempt-notifications-Ecjyzufe.js → attempt-notifications-DdmnBMUp.js} +1 -1
- package/dist/{media-understanding-provider-IPNNQre6.js → bounded-turn-CaQL96kg.js} +43 -183
- package/dist/capabilities-CLICvTxf.js +36 -0
- package/dist/cli-metadata.js +1 -1
- package/dist/{command-formatters-NCTL7A2q.js → command-formatters-DgADqnHa.js} +3 -37
- package/dist/{command-handlers-DtFbZiba.js → command-handlers-l_lVPNlB.js} +12 -11
- package/dist/{compact-Kgy26gIM.js → compact-CC5KhBzX.js} +5 -4
- package/dist/{computer-use-C7x4ZaqR.js → computer-use-Ip1-QGa-.js} +4 -4
- package/dist/{conversation-control-B0s3aIjT.js → conversation-control-sNPsbTCP.js} +6 -5
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{dynamic-tools-D_vSVmv9.js → dynamic-tools-CQI3UwqY.js} +105 -2670
- package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
- package/dist/event-projector-usage-D6tE7_qD.js +69 -0
- package/dist/harness.js +25 -6
- package/dist/incognito-session-ET_ufDH-.js +2 -0
- package/dist/index.js +60 -26
- package/dist/media-understanding-provider.js +168 -1
- package/dist/{models-DD5zBdX5.js → models-BNeMlHgg.js} +2 -2
- package/dist/{notification-correlation-C8DVQ_Bq.js → notification-correlation-BGLixv5_.js} +3 -3
- package/dist/{plugin-app-cache-key-DJbhLYSK.js → plugin-app-cache-key-CvzvmBRz.js} +2 -2
- package/dist/{rate-limits-CqhWQ2R9.js → rate-limits-D0IJT-a6.js} +1 -1
- package/dist/{request-9yf9pZjf.js → request-BTccUTD3.js} +1 -1
- package/dist/{run-attempt-BIoO8ISr.js → run-attempt--858NXDl.js} +2653 -109
- package/dist/{session-binding-Bmt20HfB.js → session-binding-ZSMX1omP.js} +7 -2
- package/dist/{session-catalog-CA7R-hX2.js → session-catalog-DsKaezgR.js} +82 -80
- package/dist/{session-cli-Bxk3-Wqz.js → session-cli-CYJTfRLG.js} +1 -1
- package/dist/session-upstream-marker-D7XlI9us.js +82 -0
- package/dist/settled-turn-finalizer-DHltNgtF.js +303 -0
- package/dist/{shared-client-CSXLtCLE.js → shared-client-wmgNFNYp.js} +33 -13
- package/dist/{side-question-DtzquMOb.js → side-question-BfFZCsJ-.js} +21 -15
- package/dist/{thread-lifecycle-CQ_9mAa1.js → thread-lifecycle-cqrOlJkq.js} +120 -26
- package/dist/{transcript-mirror-D9rTxx2P.js → transcript-mirror-2p7kl6e4.js} +433 -145
- package/dist/upstream-session-fork-vPjwkT1i.js +320 -0
- package/dist/{usage-CuPpFgTc.js → usage-DM_I3mPT.js} +3 -3
- package/dist/{web-search-provider.runtime-_x5XTeqh.js → web-search-provider.runtime-Bx6HAc_k.js} +3 -3
- package/npm-shrinkwrap.json +38 -38
- package/package.json +7 -7
|
@@ -1,32 +1,43 @@
|
|
|
1
|
-
import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError,
|
|
2
|
-
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-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { r as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { A as isCodexAppServerStartupError, B as isCodexAppServerApprovalRequest, C as resolveCodexAppServerFallbackApiKeyCacheKey, D as resolveCodexAppServerHomeDir, F as resolveCodexTurnCompletionIdleTimeoutMs, H as isCodexAppServerConnectionClosedError, I as resolveCodexTurnTerminalIdleTimeoutMs, K as isCodexAppServerRequestTimeoutError, L as withCodexStartupTimeout, M as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, N as resolveCodexStartupTimeoutMs, O as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, P as resolveCodexTurnAssistantCompletionIdleTimeoutMs, Q as isJsonObject, R as CodexAppServerRpcError, S as resolveCodexAppServerAuthProfileIdForAgent, T as resolveCodexAppServerPreparedAuthHandoff, V as isCodexAppServerBrokenPipeError, Z as flattenCodexDynamicToolFunctions, _ as readCodexRateLimitsRevision, a as getLeasedSharedCodexAppServerClient, b as resolveCodexAppServerAuthAccountCacheKey, c as releaseLeasedSharedCodexAppServerClient, d as retireSharedCodexAppServerClientIfCurrent, g as ensureCodexAppServerClientRuntime, k as CodexAppServerStartupError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent, u as retainSharedCodexAppServerClientIfCurrent, v as readRecentCodexRateLimits, w as resolveCodexAppServerPreparedApiKeyCacheKey, x as resolveCodexAppServerAuthProfileId, y as rememberCodexRateLimitsRead } from "./shared-client-wmgNFNYp.js";
|
|
2
|
+
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-DdmnBMUp.js";
|
|
3
|
+
import { A as withMcpElicitationsApprovalPolicy, E as resolveCodexPluginsPolicy, O as resolveOpenClawExecPolicyForCodexAppServer, T as resolveCodexModelBackedReviewerPolicyContext, _ as isCodexAppServerApprovalPolicyAllowedByRequirements, b as readCodexPluginConfig, c as reclaimCurrentCodexSessionGeneration, i as createCodexSessionGenerationSupersededError, k as shouldAutoApproveCodexAppServerApprovals, l as sessionBindingIdentity, w as resolveCodexComputerUseConfig, y as isCodexSandboxExecServerEnabled } from "./session-binding-ZSMX1omP.js";
|
|
4
|
+
import { $ as shouldBuildCodexPluginThreadConfig, B as codexDynamicToolsFingerprint, F as closeCodexStartupClientBestEffort, G as projectContextEngineAssemblyForCodex, H as buildContextEngineBinding, I as interruptCodexTurnBestEffort, K as resolveCodexContextEngineProjectionMaxChars, L as retireCodexAppServerClientAfterTimedOutTurn, M as CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS, N as CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS, O as isSystemAgentOnlyCodexDynamicToolAllowlist, P as CodexAppServerUnsafeSubscriptionError, Q as mergeCodexThreadConfigs, R as unsubscribeCodexThreadBestEffort, T as filterCodexDynamicTools, U as isContextEngineBindingCompatible, V as codexLegacyDynamicToolsFingerprint, W as fitCodexProjectedContextForTurnStart, X as buildCodexPluginThreadConfigInputFingerprint, Y as buildCodexPluginThreadConfig, Z as buildCodexPluginThreadConfigTimeoutFallback, a as sanitizeCodexHistoryImagePayloads, at as readCodexErrorNotificationMessage, b as resolveCodexAppServerThreadModelSelection, ct as readItemString, dt as readNonNegativeInteger, ft as readNullableString$1, g as buildDeveloperInstructions, h as resolveCodexWebSearchPlan, ht as splitPlanText, it as normalizeNonEmptyString, j as resolveCodexDynamicToolsLoadingForRuntime, lt as readNonEmptyString$1, mt as readString$5, n as buildTurnStartParams, nt as resolveRecoverableCodexPluginConfigKeys, ot as readHookOutputEntries, pt as readNumber, q as resolveCodexContextEngineProjectionReserveTokens, r as buildCodexUserInput, rt as extractRawAssistantText, s as startOrResumeThread, st as readItem, t as buildTurnCollaborationMode, ut as readNonEmptyStringArray, w as isCodexAppServerProfilerEnabled, z as areCodexDynamicToolFingerprintsCompatible } from "./thread-lifecycle-cqrOlJkq.js";
|
|
5
|
+
import { n as projectCodexThreadUsageUpdate, t as normalizeCodexResponseTokenUsage } from "./event-projector-usage-D6tE7_qD.js";
|
|
6
|
+
import { C as readCodexTurnCompletedNotification, S as readCodexTurn, d as attachCodexMirrorIdentity, f as readMirrorIdentity, i as mirrorPromptAtTurnStartBestEffort, n as createCodexAppServerUserMessagePersistenceNotifier, o as buildCodexUserPromptMessage, s as promptSnapshot, t as codexTranscriptMirrorRuntime, u as serializeCodexMirrorSourceEvidence, v as assertCodexTurnStartResponse, y as readCodexDynamicToolCallParams } from "./transcript-mirror-2p7kl6e4.js";
|
|
7
|
+
import { i as defaultCodexAppInventoryCache, n as buildCodexAppServerRuntimeFingerprint, r as buildCodexPluginAppCacheKey } from "./plugin-app-cache-key-CvzvmBRz.js";
|
|
8
|
+
import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
|
|
9
|
+
import { t as CODEX_CONTROL_METHODS } from "./capabilities-CLICvTxf.js";
|
|
10
|
+
import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-D0IJT-a6.js";
|
|
11
|
+
import { r as formatCodexDisplayText } from "./command-formatters-DgADqnHa.js";
|
|
12
|
+
import { n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BO3jYBkv.js";
|
|
13
|
+
import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId, t as isCodexNotificationForTurn } from "./notification-correlation-BGLixv5_.js";
|
|
10
14
|
import { n as prepareCodexAppServerAuthBinding } from "./auth-binding-C1czuHPA.js";
|
|
11
|
-
import {
|
|
12
|
-
import { a as
|
|
15
|
+
import { i as resolveCodexLocalRuntimeAttribution, n as createAssistantMessage, r as createAssistantMirrorMessage, t as createAssistantCommentaryMessage } from "./event-projector-assistant-message-DTgnPPVF.js";
|
|
16
|
+
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-CQI3UwqY.js";
|
|
17
|
+
import { a as runCodexComputerUseLiveTest, r as killStaleComputerUseMcpChildren, t as ensureCodexComputerUse } from "./computer-use-Ip1-QGa-.js";
|
|
13
18
|
import fs from "node:fs/promises";
|
|
14
19
|
import path, { posix } from "node:path";
|
|
15
|
-
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
20
|
+
import { asDateTimestampMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
16
21
|
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
17
22
|
import { createHash, randomUUID } from "node:crypto";
|
|
18
|
-
import { resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
23
|
+
import { markAuthProfileBlockedUntil, resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
19
24
|
import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
|
|
20
25
|
import { asFiniteNumber, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
21
|
-
import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, cancelPendingAgentQuestionForSession, claimPendingAgentQuestionAnswer, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, isActiveHarnessContextEngine, isHostScopedAgentToolActive, loadCodexBundleMcpThreadConfig, materializeRequesterScopedMcpToolsForHarnessRun, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
26
|
+
import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, 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, projectAgentHarnessTranscriptMessageForDisplay, resolveAgentDir as resolveAgentDir$1, resolveAgentHarnessBeforePromptBuildResult, resolveAgentRunAbortLifecycleFields, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessGatewayQuestion, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
22
27
|
import { spawn } from "node:child_process";
|
|
23
28
|
import { once } from "node:events";
|
|
24
29
|
import { isIP } from "node:net";
|
|
25
30
|
import { WebSocketServer } from "ws";
|
|
26
|
-
import { parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
31
|
+
import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
|
|
27
32
|
import { fileURLToPath } from "node:url";
|
|
33
|
+
import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
28
34
|
import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent, emitTrustedDiagnosticEventWithPrivateData, freezeDiagnosticTraceContext, onInternalDiagnosticEvent, resolveDiagnosticModelContentCapturePolicy } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
35
|
+
import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
|
|
29
36
|
import { prepareMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
|
|
37
|
+
import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
|
|
38
|
+
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
|
|
39
|
+
import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
|
|
40
|
+
import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
|
|
30
41
|
import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
|
|
31
42
|
import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
|
|
32
43
|
import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
@@ -190,6 +201,2430 @@ function normalizeCodexSteerDebounceMs(value) {
|
|
|
190
201
|
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : CODEX_STEER_ALL_DEBOUNCE_MS;
|
|
191
202
|
}
|
|
192
203
|
//#endregion
|
|
204
|
+
//#region extensions/codex/src/app-server/event-projector-assistant.ts
|
|
205
|
+
var CodexAssistantProjection = class {
|
|
206
|
+
constructor(params, emitAgentEvent, matchesToolProgressEcho, nextTranscriptTimestamp) {
|
|
207
|
+
this.params = params;
|
|
208
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
209
|
+
this.matchesToolProgressEcho = matchesToolProgressEcho;
|
|
210
|
+
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
211
|
+
this.assistantTextByItem = /* @__PURE__ */ new Map();
|
|
212
|
+
this.assistantItemOrder = [];
|
|
213
|
+
this.assistantTimestampByItem = /* @__PURE__ */ new Map();
|
|
214
|
+
this.assistantPhaseByItem = /* @__PURE__ */ new Map();
|
|
215
|
+
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
216
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
217
|
+
this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
|
|
218
|
+
this.lastCommentaryProgressTextByItem = /* @__PURE__ */ new Map();
|
|
219
|
+
this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
|
|
220
|
+
this.pendingRawCommentaryEchoes = 0;
|
|
221
|
+
this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
|
|
222
|
+
this.assistantStarted = false;
|
|
223
|
+
this.streamedPartialAssistantItemReplaceable = false;
|
|
224
|
+
}
|
|
225
|
+
hasCompletedTerminalAssistantText(completedItemIds) {
|
|
226
|
+
const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
|
|
227
|
+
if (!latestCompletedItemId) return false;
|
|
228
|
+
const finalItem = this.resolveFinalAssistantTextItem();
|
|
229
|
+
return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
|
|
230
|
+
}
|
|
231
|
+
getLatestTerminalAssistantCandidate() {
|
|
232
|
+
const itemId = this.latestTerminalAssistantCandidateItemId;
|
|
233
|
+
if (!itemId) return;
|
|
234
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
235
|
+
return {
|
|
236
|
+
itemId,
|
|
237
|
+
hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
hasLatestTerminalAssistantCandidateText() {
|
|
241
|
+
return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
|
|
242
|
+
}
|
|
243
|
+
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
244
|
+
return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
|
|
245
|
+
}
|
|
246
|
+
async handleAssistantDelta(params) {
|
|
247
|
+
const itemId = readString$5(params, "itemId") ?? "assistant";
|
|
248
|
+
const delta = readString$5(params, "delta") ?? "";
|
|
249
|
+
if (!delta) return;
|
|
250
|
+
if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
251
|
+
const isCommentary = this.isCommentaryAssistantItem(itemId);
|
|
252
|
+
if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
|
|
253
|
+
if (!this.assistantStarted) {
|
|
254
|
+
this.assistantStarted = true;
|
|
255
|
+
await this.params.onAssistantMessageStart?.();
|
|
256
|
+
}
|
|
257
|
+
this.rememberAssistantItem(itemId);
|
|
258
|
+
const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
|
|
259
|
+
this.assistantTextByItem.set(itemId, text);
|
|
260
|
+
if (isCommentary) {
|
|
261
|
+
this.emitCommentaryProgress({
|
|
262
|
+
itemId,
|
|
263
|
+
text
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (this.isFinalAnswerAssistantItem(itemId)) this.emitAnswerCandidate(itemId, "candidate");
|
|
268
|
+
const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
|
|
269
|
+
const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
|
|
270
|
+
if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
|
|
271
|
+
else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
|
|
272
|
+
this.streamedPartialAssistantItemId = itemId;
|
|
273
|
+
const replaceable = this.streamedPartialAssistantItemReplaceable;
|
|
274
|
+
const replacement = replace && replaceable;
|
|
275
|
+
const streamPayload = {
|
|
276
|
+
text,
|
|
277
|
+
delta: replacement ? "" : delta,
|
|
278
|
+
...replacement ? { replace: true } : {}
|
|
279
|
+
};
|
|
280
|
+
this.emitAgentEvent({
|
|
281
|
+
stream: "assistant",
|
|
282
|
+
data: {
|
|
283
|
+
...streamPayload,
|
|
284
|
+
...replaceable ? { replaceable: true } : {}
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
|
|
288
|
+
}
|
|
289
|
+
recordItemStarted(item, itemId) {
|
|
290
|
+
if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
291
|
+
this.rememberAssistantPhase(item);
|
|
292
|
+
if (item?.type === "agentMessage" && itemId) this.rememberAssistantItem(itemId);
|
|
293
|
+
if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
|
|
294
|
+
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
295
|
+
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
recordItemCompleted(item, itemId, activeItemIds) {
|
|
299
|
+
if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
300
|
+
if (itemId) this.latestCompletedItemId = itemId;
|
|
301
|
+
this.rememberAssistantPhase(item);
|
|
302
|
+
if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
|
|
303
|
+
this.latestCompletedTerminalAssistantItemId = item.id;
|
|
304
|
+
this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
|
|
305
|
+
this.pendingRawTerminalAssistantEchoItemId = item.id;
|
|
306
|
+
} else if (itemId) {
|
|
307
|
+
this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
|
|
308
|
+
if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
309
|
+
}
|
|
310
|
+
if (item?.type === "agentMessage" && typeof item.text === "string") {
|
|
311
|
+
this.rememberAssistantItem(item.id);
|
|
312
|
+
this.assistantTextByItem.set(item.id, item.text);
|
|
313
|
+
if (item.text && this.isCommentaryAssistantItem(item.id)) {
|
|
314
|
+
this.emitCommentaryProgress({
|
|
315
|
+
itemId: item.id,
|
|
316
|
+
text: item.text
|
|
317
|
+
});
|
|
318
|
+
this.pendingRawCommentaryEchoes += 1;
|
|
319
|
+
} else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
recordSnapshotItem(item) {
|
|
323
|
+
this.rememberAssistantPhase(item);
|
|
324
|
+
if (item.type === "agentMessage" && typeof item.text === "string") {
|
|
325
|
+
this.rememberAssistantItem(item.id);
|
|
326
|
+
this.assistantTextByItem.set(item.id, item.text);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
handleRawResponseItemCompleted(item, activeItemIds) {
|
|
330
|
+
const role = readString$5(item, "role");
|
|
331
|
+
const phase = readString$5(item, "phase");
|
|
332
|
+
const rawItemId = readString$5(item, "id");
|
|
333
|
+
const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
|
|
334
|
+
const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
|
|
335
|
+
const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
|
|
336
|
+
if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
337
|
+
if (!isPendingTerminalAssistantEcho) {
|
|
338
|
+
this.latestCompletedItemId = void 0;
|
|
339
|
+
this.markTerminalAssistantCandidateSupersededBy(rawItemId);
|
|
340
|
+
}
|
|
341
|
+
if (role !== "assistant") return;
|
|
342
|
+
if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
|
|
343
|
+
this.pendingRawCommentaryEchoes -= 1;
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const text = extractRawAssistantText(item);
|
|
347
|
+
if (isPendingTerminalAssistantEcho) {
|
|
348
|
+
const typedItemId = pendingTerminalAssistantEchoItemId;
|
|
349
|
+
this.pendingRawTerminalAssistantEchoItemId = void 0;
|
|
350
|
+
if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
|
|
351
|
+
this.rememberAssistantItem(typedItemId);
|
|
352
|
+
this.assistantTextByItem.set(typedItemId, text);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
if (!text) return;
|
|
356
|
+
const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
|
|
357
|
+
const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
|
|
358
|
+
if (phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
|
|
359
|
+
if (phase) this.assistantPhaseByItem.set(itemId, phase);
|
|
360
|
+
this.rememberAssistantItem(itemId);
|
|
361
|
+
this.assistantTextByItem.set(itemId, text);
|
|
362
|
+
this.rawPromotedAssistantItemIds.add(itemId);
|
|
363
|
+
if (phase === "commentary") this.emitCommentaryProgress({
|
|
364
|
+
itemId,
|
|
365
|
+
text
|
|
366
|
+
});
|
|
367
|
+
else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
|
|
368
|
+
}
|
|
369
|
+
collectAssistantTexts() {
|
|
370
|
+
const finalText = this.resolveFinalAssistantTextItem()?.text;
|
|
371
|
+
return finalText ? [finalText] : [];
|
|
372
|
+
}
|
|
373
|
+
collectCommentaryMessages() {
|
|
374
|
+
return this.assistantItemOrder.flatMap((itemId) => {
|
|
375
|
+
if (!this.isCommentaryAssistantItem(itemId)) return [];
|
|
376
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
377
|
+
const timestamp = this.assistantTimestampByItem.get(itemId);
|
|
378
|
+
if (!text || timestamp === void 0) return [];
|
|
379
|
+
return [{
|
|
380
|
+
itemId,
|
|
381
|
+
message: createAssistantCommentaryMessage(this.params, text, itemId, timestamp)
|
|
382
|
+
}];
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
finalizeAnswerCandidate(turn) {
|
|
386
|
+
if (turn.status !== "completed") {
|
|
387
|
+
this.supersedeVisibleAnswerCandidate();
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const turnItems = turn.items ?? [];
|
|
391
|
+
const authoritativeIndex = turnItems.findLastIndex((item) => item.type === "agentMessage" && readItemString(item, "phase") === "final_answer" && typeof item.text === "string" && item.text.trim().length > 0);
|
|
392
|
+
const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
|
|
393
|
+
if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
|
|
394
|
+
this.supersedeVisibleAnswerCandidate();
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const itemId = authoritative?.id ?? this.visibleAnswerCandidateItemId;
|
|
398
|
+
if (!itemId) return;
|
|
399
|
+
if (itemId !== this.visibleAnswerCandidateItemId) {
|
|
400
|
+
this.supersedeVisibleAnswerCandidate();
|
|
401
|
+
this.visibleAnswerCandidateItemId = itemId;
|
|
402
|
+
}
|
|
403
|
+
this.emitAnswerCandidate(itemId, "selected");
|
|
404
|
+
}
|
|
405
|
+
hasAssistantItemTextForSynthesis() {
|
|
406
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
407
|
+
const itemId = this.assistantItemOrder[i];
|
|
408
|
+
if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
|
|
409
|
+
const text = this.assistantTextByItem.get(itemId);
|
|
410
|
+
if (text && text.length > 0) return true;
|
|
411
|
+
}
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
createCurrentAttemptAssistantMessage(options) {
|
|
415
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
416
|
+
const itemId = this.assistantItemOrder[i];
|
|
417
|
+
if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
|
|
418
|
+
const text = this.assistantTextByItem.get(itemId) ?? "";
|
|
419
|
+
const normalizedText = text.trim();
|
|
420
|
+
if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
|
|
421
|
+
return this.createAssistantMessage(text, options);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
createAssistantMessage(text, options) {
|
|
425
|
+
return createAssistantMessage(this.params, text, options);
|
|
426
|
+
}
|
|
427
|
+
createAssistantMirrorMessage(title, text) {
|
|
428
|
+
return createAssistantMirrorMessage(this.params, title, text);
|
|
429
|
+
}
|
|
430
|
+
rememberAssistantPhase(item) {
|
|
431
|
+
if (item?.type !== "agentMessage") return;
|
|
432
|
+
const phase = readItemString(item, "phase");
|
|
433
|
+
if (phase) this.assistantPhaseByItem.set(item.id, phase);
|
|
434
|
+
}
|
|
435
|
+
isCommentaryAssistantItem(itemId) {
|
|
436
|
+
return this.assistantPhaseByItem.get(itemId) === "commentary";
|
|
437
|
+
}
|
|
438
|
+
isFinalAnswerAssistantItem(itemId) {
|
|
439
|
+
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
440
|
+
}
|
|
441
|
+
shouldStreamAssistantPartial(itemId) {
|
|
442
|
+
return this.assistantPhaseByItem.get(itemId) === "final_answer";
|
|
443
|
+
}
|
|
444
|
+
emitCommentaryProgress(params) {
|
|
445
|
+
const progressText = params.text.replace(/\s+/g, " ").trim();
|
|
446
|
+
if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
|
|
447
|
+
this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
|
|
448
|
+
this.emitAgentEvent({
|
|
449
|
+
stream: "item",
|
|
450
|
+
data: {
|
|
451
|
+
itemId: params.itemId,
|
|
452
|
+
kind: "preamble",
|
|
453
|
+
title: "Preamble",
|
|
454
|
+
phase: "update",
|
|
455
|
+
progressText,
|
|
456
|
+
source: "codex-app-server"
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
emitAnswerCandidate(itemId, status) {
|
|
461
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
462
|
+
if (!text) return;
|
|
463
|
+
if (status === "candidate" && this.visibleAnswerCandidateItemId !== itemId) {
|
|
464
|
+
this.supersedeVisibleAnswerCandidate();
|
|
465
|
+
this.visibleAnswerCandidateItemId = itemId;
|
|
466
|
+
}
|
|
467
|
+
const signature = `${status}\0${text}`;
|
|
468
|
+
if (this.lastAnswerCandidateEventByItem.get(itemId) === signature) return;
|
|
469
|
+
this.lastAnswerCandidateEventByItem.set(itemId, signature);
|
|
470
|
+
this.emitAgentEvent({
|
|
471
|
+
stream: "item",
|
|
472
|
+
data: {
|
|
473
|
+
itemId,
|
|
474
|
+
kind: "answer_candidate",
|
|
475
|
+
title: "Answer candidate",
|
|
476
|
+
phase: "update",
|
|
477
|
+
status,
|
|
478
|
+
progressText: text,
|
|
479
|
+
source: "codex-app-server",
|
|
480
|
+
hideFromChannelProgress: true
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
supersedeVisibleAnswerCandidate() {
|
|
485
|
+
const itemId = this.visibleAnswerCandidateItemId;
|
|
486
|
+
if (!itemId) return;
|
|
487
|
+
this.emitAnswerCandidate(itemId, "superseded");
|
|
488
|
+
this.visibleAnswerCandidateItemId = void 0;
|
|
489
|
+
}
|
|
490
|
+
markLatestTerminalAssistantCandidate(itemId, activeItemIds, options) {
|
|
491
|
+
this.latestTerminalAssistantCandidateItemId = itemId;
|
|
492
|
+
this.latestTerminalAssistantCandidateSuperseded = false;
|
|
493
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
|
|
494
|
+
this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
|
|
495
|
+
}
|
|
496
|
+
markTerminalAssistantCandidateSupersededBy(itemId, options) {
|
|
497
|
+
if (!this.latestTerminalAssistantCandidateItemId) return;
|
|
498
|
+
if (itemId && this.terminalAssistantCandidateEarlierActiveItemIds.has(itemId)) {
|
|
499
|
+
if (!options?.preserveEarlierActiveItem) this.terminalAssistantCandidateEarlierActiveItemIds.delete(itemId);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
this.latestTerminalAssistantCandidateSuperseded = true;
|
|
503
|
+
this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
|
|
504
|
+
this.terminalAssistantCandidateEarlierActiveItemIds.clear();
|
|
505
|
+
this.supersedeVisibleAnswerCandidate();
|
|
506
|
+
}
|
|
507
|
+
resolveFinalAssistantTextItem() {
|
|
508
|
+
for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
|
|
509
|
+
const itemId = this.assistantItemOrder[i];
|
|
510
|
+
if (!itemId) continue;
|
|
511
|
+
const text = this.assistantTextByItem.get(itemId)?.trim();
|
|
512
|
+
if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
|
|
513
|
+
if (text && !this.isToolProgressEchoText(itemId, text)) return {
|
|
514
|
+
itemId,
|
|
515
|
+
text
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
rememberAssistantItem(itemId) {
|
|
520
|
+
if (!itemId || this.assistantItemOrder.includes(itemId)) return;
|
|
521
|
+
this.assistantItemOrder.push(itemId);
|
|
522
|
+
this.assistantTimestampByItem.set(itemId, this.nextTranscriptTimestamp());
|
|
523
|
+
}
|
|
524
|
+
isToolProgressEchoText(itemId, text) {
|
|
525
|
+
return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
//#endregion
|
|
529
|
+
//#region extensions/codex/src/app-server/event-projector-diagnostics.ts
|
|
530
|
+
function redactCodexEventKind(method) {
|
|
531
|
+
return redactSensitiveText(sanitizeTerminalText(method));
|
|
532
|
+
}
|
|
533
|
+
var CodexProjectionDiagnostics = class {
|
|
534
|
+
constructor(threadId, turnId) {
|
|
535
|
+
this.threadId = threadId;
|
|
536
|
+
this.turnId = turnId;
|
|
537
|
+
this.warningKeys = /* @__PURE__ */ new Set();
|
|
538
|
+
}
|
|
539
|
+
warnUnknownItemStatus(item) {
|
|
540
|
+
if (!item) return;
|
|
541
|
+
const status = unknownItemStatus(item);
|
|
542
|
+
if (!status) return;
|
|
543
|
+
const safeStatus = redactCodexEventKind(status);
|
|
544
|
+
const safeItemType = redactCodexEventKind(item.type);
|
|
545
|
+
this.warnOnce(JSON.stringify([
|
|
546
|
+
"status",
|
|
547
|
+
item.type,
|
|
548
|
+
status
|
|
549
|
+
]), "codex app-server item reported unknown status; continuing projection", {
|
|
550
|
+
itemId: item.id,
|
|
551
|
+
itemType: safeItemType,
|
|
552
|
+
status: safeStatus
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
warnUnknownEvent(notification, params) {
|
|
556
|
+
const notificationThreadId = readCodexNotificationThreadId(params);
|
|
557
|
+
const notificationTurnId = readCodexNotificationTurnId(params);
|
|
558
|
+
const eventKind = redactCodexEventKind(notification.method);
|
|
559
|
+
this.warnOnce(JSON.stringify(["method", notification.method]), `codex app-server projector received unknown event kind; continuing: ${eventKind}`, {
|
|
560
|
+
eventKind,
|
|
561
|
+
activeThreadId: this.threadId,
|
|
562
|
+
activeTurnId: this.turnId,
|
|
563
|
+
threadId: notificationThreadId,
|
|
564
|
+
turnId: notificationTurnId,
|
|
565
|
+
matchesActiveThread: notificationThreadId === this.threadId,
|
|
566
|
+
matchesActiveTurn: notificationTurnId === this.turnId
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
warnOnce(key, message, context) {
|
|
570
|
+
if (this.warningKeys.has(key)) return;
|
|
571
|
+
this.warningKeys.add(key);
|
|
572
|
+
embeddedAgentLog.warn(message, context);
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region extensions/codex/src/app-server/event-projector-tool-output.ts
|
|
577
|
+
const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 1e4;
|
|
578
|
+
const TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX = "...(OpenClaw truncated Codex native tool output";
|
|
579
|
+
var ToolOutputAccumulator = class {
|
|
580
|
+
constructor() {
|
|
581
|
+
this.prefixByItem = /* @__PURE__ */ new Map();
|
|
582
|
+
this.originalLengthByItem = /* @__PURE__ */ new Map();
|
|
583
|
+
this.normalizedLengthByItem = /* @__PURE__ */ new Map();
|
|
584
|
+
this.trimStateByItem = /* @__PURE__ */ new Map();
|
|
585
|
+
this.truncatedItemIds = /* @__PURE__ */ new Set();
|
|
586
|
+
this.textByItem = /* @__PURE__ */ new Map();
|
|
587
|
+
}
|
|
588
|
+
append(itemId, delta) {
|
|
589
|
+
const originalLength = (this.originalLengthByItem.get(itemId) ?? this.textByItem.get(itemId)?.length ?? 0) + delta.length;
|
|
590
|
+
this.originalLengthByItem.set(itemId, originalLength);
|
|
591
|
+
const normalizedLength = updateToolOutputTrimState(this.trimStateByItem, itemId, delta);
|
|
592
|
+
this.normalizedLengthByItem.set(itemId, normalizedLength);
|
|
593
|
+
if (this.truncatedItemIds.has(itemId)) {
|
|
594
|
+
const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", "", originalLength);
|
|
595
|
+
this.prefixByItem.set(itemId, next.rawPrefix);
|
|
596
|
+
this.textByItem.set(itemId, next.text);
|
|
597
|
+
return {
|
|
598
|
+
text: next.text,
|
|
599
|
+
originalLength,
|
|
600
|
+
normalizedLength,
|
|
601
|
+
rawPrefix: next.rawPrefix
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", delta, originalLength);
|
|
605
|
+
this.prefixByItem.set(itemId, next.rawPrefix);
|
|
606
|
+
this.textByItem.set(itemId, next.text);
|
|
607
|
+
if (originalLength > 1e4) this.truncatedItemIds.add(itemId);
|
|
608
|
+
return {
|
|
609
|
+
text: next.text,
|
|
610
|
+
originalLength,
|
|
611
|
+
normalizedLength,
|
|
612
|
+
rawPrefix: next.rawPrefix
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
function updateToolOutputTrimState(trimStateByItem, itemId, delta) {
|
|
617
|
+
const state = trimStateByItem.get(itemId) ?? {
|
|
618
|
+
totalLength: 0,
|
|
619
|
+
leadingWhitespaceLength: 0,
|
|
620
|
+
trailingWhitespaceLength: 0,
|
|
621
|
+
sawNonWhitespace: false
|
|
622
|
+
};
|
|
623
|
+
state.totalLength += delta.length;
|
|
624
|
+
const firstNonWhitespace = delta.search(/\S/u);
|
|
625
|
+
if (firstNonWhitespace === -1) {
|
|
626
|
+
if (!state.sawNonWhitespace) state.leadingWhitespaceLength += delta.length;
|
|
627
|
+
state.trailingWhitespaceLength += delta.length;
|
|
628
|
+
trimStateByItem.set(itemId, state);
|
|
629
|
+
return state.sawNonWhitespace ? state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength : 0;
|
|
630
|
+
}
|
|
631
|
+
if (!state.sawNonWhitespace) {
|
|
632
|
+
state.leadingWhitespaceLength += firstNonWhitespace;
|
|
633
|
+
state.sawNonWhitespace = true;
|
|
634
|
+
}
|
|
635
|
+
state.trailingWhitespaceLength = delta.match(/\s*$/u)?.[0].length ?? 0;
|
|
636
|
+
trimStateByItem.set(itemId, state);
|
|
637
|
+
return state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength;
|
|
638
|
+
}
|
|
639
|
+
function toolOutputRawEchoSignature(text) {
|
|
640
|
+
const trimmed = text.trim();
|
|
641
|
+
if (!trimmed) return;
|
|
642
|
+
return {
|
|
643
|
+
rawLength: trimmed.length,
|
|
644
|
+
rawPrefix: trimmed.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
function normalizeToolTranscriptArguments(value) {
|
|
648
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
649
|
+
return value;
|
|
650
|
+
}
|
|
651
|
+
function collectDynamicToolContentText(contentItems) {
|
|
652
|
+
if (!Array.isArray(contentItems)) return "";
|
|
653
|
+
return contentItems.flatMap((entry) => {
|
|
654
|
+
if (!isJsonObject(entry)) return [];
|
|
655
|
+
const text = readString$5(entry, "text");
|
|
656
|
+
return text ? [text] : [];
|
|
657
|
+
}).join("\n");
|
|
658
|
+
}
|
|
659
|
+
function appendBoundedToolTranscriptText(currentPrefix, delta, originalLength) {
|
|
660
|
+
if (originalLength <= 1e4) {
|
|
661
|
+
const rawPrefix = currentPrefix + delta;
|
|
662
|
+
return {
|
|
663
|
+
text: rawPrefix,
|
|
664
|
+
rawPrefix
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const notice = toolTranscriptTruncationNotice(originalLength);
|
|
668
|
+
if (notice.length >= 1e4) return {
|
|
669
|
+
text: notice.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS),
|
|
670
|
+
rawPrefix: ""
|
|
671
|
+
};
|
|
672
|
+
const textBudget = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length;
|
|
673
|
+
const remaining = Math.max(0, textBudget - currentPrefix.length);
|
|
674
|
+
const rawPrefix = truncateUtf16Safe(remaining > 0 ? `${currentPrefix}${truncateUtf16Safe(delta, remaining)}` : currentPrefix, textBudget);
|
|
675
|
+
return {
|
|
676
|
+
text: `${rawPrefix}${notice}`,
|
|
677
|
+
rawPrefix
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function toolTranscriptTruncationNotice(originalLength) {
|
|
681
|
+
return `\n${`${TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX}: original ${originalLength} chars, showing ${TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS}; rerun with narrower args.)`}`;
|
|
682
|
+
}
|
|
683
|
+
function truncateToolTranscriptText(text, originalLength = text.length) {
|
|
684
|
+
if (originalLength <= 1e4 && text.length <= 1e4) return text;
|
|
685
|
+
const notice = toolTranscriptTruncationNotice(originalLength);
|
|
686
|
+
if (notice.length >= 1e4) return notice.slice(1, 10001);
|
|
687
|
+
return `${truncateUtf16Safe(text, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length)}${notice}`;
|
|
688
|
+
}
|
|
689
|
+
function formatToolSummary(toolName, meta) {
|
|
690
|
+
const trimmedMeta = meta?.trim();
|
|
691
|
+
return formatToolAggregate(toolName, trimmedMeta ? [trimmedMeta] : void 0, { markdown: true });
|
|
692
|
+
}
|
|
693
|
+
function formatToolOutput(toolName, meta, output) {
|
|
694
|
+
const formattedOutput = formatToolProgressOutput(output);
|
|
695
|
+
if (!formattedOutput) return formatToolSummary(toolName, meta);
|
|
696
|
+
const fence = markdownFenceForText(formattedOutput);
|
|
697
|
+
return `${formatToolSummary(toolName, meta)}\n${fence}txt\n${formattedOutput}\n${fence}`;
|
|
698
|
+
}
|
|
699
|
+
function markdownFenceForText(text) {
|
|
700
|
+
return "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
|
|
701
|
+
}
|
|
702
|
+
function longestBacktickRun(value) {
|
|
703
|
+
let longest = 0;
|
|
704
|
+
let current = 0;
|
|
705
|
+
for (const char of value) {
|
|
706
|
+
if (char === "`") {
|
|
707
|
+
current += 1;
|
|
708
|
+
longest = Math.max(longest, current);
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
current = 0;
|
|
712
|
+
}
|
|
713
|
+
return longest;
|
|
714
|
+
}
|
|
715
|
+
//#endregion
|
|
716
|
+
//#region extensions/codex/src/app-server/tool-progress-normalization.ts
|
|
717
|
+
/**
|
|
718
|
+
* Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
|
|
719
|
+
* emitted into OpenClaw events or logs.
|
|
720
|
+
*/
|
|
721
|
+
/** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
|
|
722
|
+
function resolveCodexToolProgressDetailMode(value) {
|
|
723
|
+
return value === "raw" ? "raw" : "explain";
|
|
724
|
+
}
|
|
725
|
+
/** Recursively redacts sensitive strings and handles circular values in event payloads. */
|
|
726
|
+
function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
727
|
+
if (typeof value === "string") return redactToolPayloadText(value);
|
|
728
|
+
if (Array.isArray(value)) {
|
|
729
|
+
if (seen.has(value)) return "[Circular]";
|
|
730
|
+
seen.add(value);
|
|
731
|
+
return value.map((entry) => sanitizeCodexAgentEventValue(entry, seen));
|
|
732
|
+
}
|
|
733
|
+
if (value && typeof value === "object") {
|
|
734
|
+
if (seen.has(value)) return "[Circular]";
|
|
735
|
+
seen.add(value);
|
|
736
|
+
const out = {};
|
|
737
|
+
for (const [key, child] of Object.entries(value)) out[key] = typeof child === "string" ? redactSensitiveFieldValue(key, child) : sanitizeCodexAgentEventValue(child, seen);
|
|
738
|
+
return out;
|
|
739
|
+
}
|
|
740
|
+
return value;
|
|
741
|
+
}
|
|
742
|
+
/** Sanitizes a record-shaped Codex agent event payload. */
|
|
743
|
+
function sanitizeCodexAgentEventRecord(value) {
|
|
744
|
+
return sanitizeCodexAgentEventValue(value);
|
|
745
|
+
}
|
|
746
|
+
/** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
|
|
747
|
+
function sanitizeCodexToolArguments(value) {
|
|
748
|
+
if (!isJsonObject(value)) return;
|
|
749
|
+
return sanitizeCodexAgentEventRecord(value);
|
|
750
|
+
}
|
|
751
|
+
/** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
|
|
752
|
+
function sanitizeCodexToolResponse(response) {
|
|
753
|
+
return sanitizeCodexAgentEventRecord(response);
|
|
754
|
+
}
|
|
755
|
+
/** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
|
|
756
|
+
function inferCodexDynamicToolMeta(call, detailMode) {
|
|
757
|
+
return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
|
|
758
|
+
}
|
|
759
|
+
//#endregion
|
|
760
|
+
//#region extensions/codex/src/app-server/event-projector-tool-items.ts
|
|
761
|
+
function nativeToolActionFingerprint(item) {
|
|
762
|
+
if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
|
|
763
|
+
type: item.type,
|
|
764
|
+
command: item.command,
|
|
765
|
+
cwd: typeof item.cwd === "string" ? item.cwd : ""
|
|
766
|
+
});
|
|
767
|
+
if (item.type === "fileChange") return JSON.stringify({
|
|
768
|
+
type: item.type,
|
|
769
|
+
changes: itemFileChanges(item)
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
function isNativePostToolUseRelayItem(item) {
|
|
773
|
+
switch (item.type) {
|
|
774
|
+
case "commandExecution":
|
|
775
|
+
case "fileChange":
|
|
776
|
+
case "mcpToolCall": return true;
|
|
777
|
+
default: return false;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
function shouldSuppressChannelProgressForItem(item) {
|
|
781
|
+
if (shouldSynthesizeToolProgressForItem(item)) return true;
|
|
782
|
+
return item.type === "dynamicToolCall";
|
|
783
|
+
}
|
|
784
|
+
function itemToolArgs(item) {
|
|
785
|
+
if (item.type === "commandExecution") return sanitizeCodexAgentEventRecord({
|
|
786
|
+
command: item.command,
|
|
787
|
+
...typeof item.cwd === "string" ? { cwd: item.cwd } : {}
|
|
788
|
+
});
|
|
789
|
+
if (item.type === "fileChange") return sanitizeCodexAgentEventRecord({ changes: itemFileChangesForTranscript(item) });
|
|
790
|
+
if (item.type === "webSearch") return webSearchToolArgs(item);
|
|
791
|
+
if (item.type === "dynamicToolCall" || item.type === "mcpToolCall") return sanitizeCodexToolArguments(item.arguments);
|
|
792
|
+
}
|
|
793
|
+
function webSearchToolArgs(item) {
|
|
794
|
+
const action = isJsonObject(item.action) ? item.action : void 0;
|
|
795
|
+
const actionType = action ? readNonEmptyString$1(action, "type") : void 0;
|
|
796
|
+
const queries = action && actionType === "search" ? readNonEmptyStringArray(action, "queries") : [];
|
|
797
|
+
const query = normalizeNonEmptyString(item.query) ?? (action && actionType === "search" ? readNonEmptyString$1(action, "query") : void 0) ?? queries[0];
|
|
798
|
+
const url = action ? readNonEmptyString$1(action, "url") : void 0;
|
|
799
|
+
const pattern = action ? readNonEmptyString$1(action, "pattern") : void 0;
|
|
800
|
+
const args = {};
|
|
801
|
+
if (query) args.query = query;
|
|
802
|
+
if (queries.length > 0) args.queries = queries;
|
|
803
|
+
if (actionType && actionType !== "search") args.action = actionType;
|
|
804
|
+
if (url) args.url = url;
|
|
805
|
+
if (pattern) args.pattern = pattern;
|
|
806
|
+
if (!query && !url && !pattern) args.queryUnavailable = true;
|
|
807
|
+
return sanitizeCodexAgentEventRecord(args);
|
|
808
|
+
}
|
|
809
|
+
function itemToolResult(item) {
|
|
810
|
+
if (item.type === "commandExecution") return { result: sanitizeCodexAgentEventRecord({
|
|
811
|
+
status: item.status,
|
|
812
|
+
exitCode: item.exitCode,
|
|
813
|
+
durationMs: item.durationMs
|
|
814
|
+
}) };
|
|
815
|
+
if (item.type === "fileChange") return { result: sanitizeCodexAgentEventRecord({
|
|
816
|
+
status: item.status,
|
|
817
|
+
changes: itemFileChanges(item)
|
|
818
|
+
}) };
|
|
819
|
+
if (item.type === "mcpToolCall") return { result: sanitizeCodexAgentEventRecord({
|
|
820
|
+
status: item.status,
|
|
821
|
+
durationMs: item.durationMs,
|
|
822
|
+
...item.error ? { error: item.error } : {},
|
|
823
|
+
...item.result ? { result: item.result } : {}
|
|
824
|
+
}) };
|
|
825
|
+
if (item.type === "webSearch") return { result: webSearchToolResult(item) };
|
|
826
|
+
return {};
|
|
827
|
+
}
|
|
828
|
+
function webSearchToolResult(item) {
|
|
829
|
+
return sanitizeCodexAgentEventRecord({
|
|
830
|
+
status: itemStatus(item),
|
|
831
|
+
...typeof item.durationMs === "number" ? { durationMs: item.durationMs } : {},
|
|
832
|
+
...webSearchToolArgs(item)
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
function itemFileChangeRecords(item) {
|
|
836
|
+
const changes = item.changes;
|
|
837
|
+
return Array.isArray(changes) ? changes.filter(isJsonObject) : [];
|
|
838
|
+
}
|
|
839
|
+
function itemFileChanges(item) {
|
|
840
|
+
return itemFileChangeRecords(item).flatMap((change) => {
|
|
841
|
+
const path = normalizeNonEmptyString(change.path);
|
|
842
|
+
if (!path || change.kind === void 0) return [];
|
|
843
|
+
return [{
|
|
844
|
+
path,
|
|
845
|
+
kind: change.kind
|
|
846
|
+
}];
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
function fileChangeKindType(kind) {
|
|
850
|
+
if (typeof kind === "string") return kind;
|
|
851
|
+
return isJsonObject(kind) ? normalizeNonEmptyString(kind.type) : void 0;
|
|
852
|
+
}
|
|
853
|
+
function countFileContentLines(content) {
|
|
854
|
+
if (!content) return 0;
|
|
855
|
+
const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
856
|
+
if (lines.length > 1 && lines.at(-1) === "") lines.pop();
|
|
857
|
+
return lines.length;
|
|
858
|
+
}
|
|
859
|
+
function fileChangeDiffStat(diff, kind) {
|
|
860
|
+
const kindType = fileChangeKindType(kind);
|
|
861
|
+
if (kindType === "add") return {
|
|
862
|
+
added: countFileContentLines(diff),
|
|
863
|
+
removed: 0
|
|
864
|
+
};
|
|
865
|
+
if (kindType === "delete") return {
|
|
866
|
+
added: 0,
|
|
867
|
+
removed: countFileContentLines(diff)
|
|
868
|
+
};
|
|
869
|
+
let added = 0;
|
|
870
|
+
let removed = 0;
|
|
871
|
+
let inHunk = false;
|
|
872
|
+
for (const line of diff.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
|
|
873
|
+
if (line.startsWith("@@")) {
|
|
874
|
+
inHunk = true;
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
if (!inHunk) continue;
|
|
878
|
+
if (line.startsWith("+")) added += 1;
|
|
879
|
+
else if (line.startsWith("-")) removed += 1;
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
added,
|
|
883
|
+
removed
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function truncateFileChangeDiffAtLineBoundary(diff, maxChars) {
|
|
887
|
+
if (diff.length <= maxChars) return { diff };
|
|
888
|
+
if (maxChars <= 0) return { diffTruncated: true };
|
|
889
|
+
const boundary = diff.lastIndexOf("\n", maxChars - 1);
|
|
890
|
+
return boundary >= 0 ? {
|
|
891
|
+
diff: diff.slice(0, boundary + 1),
|
|
892
|
+
diffTruncated: true
|
|
893
|
+
} : { diffTruncated: true };
|
|
894
|
+
}
|
|
895
|
+
function itemFileChangesForTranscript(item) {
|
|
896
|
+
let remainingDiffChars = 1e4;
|
|
897
|
+
return itemFileChangeRecords(item).flatMap((change) => {
|
|
898
|
+
const path = normalizeNonEmptyString(change.path);
|
|
899
|
+
if (!path || change.kind === void 0) return [];
|
|
900
|
+
const result = {
|
|
901
|
+
path,
|
|
902
|
+
kind: change.kind
|
|
903
|
+
};
|
|
904
|
+
if (typeof change.diff !== "string") return [result];
|
|
905
|
+
result.stat = fileChangeDiffStat(change.diff, change.kind);
|
|
906
|
+
const bounded = truncateFileChangeDiffAtLineBoundary(change.diff, remainingDiffChars);
|
|
907
|
+
if (bounded.diff !== void 0) {
|
|
908
|
+
result.diff = bounded.diff;
|
|
909
|
+
remainingDiffChars -= bounded.diff.length;
|
|
910
|
+
}
|
|
911
|
+
if (bounded.diffTruncated) result.diffTruncated = true;
|
|
912
|
+
return [result];
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
function itemToolError(item, status, outputTextByItem) {
|
|
916
|
+
if (status === "blocked") return "codex native tool blocked";
|
|
917
|
+
if (status !== "failed") return;
|
|
918
|
+
return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
|
|
919
|
+
}
|
|
920
|
+
function itemMeta(item, detailMode = "explain") {
|
|
921
|
+
if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
|
|
922
|
+
command: item.command,
|
|
923
|
+
cwd: typeof item.cwd === "string" ? item.cwd : void 0
|
|
924
|
+
}, { detailMode });
|
|
925
|
+
if (item.type === "webSearch") return inferToolMetaFromArgs("web_search", webSearchToolArgs(item), { detailMode });
|
|
926
|
+
const toolName = itemName(item);
|
|
927
|
+
if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
|
|
928
|
+
}
|
|
929
|
+
function itemOutputText(item, outputTextByItem) {
|
|
930
|
+
if (item.type === "commandExecution") {
|
|
931
|
+
const output = item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim();
|
|
932
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
933
|
+
}
|
|
934
|
+
if (item.type === "dynamicToolCall") {
|
|
935
|
+
const output = collectDynamicToolContentText(item.contentItems).trim();
|
|
936
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
937
|
+
}
|
|
938
|
+
if (item.type === "mcpToolCall") {
|
|
939
|
+
const output = item.error ? stringifyJsonValue(item.error) : item.result ? stringifyJsonValue(item.result) : void 0;
|
|
940
|
+
return output ? truncateToolTranscriptText(output) : void 0;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
function itemTranscriptResultText(item, outputTextByItem) {
|
|
944
|
+
const output = itemOutputText(item, outputTextByItem);
|
|
945
|
+
if (output) return output;
|
|
946
|
+
const result = itemToolResult(item).result;
|
|
947
|
+
const resultText = result ? stringifyJsonValue(result) : void 0;
|
|
948
|
+
return resultText ? truncateToolTranscriptText(resultText) : itemStatus(item);
|
|
949
|
+
}
|
|
950
|
+
function stringifyJsonValue(value) {
|
|
951
|
+
try {
|
|
952
|
+
return JSON.stringify(value, null, 2);
|
|
953
|
+
} catch {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region extensions/codex/src/app-server/event-projector-tool-progress.ts
|
|
959
|
+
const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
960
|
+
"message",
|
|
961
|
+
"messages",
|
|
962
|
+
"reply",
|
|
963
|
+
"send",
|
|
964
|
+
"reaction",
|
|
965
|
+
"react",
|
|
966
|
+
"typing"
|
|
967
|
+
]);
|
|
968
|
+
function shouldEmitTranscriptToolProgress(toolName, _args) {
|
|
969
|
+
const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
|
|
970
|
+
return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
|
|
971
|
+
}
|
|
972
|
+
var CodexToolProgressProjection = class {
|
|
973
|
+
constructor(params) {
|
|
974
|
+
this.params = params;
|
|
975
|
+
this.echoesByItem = /* @__PURE__ */ new Map();
|
|
976
|
+
this.resultSummaryItemIds = /* @__PURE__ */ new Set();
|
|
977
|
+
this.resultOutputItemIds = /* @__PURE__ */ new Set();
|
|
978
|
+
this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
|
|
979
|
+
this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
|
|
980
|
+
this.transcriptArgumentsById = /* @__PURE__ */ new Map();
|
|
981
|
+
this.resultOutputDeltaState = /* @__PURE__ */ new Map();
|
|
982
|
+
this.output = new ToolOutputAccumulator();
|
|
983
|
+
this.metas = /* @__PURE__ */ new Map();
|
|
984
|
+
this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
|
|
985
|
+
this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
|
|
986
|
+
this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
|
|
987
|
+
}
|
|
988
|
+
get outputTextByItem() {
|
|
989
|
+
return this.output.textByItem;
|
|
990
|
+
}
|
|
991
|
+
get toolMetas() {
|
|
992
|
+
return [...this.metas.values()];
|
|
993
|
+
}
|
|
994
|
+
getToolMeta(itemId) {
|
|
995
|
+
return this.metas.get(itemId);
|
|
996
|
+
}
|
|
997
|
+
get lastToolError() {
|
|
998
|
+
return this.lastNativeToolError;
|
|
999
|
+
}
|
|
1000
|
+
get hasPotentialSideEffects() {
|
|
1001
|
+
return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
|
|
1002
|
+
}
|
|
1003
|
+
setLastToolError(error) {
|
|
1004
|
+
if (!error) {
|
|
1005
|
+
this.lastNativeToolError = void 0;
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
1009
|
+
toolName: error.toolName,
|
|
1010
|
+
...error.meta ? { meta: error.meta } : {},
|
|
1011
|
+
outcome: "failure",
|
|
1012
|
+
failure: {
|
|
1013
|
+
...error.errorCode ? { errorCode: error.errorCode } : {},
|
|
1014
|
+
...error.error ? { error: error.error } : {},
|
|
1015
|
+
...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
|
|
1016
|
+
...error.timedOut ? { timedOut: true } : {},
|
|
1017
|
+
...error.middlewareError ? { middlewareError: true } : {}
|
|
1018
|
+
},
|
|
1019
|
+
nativeMutation: {
|
|
1020
|
+
mutatingAction: error.mutatingAction === true,
|
|
1021
|
+
replaySafe: error.mutatingAction !== true,
|
|
1022
|
+
...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
|
|
1023
|
+
...error.fileTarget ? { fileTarget: error.fileTarget } : {}
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
|
|
1027
|
+
}
|
|
1028
|
+
recordDynamicToolResult(params) {
|
|
1029
|
+
const resultText = collectDynamicToolContentText(params.contentItems);
|
|
1030
|
+
const existing = this.metas.get(params.callId);
|
|
1031
|
+
this.metas.set(params.callId, {
|
|
1032
|
+
toolName: existing?.toolName ?? params.tool,
|
|
1033
|
+
...existing?.meta ? { meta: existing.meta } : {},
|
|
1034
|
+
...params.asyncStarted === true ? { asyncStarted: true } : {},
|
|
1035
|
+
...!params.success ? { isError: true } : {}
|
|
1036
|
+
});
|
|
1037
|
+
if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
|
|
1038
|
+
else if (!params.success) this.lastNativeToolError = {
|
|
1039
|
+
toolName: params.tool,
|
|
1040
|
+
error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
|
|
1041
|
+
};
|
|
1042
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
1043
|
+
if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
|
|
1044
|
+
}
|
|
1045
|
+
handleOutputDelta(params, toolName) {
|
|
1046
|
+
const itemId = readString$5(params, "itemId");
|
|
1047
|
+
const delta = readString$5(params, "delta");
|
|
1048
|
+
if (!itemId || !delta) return;
|
|
1049
|
+
const storedOutput = this.output.append(itemId, delta);
|
|
1050
|
+
this.rememberEcho(itemId, {
|
|
1051
|
+
displayText: storedOutput.text,
|
|
1052
|
+
rawLength: storedOutput.normalizedLength,
|
|
1053
|
+
rawPrefix: storedOutput.rawPrefix,
|
|
1054
|
+
streamedDisplay: true
|
|
1055
|
+
});
|
|
1056
|
+
if (!this.shouldEmitToolOutput()) return;
|
|
1057
|
+
if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
|
|
1058
|
+
const state = this.resultOutputDeltaState.get(itemId) ?? {
|
|
1059
|
+
chars: 0,
|
|
1060
|
+
messages: 0,
|
|
1061
|
+
truncated: false
|
|
1062
|
+
};
|
|
1063
|
+
if (state.truncated) return;
|
|
1064
|
+
const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
|
|
1065
|
+
const remainingMessages = Math.max(0, 20 - state.messages);
|
|
1066
|
+
if (remainingChars === 0 || remainingMessages === 0) {
|
|
1067
|
+
state.truncated = true;
|
|
1068
|
+
this.resultOutputDeltaState.set(itemId, state);
|
|
1069
|
+
this.emitToolResultMessage({
|
|
1070
|
+
itemId,
|
|
1071
|
+
text: formatToolOutput(toolName, void 0, "(output truncated)")
|
|
1072
|
+
});
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
|
|
1076
|
+
state.chars += chunk.length;
|
|
1077
|
+
state.messages += 1;
|
|
1078
|
+
const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
|
|
1079
|
+
if (reachedLimit) state.truncated = true;
|
|
1080
|
+
this.resultOutputDeltaState.set(itemId, state);
|
|
1081
|
+
this.resultOutputStreamedItemIds.add(itemId);
|
|
1082
|
+
this.emitToolResultMessage({
|
|
1083
|
+
itemId,
|
|
1084
|
+
text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
recordNativeToolError(params) {
|
|
1088
|
+
const executionStarted = params.status !== "blocked";
|
|
1089
|
+
const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
|
|
1090
|
+
const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
|
|
1091
|
+
const isFailure = isNonSuccessItemStatus(params.status);
|
|
1092
|
+
const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
|
|
1093
|
+
const terminalResolution = this.params.observeToolTerminal?.({
|
|
1094
|
+
toolCallId: params.item.id,
|
|
1095
|
+
toolName: params.name,
|
|
1096
|
+
arguments: itemToolArgs(params.item),
|
|
1097
|
+
...params.meta ? { meta: params.meta } : {},
|
|
1098
|
+
executionStarted,
|
|
1099
|
+
outcome: isFailure ? "failure" : "success",
|
|
1100
|
+
...isFailure ? { failure: error ? { error } : {} } : {},
|
|
1101
|
+
nativeMutation: {
|
|
1102
|
+
mutatingAction,
|
|
1103
|
+
replaySafe: !mutatingAction,
|
|
1104
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1105
|
+
}
|
|
1106
|
+
});
|
|
1107
|
+
if (terminalResolution) {
|
|
1108
|
+
this.lastNativeToolError = terminalResolution.lastToolError;
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
if (isFailure) this.lastNativeToolError = {
|
|
1112
|
+
toolName: params.name,
|
|
1113
|
+
...params.meta ? { meta: params.meta } : {},
|
|
1114
|
+
...error ? { error } : {},
|
|
1115
|
+
...mutatingAction ? { mutatingAction: true } : {},
|
|
1116
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1117
|
+
};
|
|
1118
|
+
else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
|
|
1119
|
+
}
|
|
1120
|
+
emitToolResultSummary(item) {
|
|
1121
|
+
if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
|
|
1122
|
+
if (this.resultSummaryItemIds.has(item.id)) return;
|
|
1123
|
+
const toolName = itemName(item);
|
|
1124
|
+
if (!toolName || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1125
|
+
this.resultSummaryItemIds.add(item.id);
|
|
1126
|
+
this.emitToolResultMessage({
|
|
1127
|
+
itemId: item.id,
|
|
1128
|
+
text: formatToolSummary(toolName, itemMeta(item, this.toolProgressDetailMode()))
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
emitToolResultOutput(item) {
|
|
1132
|
+
if (!item || !this.params.onToolResult || !this.shouldEmitToolOutput()) return;
|
|
1133
|
+
if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
|
|
1134
|
+
const toolName = itemName(item);
|
|
1135
|
+
const output = itemOutputText(item, this.output.textByItem);
|
|
1136
|
+
if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
|
|
1137
|
+
this.emitToolResultMessage({
|
|
1138
|
+
itemId: item.id,
|
|
1139
|
+
text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
|
|
1140
|
+
finalOutput: true,
|
|
1141
|
+
isError: isNonSuccessItemStatus(itemStatus(item))
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
recordToolMeta(item) {
|
|
1145
|
+
if (!item) return;
|
|
1146
|
+
if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
|
|
1147
|
+
else this.sideEffectingNativeIds.delete(item.id);
|
|
1148
|
+
const toolName = itemName(item);
|
|
1149
|
+
if (!toolName) return;
|
|
1150
|
+
const meta = itemMeta(item, this.toolProgressDetailMode());
|
|
1151
|
+
const status = itemStatus(item);
|
|
1152
|
+
const existing = this.metas.get(item.id);
|
|
1153
|
+
this.metas.set(item.id, {
|
|
1154
|
+
toolName,
|
|
1155
|
+
...meta ? { meta } : {},
|
|
1156
|
+
...existing?.asyncStarted ? { asyncStarted: true } : {},
|
|
1157
|
+
...status !== "running" && isNonSuccessItemStatus(status) ? { isError: true } : {}
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
recordTranscriptCall(params) {
|
|
1161
|
+
this.transcriptArgumentsById.set(params.id, params.arguments);
|
|
1162
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
|
|
1163
|
+
else this.transcriptProgressSuppressedIds.delete(params.id);
|
|
1164
|
+
this.emitTranscriptToolCallProgress(params);
|
|
1165
|
+
}
|
|
1166
|
+
recordTranscriptResult(params) {
|
|
1167
|
+
this.emitTranscriptToolResultProgress(params);
|
|
1168
|
+
}
|
|
1169
|
+
matchesEcho(text) {
|
|
1170
|
+
for (const state of this.echoesByItem.values()) {
|
|
1171
|
+
if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
|
|
1172
|
+
if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
|
|
1173
|
+
for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
|
|
1174
|
+
}
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
rememberCommandAggregateOutputEcho(item) {
|
|
1178
|
+
if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
|
|
1179
|
+
const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
|
|
1180
|
+
if (signature) this.rememberEcho(item.id, signature);
|
|
1181
|
+
}
|
|
1182
|
+
toolProgressDetailMode() {
|
|
1183
|
+
return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
|
|
1184
|
+
}
|
|
1185
|
+
emitToolResultMessage(params) {
|
|
1186
|
+
const rawText = params.text.trim();
|
|
1187
|
+
const text = truncateToolTranscriptText(rawText);
|
|
1188
|
+
if (!text) return;
|
|
1189
|
+
this.rememberEcho(params.itemId, {
|
|
1190
|
+
displayText: text,
|
|
1191
|
+
rawText
|
|
1192
|
+
});
|
|
1193
|
+
if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
|
|
1194
|
+
try {
|
|
1195
|
+
Promise.resolve(this.params.onToolResult?.({
|
|
1196
|
+
text,
|
|
1197
|
+
...params.isError === true ? { isError: true } : {}
|
|
1198
|
+
})).catch(() => {});
|
|
1199
|
+
} catch {}
|
|
1200
|
+
}
|
|
1201
|
+
shouldEmitToolResult() {
|
|
1202
|
+
return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
|
|
1203
|
+
}
|
|
1204
|
+
shouldEmitToolOutput() {
|
|
1205
|
+
return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
|
|
1206
|
+
}
|
|
1207
|
+
emitTranscriptToolCallProgress(params) {
|
|
1208
|
+
if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
|
|
1209
|
+
this.transcriptProgressCallIds.add(params.id);
|
|
1210
|
+
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1211
|
+
const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
|
|
1212
|
+
if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
|
|
1213
|
+
this.resultSummaryItemIds.add(params.id);
|
|
1214
|
+
this.emitToolResultMessage({
|
|
1215
|
+
itemId: params.id,
|
|
1216
|
+
text: formatToolSummary(params.name, meta)
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
emitTranscriptToolResultProgress(params) {
|
|
1220
|
+
if (this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
|
|
1221
|
+
if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
|
|
1222
|
+
id: params.id,
|
|
1223
|
+
name: params.name,
|
|
1224
|
+
arguments: {}
|
|
1225
|
+
});
|
|
1226
|
+
if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
|
|
1227
|
+
const text = params.text?.trim();
|
|
1228
|
+
if (text) this.emitToolResultMessage({
|
|
1229
|
+
itemId: params.id,
|
|
1230
|
+
text: formatToolOutput(params.name, void 0, text),
|
|
1231
|
+
finalOutput: true,
|
|
1232
|
+
isError: params.isError
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
rememberEcho(itemId, signature) {
|
|
1236
|
+
if (!itemId) return;
|
|
1237
|
+
const existing = this.echoesByItem.get(itemId) ?? {
|
|
1238
|
+
displayTexts: [],
|
|
1239
|
+
rawSignatures: []
|
|
1240
|
+
};
|
|
1241
|
+
const displayText = signature.displayText?.trim();
|
|
1242
|
+
if (displayText) {
|
|
1243
|
+
if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
|
|
1244
|
+
else if (!existing.displayTexts.includes(displayText)) {
|
|
1245
|
+
if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
|
|
1246
|
+
existing.displayTexts.push(displayText);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
const rawText = signature.rawText?.trim();
|
|
1250
|
+
const rawLength = signature.rawLength ?? rawText?.length;
|
|
1251
|
+
const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
|
|
1252
|
+
if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
|
|
1253
|
+
const next = {
|
|
1254
|
+
length: rawLength,
|
|
1255
|
+
prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
|
|
1256
|
+
};
|
|
1257
|
+
if (signature.streamedDisplay) existing.streamedRawSignature = next;
|
|
1258
|
+
else {
|
|
1259
|
+
const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
|
|
1260
|
+
if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
|
|
1261
|
+
else {
|
|
1262
|
+
if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
|
|
1263
|
+
existing.rawSignatures.push(next);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
this.echoesByItem.set(itemId, existing);
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
//#endregion
|
|
1271
|
+
//#region extensions/codex/src/app-server/session-history.ts
|
|
1272
|
+
/**
|
|
1273
|
+
* Reads OpenClaw session history for Codex transcript mirroring and sanitizes
|
|
1274
|
+
* image payloads before replaying messages into the app-server projector.
|
|
1275
|
+
*/
|
|
1276
|
+
function isMissingFileError(error) {
|
|
1277
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
1278
|
+
}
|
|
1279
|
+
/** Returns sanitized session-context messages for a Codex mirrored session file. */
|
|
1280
|
+
async function readCodexMirroredSessionHistoryMessages(target) {
|
|
1281
|
+
try {
|
|
1282
|
+
const entries = await readCodexMirroredSessionEntries(target);
|
|
1283
|
+
if (entries.length === 0) return [];
|
|
1284
|
+
const firstEntry = entries[0];
|
|
1285
|
+
if (firstEntry?.type !== "session") return [];
|
|
1286
|
+
if (typeof firstEntry.id !== "string") return;
|
|
1287
|
+
migrateSessionEntries(entries);
|
|
1288
|
+
return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
|
|
1289
|
+
return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
|
|
1290
|
+
})).messages, "codex mirrored history");
|
|
1291
|
+
} catch (error) {
|
|
1292
|
+
if (isMissingFileError(error)) return [];
|
|
1293
|
+
return;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
async function readCodexMirroredSessionEntries(target) {
|
|
1297
|
+
const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
|
|
1298
|
+
if (sqliteMarker) {
|
|
1299
|
+
if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return [];
|
|
1300
|
+
const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
|
|
1301
|
+
if (!sessionKey) return [];
|
|
1302
|
+
return await readSessionTranscriptEvents({
|
|
1303
|
+
agentId: sqliteMarker.agentId,
|
|
1304
|
+
sessionId: sqliteMarker.sessionId,
|
|
1305
|
+
sessionKey,
|
|
1306
|
+
storePath: sqliteMarker.storePath
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
return parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
|
|
1310
|
+
}
|
|
1311
|
+
function resolveSqliteMarkerSessionKey(target, marker) {
|
|
1312
|
+
const explicitSessionKey = target.sessionKey?.trim();
|
|
1313
|
+
if (explicitSessionKey) return explicitSessionKey;
|
|
1314
|
+
const entries = listSessionEntries({
|
|
1315
|
+
agentId: marker.agentId,
|
|
1316
|
+
readOnly: true,
|
|
1317
|
+
storePath: marker.storePath
|
|
1318
|
+
});
|
|
1319
|
+
return (entries.find(({ entry }) => {
|
|
1320
|
+
return entry.sessionId === marker.sessionId && entry.sessionFile === target.sessionFile;
|
|
1321
|
+
}) ?? entries.find(({ entry }) => {
|
|
1322
|
+
return entry.sessionId === marker.sessionId;
|
|
1323
|
+
}))?.sessionKey;
|
|
1324
|
+
}
|
|
1325
|
+
//#endregion
|
|
1326
|
+
//#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
|
|
1327
|
+
const ZERO_USAGE = {
|
|
1328
|
+
input: 0,
|
|
1329
|
+
output: 0,
|
|
1330
|
+
cacheRead: 0,
|
|
1331
|
+
cacheWrite: 0,
|
|
1332
|
+
totalTokens: 0,
|
|
1333
|
+
cost: {
|
|
1334
|
+
input: 0,
|
|
1335
|
+
output: 0,
|
|
1336
|
+
cacheRead: 0,
|
|
1337
|
+
cacheWrite: 0,
|
|
1338
|
+
total: 0
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
|
|
1342
|
+
var CodexToolTranscriptProjection = class {
|
|
1343
|
+
constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
|
|
1344
|
+
this.params = params;
|
|
1345
|
+
this.threadId = threadId;
|
|
1346
|
+
this.turnId = turnId;
|
|
1347
|
+
this.progress = progress;
|
|
1348
|
+
this.nextTranscriptTimestamp = nextTranscriptTimestamp;
|
|
1349
|
+
this.options = options;
|
|
1350
|
+
this.messages = [];
|
|
1351
|
+
this.callIds = /* @__PURE__ */ new Set();
|
|
1352
|
+
this.resultIds = /* @__PURE__ */ new Set();
|
|
1353
|
+
this.namesById = /* @__PURE__ */ new Map();
|
|
1354
|
+
this.trajectoryCallIds = /* @__PURE__ */ new Set();
|
|
1355
|
+
this.trajectoryResultIds = /* @__PURE__ */ new Set();
|
|
1356
|
+
this.trajectoryNamesById = /* @__PURE__ */ new Map();
|
|
1357
|
+
this.trajectoryItemsById = /* @__PURE__ */ new Map();
|
|
1358
|
+
this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
|
|
1359
|
+
}
|
|
1360
|
+
get transcriptMessages() {
|
|
1361
|
+
return this.messages;
|
|
1362
|
+
}
|
|
1363
|
+
recordDynamicToolCall(params) {
|
|
1364
|
+
this.recordToolCall({
|
|
1365
|
+
id: params.callId,
|
|
1366
|
+
name: params.tool,
|
|
1367
|
+
arguments: sanitizeCodexToolArguments(params.arguments)
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
recordDynamicToolResult(params) {
|
|
1371
|
+
this.recordToolResult({
|
|
1372
|
+
id: params.callId,
|
|
1373
|
+
name: params.tool,
|
|
1374
|
+
text: collectDynamicToolContentText(params.contentItems),
|
|
1375
|
+
isError: !params.success
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
recordNativeToolCall(item) {
|
|
1379
|
+
if (!item || !shouldRecordNativeToolTranscript(item)) return;
|
|
1380
|
+
const name = itemName(item);
|
|
1381
|
+
if (name) this.recordToolCall({
|
|
1382
|
+
id: item.id,
|
|
1383
|
+
name,
|
|
1384
|
+
arguments: itemToolArgs(item)
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
recordNativeToolResult(item) {
|
|
1388
|
+
if (!item || !shouldRecordNativeToolTranscript(item)) return;
|
|
1389
|
+
const name = itemName(item);
|
|
1390
|
+
if (name) this.recordToolResult({
|
|
1391
|
+
id: item.id,
|
|
1392
|
+
name,
|
|
1393
|
+
text: itemTranscriptResultText(item, this.progress.outputTextByItem),
|
|
1394
|
+
isError: isNonSuccessItemStatus(itemStatus(item))
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
recordTrajectoryEvent(params) {
|
|
1398
|
+
if (params.phase === "start") {
|
|
1399
|
+
this.trajectoryCallIds.add(params.item.id);
|
|
1400
|
+
this.trajectoryNamesById.set(params.item.id, params.name);
|
|
1401
|
+
this.trajectoryItemsById.set(params.item.id, params.item);
|
|
1402
|
+
this.options.trajectoryRecorder?.recordEvent("tool.call", {
|
|
1403
|
+
threadId: this.threadId,
|
|
1404
|
+
turnId: this.turnId,
|
|
1405
|
+
itemId: params.item.id,
|
|
1406
|
+
toolCallId: params.item.id,
|
|
1407
|
+
name: params.name,
|
|
1408
|
+
arguments: params.args
|
|
1409
|
+
});
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
this.trajectoryResultIds.add(params.item.id);
|
|
1413
|
+
const toolResult = itemToolResult(params.item).result;
|
|
1414
|
+
const output = itemOutputText(params.item, this.progress.outputTextByItem);
|
|
1415
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1416
|
+
threadId: this.threadId,
|
|
1417
|
+
turnId: this.turnId,
|
|
1418
|
+
itemId: params.item.id,
|
|
1419
|
+
toolCallId: params.item.id,
|
|
1420
|
+
name: params.name,
|
|
1421
|
+
status: params.status,
|
|
1422
|
+
isError: isNonSuccessItemStatus(params.status),
|
|
1423
|
+
...toolResult ? { result: toolResult } : {},
|
|
1424
|
+
...output ? { output } : {}
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
emitAfterToolCallObservation(item) {
|
|
1428
|
+
if (!this.shouldEmitAfterToolCallObservation(item)) return;
|
|
1429
|
+
const name = itemName(item);
|
|
1430
|
+
const status = itemStatus(item);
|
|
1431
|
+
if (!name || status === "running") return;
|
|
1432
|
+
this.afterToolCallObservedItemIds.add(item.id);
|
|
1433
|
+
const result = itemToolResult(item).result;
|
|
1434
|
+
const error = itemToolError(item, status, this.progress.outputTextByItem);
|
|
1435
|
+
const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
|
|
1436
|
+
const hookParams = {
|
|
1437
|
+
toolName: name,
|
|
1438
|
+
toolCallId: item.id,
|
|
1439
|
+
runId: this.params.runId,
|
|
1440
|
+
agentId: this.params.agentId,
|
|
1441
|
+
sessionId: this.params.sessionId,
|
|
1442
|
+
sessionKey: this.params.sessionKey,
|
|
1443
|
+
startArgs: itemToolArgs(item) ?? {},
|
|
1444
|
+
...result !== void 0 ? { result } : {},
|
|
1445
|
+
...error ? { error } : {},
|
|
1446
|
+
...startedAt !== void 0 ? { startedAt } : {}
|
|
1447
|
+
};
|
|
1448
|
+
setImmediate(() => {
|
|
1449
|
+
runAgentHarnessAfterToolCallHook(hookParams);
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
synthesizeMissingToolResults(params) {
|
|
1453
|
+
if (!params.synthesize) return;
|
|
1454
|
+
const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
|
|
1455
|
+
const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
|
|
1456
|
+
if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
|
|
1457
|
+
for (const id of missingTranscriptIds) {
|
|
1458
|
+
const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
|
|
1459
|
+
if (name) this.recordToolResult({
|
|
1460
|
+
id,
|
|
1461
|
+
name,
|
|
1462
|
+
text: formatMissingToolResultError({
|
|
1463
|
+
id,
|
|
1464
|
+
name
|
|
1465
|
+
}),
|
|
1466
|
+
isError: true
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
for (const id of missingTrajectoryIds) {
|
|
1470
|
+
const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
|
|
1471
|
+
if (!name) continue;
|
|
1472
|
+
this.trajectoryResultIds.add(id);
|
|
1473
|
+
const text = formatMissingToolResultError({
|
|
1474
|
+
id,
|
|
1475
|
+
name
|
|
1476
|
+
});
|
|
1477
|
+
this.options.trajectoryRecorder?.recordEvent("tool.result", {
|
|
1478
|
+
threadId: this.threadId,
|
|
1479
|
+
turnId: this.turnId,
|
|
1480
|
+
itemId: id,
|
|
1481
|
+
toolCallId: id,
|
|
1482
|
+
name,
|
|
1483
|
+
status: "failed",
|
|
1484
|
+
isError: true,
|
|
1485
|
+
result: {
|
|
1486
|
+
status: "failed",
|
|
1487
|
+
reason: "missing_tool_result"
|
|
1488
|
+
},
|
|
1489
|
+
output: text
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
if (!params.recordPromptError) {
|
|
1493
|
+
this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
|
|
1497
|
+
return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
|
|
1498
|
+
}
|
|
1499
|
+
async readMirroredSessionMessages() {
|
|
1500
|
+
return await readCodexMirroredSessionHistoryMessages({
|
|
1501
|
+
agentId: this.params.agentId,
|
|
1502
|
+
sessionFile: this.params.sessionFile,
|
|
1503
|
+
sessionId: this.params.sessionId,
|
|
1504
|
+
sessionKey: this.params.sessionKey
|
|
1505
|
+
}) ?? [];
|
|
1506
|
+
}
|
|
1507
|
+
recordToolCall(params) {
|
|
1508
|
+
if (!params.id || !params.name || this.callIds.has(params.id)) return;
|
|
1509
|
+
this.callIds.add(params.id);
|
|
1510
|
+
this.namesById.set(params.id, params.name);
|
|
1511
|
+
this.progress.recordTranscriptCall(params);
|
|
1512
|
+
this.messages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
|
|
1513
|
+
}
|
|
1514
|
+
recordToolResult(params) {
|
|
1515
|
+
if (!params.id || !params.name || this.resultIds.has(params.id)) return;
|
|
1516
|
+
this.resultIds.add(params.id);
|
|
1517
|
+
this.progress.recordTranscriptResult(params);
|
|
1518
|
+
this.messages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
|
|
1519
|
+
}
|
|
1520
|
+
recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
|
|
1521
|
+
const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
|
|
1522
|
+
if (!firstMissingId) return;
|
|
1523
|
+
const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
|
|
1524
|
+
if (!name) return;
|
|
1525
|
+
const item = this.trajectoryItemsById.get(firstMissingId);
|
|
1526
|
+
const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
|
|
1527
|
+
const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
|
|
1528
|
+
this.progress.setLastToolError({
|
|
1529
|
+
toolName: name,
|
|
1530
|
+
...meta ? { meta } : {},
|
|
1531
|
+
error: formatMissingToolResultError({
|
|
1532
|
+
id: firstMissingId,
|
|
1533
|
+
name
|
|
1534
|
+
}),
|
|
1535
|
+
...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
|
|
1536
|
+
...actionFingerprint ? { actionFingerprint } : {}
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
shouldEmitAfterToolCallObservation(item) {
|
|
1540
|
+
if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
|
|
1541
|
+
return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
|
|
1542
|
+
}
|
|
1543
|
+
createToolCallMessage(params) {
|
|
1544
|
+
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1545
|
+
const attribution = resolveCodexLocalRuntimeAttribution(this.params);
|
|
1546
|
+
return {
|
|
1547
|
+
role: "assistant",
|
|
1548
|
+
content: [{
|
|
1549
|
+
type: "toolCall",
|
|
1550
|
+
id: params.id,
|
|
1551
|
+
name: params.name,
|
|
1552
|
+
arguments: args,
|
|
1553
|
+
input: args
|
|
1554
|
+
}],
|
|
1555
|
+
api: attribution.api ?? "openai-chatgpt-responses",
|
|
1556
|
+
provider: attribution.provider,
|
|
1557
|
+
model: this.params.modelId,
|
|
1558
|
+
usage: ZERO_USAGE,
|
|
1559
|
+
stopReason: "toolUse",
|
|
1560
|
+
timestamp: this.nextTranscriptTimestamp()
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
createToolResultMessage(params) {
|
|
1564
|
+
const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
|
|
1565
|
+
return {
|
|
1566
|
+
role: "toolResult",
|
|
1567
|
+
toolCallId: params.id,
|
|
1568
|
+
toolName: params.name,
|
|
1569
|
+
isError: params.isError,
|
|
1570
|
+
content: [{
|
|
1571
|
+
type: "toolResult",
|
|
1572
|
+
id: params.id,
|
|
1573
|
+
name: params.name,
|
|
1574
|
+
toolName: params.name,
|
|
1575
|
+
toolCallId: params.id,
|
|
1576
|
+
toolUseId: params.id,
|
|
1577
|
+
tool_use_id: params.id,
|
|
1578
|
+
content: text,
|
|
1579
|
+
text
|
|
1580
|
+
}],
|
|
1581
|
+
timestamp: this.nextTranscriptTimestamp()
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
function formatMissingToolResultError(params) {
|
|
1586
|
+
return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
|
|
1587
|
+
}
|
|
1588
|
+
function toolResultStatusText(params) {
|
|
1589
|
+
return params.isError ? `${params.name} failed` : `${params.name} completed`;
|
|
1590
|
+
}
|
|
1591
|
+
function resolveStartedAtFromDurationMs(durationMs) {
|
|
1592
|
+
if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
|
|
1593
|
+
return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
|
|
1594
|
+
}
|
|
1595
|
+
//#endregion
|
|
1596
|
+
//#region extensions/codex/src/app-server/event-projector-events.ts
|
|
1597
|
+
var CodexEventProjection = class {
|
|
1598
|
+
constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
|
|
1599
|
+
this.threadId = threadId;
|
|
1600
|
+
this.turnId = turnId;
|
|
1601
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
1602
|
+
this.toolProgress = toolProgress;
|
|
1603
|
+
this.toolTranscript = toolTranscript;
|
|
1604
|
+
this.onNativeToolResultRecorded = onNativeToolResultRecorded;
|
|
1605
|
+
this.reviewCount = 0;
|
|
1606
|
+
}
|
|
1607
|
+
get guardianReviewCount() {
|
|
1608
|
+
return this.reviewCount;
|
|
1609
|
+
}
|
|
1610
|
+
handleGuardianReview(method, params) {
|
|
1611
|
+
this.reviewCount += 1;
|
|
1612
|
+
const review = isJsonObject(params.review) ? params.review : void 0;
|
|
1613
|
+
const action = isJsonObject(params.action) ? params.action : void 0;
|
|
1614
|
+
this.emitAgentEvent({
|
|
1615
|
+
stream: "codex_app_server.guardian",
|
|
1616
|
+
data: {
|
|
1617
|
+
method,
|
|
1618
|
+
phase: method.endsWith("/started") ? "started" : "completed",
|
|
1619
|
+
reviewId: readString$5(params, "reviewId"),
|
|
1620
|
+
targetItemId: readNullableString$1(params, "targetItemId"),
|
|
1621
|
+
decisionSource: readString$5(params, "decisionSource"),
|
|
1622
|
+
status: review ? readString$5(review, "status") : void 0,
|
|
1623
|
+
riskLevel: review ? readString$5(review, "riskLevel") : void 0,
|
|
1624
|
+
userAuthorization: review ? readString$5(review, "userAuthorization") : void 0,
|
|
1625
|
+
rationale: review ? readNullableString$1(review, "rationale") : void 0,
|
|
1626
|
+
actionType: action ? readString$5(action, "type") : void 0
|
|
1627
|
+
}
|
|
1628
|
+
});
|
|
1629
|
+
}
|
|
1630
|
+
handleGuardianWarning(params) {
|
|
1631
|
+
this.emitAgentEvent({
|
|
1632
|
+
stream: "codex_app_server.guardian",
|
|
1633
|
+
data: {
|
|
1634
|
+
phase: "warning",
|
|
1635
|
+
message: readString$5(params, "message")
|
|
1636
|
+
}
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
handleHook(method, params) {
|
|
1640
|
+
const run = isJsonObject(params.run) ? params.run : void 0;
|
|
1641
|
+
if (!run) return;
|
|
1642
|
+
const durationMs = readNumber(run, "durationMs");
|
|
1643
|
+
const entries = readHookOutputEntries(run.entries);
|
|
1644
|
+
const hookTurnId = readNullableString$1(params, "turnId");
|
|
1645
|
+
this.emitAgentEvent({
|
|
1646
|
+
stream: "codex_app_server.hook",
|
|
1647
|
+
data: {
|
|
1648
|
+
phase: method === "hook/started" ? "started" : "completed",
|
|
1649
|
+
threadId: this.threadId,
|
|
1650
|
+
turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
|
|
1651
|
+
hookRunId: readString$5(run, "id"),
|
|
1652
|
+
eventName: readString$5(run, "eventName"),
|
|
1653
|
+
handlerType: readString$5(run, "handlerType"),
|
|
1654
|
+
executionMode: readString$5(run, "executionMode"),
|
|
1655
|
+
scope: readString$5(run, "scope"),
|
|
1656
|
+
source: readString$5(run, "source"),
|
|
1657
|
+
sourcePath: readString$5(run, "sourcePath"),
|
|
1658
|
+
status: readString$5(run, "status"),
|
|
1659
|
+
statusMessage: readNullableString$1(run, "statusMessage"),
|
|
1660
|
+
...durationMs !== void 0 ? { durationMs } : {},
|
|
1661
|
+
...entries.length > 0 ? { entries } : {}
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
emitStandardItemEvent(params) {
|
|
1666
|
+
const { item } = params;
|
|
1667
|
+
if (!item) return;
|
|
1668
|
+
const kind = itemKind(item);
|
|
1669
|
+
if (!kind) return;
|
|
1670
|
+
const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
|
|
1671
|
+
const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
|
|
1672
|
+
this.emitAgentEvent({
|
|
1673
|
+
stream: "item",
|
|
1674
|
+
data: {
|
|
1675
|
+
itemId: item.id,
|
|
1676
|
+
phase: params.phase,
|
|
1677
|
+
kind,
|
|
1678
|
+
title: itemTitle(item),
|
|
1679
|
+
status: params.phase === "start" ? "running" : itemStatus(item),
|
|
1680
|
+
...itemName(item) ? { name: itemName(item) } : {},
|
|
1681
|
+
...meta ? { meta } : {},
|
|
1682
|
+
...suppressChannelProgress ? { suppressChannelProgress: true } : {}
|
|
1683
|
+
}
|
|
1684
|
+
});
|
|
1685
|
+
}
|
|
1686
|
+
async emitNormalizedToolItemEvent(params) {
|
|
1687
|
+
const { item } = params;
|
|
1688
|
+
if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
|
|
1689
|
+
const name = itemName(item);
|
|
1690
|
+
if (!name) return;
|
|
1691
|
+
const status = params.phase === "result" ? itemStatus(item) : "running";
|
|
1692
|
+
const args = itemToolArgs(item);
|
|
1693
|
+
const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
|
|
1694
|
+
this.toolTranscript.recordTrajectoryEvent({
|
|
1695
|
+
phase: params.phase,
|
|
1696
|
+
item,
|
|
1697
|
+
name,
|
|
1698
|
+
args,
|
|
1699
|
+
status
|
|
1700
|
+
});
|
|
1701
|
+
if (params.phase === "result") this.toolProgress.recordNativeToolError({
|
|
1702
|
+
item,
|
|
1703
|
+
name,
|
|
1704
|
+
meta,
|
|
1705
|
+
status
|
|
1706
|
+
});
|
|
1707
|
+
if (!shouldEmitTranscriptToolProgress(name, args)) {
|
|
1708
|
+
if (params.phase === "result") {
|
|
1709
|
+
this.toolTranscript.emitAfterToolCallObservation(item);
|
|
1710
|
+
await this.onNativeToolResultRecorded?.();
|
|
1711
|
+
}
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
this.emitAgentEvent({
|
|
1715
|
+
stream: "tool",
|
|
1716
|
+
data: {
|
|
1717
|
+
phase: params.phase,
|
|
1718
|
+
name,
|
|
1719
|
+
itemId: item.id,
|
|
1720
|
+
toolCallId: item.id,
|
|
1721
|
+
...meta ? { meta } : {},
|
|
1722
|
+
...params.phase === "start" && args ? { args } : {},
|
|
1723
|
+
...params.phase === "result" ? {
|
|
1724
|
+
status,
|
|
1725
|
+
isError: isNonSuccessItemStatus(status),
|
|
1726
|
+
...itemToolResult(item)
|
|
1727
|
+
} : {}
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
if (params.phase === "result") {
|
|
1731
|
+
this.toolTranscript.emitAfterToolCallObservation(item);
|
|
1732
|
+
await this.onNativeToolResultRecorded?.();
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
//#endregion
|
|
1737
|
+
//#region extensions/codex/src/app-server/event-projector-media.ts
|
|
1738
|
+
const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
|
|
1739
|
+
const BYTES_PER_MB = 1024 * 1024;
|
|
1740
|
+
const DEFAULT_GENERATED_IMAGE_MAX_BYTES = 6 * BYTES_PER_MB;
|
|
1741
|
+
var CodexGeneratedMediaProjection = class {
|
|
1742
|
+
constructor(config) {
|
|
1743
|
+
this.config = config;
|
|
1744
|
+
this.itemIds = /* @__PURE__ */ new Set();
|
|
1745
|
+
this.urlsByItemId = /* @__PURE__ */ new Map();
|
|
1746
|
+
}
|
|
1747
|
+
hasGeneratedMedia() {
|
|
1748
|
+
return this.itemIds.size > 0;
|
|
1749
|
+
}
|
|
1750
|
+
recordNative(item) {
|
|
1751
|
+
if (item?.type !== "imageGeneration") return;
|
|
1752
|
+
const savedPath = readItemString(item, "savedPath")?.trim();
|
|
1753
|
+
if (savedPath) this.recordUrl({
|
|
1754
|
+
itemId: item.id,
|
|
1755
|
+
mediaUrl: savedPath
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
1758
|
+
async recordRaw(item) {
|
|
1759
|
+
if (readString$5(item, "type") !== "image_generation_call") return;
|
|
1760
|
+
const result = readString$5(item, "result");
|
|
1761
|
+
if (!result) return;
|
|
1762
|
+
const itemId = readString$5(item, "id") ?? `raw-image-${this.itemIds.size}`;
|
|
1763
|
+
this.itemIds.add(itemId);
|
|
1764
|
+
const maxBytes = resolveGeneratedImageMaxBytes(this.config);
|
|
1765
|
+
const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
|
|
1766
|
+
if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
|
|
1767
|
+
embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
|
|
1768
|
+
itemId,
|
|
1769
|
+
estimatedDecodedBytes,
|
|
1770
|
+
maxBytes
|
|
1771
|
+
});
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const asset = generatedImageAssetFromBase64({
|
|
1775
|
+
base64: result,
|
|
1776
|
+
index: this.itemIds.size,
|
|
1777
|
+
revisedPrompt: readString$5(item, "revised_prompt") ?? readString$5(item, "revisedPrompt"),
|
|
1778
|
+
fileNamePrefix: "codex-image-generation",
|
|
1779
|
+
sniffMimeType: true
|
|
1780
|
+
});
|
|
1781
|
+
if (!asset) return;
|
|
1782
|
+
try {
|
|
1783
|
+
const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
|
|
1784
|
+
this.recordUrl({
|
|
1785
|
+
itemId,
|
|
1786
|
+
mediaUrl: saved.path,
|
|
1787
|
+
replaceExisting: true
|
|
1788
|
+
});
|
|
1789
|
+
} catch (error) {
|
|
1790
|
+
embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
|
|
1791
|
+
itemId,
|
|
1792
|
+
error
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
buildToolMediaUrls(params) {
|
|
1797
|
+
const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
|
|
1798
|
+
if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
|
|
1799
|
+
return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
|
|
1800
|
+
}
|
|
1801
|
+
buildHostOwnedMediaUrls(params) {
|
|
1802
|
+
if ((params.messagingToolSentMediaUrls?.length ?? 0) > 0) return;
|
|
1803
|
+
const mediaUrls = [...this.urlsByItemId.values()];
|
|
1804
|
+
return mediaUrls.length > 0 ? mediaUrls : void 0;
|
|
1805
|
+
}
|
|
1806
|
+
recordUrl(params) {
|
|
1807
|
+
if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
|
|
1808
|
+
this.itemIds.add(params.itemId);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
this.urlsByItemId.set(params.itemId, params.mediaUrl);
|
|
1812
|
+
this.itemIds.add(params.itemId);
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
function estimateBase64DecodedBytes(base64) {
|
|
1816
|
+
let nonWhitespaceLength = 0;
|
|
1817
|
+
let previousCode = -1;
|
|
1818
|
+
let lastCode = -1;
|
|
1819
|
+
for (let i = 0; i < base64.length; i += 1) {
|
|
1820
|
+
const code = base64.charCodeAt(i);
|
|
1821
|
+
if (isBase64WhitespaceCode(code)) continue;
|
|
1822
|
+
nonWhitespaceLength += 1;
|
|
1823
|
+
previousCode = lastCode;
|
|
1824
|
+
lastCode = code;
|
|
1825
|
+
}
|
|
1826
|
+
if (nonWhitespaceLength === 0) return;
|
|
1827
|
+
const equalsCode = "=".charCodeAt(0);
|
|
1828
|
+
const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
|
|
1829
|
+
return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
|
|
1830
|
+
}
|
|
1831
|
+
function isBase64WhitespaceCode(code) {
|
|
1832
|
+
return code === 32 || code === 9 || code === 10 || code === 13;
|
|
1833
|
+
}
|
|
1834
|
+
function resolveGeneratedImageMaxBytes(config) {
|
|
1835
|
+
const configured = config?.agents?.defaults?.mediaMaxMb;
|
|
1836
|
+
if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * BYTES_PER_MB);
|
|
1837
|
+
return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
|
|
1838
|
+
}
|
|
1839
|
+
//#endregion
|
|
1840
|
+
//#region extensions/codex/src/app-server/event-projector-reasoning.ts
|
|
1841
|
+
var CodexReasoningProjection = class {
|
|
1842
|
+
constructor(params, emitAgentEvent) {
|
|
1843
|
+
this.params = params;
|
|
1844
|
+
this.emitAgentEvent = emitAgentEvent;
|
|
1845
|
+
this.reasoningTextByGroup = /* @__PURE__ */ new Map();
|
|
1846
|
+
this.reasoningItemOrder = /* @__PURE__ */ new Map();
|
|
1847
|
+
this.planTextByItem = /* @__PURE__ */ new Map();
|
|
1848
|
+
this.reasoningStarted = false;
|
|
1849
|
+
this.reasoningEnded = false;
|
|
1850
|
+
}
|
|
1851
|
+
async handleReasoningDelta(method, params) {
|
|
1852
|
+
const itemId = readString$5(params, "itemId") ?? "reasoning";
|
|
1853
|
+
const delta = readString$5(params, "delta") ?? "";
|
|
1854
|
+
if (!delta) return;
|
|
1855
|
+
this.reasoningStarted = true;
|
|
1856
|
+
if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
|
|
1857
|
+
const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
|
|
1858
|
+
const groupKey = `${method}\0${itemId}\0${groupIndex}`;
|
|
1859
|
+
const current = this.reasoningTextByGroup.get(groupKey);
|
|
1860
|
+
this.reasoningTextByGroup.set(groupKey, {
|
|
1861
|
+
itemId,
|
|
1862
|
+
method,
|
|
1863
|
+
index: groupIndex,
|
|
1864
|
+
text: `${current?.text ?? ""}${delta}`
|
|
1865
|
+
});
|
|
1866
|
+
await this.params.onReasoningStream?.({
|
|
1867
|
+
text: this.reasoningText(),
|
|
1868
|
+
isReasoningSnapshot: true
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
handlePlanDelta(params) {
|
|
1872
|
+
const itemId = readString$5(params, "itemId") ?? "plan";
|
|
1873
|
+
const delta = readString$5(params, "delta") ?? "";
|
|
1874
|
+
if (!delta) return;
|
|
1875
|
+
const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
|
|
1876
|
+
this.planTextByItem.set(itemId, text);
|
|
1877
|
+
this.emitPlanUpdate({
|
|
1878
|
+
explanation: void 0,
|
|
1879
|
+
steps: splitPlanText(text).map((step) => ({
|
|
1880
|
+
step,
|
|
1881
|
+
status: "pending"
|
|
1882
|
+
}))
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
handleTurnPlanUpdated(params) {
|
|
1886
|
+
const explanation = readNullableString$1(params, "explanation");
|
|
1887
|
+
const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
|
|
1888
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
|
|
1889
|
+
const record = entry;
|
|
1890
|
+
const step = readString$5(record, "step");
|
|
1891
|
+
if (!step) return [];
|
|
1892
|
+
return [{
|
|
1893
|
+
step,
|
|
1894
|
+
status: normalizePlanStepStatus(readString$5(record, "status"))
|
|
1895
|
+
}];
|
|
1896
|
+
}) : void 0;
|
|
1897
|
+
const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
|
|
1898
|
+
if (planText) this.turnPlanText = planText;
|
|
1899
|
+
this.emitPlanUpdate({
|
|
1900
|
+
explanation,
|
|
1901
|
+
steps: plan
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
recordItem(item) {
|
|
1905
|
+
if (item?.type === "plan" && typeof item.text === "string" && item.text) {
|
|
1906
|
+
this.planTextByItem.set(item.id, item.text);
|
|
1907
|
+
this.emitPlanUpdate({
|
|
1908
|
+
explanation: void 0,
|
|
1909
|
+
steps: splitPlanText(item.text).map((step) => ({
|
|
1910
|
+
step,
|
|
1911
|
+
status: "pending"
|
|
1912
|
+
}))
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
async maybeEndReasoning() {
|
|
1917
|
+
if (!this.reasoningStarted || this.reasoningEnded) return;
|
|
1918
|
+
this.reasoningEnded = true;
|
|
1919
|
+
await this.params.onReasoningEnd?.();
|
|
1920
|
+
}
|
|
1921
|
+
reasoningText() {
|
|
1922
|
+
return collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
|
|
1923
|
+
}
|
|
1924
|
+
planText() {
|
|
1925
|
+
return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
|
|
1926
|
+
}
|
|
1927
|
+
emitPlanUpdate(params) {
|
|
1928
|
+
if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
|
|
1929
|
+
this.emitAgentEvent({
|
|
1930
|
+
stream: "plan",
|
|
1931
|
+
data: {
|
|
1932
|
+
phase: "update",
|
|
1933
|
+
title: "Plan updated",
|
|
1934
|
+
source: "codex-app-server",
|
|
1935
|
+
...params.explanation ? { explanation: params.explanation } : {},
|
|
1936
|
+
...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
|
|
1937
|
+
}
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1940
|
+
};
|
|
1941
|
+
function normalizePlanStepStatus(status) {
|
|
1942
|
+
if (status === "inProgress" || status === "in_progress") return "in_progress";
|
|
1943
|
+
return status === "completed" ? "completed" : "pending";
|
|
1944
|
+
}
|
|
1945
|
+
function collectReasoningTextValues(groups, itemOrder) {
|
|
1946
|
+
return [...groups.values()].toSorted((left, right) => {
|
|
1947
|
+
const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
|
|
1948
|
+
if (itemDelta !== 0) return itemDelta;
|
|
1949
|
+
const methodDelta = reasoningMethodOrder(left.method) - reasoningMethodOrder(right.method);
|
|
1950
|
+
return methodDelta !== 0 ? methodDelta : left.index - right.index;
|
|
1951
|
+
}).map((group) => group.text).filter((text) => text.trim().length > 0);
|
|
1952
|
+
}
|
|
1953
|
+
function reasoningMethodOrder(method) {
|
|
1954
|
+
return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
|
|
1955
|
+
}
|
|
1956
|
+
//#endregion
|
|
1957
|
+
//#region extensions/codex/src/app-server/event-projector-snapshot.ts
|
|
1958
|
+
function buildCodexMessagesSnapshot(params) {
|
|
1959
|
+
const messages = promptSnapshot(params.runParams, params.turnId, params.upstreamUserText);
|
|
1960
|
+
if (params.reasoningText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex reasoning", params.reasoningText), `${params.turnId}:reasoning`));
|
|
1961
|
+
if (params.planText) messages.push(attachCodexMirrorIdentity(params.createAssistantMirrorMessage("Codex plan", params.planText), `${params.turnId}:plan`));
|
|
1962
|
+
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));
|
|
1963
|
+
messages.push(...visibleWorkMessages);
|
|
1964
|
+
if (params.lastAssistant) messages.push(attachCodexMirrorIdentity(params.lastAssistant, `${params.turnId}:assistant`));
|
|
1965
|
+
return messages.map((message) => projectAgentHarnessTranscriptMessageForDisplay({
|
|
1966
|
+
hidden: params.runParams.trigger === "memory",
|
|
1967
|
+
message
|
|
1968
|
+
}));
|
|
1969
|
+
}
|
|
1970
|
+
//#endregion
|
|
1971
|
+
//#region extensions/codex/src/app-server/usage-limit-error.ts
|
|
1972
|
+
/**
|
|
1973
|
+
* Enriches Codex usage-limit failures with current rate-limit information and
|
|
1974
|
+
* marks blocked auth profiles when Codex exposes a reset time.
|
|
1975
|
+
*/
|
|
1976
|
+
const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
|
|
1977
|
+
function createCodexUsageLimitPromptError(message) {
|
|
1978
|
+
return Object.assign(new Error(message), { status: 429 });
|
|
1979
|
+
}
|
|
1980
|
+
function isCodexUsageLimitPromptError(error) {
|
|
1981
|
+
return error instanceof Error && "status" in error && error.status === 429;
|
|
1982
|
+
}
|
|
1983
|
+
/** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
|
|
1984
|
+
async function markCodexAuthProfileBlockedFromRateLimits(params) {
|
|
1985
|
+
const authProfileId = params.authProfileId?.trim();
|
|
1986
|
+
if (!authProfileId || !params.params.authProfileStore) return;
|
|
1987
|
+
const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
|
|
1988
|
+
if (!blockedUntil) return;
|
|
1989
|
+
try {
|
|
1990
|
+
await markAuthProfileBlockedUntil({
|
|
1991
|
+
store: params.params.authProfileStore,
|
|
1992
|
+
profileId: authProfileId,
|
|
1993
|
+
blockedUntil,
|
|
1994
|
+
source: "codex_rate_limits",
|
|
1995
|
+
agentDir: params.params.agentDir,
|
|
1996
|
+
runId: params.params.runId,
|
|
1997
|
+
modelId: params.params.modelId
|
|
1998
|
+
});
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
|
|
2001
|
+
authProfileId,
|
|
2002
|
+
error: formatErrorMessage(error)
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
/** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
|
|
2007
|
+
async function formatCodexTurnStartUsageLimitError(params) {
|
|
2008
|
+
return refreshCodexUsageLimitError({
|
|
2009
|
+
client: params.client,
|
|
2010
|
+
source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
|
|
2011
|
+
timeoutMs: params.timeoutMs,
|
|
2012
|
+
signal: params.signal
|
|
2013
|
+
});
|
|
2014
|
+
}
|
|
2015
|
+
/** Refreshes a generic prompt usage-limit message into a reset-aware message. */
|
|
2016
|
+
async function refreshCodexUsageLimitPromptError(params) {
|
|
2017
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
|
|
2018
|
+
return refreshCodexUsageLimitError({
|
|
2019
|
+
client: params.client,
|
|
2020
|
+
source: {
|
|
2021
|
+
message: params.message,
|
|
2022
|
+
codexErrorInfo: "usageLimitExceeded",
|
|
2023
|
+
rateLimits: readRecentCodexRateLimits(params.client)
|
|
2024
|
+
},
|
|
2025
|
+
timeoutMs: params.timeoutMs,
|
|
2026
|
+
signal: params.signal
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
async function refreshCodexUsageLimitError(params) {
|
|
2030
|
+
const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
|
|
2031
|
+
if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
|
|
2032
|
+
message: initialMessage,
|
|
2033
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2034
|
+
} : void 0;
|
|
2035
|
+
const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
|
|
2036
|
+
client: params.client,
|
|
2037
|
+
timeoutMs: params.timeoutMs,
|
|
2038
|
+
signal: params.signal
|
|
2039
|
+
});
|
|
2040
|
+
if (!rateLimits) return initialMessage ? {
|
|
2041
|
+
message: initialMessage,
|
|
2042
|
+
...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
|
|
2043
|
+
} : void 0;
|
|
2044
|
+
const message = formatCodexUsageLimitErrorMessage({
|
|
2045
|
+
message: params.source.message,
|
|
2046
|
+
codexErrorInfo: params.source.codexErrorInfo,
|
|
2047
|
+
rateLimits,
|
|
2048
|
+
rateLimitsAuthoritative: true
|
|
2049
|
+
}) ?? initialMessage;
|
|
2050
|
+
return message ? {
|
|
2051
|
+
message,
|
|
2052
|
+
rateLimitsForProfile: rateLimits
|
|
2053
|
+
} : void 0;
|
|
2054
|
+
}
|
|
2055
|
+
async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
|
|
2056
|
+
if (params.signal?.aborted) return;
|
|
2057
|
+
try {
|
|
2058
|
+
const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
|
|
2059
|
+
timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
|
|
2060
|
+
signal: params.signal
|
|
2061
|
+
});
|
|
2062
|
+
rememberCodexRateLimitsRead(params.client, rateLimits);
|
|
2063
|
+
return rateLimits;
|
|
2064
|
+
} catch (error) {
|
|
2065
|
+
embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
|
|
2070
|
+
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
|
|
2071
|
+
return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
|
|
2072
|
+
}
|
|
2073
|
+
function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
|
|
2074
|
+
const notificationError = readCodexErrorNotification(errorNotification);
|
|
2075
|
+
const errorPayload = readCodexErrorPayload(error);
|
|
2076
|
+
const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
|
|
2077
|
+
const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
|
|
2078
|
+
return {
|
|
2079
|
+
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
2080
|
+
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
2081
|
+
rateLimits,
|
|
2082
|
+
rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
function readCodexErrorNotification(notification) {
|
|
2086
|
+
if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
|
|
2087
|
+
const error = notification.params.error;
|
|
2088
|
+
return isJsonObject(error) ? {
|
|
2089
|
+
message: readString$4(error, "message"),
|
|
2090
|
+
codexErrorInfo: error.codexErrorInfo
|
|
2091
|
+
} : void 0;
|
|
2092
|
+
}
|
|
2093
|
+
function readCodexErrorPayload(error) {
|
|
2094
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
2095
|
+
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
2096
|
+
const data = error.data;
|
|
2097
|
+
if (!isJsonObject(data)) return { message };
|
|
2098
|
+
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
2099
|
+
const rateLimits = nestedError.rateLimits ?? data.rateLimits;
|
|
2100
|
+
return {
|
|
2101
|
+
message: readString$4(nestedError, "message") ?? message,
|
|
2102
|
+
codexErrorInfo: nestedError.codexErrorInfo,
|
|
2103
|
+
rateLimits
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
function readString$4(record, key) {
|
|
2107
|
+
const value = record[key];
|
|
2108
|
+
return typeof value === "string" ? value : void 0;
|
|
2109
|
+
}
|
|
2110
|
+
//#endregion
|
|
2111
|
+
//#region extensions/codex/src/app-server/event-projector.ts
|
|
2112
|
+
var CodexAppServerEventProjector = class {
|
|
2113
|
+
constructor(params, threadId, turnId, options = {}) {
|
|
2114
|
+
this.params = params;
|
|
2115
|
+
this.threadId = threadId;
|
|
2116
|
+
this.turnId = turnId;
|
|
2117
|
+
this.options = options;
|
|
2118
|
+
this.activeItemIds = /* @__PURE__ */ new Set();
|
|
2119
|
+
this.completedItemIds = /* @__PURE__ */ new Set();
|
|
2120
|
+
this.activeCompactionItemIds = /* @__PURE__ */ new Set();
|
|
2121
|
+
this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
|
|
2122
|
+
this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
|
|
2123
|
+
this.promptErrorSource = null;
|
|
2124
|
+
this.synthesizedMissingToolResultError = null;
|
|
2125
|
+
this.aborted = false;
|
|
2126
|
+
this.completedCompactionCount = 0;
|
|
2127
|
+
this.lastTranscriptTimestamp = 0;
|
|
2128
|
+
this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
|
|
2129
|
+
this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
|
|
2130
|
+
this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
|
|
2131
|
+
this.toolProgressProjection = new CodexToolProgressProjection(params);
|
|
2132
|
+
this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, () => this.nextTranscriptTimestamp(), {
|
|
2133
|
+
nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
|
|
2134
|
+
trajectoryRecorder: options.trajectoryRecorder
|
|
2135
|
+
});
|
|
2136
|
+
this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
|
|
2137
|
+
this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text), () => this.nextTranscriptTimestamp());
|
|
2138
|
+
this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
|
|
2139
|
+
}
|
|
2140
|
+
nextTranscriptTimestamp() {
|
|
2141
|
+
this.lastTranscriptTimestamp = Math.max(Date.now(), this.lastTranscriptTimestamp + 1);
|
|
2142
|
+
return this.lastTranscriptTimestamp;
|
|
2143
|
+
}
|
|
2144
|
+
getCompletedTurnStatus() {
|
|
2145
|
+
return this.completedTurn?.status;
|
|
2146
|
+
}
|
|
2147
|
+
hasCompletedTerminalAssistantText() {
|
|
2148
|
+
return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
|
|
2149
|
+
}
|
|
2150
|
+
getLatestTerminalAssistantCandidate() {
|
|
2151
|
+
return this.assistantProjection.getLatestTerminalAssistantCandidate();
|
|
2152
|
+
}
|
|
2153
|
+
hasLatestTerminalAssistantCandidateText() {
|
|
2154
|
+
return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
|
|
2155
|
+
}
|
|
2156
|
+
canReleaseLatestTerminalAssistantAfterToolHandoff() {
|
|
2157
|
+
return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
|
|
2158
|
+
}
|
|
2159
|
+
/** Restores a completed final item after only the enclosing turn timeout fired. */
|
|
2160
|
+
recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
|
|
2161
|
+
if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
|
|
2162
|
+
this.aborted = false;
|
|
2163
|
+
this.promptError = void 0;
|
|
2164
|
+
this.promptErrorSource = null;
|
|
2165
|
+
return true;
|
|
2166
|
+
}
|
|
2167
|
+
/** Resolves the shared model-order position for a native tool item. */
|
|
2168
|
+
recordNativeToolOutcome(item) {
|
|
2169
|
+
if (!item || this.nativeToolOutcomeOrdinals.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
|
|
2170
|
+
const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
|
|
2171
|
+
if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
|
|
2172
|
+
}
|
|
2173
|
+
recordNativeToolApprovalFailure(toolCallId, disposition) {
|
|
2174
|
+
this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
|
|
2175
|
+
}
|
|
2176
|
+
recordNativeToolPreToolUseFailure(failure) {
|
|
2177
|
+
this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
|
|
2178
|
+
}
|
|
2179
|
+
async handleNotification(notification) {
|
|
2180
|
+
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
2181
|
+
if (!params) return;
|
|
2182
|
+
if (isHookNotificationMethod(notification.method)) {
|
|
2183
|
+
if (!this.isHookNotificationForCurrentThread(params)) return;
|
|
2184
|
+
} else if (notification.method === "guardianWarning") {
|
|
2185
|
+
if (readCodexNotificationThreadId(params) !== this.threadId) return;
|
|
2186
|
+
} else if (!this.isNotificationForTurn(params)) return;
|
|
2187
|
+
this.nativeToolLifecycleProjector.handleNotification(notification);
|
|
2188
|
+
switch (notification.method) {
|
|
2189
|
+
case "item/agentMessage/delta":
|
|
2190
|
+
await this.assistantProjection.handleAssistantDelta(params);
|
|
2191
|
+
break;
|
|
2192
|
+
case "item/reasoning/summaryTextDelta":
|
|
2193
|
+
case "item/reasoning/textDelta":
|
|
2194
|
+
await this.reasoningProjection.handleReasoningDelta(notification.method, params);
|
|
2195
|
+
break;
|
|
2196
|
+
case "item/plan/delta":
|
|
2197
|
+
this.reasoningProjection.handlePlanDelta(params);
|
|
2198
|
+
break;
|
|
2199
|
+
case "turn/plan/updated":
|
|
2200
|
+
this.reasoningProjection.handleTurnPlanUpdated(params);
|
|
2201
|
+
break;
|
|
2202
|
+
case "item/started":
|
|
2203
|
+
await this.handleItemStarted(params);
|
|
2204
|
+
break;
|
|
2205
|
+
case "item/completed":
|
|
2206
|
+
await this.handleItemCompleted(params);
|
|
2207
|
+
break;
|
|
2208
|
+
case "item/commandExecution/outputDelta":
|
|
2209
|
+
this.toolProgressProjection.handleOutputDelta(params, "bash");
|
|
2210
|
+
break;
|
|
2211
|
+
case "item/autoApprovalReview/started":
|
|
2212
|
+
case "item/autoApprovalReview/completed":
|
|
2213
|
+
this.eventProjection.handleGuardianReview(notification.method, params);
|
|
2214
|
+
break;
|
|
2215
|
+
case "guardianWarning":
|
|
2216
|
+
this.eventProjection.handleGuardianWarning(params);
|
|
2217
|
+
break;
|
|
2218
|
+
case "hook/started":
|
|
2219
|
+
case "hook/completed":
|
|
2220
|
+
this.eventProjection.handleHook(notification.method, params);
|
|
2221
|
+
break;
|
|
2222
|
+
case "thread/tokenUsage/updated":
|
|
2223
|
+
projectCodexThreadUsageUpdate(params, this.tokenUsage, (usage) => this.tokenUsage = usage, (data) => this.emitAgentEvent({
|
|
2224
|
+
stream: "codex_app_server.usage",
|
|
2225
|
+
data
|
|
2226
|
+
}));
|
|
2227
|
+
break;
|
|
2228
|
+
case "turn/completed":
|
|
2229
|
+
await this.handleTurnCompleted(params);
|
|
2230
|
+
break;
|
|
2231
|
+
case "rawResponse/completed":
|
|
2232
|
+
this.handleRawResponseCompleted(params);
|
|
2233
|
+
break;
|
|
2234
|
+
case "rawResponseItem/completed":
|
|
2235
|
+
await this.handleRawResponseItemCompleted(params);
|
|
2236
|
+
break;
|
|
2237
|
+
case "error":
|
|
2238
|
+
this.responseUsage = void 0;
|
|
2239
|
+
if (params.willRetry === true) break;
|
|
2240
|
+
this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
|
|
2241
|
+
this.promptErrorSource = "prompt";
|
|
2242
|
+
break;
|
|
2243
|
+
case "thread/compacted":
|
|
2244
|
+
case "turn/started":
|
|
2245
|
+
case "turn/diff/updated":
|
|
2246
|
+
case "item/reasoning/summaryPartAdded":
|
|
2247
|
+
case "item/commandExecution/terminalInteraction":
|
|
2248
|
+
case "item/fileChange/outputDelta":
|
|
2249
|
+
case "item/fileChange/patchUpdated":
|
|
2250
|
+
case "item/mcpToolCall/progress":
|
|
2251
|
+
case "model/rerouted":
|
|
2252
|
+
case "model/verification":
|
|
2253
|
+
case "turn/moderationMetadata":
|
|
2254
|
+
case "model/safetyBuffering/updated": break;
|
|
2255
|
+
default:
|
|
2256
|
+
this.diagnostics.warnUnknownEvent(notification, params);
|
|
2257
|
+
break;
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
buildResult(toolTelemetry, options) {
|
|
2261
|
+
this.nativeToolLifecycleProjector.finalizeActive();
|
|
2262
|
+
const assistantTexts = this.assistantProjection.collectAssistantTexts();
|
|
2263
|
+
const commentaryMessages = this.assistantProjection.collectCommentaryMessages();
|
|
2264
|
+
const reasoningText = this.reasoningProjection.reasoningText();
|
|
2265
|
+
const planText = this.reasoningProjection.planText();
|
|
2266
|
+
const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
|
|
2267
|
+
const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
|
|
2268
|
+
const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
|
|
2269
|
+
const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
|
|
2270
|
+
const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
|
|
2271
|
+
synthesize: legacyFailClosed,
|
|
2272
|
+
recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
|
|
2273
|
+
});
|
|
2274
|
+
if (synthesizedMissingToolResultError) {
|
|
2275
|
+
this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
|
|
2276
|
+
this.promptErrorSource = this.promptErrorSource ?? "prompt";
|
|
2277
|
+
}
|
|
2278
|
+
const assistantMessageOptions = {
|
|
2279
|
+
tokenUsage: projectedUsage,
|
|
2280
|
+
aborted: this.aborted,
|
|
2281
|
+
promptError: this.promptError
|
|
2282
|
+
};
|
|
2283
|
+
const lastAssistant = assistantTexts.length ? this.assistantProjection.createAssistantMessage(assistantTexts.join("\n\n"), assistantMessageOptions) : void 0;
|
|
2284
|
+
const currentAttemptAssistant = this.assistantProjection.createCurrentAttemptAssistantMessage(assistantMessageOptions);
|
|
2285
|
+
const messagesSnapshot = buildCodexMessagesSnapshot({
|
|
2286
|
+
runParams: this.params,
|
|
2287
|
+
turnId: this.turnId,
|
|
2288
|
+
upstreamUserText: this.options.upstreamUserText,
|
|
2289
|
+
reasoningText,
|
|
2290
|
+
planText,
|
|
2291
|
+
commentaryMessages,
|
|
2292
|
+
toolMessages: this.toolTranscriptProjection.transcriptMessages,
|
|
2293
|
+
lastAssistant,
|
|
2294
|
+
createAssistantMirrorMessage: (title, text) => this.assistantProjection.createAssistantMirrorMessage(title, text)
|
|
2295
|
+
});
|
|
2296
|
+
const turnFailed = this.completedTurn?.status === "failed";
|
|
2297
|
+
const promptError = this.promptError ?? this.synthesizedMissingToolResultError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
|
|
2298
|
+
const agentHarnessResultClassification = classifyAgentHarnessTerminalOutcome({
|
|
2299
|
+
assistantTexts,
|
|
2300
|
+
reasoningText,
|
|
2301
|
+
planText,
|
|
2302
|
+
promptError,
|
|
2303
|
+
turnCompleted: Boolean(this.completedTurn)
|
|
2304
|
+
});
|
|
2305
|
+
const toolMetas = this.toolProgressProjection.toolMetas;
|
|
2306
|
+
const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
|
|
2307
|
+
return {
|
|
2308
|
+
aborted: this.aborted,
|
|
2309
|
+
externalAbort: false,
|
|
2310
|
+
timedOut: false,
|
|
2311
|
+
idleTimedOut: false,
|
|
2312
|
+
timedOutDuringCompaction: false,
|
|
2313
|
+
timedOutDuringToolExecution: false,
|
|
2314
|
+
promptError,
|
|
2315
|
+
promptErrorSource: promptError ? this.promptErrorSource || "prompt" : null,
|
|
2316
|
+
sessionIdUsed: this.params.sessionId,
|
|
2317
|
+
...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
|
|
2318
|
+
bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
|
|
2319
|
+
bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
|
|
2320
|
+
messagesSnapshot,
|
|
2321
|
+
assistantTexts,
|
|
2322
|
+
toolMetas,
|
|
2323
|
+
lastAssistant,
|
|
2324
|
+
currentAttemptAssistant,
|
|
2325
|
+
...this.toolProgressProjection.lastToolError ? { lastToolError: this.toolProgressProjection.lastToolError } : {},
|
|
2326
|
+
didSendViaMessagingTool: toolTelemetry.didSendViaMessagingTool,
|
|
2327
|
+
didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
|
|
2328
|
+
messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
|
|
2329
|
+
messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
|
|
2330
|
+
messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
|
|
2331
|
+
messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
|
|
2332
|
+
heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
|
|
2333
|
+
toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
|
|
2334
|
+
hostOwnedToolMediaUrls: this.generatedMediaProjection.buildHostOwnedMediaUrls(toolTelemetry),
|
|
2335
|
+
toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
|
|
2336
|
+
successfulCronAdds: toolTelemetry.successfulCronAdds,
|
|
2337
|
+
cloudCodeAssistFormatError: false,
|
|
2338
|
+
attemptUsage: projectedUsage,
|
|
2339
|
+
...this.completedCompactionCount > 0 ? { compactionCount: this.completedCompactionCount } : {},
|
|
2340
|
+
replayMetadata: {
|
|
2341
|
+
hadPotentialSideEffects,
|
|
2342
|
+
replaySafe: !hadPotentialSideEffects
|
|
2343
|
+
},
|
|
2344
|
+
itemLifecycle: {
|
|
2345
|
+
startedCount: this.activeItemIds.size + this.completedItemIds.size,
|
|
2346
|
+
completedCount: this.completedItemIds.size,
|
|
2347
|
+
activeCount: this.activeItemIds.size
|
|
2348
|
+
},
|
|
2349
|
+
yieldDetected: options?.yieldDetected || false,
|
|
2350
|
+
didSendDeterministicApprovalPrompt: this.eventProjection.guardianReviewCount > 0 ? false : void 0
|
|
2351
|
+
};
|
|
2352
|
+
}
|
|
2353
|
+
recordDynamicToolCall(params) {
|
|
2354
|
+
this.toolTranscriptProjection.recordDynamicToolCall(params);
|
|
2355
|
+
}
|
|
2356
|
+
recordDynamicToolResult(params) {
|
|
2357
|
+
this.toolProgressProjection.recordDynamicToolResult(params);
|
|
2358
|
+
this.toolTranscriptProjection.recordDynamicToolResult(params);
|
|
2359
|
+
}
|
|
2360
|
+
markTimedOut() {
|
|
2361
|
+
this.aborted = true;
|
|
2362
|
+
this.promptError = "codex app-server attempt timed out";
|
|
2363
|
+
this.promptErrorSource = "prompt";
|
|
2364
|
+
}
|
|
2365
|
+
markAborted() {
|
|
2366
|
+
this.aborted = true;
|
|
2367
|
+
this.responseUsage = void 0;
|
|
2368
|
+
}
|
|
2369
|
+
isCompacting() {
|
|
2370
|
+
return this.activeCompactionItemIds.size > 0;
|
|
2371
|
+
}
|
|
2372
|
+
async handleItemStarted(params) {
|
|
2373
|
+
const item = readItem(params.item);
|
|
2374
|
+
const itemId = item?.id ?? readString$5(params, "itemId");
|
|
2375
|
+
this.assistantProjection.recordItemStarted(item, itemId);
|
|
2376
|
+
if (itemId) this.activeItemIds.add(itemId);
|
|
2377
|
+
this.recordNativeToolOutcome(item);
|
|
2378
|
+
if (item?.type === "contextCompaction" && itemId) {
|
|
2379
|
+
this.activeCompactionItemIds.add(itemId);
|
|
2380
|
+
await runAgentHarnessBeforeCompactionHook({
|
|
2381
|
+
sessionFile: this.params.sessionFile,
|
|
2382
|
+
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
2383
|
+
ctx: {
|
|
2384
|
+
runId: this.params.runId,
|
|
2385
|
+
agentId: this.params.agentId,
|
|
2386
|
+
sessionKey: this.params.sessionKey,
|
|
2387
|
+
sessionId: this.params.sessionId,
|
|
2388
|
+
workspaceDir: this.params.workspaceDir,
|
|
2389
|
+
messageProvider: this.params.messageProvider ?? void 0,
|
|
2390
|
+
trigger: this.params.trigger,
|
|
2391
|
+
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
2392
|
+
}
|
|
2393
|
+
});
|
|
2394
|
+
this.emitAgentEvent({
|
|
2395
|
+
stream: "compaction",
|
|
2396
|
+
data: {
|
|
2397
|
+
phase: "start",
|
|
2398
|
+
backend: "codex-app-server",
|
|
2399
|
+
threadId: this.threadId,
|
|
2400
|
+
turnId: this.turnId,
|
|
2401
|
+
itemId
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
}
|
|
2405
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2406
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2407
|
+
phase: "start",
|
|
2408
|
+
item
|
|
2409
|
+
});
|
|
2410
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2411
|
+
phase: "start",
|
|
2412
|
+
item
|
|
2413
|
+
});
|
|
2414
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2415
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2416
|
+
this.emitAgentEvent({
|
|
2417
|
+
stream: "codex_app_server.item",
|
|
2418
|
+
data: {
|
|
2419
|
+
phase: "started",
|
|
2420
|
+
itemId,
|
|
2421
|
+
type: item?.type
|
|
2422
|
+
}
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
async handleItemCompleted(params) {
|
|
2426
|
+
const item = readItem(params.item);
|
|
2427
|
+
this.diagnostics.warnUnknownItemStatus(item);
|
|
2428
|
+
this.recordNativeToolOutcome(item);
|
|
2429
|
+
this.clearTerminalPresentationForNativeItem(item);
|
|
2430
|
+
const itemId = item?.id ?? readString$5(params, "itemId");
|
|
2431
|
+
if (itemId) {
|
|
2432
|
+
this.activeItemIds.delete(itemId);
|
|
2433
|
+
this.completedItemIds.add(itemId);
|
|
2434
|
+
}
|
|
2435
|
+
this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
|
|
2436
|
+
this.reasoningProjection.recordItem(item);
|
|
2437
|
+
this.generatedMediaProjection.recordNative(item);
|
|
2438
|
+
if (item?.type === "contextCompaction" && itemId) {
|
|
2439
|
+
this.activeCompactionItemIds.delete(itemId);
|
|
2440
|
+
this.completedCompactionCount += 1;
|
|
2441
|
+
this.options.onContextCompacted?.();
|
|
2442
|
+
await runAgentHarnessAfterCompactionHook({
|
|
2443
|
+
sessionFile: this.params.sessionFile,
|
|
2444
|
+
messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
|
|
2445
|
+
compactedCount: -1,
|
|
2446
|
+
ctx: {
|
|
2447
|
+
runId: this.params.runId,
|
|
2448
|
+
agentId: this.params.agentId,
|
|
2449
|
+
sessionKey: this.params.sessionKey,
|
|
2450
|
+
sessionId: this.params.sessionId,
|
|
2451
|
+
workspaceDir: this.params.workspaceDir,
|
|
2452
|
+
messageProvider: this.params.messageProvider ?? void 0,
|
|
2453
|
+
trigger: this.params.trigger,
|
|
2454
|
+
channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2457
|
+
this.emitAgentEvent({
|
|
2458
|
+
stream: "compaction",
|
|
2459
|
+
data: {
|
|
2460
|
+
phase: "end",
|
|
2461
|
+
backend: "codex-app-server",
|
|
2462
|
+
completed: true,
|
|
2463
|
+
threadId: this.threadId,
|
|
2464
|
+
turnId: this.turnId,
|
|
2465
|
+
itemId
|
|
2466
|
+
}
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2470
|
+
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
2471
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2472
|
+
phase: "end",
|
|
2473
|
+
item
|
|
2474
|
+
});
|
|
2475
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2476
|
+
phase: "result",
|
|
2477
|
+
item
|
|
2478
|
+
});
|
|
2479
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2480
|
+
this.toolTranscriptProjection.recordNativeToolResult(item);
|
|
2481
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2482
|
+
this.toolProgressProjection.emitToolResultOutput(item);
|
|
2483
|
+
this.emitAgentEvent({
|
|
2484
|
+
stream: "codex_app_server.item",
|
|
2485
|
+
data: {
|
|
2486
|
+
phase: "completed",
|
|
2487
|
+
itemId,
|
|
2488
|
+
type: item?.type
|
|
2489
|
+
}
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
handleRawResponseCompleted(params) {
|
|
2493
|
+
const usage = isJsonObject(params.usage) ? params.usage : void 0;
|
|
2494
|
+
this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
|
|
2495
|
+
}
|
|
2496
|
+
async handleTurnCompleted(params) {
|
|
2497
|
+
const turn = readCodexTurn(params.turn);
|
|
2498
|
+
if (!turn || turn.id !== this.turnId) return;
|
|
2499
|
+
this.completedTurn = turn;
|
|
2500
|
+
if (turn.status !== "completed") this.responseUsage = void 0;
|
|
2501
|
+
if (turn.status === "failed") {
|
|
2502
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
2503
|
+
message: turn.error?.message,
|
|
2504
|
+
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
2505
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
2506
|
+
});
|
|
2507
|
+
this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
|
|
2508
|
+
this.promptErrorSource = "prompt";
|
|
2509
|
+
}
|
|
2510
|
+
const turnItems = turn.items ?? [];
|
|
2511
|
+
for (let index = turnItems.length - 1; index >= 0; index -= 1) {
|
|
2512
|
+
const item = turnItems[index];
|
|
2513
|
+
if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
|
|
2514
|
+
if (item?.type === "dynamicToolCall") break;
|
|
2515
|
+
if (shouldClearTerminalPresentationForNativeItem(item)) {
|
|
2516
|
+
this.clearTerminalPresentationForNativeItem(item);
|
|
2517
|
+
break;
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
for (const item of turnItems) {
|
|
2521
|
+
this.diagnostics.warnUnknownItemStatus(item);
|
|
2522
|
+
this.assistantProjection.recordSnapshotItem(item);
|
|
2523
|
+
this.reasoningProjection.recordItem(item);
|
|
2524
|
+
this.generatedMediaProjection.recordNative(item);
|
|
2525
|
+
this.toolProgressProjection.recordToolMeta(item);
|
|
2526
|
+
this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
|
|
2527
|
+
await this.emitSnapshotOnlyNativeToolProgress(item);
|
|
2528
|
+
this.toolTranscriptProjection.recordNativeToolCall(item);
|
|
2529
|
+
this.toolTranscriptProjection.recordNativeToolResult(item);
|
|
2530
|
+
this.toolTranscriptProjection.emitAfterToolCallObservation(item);
|
|
2531
|
+
this.toolProgressProjection.emitToolResultSummary(item);
|
|
2532
|
+
this.toolProgressProjection.emitToolResultOutput(item);
|
|
2533
|
+
}
|
|
2534
|
+
this.assistantProjection.finalizeAnswerCandidate(turn);
|
|
2535
|
+
this.activeCompactionItemIds.clear();
|
|
2536
|
+
await this.reasoningProjection.maybeEndReasoning();
|
|
2537
|
+
}
|
|
2538
|
+
async emitSnapshotOnlyNativeToolProgress(item) {
|
|
2539
|
+
if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
|
|
2540
|
+
if (!this.activeItemIds.has(item.id)) {
|
|
2541
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2542
|
+
phase: "start",
|
|
2543
|
+
item
|
|
2544
|
+
});
|
|
2545
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2546
|
+
phase: "start",
|
|
2547
|
+
item
|
|
2548
|
+
});
|
|
2549
|
+
}
|
|
2550
|
+
this.activeItemIds.delete(item.id);
|
|
2551
|
+
this.eventProjection.emitStandardItemEvent({
|
|
2552
|
+
phase: "end",
|
|
2553
|
+
item
|
|
2554
|
+
});
|
|
2555
|
+
await this.eventProjection.emitNormalizedToolItemEvent({
|
|
2556
|
+
phase: "result",
|
|
2557
|
+
item
|
|
2558
|
+
});
|
|
2559
|
+
this.completedItemIds.add(item.id);
|
|
2560
|
+
}
|
|
2561
|
+
isCurrentTurnSnapshotItem(item) {
|
|
2562
|
+
const itemTurnId = readItemString(item, "turnId");
|
|
2563
|
+
return itemTurnId === void 0 || itemTurnId === this.turnId;
|
|
2564
|
+
}
|
|
2565
|
+
async handleRawResponseItemCompleted(params) {
|
|
2566
|
+
const item = isJsonObject(params.item) ? params.item : void 0;
|
|
2567
|
+
if (!item) return;
|
|
2568
|
+
this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
|
|
2569
|
+
await this.generatedMediaProjection.recordRaw(item);
|
|
2570
|
+
}
|
|
2571
|
+
clearTerminalPresentationForNativeItem(item) {
|
|
2572
|
+
if (!item || this.terminalPresentationClearedItemIds.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
|
|
2573
|
+
const toolCallOrdinal = this.nativeToolOutcomeOrdinals.get(item.id);
|
|
2574
|
+
this.terminalPresentationClearedItemIds.add(item.id);
|
|
2575
|
+
this.params.onToolOutcome?.({
|
|
2576
|
+
toolName: itemName(item) ?? item.type,
|
|
2577
|
+
argsHash: "",
|
|
2578
|
+
resultHash: "",
|
|
2579
|
+
...toolCallOrdinal !== void 0 ? { toolCallOrdinal } : {},
|
|
2580
|
+
terminalPresentation: void 0,
|
|
2581
|
+
presentationOnly: true
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
formatCodexErrorMessage(params) {
|
|
2585
|
+
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
2586
|
+
const usageLimitMessage = formatCodexUsageLimitErrorMessage({
|
|
2587
|
+
message: error ? readString$5(error, "message") : void 0,
|
|
2588
|
+
codexErrorInfo: error?.codexErrorInfo,
|
|
2589
|
+
rateLimits: this.options.readRecentRateLimits?.()
|
|
2590
|
+
});
|
|
2591
|
+
return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
|
|
2592
|
+
}
|
|
2593
|
+
emitAgentEvent(event) {
|
|
2594
|
+
try {
|
|
2595
|
+
emitAgentEvent({
|
|
2596
|
+
runId: this.params.runId,
|
|
2597
|
+
stream: event.stream,
|
|
2598
|
+
data: event.data,
|
|
2599
|
+
...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
|
|
2600
|
+
});
|
|
2601
|
+
} catch (error) {
|
|
2602
|
+
embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
|
|
2603
|
+
}
|
|
2604
|
+
try {
|
|
2605
|
+
const maybePromise = this.params.onAgentEvent?.(event);
|
|
2606
|
+
Promise.resolve(maybePromise).catch((error) => {
|
|
2607
|
+
embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
|
|
2608
|
+
});
|
|
2609
|
+
} catch (error) {
|
|
2610
|
+
embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
isNotificationForTurn(params) {
|
|
2614
|
+
const threadId = readCodexNotificationThreadId(params);
|
|
2615
|
+
const turnId = readCodexNotificationTurnId(params);
|
|
2616
|
+
return threadId === this.threadId && turnId === this.turnId;
|
|
2617
|
+
}
|
|
2618
|
+
isHookNotificationForCurrentThread(params) {
|
|
2619
|
+
const threadId = readString$5(params, "threadId");
|
|
2620
|
+
const turnId = params.turnId;
|
|
2621
|
+
return threadId === this.threadId && (turnId === this.turnId || turnId === null);
|
|
2622
|
+
}
|
|
2623
|
+
};
|
|
2624
|
+
function isHookNotificationMethod(method) {
|
|
2625
|
+
return method === "hook/started" || method === "hook/completed";
|
|
2626
|
+
}
|
|
2627
|
+
//#endregion
|
|
193
2628
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
194
2629
|
/** Bridges Codex request_user_input calls to gateway questions and secret text prompts. */
|
|
195
2630
|
const DEFAULT_USER_INPUT_TIMEOUT_MS = 15 * 6e4;
|
|
@@ -267,7 +2702,7 @@ function createCodexUserInputBridge(params) {
|
|
|
267
2702
|
},
|
|
268
2703
|
signal: abort.signal
|
|
269
2704
|
});
|
|
270
|
-
return result.status === "answered" ? result.answers : emptyUserInputResponse();
|
|
2705
|
+
return result.status === "answered" ? gatewayAnswersToCodexResponse(result.answers.answers) : emptyUserInputResponse();
|
|
271
2706
|
} catch (error) {
|
|
272
2707
|
embeddedAgentLog.warn("failed to bridge codex user input through gateway", { error });
|
|
273
2708
|
return emptyUserInputResponse();
|
|
@@ -350,6 +2785,9 @@ function readOption(value) {
|
|
|
350
2785
|
function buildUserInputResponse(questions, inputText) {
|
|
351
2786
|
return buildAgentHarnessUserInputAnswers(questions, inputText);
|
|
352
2787
|
}
|
|
2788
|
+
function gatewayAnswersToCodexResponse(answers) {
|
|
2789
|
+
return { answers: Object.fromEntries(Object.entries(answers).map(([questionId, values]) => [questionId, { answers: values }])) };
|
|
2790
|
+
}
|
|
353
2791
|
function emptyUserInputResponse() {
|
|
354
2792
|
return emptyAgentHarnessUserInputAnswers();
|
|
355
2793
|
}
|
|
@@ -474,6 +2912,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
474
2912
|
isStopped: () => state.completed || state.timedOut || runAbortController.signal.aborted,
|
|
475
2913
|
isAbortable: () => !terminalState.terminalOutcomeFrozen || terminalState.sharedAbortAllowedAfterTerminalOutcome,
|
|
476
2914
|
isCompacting: () => projectorRef.current?.isCompacting() ?? false,
|
|
2915
|
+
supportsTranscriptCommitWait: true,
|
|
477
2916
|
supportsQueueMessageImages: true,
|
|
478
2917
|
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
479
2918
|
cancel: () => abortExplicitly("cancelled"),
|
|
@@ -536,7 +2975,7 @@ async function activateCodexAttemptTurn(resources, turnRuntime, lifecycle, notif
|
|
|
536
2975
|
async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRuntime, activeTurn) {
|
|
537
2976
|
const { prompt, state: resourceState, trajectoryRecorder, releaseCurrentRoute, releaseSharedClientLeaseAndRetireOneShotClient, releaseSandboxExecEnvironment } = resources;
|
|
538
2977
|
const { connection } = prompt.context.runtime;
|
|
539
|
-
const { params, options, runAbortController } = connection;
|
|
2978
|
+
const { params, options, runAbortController, terminalState, bindingStore, bindingIdentity } = connection;
|
|
540
2979
|
const { state, steeringQueueRef, userInputBridgeRef, turnWatches } = turnRuntime;
|
|
541
2980
|
const { maybeEmitFastModeAutoResetBestEffort, emitLifecycleTerminal, buildLifecycleTerminalMeta } = lifecycle;
|
|
542
2981
|
const { codexModelCallDiagnostics } = requestRuntime;
|
|
@@ -566,10 +3005,17 @@ async function cleanupCodexAttempt(resources, turnRuntime, lifecycle, requestRun
|
|
|
566
3005
|
cleanup: async () => trajectoryRecorder?.flush()
|
|
567
3006
|
});
|
|
568
3007
|
if (!state.timedOut && !runAbortController.signal.aborted) await steeringQueueRef.current?.flushPending();
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
3008
|
+
const retainLiveIncognitoThread = terminalState.turnSucceeded && isIncognitoSessionKey(params.sessionKey);
|
|
3009
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) && !retainLiveIncognitoThread ? await bindingStore.mutate(bindingIdentity, {
|
|
3010
|
+
kind: "clear",
|
|
3011
|
+
threadId: resourceState.thread.threadId
|
|
3012
|
+
}) : true;
|
|
3013
|
+
if (!state.timedOut && !retainLiveIncognitoThread) {
|
|
3014
|
+
if (bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
3015
|
+
threadId: resourceState.thread.threadId,
|
|
3016
|
+
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
573
3019
|
userInputBridgeRef.current?.cancelPending();
|
|
574
3020
|
turnWatches.clearAllTimers();
|
|
575
3021
|
releaseCurrentRoute();
|
|
@@ -830,19 +3276,11 @@ function readCodexAppServerRolloutTokenSnapshotLine(line) {
|
|
|
830
3276
|
return;
|
|
831
3277
|
}
|
|
832
3278
|
}
|
|
833
|
-
function toNonNegativeInt(value) {
|
|
834
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return;
|
|
835
|
-
return Math.floor(value);
|
|
836
|
-
}
|
|
837
3279
|
function readCompactionConfig(config) {
|
|
838
3280
|
return isJsonObject(config?.agents?.defaults?.compaction) ? config.agents.defaults.compaction : void 0;
|
|
839
3281
|
}
|
|
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;
|
|
3282
|
+
function resolveCodexAppServerNativeThreadReserveTokens(_config) {
|
|
3283
|
+
return CODEX_APP_SERVER_NATIVE_THREAD_DEFAULT_RESERVE_TOKENS;
|
|
846
3284
|
}
|
|
847
3285
|
function resolveCodexAppServerNativeThreadTokenFuse(params) {
|
|
848
3286
|
const projectedTurnTokens = typeof params.projectedTurnTokens === "number" && Number.isFinite(params.projectedTurnTokens) && params.projectedTurnTokens > 0 ? Math.floor(params.projectedTurnTokens) : 0;
|
|
@@ -938,6 +3376,14 @@ async function rotateOversizedCodexAppServerStartupBinding(params) {
|
|
|
938
3376
|
}
|
|
939
3377
|
//#endregion
|
|
940
3378
|
//#region extensions/codex/src/app-server/run-attempt-connection.ts
|
|
3379
|
+
function applyStoredBindingPermissions(params) {
|
|
3380
|
+
if (params.execPolicyTouched || params.binding?.connectionScope === "supervision") return params.appServer;
|
|
3381
|
+
return {
|
|
3382
|
+
...params.appServer,
|
|
3383
|
+
approvalPolicy: params.binding?.approvalPolicy ?? params.appServer.approvalPolicy,
|
|
3384
|
+
sandbox: params.binding?.sandbox ?? params.appServer.sandbox
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
941
3387
|
async function prepareCodexAttemptConnection({ params, options }) {
|
|
942
3388
|
const attemptStartedAt = Date.now();
|
|
943
3389
|
const profilerEnabled = isCodexAppServerProfilerEnabled(params.config);
|
|
@@ -995,23 +3441,27 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
995
3441
|
bindingStore,
|
|
996
3442
|
identity: bindingIdentity,
|
|
997
3443
|
config: params.config
|
|
998
|
-
})) throw
|
|
3444
|
+
})) throw createCodexSessionGenerationSupersededError(bindingIdentity.sessionId);
|
|
999
3445
|
startupBinding = await bindingStore.read(bindingIdentity);
|
|
1000
3446
|
}
|
|
1001
3447
|
preDynamicStartupStages.mark("read-binding");
|
|
1002
3448
|
const usesSupervisionConnection = startupBinding?.connectionScope === "supervision";
|
|
1003
3449
|
if (usesSupervisionConnection) activeContextEngine = void 0;
|
|
1004
3450
|
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) =>
|
|
3451
|
+
const resolveRuntimeOptionsForBinding = (selection) => applyStoredBindingPermissions({
|
|
3452
|
+
appServer: resolveCodexBindingAppServerConnection({
|
|
3453
|
+
binding: startupBinding,
|
|
3454
|
+
pluginConfig,
|
|
3455
|
+
execPolicy,
|
|
3456
|
+
modelProvider: selection.modelProvider,
|
|
3457
|
+
model: selection.model,
|
|
3458
|
+
config: params.config,
|
|
3459
|
+
agentDir,
|
|
3460
|
+
openClawSandboxActive: sandbox?.enabled === true
|
|
3461
|
+
}).appServer,
|
|
1006
3462
|
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;
|
|
3463
|
+
execPolicyTouched: execPolicy.touched
|
|
3464
|
+
});
|
|
1015
3465
|
const initialStartupBindingHadInactiveThreadBootstrap = isInactiveThreadBootstrapBinding(startupBinding);
|
|
1016
3466
|
const preparedAuthRoute = usesSupervisionConnection ? void 0 : params.runtimePlan?.auth.modelRoute;
|
|
1017
3467
|
const startupAuthProfileCandidate = usesSupervisionConnection ? void 0 : preparedAuthRoute ? params.runtimePlan?.auth.forwardedAuthProfileId : params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
|
|
@@ -1087,6 +3537,7 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1087
3537
|
preDynamicStartupStages.mark("app-server-policy");
|
|
1088
3538
|
preDynamicStartupStages.mark("native-hook-relay");
|
|
1089
3539
|
const terminalState = {
|
|
3540
|
+
turnSucceeded: false,
|
|
1090
3541
|
explicitCancellationObserved: false,
|
|
1091
3542
|
explicitCancellationReason: void 0,
|
|
1092
3543
|
terminalOutcomeFrozen: false,
|
|
@@ -1148,16 +3599,20 @@ async function prepareCodexAttemptConnection({ params, options }) {
|
|
|
1148
3599
|
startupBinding,
|
|
1149
3600
|
pluginAppServer: appServer
|
|
1150
3601
|
};
|
|
1151
|
-
const resolveRuntimeOptionsForCurrentBinding = (selection) =>
|
|
3602
|
+
const resolveRuntimeOptionsForCurrentBinding = (selection) => applyStoredBindingPermissions({
|
|
3603
|
+
appServer: resolveCodexBindingAppServerConnection({
|
|
3604
|
+
binding: mutable.startupBinding,
|
|
3605
|
+
pluginConfig,
|
|
3606
|
+
execPolicy,
|
|
3607
|
+
modelProvider: selection.modelProvider,
|
|
3608
|
+
model: selection.model,
|
|
3609
|
+
config: params.config,
|
|
3610
|
+
agentDir,
|
|
3611
|
+
openClawSandboxActive: sandbox?.enabled === true
|
|
3612
|
+
}).appServer,
|
|
1152
3613
|
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;
|
|
3614
|
+
execPolicyTouched: execPolicy.touched
|
|
3615
|
+
});
|
|
1161
3616
|
return {
|
|
1162
3617
|
params,
|
|
1163
3618
|
options,
|
|
@@ -1217,7 +3672,6 @@ const CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */
|
|
|
1217
3672
|
"user.md"
|
|
1218
3673
|
]);
|
|
1219
3674
|
const CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES = /* @__PURE__ */ new Set([...CODEX_INHERITED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES, ...CODEX_TURN_SCOPED_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES]);
|
|
1220
|
-
const CODEX_HEARTBEAT_CONTEXT_BASENAME = "heartbeat.md";
|
|
1221
3675
|
const CODEX_MEMORY_CONTEXT_BASENAME = "memory.md";
|
|
1222
3676
|
const CODEX_MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set(["memory_search", "memory_get"]);
|
|
1223
3677
|
const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
|
|
@@ -1226,8 +3680,7 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = /* @__PURE__ */ new Map([
|
|
|
1226
3680
|
["user.md", 30],
|
|
1227
3681
|
["tools.md", 40],
|
|
1228
3682
|
["bootstrap.md", 50],
|
|
1229
|
-
["memory.md", 60]
|
|
1230
|
-
["heartbeat.md", 70]
|
|
3683
|
+
["memory.md", 60]
|
|
1231
3684
|
]);
|
|
1232
3685
|
/** Reads mirrored Codex session history for harness hooks. */
|
|
1233
3686
|
async function readMirroredSessionHistoryMessages(params) {
|
|
@@ -1328,14 +3781,12 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
1328
3781
|
});
|
|
1329
3782
|
const developerInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceInheritedDeveloperInstructionFiles(contextFiles) : [];
|
|
1330
3783
|
const turnScopedDeveloperInstructionFiles = shouldInjectCodexOpenClawPromptContext(params.params) ? selectCodexWorkspaceTurnScopedDeveloperInstructionFiles(contextFiles) : [];
|
|
1331
|
-
const heartbeatReferenceFiles = selectCodexWorkspaceHeartbeatReferenceFiles(contextFiles);
|
|
1332
3784
|
return {
|
|
1333
3785
|
bootstrapFiles,
|
|
1334
3786
|
contextFiles,
|
|
1335
3787
|
promptContextFiles,
|
|
1336
3788
|
developerInstructionFiles,
|
|
1337
3789
|
turnScopedDeveloperInstructionFiles,
|
|
1338
|
-
heartbeatReferenceFiles,
|
|
1339
3790
|
memoryReferenceFiles,
|
|
1340
3791
|
memoryToolRoutedBootstrapFiles,
|
|
1341
3792
|
memoryToolNames: [...params.memoryToolNames],
|
|
@@ -1351,8 +3802,7 @@ async function buildCodexWorkspaceBootstrapContext(params) {
|
|
|
1351
3802
|
agentId: params.params.agentId ?? params.sessionAgentId,
|
|
1352
3803
|
agentSessionKey: params.sessionKey,
|
|
1353
3804
|
sandboxed: params.sandboxed
|
|
1354
|
-
}) : void 0
|
|
1355
|
-
heartbeatCollaborationInstructions: renderCodexWorkspaceHeartbeatReference(heartbeatReferenceFiles)
|
|
3805
|
+
}) : void 0
|
|
1356
3806
|
};
|
|
1357
3807
|
} catch (error) {
|
|
1358
3808
|
embeddedAgentLog.warn("failed to load codex workspace bootstrap instructions", { error });
|
|
@@ -1474,14 +3924,9 @@ function buildCodexBootstrapInjectionStats(params) {
|
|
|
1474
3924
|
const injected = memoryToolRoutedFile ? void 0 : readCodexIndexedContextFileContent(injectedIndex, pathValue, fileName) ?? readCodexIndexedContextFileContent(developerInstructionIndex, pathValue, fileName);
|
|
1475
3925
|
let injectedChars = memoryToolRoutedFile ? 0 : injected?.length ?? 0;
|
|
1476
3926
|
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
|
-
}
|
|
3927
|
+
if (injected === void 0 && CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName)) {
|
|
3928
|
+
injectedChars = rawChars;
|
|
3929
|
+
truncated = false;
|
|
1485
3930
|
}
|
|
1486
3931
|
return {
|
|
1487
3932
|
name: displayName,
|
|
@@ -1605,7 +4050,7 @@ function renderCodexWorkspaceBootstrapPromptContext(contextFiles) {
|
|
|
1605
4050
|
const files = contextFiles;
|
|
1606
4051
|
if (files.length === 0) return;
|
|
1607
4052
|
const lines = [
|
|
1608
|
-
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. TOOLS.md is provided as inherited Codex developer instructions. SOUL.md, IDENTITY.md, and USER.md are provided as turn-scoped collaboration instructions so native Codex subagents do not inherit them.
|
|
4053
|
+
"OpenClaw loaded these user-editable workspace files for the current turn. Codex loads AGENTS.md natively. TOOLS.md is provided as inherited Codex developer instructions. 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
4054
|
"",
|
|
1610
4055
|
"# Project Context",
|
|
1611
4056
|
"",
|
|
@@ -1619,7 +4064,7 @@ function selectCodexWorkspacePromptContextFiles(contextFiles, options = {}) {
|
|
|
1619
4064
|
const excludeMemory = options.excludeMemory ?? true;
|
|
1620
4065
|
return contextFiles.filter((file) => {
|
|
1621
4066
|
const baseName = getCodexContextFileBasename(file.path);
|
|
1622
|
-
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) &&
|
|
4067
|
+
return baseName && !CODEX_NATIVE_PROJECT_DOC_BASENAMES.has(baseName) && !CODEX_WORKSPACE_DEVELOPER_CONTEXT_BASENAMES.has(baseName) && (!excludeMemory || !isCodexWorkspaceRootMemoryContextFile({
|
|
1623
4068
|
file,
|
|
1624
4069
|
workspaceDir: options.memoryWorkspaceDir
|
|
1625
4070
|
})) && !isMissingCodexBootstrapContextFile(file);
|
|
@@ -1666,22 +4111,6 @@ function renderCodexWorkspaceDeveloperInstructions(params) {
|
|
|
1666
4111
|
if (wrapperTag) lines.push(`</${wrapperTag}>`);
|
|
1667
4112
|
return lines.join("\n").trim();
|
|
1668
4113
|
}
|
|
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
4114
|
function selectCodexWorkspaceMemoryReferenceFiles(params) {
|
|
1686
4115
|
return params.bootstrapFiles.filter((file) => {
|
|
1687
4116
|
return isCodexWorkspaceRootMemoryBootstrapFile({
|
|
@@ -2020,7 +4449,7 @@ async function prepareCodexAttemptContext(runtime, attemptTools) {
|
|
|
2020
4449
|
},
|
|
2021
4450
|
codexContextProjectionMaxChars: resolveCodexContextEngineProjectionMaxChars({
|
|
2022
4451
|
contextTokenBudget: effectiveContextTokenBudget,
|
|
2023
|
-
reserveTokens: resolveCodexContextEngineProjectionReserveTokens(
|
|
4452
|
+
reserveTokens: resolveCodexContextEngineProjectionReserveTokens()
|
|
2024
4453
|
})
|
|
2025
4454
|
};
|
|
2026
4455
|
}
|
|
@@ -2235,6 +4664,67 @@ function isInvalidCodexImagePayloadError(message) {
|
|
|
2235
4664
|
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
4665
|
}
|
|
2237
4666
|
//#endregion
|
|
4667
|
+
//#region extensions/codex/src/app-server/settled-turn-context.ts
|
|
4668
|
+
function collectUniqueMessageIdentities(messages) {
|
|
4669
|
+
const identities = /* @__PURE__ */ new Map();
|
|
4670
|
+
for (const [index, message] of messages.entries()) {
|
|
4671
|
+
const identity = readMirrorIdentity(message);
|
|
4672
|
+
if (!identity) continue;
|
|
4673
|
+
if (identities.has(identity)) return;
|
|
4674
|
+
identities.set(identity, index);
|
|
4675
|
+
}
|
|
4676
|
+
return identities;
|
|
4677
|
+
}
|
|
4678
|
+
/** Freezes one complete active transcript branch through the settled tool-result boundary. */
|
|
4679
|
+
function buildCodexSettledTurnFinalizationContext(params) {
|
|
4680
|
+
const boundaryMessage = params.settledMessages.findLast((message) => message.role === "toolResult");
|
|
4681
|
+
const boundaryIdentity = boundaryMessage ? readMirrorIdentity(boundaryMessage) : void 0;
|
|
4682
|
+
if (!boundaryMessage || !boundaryIdentity || !boundaryIdentity.startsWith(`${params.turnId}:tool:`)) return;
|
|
4683
|
+
const settledBoundaryIndex = params.settledMessages.indexOf(boundaryMessage);
|
|
4684
|
+
const requiredIdentities = params.settledMessages.slice(0, settledBoundaryIndex + 1).map(readMirrorIdentity);
|
|
4685
|
+
if (requiredIdentities.length === 0 || requiredIdentities.some((identity) => !identity) || new Set(requiredIdentities).size !== requiredIdentities.length || !requiredIdentities.includes(`${params.turnId}:prompt`)) return;
|
|
4686
|
+
const historyIdentities = collectUniqueMessageIdentities(params.historyMessages);
|
|
4687
|
+
const mirroredIdentities = collectUniqueMessageIdentities(params.mirroredMessages);
|
|
4688
|
+
if (!historyIdentities || !mirroredIdentities) return;
|
|
4689
|
+
const mirroredBoundaryIndex = mirroredIdentities.get(boundaryIdentity);
|
|
4690
|
+
if (mirroredBoundaryIndex === void 0) return;
|
|
4691
|
+
const mirroredThroughBoundary = params.mirroredMessages.slice(0, mirroredBoundaryIndex + 1);
|
|
4692
|
+
if (mirroredThroughBoundary.length !== requiredIdentities.length || mirroredThroughBoundary.some((message, index) => readMirrorIdentity(message) !== requiredIdentities[index])) return;
|
|
4693
|
+
const historyBoundaryIndex = historyIdentities.get(boundaryIdentity);
|
|
4694
|
+
if (historyBoundaryIndex === void 0) return;
|
|
4695
|
+
let previousHistoryIndex = -1;
|
|
4696
|
+
for (const mirroredMessage of mirroredThroughBoundary) {
|
|
4697
|
+
const identity = readMirrorIdentity(mirroredMessage);
|
|
4698
|
+
const historyIndex = identity ? historyIdentities.get(identity) : void 0;
|
|
4699
|
+
const historyMessage = historyIndex === void 0 ? void 0 : params.historyMessages[historyIndex];
|
|
4700
|
+
if (historyIndex === void 0 || historyIndex <= previousHistoryIndex || historyIndex > historyBoundaryIndex || !historyMessage || serializeCodexMirrorSourceEvidence(historyMessage) !== serializeCodexMirrorSourceEvidence(mirroredMessage)) return;
|
|
4701
|
+
previousHistoryIndex = historyIndex;
|
|
4702
|
+
}
|
|
4703
|
+
return {
|
|
4704
|
+
source: "openclaw-transcript",
|
|
4705
|
+
messages: Object.freeze(structuredClone(params.historyMessages.slice(0, historyBoundaryIndex + 1)))
|
|
4706
|
+
};
|
|
4707
|
+
}
|
|
4708
|
+
/** Reads and freezes the current active transcript branch after mirroring has settled. */
|
|
4709
|
+
async function captureCodexSettledTurnFinalizationContext(params) {
|
|
4710
|
+
try {
|
|
4711
|
+
const historyMessages = await readCodexMirroredSessionHistoryMessages(params);
|
|
4712
|
+
if (!historyMessages) return;
|
|
4713
|
+
return buildCodexSettledTurnFinalizationContext({
|
|
4714
|
+
historyMessages,
|
|
4715
|
+
mirroredMessages: params.mirroredMessages,
|
|
4716
|
+
settledMessages: params.settledMessages,
|
|
4717
|
+
turnId: params.turnId
|
|
4718
|
+
});
|
|
4719
|
+
} catch (error) {
|
|
4720
|
+
embeddedAgentLog.warn("codex settled-turn finalization context capture failed", {
|
|
4721
|
+
error: formatErrorMessage(error),
|
|
4722
|
+
turnId: params.turnId
|
|
4723
|
+
});
|
|
4724
|
+
return;
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
//#endregion
|
|
2238
4728
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
2239
4729
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
2240
4730
|
const PRIVATE_PAYLOAD_FIELD_RE = /(?:image|screenshot|attachment|fileData|dataUri)/iu;
|
|
@@ -2528,6 +5018,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2528
5018
|
const turnSucceeded = !finalAborted && !effectiveTimedOut && (finalPromptError === null || finalPromptError === void 0) && (completedTurnStatus === "completed" || recoveredTurnWatchTimeout || completedWithoutTerminalNotification);
|
|
2529
5019
|
if (settleCodexSourceReplyFinality(toolBridge.telemetry, turnSucceeded)) result.agentHarnessResultClassification = void 0;
|
|
2530
5020
|
const attemptSucceeded = turnSucceeded && result.agentHarnessResultClassification === void 0;
|
|
5021
|
+
terminalState.turnSucceeded = turnSucceeded;
|
|
2531
5022
|
terminalState.sharedAbortAllowedAfterTerminalOutcome = shouldKeepCodexSharedAbortOpen({
|
|
2532
5023
|
trigger: params.trigger,
|
|
2533
5024
|
result,
|
|
@@ -2547,7 +5038,7 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2547
5038
|
if (modelCallFailureKind) codexModelCallDiagnostics.emitError(finalPromptError ?? "codex app-server attempt interrupted", { failureKind: modelCallFailureKind });
|
|
2548
5039
|
else if (finalPromptError) codexModelCallDiagnostics.emitError(finalPromptError);
|
|
2549
5040
|
else codexModelCallDiagnostics.emitCompleted(result);
|
|
2550
|
-
const
|
|
5041
|
+
const mirrorOutcome = await codexTranscriptMirrorRuntime.mirrorBestEffort({
|
|
2551
5042
|
params,
|
|
2552
5043
|
agentId: sessionAgentId,
|
|
2553
5044
|
notifyUserMessagePersisted,
|
|
@@ -2557,6 +5048,18 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2557
5048
|
threadId: resourceState.thread.threadId,
|
|
2558
5049
|
turnId: activeTurnId
|
|
2559
5050
|
});
|
|
5051
|
+
const { assistantTranscriptOwned, assistantTranscriptIdempotencyKey } = mirrorOutcome;
|
|
5052
|
+
const shouldCaptureSettledTurnFinalizationContext = turnSucceeded && result.assistantTexts.every((text) => !text.trim()) && result.messagesSnapshot.some((message) => message.role === "toolResult");
|
|
5053
|
+
const settledTurnFinalizationContext = shouldCaptureSettledTurnFinalizationContext ? await captureCodexSettledTurnFinalizationContext({
|
|
5054
|
+
...activeTranscriptTarget,
|
|
5055
|
+
mirroredMessages: mirrorOutcome.mirroredMessages,
|
|
5056
|
+
settledMessages: result.messagesSnapshot,
|
|
5057
|
+
turnId: activeTurnId
|
|
5058
|
+
}) : void 0;
|
|
5059
|
+
if (shouldCaptureSettledTurnFinalizationContext && !settledTurnFinalizationContext) embeddedAgentLog.warn("codex settled-turn finalization context is unavailable", {
|
|
5060
|
+
threadId: resourceState.thread.threadId,
|
|
5061
|
+
turnId: activeTurnId
|
|
5062
|
+
});
|
|
2560
5063
|
if (activeContextEngine) {
|
|
2561
5064
|
const contextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
|
|
2562
5065
|
const isHeartbeat = params.bootstrapContextRunKind === "heartbeat" || params.bootstrapContextRunKind === "commitment-only";
|
|
@@ -2687,6 +5190,8 @@ async function finalizeCodexAttempt(resources, turnRuntime, lifecycle, notificat
|
|
|
2687
5190
|
...codexAppServerFailure ? { codexAppServerFailure } : {},
|
|
2688
5191
|
...promptTimeoutOutcome ? { promptTimeoutOutcome } : {},
|
|
2689
5192
|
...assistantTranscriptOwned ? { assistantTranscriptOwned: true } : {},
|
|
5193
|
+
...assistantTranscriptIdempotencyKey ? { assistantTranscriptIdempotencyKey } : {},
|
|
5194
|
+
...settledTurnFinalizationContext ? { settledTurnFinalizationContext } : {},
|
|
2690
5195
|
...resourceState.runtimeArtifact ? { runtimeArtifact: resourceState.runtimeArtifact } : {},
|
|
2691
5196
|
...!finalAborted && !effectiveTimedOut && !finalPromptError && preparedAuthBinding ? { authBindingFingerprint: preparedAuthBinding.fingerprint } : {},
|
|
2692
5197
|
systemPromptReport
|
|
@@ -3011,7 +5516,7 @@ var ClientTurnRouter = class {
|
|
|
3011
5516
|
this.nativeTurnCompletionWatchers = /* @__PURE__ */ new Map();
|
|
3012
5517
|
this.disposed = false;
|
|
3013
5518
|
client.addNotificationHandler((notification) => this.routeNotification(notification));
|
|
3014
|
-
client.addRequestHandler((request) => this.routeRequest(request));
|
|
5519
|
+
client.addRequestHandler((request, signal) => this.routeRequest(request, signal));
|
|
3015
5520
|
client.addCloseHandler(() => this.dispose());
|
|
3016
5521
|
}
|
|
3017
5522
|
reserveThread(options) {
|
|
@@ -3172,34 +5677,35 @@ var ClientTurnRouter = class {
|
|
|
3172
5677
|
this.enqueueNotification(route, handler, notification, routeScope);
|
|
3173
5678
|
return route.notificationTail;
|
|
3174
5679
|
}
|
|
3175
|
-
async routeRequest(request) {
|
|
3176
|
-
if (this.disposed) return;
|
|
5680
|
+
async routeRequest(request, signal = new AbortController().signal) {
|
|
5681
|
+
if (this.disposed || signal.aborted) return;
|
|
3177
5682
|
const scope = readScope(request.params);
|
|
3178
5683
|
if (!scope.threadId) return;
|
|
3179
5684
|
const route = this.routes.get(scope.threadId);
|
|
3180
5685
|
if (!route || route.released) return;
|
|
3181
|
-
if (!route.handlers
|
|
3182
|
-
if (route.released || !route.handlers) return;
|
|
5686
|
+
if (!route.handlers && !await waitForPromiseOrAbort(route.activated.promise, signal)) return;
|
|
5687
|
+
if (signal.aborted || route.released || !route.handlers) return;
|
|
3183
5688
|
const handler = route.handlers.onRequest;
|
|
3184
5689
|
if (!handler) return;
|
|
3185
5690
|
while (route.gate === "armed") {
|
|
3186
|
-
|
|
3187
|
-
if (
|
|
5691
|
+
const binding = route.binding?.promise;
|
|
5692
|
+
if (!binding || !await waitForPromiseOrAbort(binding, signal)) return;
|
|
5693
|
+
if (signal.aborted || route.released) return;
|
|
3188
5694
|
}
|
|
3189
5695
|
if (route.gate === "bound") {
|
|
3190
5696
|
if (scope.turnId && scope.turnId !== route.turnId) return;
|
|
3191
5697
|
if (route.released) return;
|
|
3192
5698
|
}
|
|
3193
|
-
await this.waitForNotifications(route);
|
|
3194
|
-
if (route.released) return;
|
|
5699
|
+
if (!await waitForPromiseOrAbort(this.waitForNotifications(route), signal)) return;
|
|
5700
|
+
if (signal.aborted || route.released) return;
|
|
3195
5701
|
try {
|
|
3196
5702
|
const result = await handler(request, {
|
|
3197
5703
|
threadId: scope.threadId,
|
|
3198
5704
|
...scope.turnId ? { turnId: scope.turnId } : {}
|
|
3199
|
-
});
|
|
3200
|
-
return route.released ? void 0 : result;
|
|
5705
|
+
}, signal);
|
|
5706
|
+
return signal.aborted || route.released ? void 0 : result;
|
|
3201
5707
|
} catch (error) {
|
|
3202
|
-
if (route.released) return;
|
|
5708
|
+
if (signal.aborted || route.released) return;
|
|
3203
5709
|
throw error;
|
|
3204
5710
|
}
|
|
3205
5711
|
}
|
|
@@ -3319,6 +5825,20 @@ function isCodexTerminalTurnNotification(notification) {
|
|
|
3319
5825
|
if (notification.method === "turn/completed") return true;
|
|
3320
5826
|
return notification.method === "error" && isJsonObject(notification.params) && notification.params.willRetry === false;
|
|
3321
5827
|
}
|
|
5828
|
+
async function waitForPromiseOrAbort(promise, signal) {
|
|
5829
|
+
if (signal.aborted) return false;
|
|
5830
|
+
let removeAbort;
|
|
5831
|
+
try {
|
|
5832
|
+
return await Promise.race([promise.then(() => true), new Promise((resolve) => {
|
|
5833
|
+
const onAbort = () => resolve(false);
|
|
5834
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
5835
|
+
removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
5836
|
+
if (signal.aborted) onAbort();
|
|
5837
|
+
})]);
|
|
5838
|
+
} finally {
|
|
5839
|
+
removeAbort?.();
|
|
5840
|
+
}
|
|
5841
|
+
}
|
|
3322
5842
|
function deferred() {
|
|
3323
5843
|
let resolve;
|
|
3324
5844
|
return {
|
|
@@ -3579,8 +6099,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
3579
6099
|
developerInstructions: promptState.developerInstructions,
|
|
3580
6100
|
messages: structuredClone(historyState.messages),
|
|
3581
6101
|
ctx: hookContext,
|
|
3582
|
-
bootstrapContextRunKind: params.bootstrapContextRunKind
|
|
3583
|
-
..."beforeAgentStartResult" in params ? { beforeAgentStartResult: params.beforeAgentStartResult } : {}
|
|
6102
|
+
bootstrapContextRunKind: params.bootstrapContextRunKind
|
|
3584
6103
|
});
|
|
3585
6104
|
const resolveShiftedPromptInputRange = (prompt, promptInputRange, turnPromptText) => {
|
|
3586
6105
|
if (!promptInputRange || promptInputRange.start < 0 || promptInputRange.end < promptInputRange.start || promptInputRange.end > prompt.length || !turnPromptText.endsWith(prompt)) return;
|
|
@@ -3631,8 +6150,7 @@ async function prepareCodexAttemptPrompt(context) {
|
|
|
3631
6150
|
const buildRenderedCodexDeveloperInstructions = () => joinPresentSections(turnState.promptBuild.developerInstructions, buildTurnCollaborationMode(params, {
|
|
3632
6151
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
3633
6152
|
skillsCollaborationInstructions,
|
|
3634
|
-
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
|
|
3635
|
-
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions
|
|
6153
|
+
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions
|
|
3636
6154
|
}).settings.developer_instructions ?? void 0);
|
|
3637
6155
|
const rebuildCodexPromptBuildFromCurrentProjection = async () => {
|
|
3638
6156
|
turnState.promptBuild = await buildPromptFromCurrentInputs();
|
|
@@ -5595,7 +8113,7 @@ async function readFile(execServer, params) {
|
|
|
5595
8113
|
const fsBridge = requireFsBridge(execServer);
|
|
5596
8114
|
const stat = await fsBridge.stat({ filePath });
|
|
5597
8115
|
if (!stat) throw new JsonRpcProtocolError(JSON_RPC_NOT_FOUND, "file not found");
|
|
5598
|
-
|
|
8116
|
+
assertSandboxFileReadWithinLimit(stat);
|
|
5599
8117
|
return { dataBase64: (await fsBridge.readFile({ filePath })).toString("base64") };
|
|
5600
8118
|
}
|
|
5601
8119
|
/** Writes base64 data to an existing sandbox directory after write-policy checks. */
|
|
@@ -5736,6 +8254,15 @@ async function copySandboxPath(execServer, params) {
|
|
|
5736
8254
|
}
|
|
5737
8255
|
return;
|
|
5738
8256
|
}
|
|
8257
|
+
if (sourceStat.type === "file" && fsBridge.copyFile) {
|
|
8258
|
+
await fsBridge.copyFile({
|
|
8259
|
+
sourcePath: params.sourcePath,
|
|
8260
|
+
destinationPath: params.destinationPath,
|
|
8261
|
+
mkdir: true
|
|
8262
|
+
});
|
|
8263
|
+
return;
|
|
8264
|
+
}
|
|
8265
|
+
assertSandboxFileReadWithinLimit(sourceStat);
|
|
5739
8266
|
const data = await fsBridge.readFile({ filePath: params.sourcePath });
|
|
5740
8267
|
await fsBridge.writeFile({
|
|
5741
8268
|
filePath: params.destinationPath,
|
|
@@ -5743,6 +8270,9 @@ async function copySandboxPath(execServer, params) {
|
|
|
5743
8270
|
mkdir: true
|
|
5744
8271
|
});
|
|
5745
8272
|
}
|
|
8273
|
+
function assertSandboxFileReadWithinLimit(stat) {
|
|
8274
|
+
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`);
|
|
8275
|
+
}
|
|
5746
8276
|
function metadataResponse(stat) {
|
|
5747
8277
|
return {
|
|
5748
8278
|
isDirectory: stat?.type === "directory",
|
|
@@ -6792,6 +9322,15 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6792
9322
|
timeoutMs: params.timeoutMs,
|
|
6793
9323
|
timeoutFloorMs: options.startupTimeoutFloorMs
|
|
6794
9324
|
});
|
|
9325
|
+
const requesterChannel = params.messageChannel ?? params.messageProvider;
|
|
9326
|
+
const requester = {
|
|
9327
|
+
...requesterChannel ? { channel: requesterChannel } : {},
|
|
9328
|
+
...params.agentAccountId ? { accountId: params.agentAccountId } : {},
|
|
9329
|
+
...params.senderId ? { senderId: params.senderId } : {},
|
|
9330
|
+
...params.senderIsOwner !== void 0 ? { senderIsOwner: params.senderIsOwner } : {},
|
|
9331
|
+
...params.memberRoleIds?.length ? { roleIds: [...params.memberRoleIds] } : {}
|
|
9332
|
+
};
|
|
9333
|
+
const hasRequester = Object.keys(requester).length > 0;
|
|
6795
9334
|
const buildNativeHookRelayFinalConfigPatch = (decision) => {
|
|
6796
9335
|
state.nativeHookRelay?.unregister();
|
|
6797
9336
|
state.nativeHookRelay = createCodexNativeHookRelay({
|
|
@@ -6805,6 +9344,7 @@ function prepareCodexAttemptResources(prompt) {
|
|
|
6805
9344
|
config: params.config,
|
|
6806
9345
|
runId: params.runId,
|
|
6807
9346
|
channelId: hookChannelId,
|
|
9347
|
+
...hasRequester ? { requester } : {},
|
|
6808
9348
|
attemptTimeoutMs: params.timeoutMs,
|
|
6809
9349
|
startupTimeoutMs,
|
|
6810
9350
|
turnStartTimeoutMs: params.timeoutMs,
|
|
@@ -7150,7 +9690,8 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7150
9690
|
const { toolBridge, toolOutcomeOrdinals, suppressedDynamicToolOutcomeOrdinals, allocateCodexToolOutcomeOrdinal } = attemptTools;
|
|
7151
9691
|
const { state, turnIdRef, userInputBridgeRef, openClawDynamicToolExecutions, pendingOpenClawDynamicToolCompletionIds, postToolRawAssistantCompletionIdleTimeoutMs, turnWatches } = turnRuntime;
|
|
7152
9692
|
const { emitExecutionPhaseOnce, scheduleTurnReleaseAfterTerminalDynamicTool, scheduleTerminalDynamicToolReleaseCheck } = lifecycle;
|
|
7153
|
-
const handleServerRequest = async (request, scope) => {
|
|
9693
|
+
const handleServerRequest = async (request, scope, requestSignal = new AbortController().signal) => {
|
|
9694
|
+
const signal = AbortSignal.any([runAbortController.signal, requestSignal]);
|
|
7154
9695
|
const turnId = turnIdRef.current;
|
|
7155
9696
|
const projector = projectorRef.current;
|
|
7156
9697
|
let armCompletionWatchOnResponse = false;
|
|
@@ -7176,7 +9717,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7176
9717
|
turnId,
|
|
7177
9718
|
pluginAppPolicyContext: resourceState.thread.pluginAppPolicyContext,
|
|
7178
9719
|
...computerUseConfig.enabled ? { computerUseMcpServerName: computerUseConfig.mcpServerName } : {},
|
|
7179
|
-
signal
|
|
9720
|
+
signal
|
|
7180
9721
|
});
|
|
7181
9722
|
}
|
|
7182
9723
|
if (request.method === "item/tool/requestUserInput") {
|
|
@@ -7203,7 +9744,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7203
9744
|
turnId,
|
|
7204
9745
|
nativeHookRelay: resourceState.nativeHookRelay,
|
|
7205
9746
|
autoApprove: shouldAutoApproveCodexAppServerApprovals(appServer),
|
|
7206
|
-
signal
|
|
9747
|
+
signal,
|
|
7207
9748
|
onNativeToolFailureDisposition: (itemId, disposition) => projector?.recordNativeToolApprovalFailure(itemId, disposition)
|
|
7208
9749
|
});
|
|
7209
9750
|
}
|
|
@@ -7279,7 +9820,7 @@ function createCodexAttemptServerRequestController(resources, turnRuntime, lifec
|
|
|
7279
9820
|
const { execution } = openClawDynamicToolExecutions.claim(call, () => handleDynamicToolCallWithTimeout({
|
|
7280
9821
|
call,
|
|
7281
9822
|
toolBridge,
|
|
7282
|
-
signal
|
|
9823
|
+
signal,
|
|
7283
9824
|
timeoutMs: dynamicToolTimeoutMs,
|
|
7284
9825
|
toolMeta,
|
|
7285
9826
|
toolCallOrdinal,
|
|
@@ -7576,7 +10117,7 @@ function buildMetadataCacheEntryKey(appCacheKey, queryKind) {
|
|
|
7576
10117
|
//#endregion
|
|
7577
10118
|
//#region extensions/codex/src/app-server/plugin-thread-config-deadline.ts
|
|
7578
10119
|
/** Enforces one bounded startup budget across Codex plugin config discovery. */
|
|
7579
|
-
const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS =
|
|
10120
|
+
const CODEX_PLUGIN_THREAD_CONFIG_MAX_TIMEOUT_MS = 6e4;
|
|
7580
10121
|
const CODEX_PLUGIN_THREAD_CONFIG_TIMEOUT_DIVISOR = 4;
|
|
7581
10122
|
const CODEX_PLUGIN_THREAD_CONFIG_MIN_TIMEOUT_MS = 100;
|
|
7582
10123
|
var CodexPluginThreadConfigDeadlineError = class extends Error {
|
|
@@ -8418,7 +10959,6 @@ async function prepareCodexAttemptTurnRequest(resources, turnRuntime, ensureCurr
|
|
|
8418
10959
|
turnScopedDeveloperInstructions: workspaceBootstrapContext.turnScopedDeveloperInstructions,
|
|
8419
10960
|
skillsCollaborationInstructions: context.skillsCollaborationInstructions,
|
|
8420
10961
|
memoryCollaborationInstructions: workspaceBootstrapContext.memoryCollaborationInstructions,
|
|
8421
|
-
heartbeatCollaborationInstructions: workspaceBootstrapContext.heartbeatCollaborationInstructions,
|
|
8422
10962
|
preserveNativeTurnSettings: usesSupervisionConnection
|
|
8423
10963
|
});
|
|
8424
10964
|
codexModelCallDiagnostics.setRequestPayloadBytes(utf8JsonByteLength(turnStartParams));
|
|
@@ -8643,7 +11183,11 @@ async function startCodexAttemptTurn(resources, turnRuntime, notifications, requ
|
|
|
8643
11183
|
ctx: hookContext,
|
|
8644
11184
|
hookRunner
|
|
8645
11185
|
});
|
|
8646
|
-
|
|
11186
|
+
const bindingReleased = isIncognitoSessionKey(params.sessionKey) ? await bindingStore.mutate(bindingIdentity, {
|
|
11187
|
+
kind: "clear",
|
|
11188
|
+
threadId: resourceState.thread.threadId
|
|
11189
|
+
}) : true;
|
|
11190
|
+
if (!state.timedOut && bindingReleased) await unsubscribeCodexThreadBestEffort(resourceState.client, {
|
|
8647
11191
|
threadId: resourceState.thread.threadId,
|
|
8648
11192
|
timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
|
|
8649
11193
|
});
|