@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.
Files changed (38) hide show
  1. package/dist/{app-server-policy-DUMF2Xyr.js → app-server-policy-BO3jYBkv.js} +1 -1
  2. package/dist/{attempt-notifications-Ecjyzufe.js → attempt-notifications-DdmnBMUp.js} +1 -1
  3. package/dist/{media-understanding-provider-IPNNQre6.js → bounded-turn-CaQL96kg.js} +43 -183
  4. package/dist/capabilities-CLICvTxf.js +36 -0
  5. package/dist/cli-metadata.js +1 -1
  6. package/dist/{command-formatters-NCTL7A2q.js → command-formatters-DgADqnHa.js} +3 -37
  7. package/dist/{command-handlers-DtFbZiba.js → command-handlers-l_lVPNlB.js} +12 -11
  8. package/dist/{compact-Kgy26gIM.js → compact-CC5KhBzX.js} +5 -4
  9. package/dist/{computer-use-C7x4ZaqR.js → computer-use-Ip1-QGa-.js} +4 -4
  10. package/dist/{conversation-control-B0s3aIjT.js → conversation-control-sNPsbTCP.js} +6 -5
  11. package/dist/doctor-contract-api.js +1 -1
  12. package/dist/{dynamic-tools-D_vSVmv9.js → dynamic-tools-CQI3UwqY.js} +105 -2670
  13. package/dist/event-projector-assistant-message-DTgnPPVF.js +101 -0
  14. package/dist/event-projector-usage-D6tE7_qD.js +69 -0
  15. package/dist/harness.js +25 -6
  16. package/dist/incognito-session-ET_ufDH-.js +2 -0
  17. package/dist/index.js +60 -26
  18. package/dist/media-understanding-provider.js +168 -1
  19. package/dist/{models-DD5zBdX5.js → models-BNeMlHgg.js} +2 -2
  20. package/dist/{notification-correlation-C8DVQ_Bq.js → notification-correlation-BGLixv5_.js} +3 -3
  21. package/dist/{plugin-app-cache-key-DJbhLYSK.js → plugin-app-cache-key-CvzvmBRz.js} +2 -2
  22. package/dist/{rate-limits-CqhWQ2R9.js → rate-limits-D0IJT-a6.js} +1 -1
  23. package/dist/{request-9yf9pZjf.js → request-BTccUTD3.js} +1 -1
  24. package/dist/{run-attempt-BIoO8ISr.js → run-attempt--858NXDl.js} +2653 -109
  25. package/dist/{session-binding-Bmt20HfB.js → session-binding-ZSMX1omP.js} +7 -2
  26. package/dist/{session-catalog-CA7R-hX2.js → session-catalog-DsKaezgR.js} +82 -80
  27. package/dist/{session-cli-Bxk3-Wqz.js → session-cli-CYJTfRLG.js} +1 -1
  28. package/dist/session-upstream-marker-D7XlI9us.js +82 -0
  29. package/dist/settled-turn-finalizer-DHltNgtF.js +303 -0
  30. package/dist/{shared-client-CSXLtCLE.js → shared-client-wmgNFNYp.js} +33 -13
  31. package/dist/{side-question-DtzquMOb.js → side-question-BfFZCsJ-.js} +21 -15
  32. package/dist/{thread-lifecycle-CQ_9mAa1.js → thread-lifecycle-cqrOlJkq.js} +120 -26
  33. package/dist/{transcript-mirror-D9rTxx2P.js → transcript-mirror-2p7kl6e4.js} +433 -145
  34. package/dist/upstream-session-fork-vPjwkT1i.js +320 -0
  35. package/dist/{usage-CuPpFgTc.js → usage-DM_I3mPT.js} +3 -3
  36. package/dist/{web-search-provider.runtime-_x5XTeqh.js → web-search-provider.runtime-Bx6HAc_k.js} +3 -3
  37. package/npm-shrinkwrap.json +38 -38
  38. package/package.json +7 -7
@@ -1,184 +1,22 @@
1
- import { Y as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, Z as isJsonObject, _ as readCodexRateLimitsRevision, c as releaseLeasedSharedCodexAppServerClient, j as resolveCodexGatewayTimeoutWithGraceMs, v as readRecentCodexRateLimits, y as rememberCodexRateLimitsRead } from "./shared-client-CSXLtCLE.js";
2
- import { y as readCodexPluginConfig } from "./session-binding-Bmt20HfB.js";
3
- import { c as attachCodexMirrorIdentity, g as readCodexTurn, s as promptSnapshot } from "./transcript-mirror-D9rTxx2P.js";
4
- import { C as isForcedPrivateQaCodexRuntime, S as filterCodexDynamicToolsWithOpenClawShell, T as normalizeCodexDynamicToolName, a as sanitizeCodexHistoryImagePayloads, d as resolveCodexWebSearchPlan, i as invalidInlineImageText, o as sanitizeInlineImageDataUrl, w as isSystemAgentOnlyCodexDynamicToolAllowlist, x as filterCodexDynamicTools } from "./thread-lifecycle-CQ_9mAa1.js";
5
- import { d as CODEX_CONTROL_METHODS, r as formatCodexDisplayText } from "./command-formatters-NCTL7A2q.js";
6
- import { a as shouldRefreshCodexRateLimitsForUsageLimitMessage, i as resolveCodexUsageLimitResetAtMs, n as formatCodexUsageLimitErrorMessage } from "./rate-limits-CqhWQ2R9.js";
1
+ import { Q as isJsonObject, X as CODEX_OPENCLAW_DIRECT_DYNAMIC_TOOL_NAMESPACE, c as releaseLeasedSharedCodexAppServerClient, j as resolveCodexGatewayTimeoutWithGraceMs } from "./shared-client-wmgNFNYp.js";
2
+ import { b as readCodexPluginConfig } from "./session-binding-ZSMX1omP.js";
3
+ import { D as isForcedPrivateQaCodexRuntime, E as filterCodexDynamicToolsWithOpenClawShell, O as isSystemAgentOnlyCodexDynamicToolAllowlist, T as filterCodexDynamicTools, ct as readItemString, h as resolveCodexWebSearchPlan, i as invalidInlineImageText, k as normalizeCodexDynamicToolName, mt as readString$2, o as sanitizeInlineImageDataUrl, st as readItem } from "./thread-lifecycle-cqrOlJkq.js";
4
+ import { S as readCodexTurn } from "./transcript-mirror-2p7kl6e4.js";
5
+ import { r as formatCodexDisplayText } from "./command-formatters-DgADqnHa.js";
7
6
  import { a as resolveCodexNodeExecToolOverrides, i as resolveCodexNativeExecutionPolicy } from "./sandbox-guard-D1Wky__S.js";
8
- import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-C8DVQ_Bq.js";
9
- import fs from "node:fs/promises";
7
+ import { n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-BGLixv5_.js";
10
8
  import { addTimerTimeoutGraceMs, asDateTimestampMs, finiteSecondsToTimerSafeMilliseconds, parseStrictNonNegativeInteger } from "openclaw/plugin-sdk/number-runtime";
11
9
  import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
12
10
  import { createHash } from "node:crypto";
13
- import { markAuthProfileBlockedUntil, resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
11
+ import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
14
12
  import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
15
13
  import { asOptionalRecord, isRecord, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
16
- import { HEARTBEAT_RESPONSE_TOOL_NAME, TOOL_PROGRESS_OUTPUT_MAX_CHARS, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, callGatewayTool, classifyAgentHarnessTerminalOutcome, consumeAdjustedParamsForToolCall, consumePreExecutionBlockedToolCall, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, emitAgentEvent, extractMessagingToolSend, extractMessagingToolSendResult, extractToolResultMediaArtifact, filterProviderNormalizableTools, filterToolResultMediaUrls, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatErrorMessage, formatToolAggregate, formatToolExecutionErrorMessage, formatToolProgressOutput, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, hasNativeHookRelayInvocation, inferToolMetaFromArgs, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isHostScopedAgentToolActive, isMessagingTool, isMessagingToolSendAction, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, normalizeHeartbeatToolResponse, normalizeUsage, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, resolveToolResultFailureKind, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runBeforeToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
17
- import { listSessionEntries, parseSqliteSessionFileMarker } from "openclaw/plugin-sdk/session-store-runtime";
14
+ import { HEARTBEAT_RESPONSE_TOOL_NAME, buildAgentHookContextChannelFields, buildEmbeddedAttemptToolRunContext, callGatewayTool, consumeAdjustedParamsForToolCall, consumePreExecutionBlockedToolCall, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractMessagingToolSend, extractMessagingToolSendResult, extractToolResultMediaArtifact, filterProviderNormalizableTools, filterToolResultMediaUrls, finalizeToolTerminalPresentation, formatApprovalDisplayPath, formatToolExecutionErrorMessage, getBeforeToolCallFailureDisposition, getChannelAgentToolMeta, getPluginToolMeta, hasNativeHookRelayInvocation, invokeNativeHookRelay, isDeliveredMessageToolOnlySourceReplyResult, isDeliveredMessagingToolResult, isHostScopedAgentToolActive, isMessagingTool, isMessagingToolSendAction, isReplaySafeToolCall, isSubagentSessionKey, isToolResultError, isToolWrappedWithBeforeToolCallHook, normalizeAgentRuntimeTools, normalizeHeartbeatToolResponse, projectRuntimeToolInputSchema, registerNativeHookRelay, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveNativeHookRelayDeferredToolApproval, resolveToolExecutionErrorKind, resolveToolResultFailureKind, runAgentHarnessAfterToolCallHook, runBeforeToolCallHook, sanitizeToolResult, setBeforeToolCallDiagnosticsEnabled, supportsModelTools, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
18
15
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
19
- import { redactSensitiveFieldValue, redactSensitiveText, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
20
16
  import { emitTrustedDiagnosticEvent, hasPendingInternalDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
21
- import { readSessionTranscriptEvents } from "openclaw/plugin-sdk/session-transcript-runtime";
22
17
  import { isToolAllowed } from "openclaw/plugin-sdk/sandbox";
23
- import { sanitizeTerminalText } from "openclaw/plugin-sdk/text-chunking";
24
- import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
25
- import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
26
- import { saveMediaBuffer } from "openclaw/plugin-sdk/media-store";
18
+ import { isApprovalNotFoundError } from "openclaw/plugin-sdk/error-runtime";
27
19
  import { normalizeOpenAIToolSchemas } from "openclaw/plugin-sdk/provider-tools";
28
- //#region extensions/codex/src/app-server/local-runtime-attribution.ts
29
- const OPENAI_PROVIDER_ID = "openai";
30
- const OPENAI_RESPONSES_API = "openai-responses";
31
- const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
32
- function normalizeRuntimeId(value) {
33
- return value?.trim().toLowerCase() ?? "";
34
- }
35
- /** Maps local Codex runtime plans onto the provider/api pair exposed to event projection. */
36
- function resolveCodexLocalRuntimeAttribution(params) {
37
- const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
38
- if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
39
- provider: OPENAI_PROVIDER_ID,
40
- api: OPENAI_CODEX_RESPONSES_API
41
- };
42
- return {
43
- provider: params.provider,
44
- api: params.model.api
45
- };
46
- }
47
- //#endregion
48
- //#region extensions/codex/src/app-server/event-projector-assistant-message.ts
49
- const ZERO_USAGE$1 = {
50
- input: 0,
51
- output: 0,
52
- cacheRead: 0,
53
- cacheWrite: 0,
54
- totalTokens: 0,
55
- cost: {
56
- input: 0,
57
- output: 0,
58
- cacheRead: 0,
59
- cacheWrite: 0,
60
- total: 0
61
- }
62
- };
63
- function createAssistantMessage(params, text, options) {
64
- const attribution = resolveCodexLocalRuntimeAttribution(params);
65
- const usage = options.tokenUsage ? {
66
- input: options.tokenUsage.input ?? 0,
67
- output: options.tokenUsage.output ?? 0,
68
- cacheRead: options.tokenUsage.cacheRead ?? 0,
69
- cacheWrite: options.tokenUsage.cacheWrite ?? 0,
70
- ...options.tokenUsage.contextUsage ? { contextUsage: options.tokenUsage.contextUsage } : {},
71
- totalTokens: options.tokenUsage.total ?? (options.tokenUsage.input ?? 0) + (options.tokenUsage.output ?? 0) + (options.tokenUsage.cacheRead ?? 0) + (options.tokenUsage.cacheWrite ?? 0),
72
- cost: ZERO_USAGE$1.cost
73
- } : ZERO_USAGE$1;
74
- return {
75
- role: "assistant",
76
- content: [{
77
- type: "text",
78
- text
79
- }],
80
- api: attribution.api ?? "openai-chatgpt-responses",
81
- provider: attribution.provider,
82
- model: params.modelId,
83
- usage,
84
- stopReason: options.aborted ? "aborted" : options.promptError ? "error" : "stop",
85
- errorMessage: options.promptError ? formatErrorMessage(options.promptError) : void 0,
86
- timestamp: Date.now()
87
- };
88
- }
89
- function createAssistantMirrorMessage(params, title, text) {
90
- const attribution = resolveCodexLocalRuntimeAttribution(params);
91
- return {
92
- role: "assistant",
93
- content: [{
94
- type: "text",
95
- text: `${title}:\n${text}`
96
- }],
97
- api: attribution.api ?? "openai-chatgpt-responses",
98
- provider: attribution.provider,
99
- model: params.modelId,
100
- usage: ZERO_USAGE$1,
101
- stopReason: "stop",
102
- timestamp: Date.now()
103
- };
104
- }
105
- //#endregion
106
- //#region extensions/codex/src/app-server/event-projector-values.ts
107
- function readString$3(record, key) {
108
- const value = record[key];
109
- return typeof value === "string" ? value : void 0;
110
- }
111
- function normalizeNonEmptyString(value) {
112
- if (typeof value !== "string") return;
113
- return value.trim() || void 0;
114
- }
115
- function readNonEmptyString(record, key) {
116
- return normalizeNonEmptyString(record[key]);
117
- }
118
- function readNonEmptyStringArray(record, key) {
119
- const value = record[key];
120
- if (!Array.isArray(value)) return [];
121
- const entries = [];
122
- for (const entry of value) {
123
- const normalized = normalizeNonEmptyString(entry);
124
- if (normalized) entries.push(normalized);
125
- }
126
- return entries;
127
- }
128
- function readNullableString(record, key) {
129
- const value = record[key];
130
- if (value === null) return null;
131
- return typeof value === "string" ? value : void 0;
132
- }
133
- function readNumber(record, key) {
134
- const value = record[key];
135
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
136
- }
137
- function readNonNegativeInteger(record, key) {
138
- const value = readNumber(record, key);
139
- return value !== void 0 && Number.isInteger(value) && value >= 0 ? value : void 0;
140
- }
141
- function readCodexErrorNotificationMessage(record) {
142
- const error = record.error;
143
- return isJsonObject(error) ? readString$3(error, "message") : void 0;
144
- }
145
- function readHookOutputEntries(value) {
146
- if (!Array.isArray(value)) return [];
147
- return value.flatMap((entry) => {
148
- if (!isJsonObject(entry)) return [];
149
- const text = readString$3(entry, "text");
150
- if (!text) return [];
151
- const kind = readString$3(entry, "kind");
152
- return [{
153
- ...kind ? { kind } : {},
154
- text
155
- }];
156
- });
157
- }
158
- function splitPlanText(text) {
159
- return text.split(/\r?\n/).map((line) => line.trim().replace(/^[-*]\s+/, "")).filter((line) => line.length > 0);
160
- }
161
- function extractRawAssistantText(item) {
162
- return (Array.isArray(item.content) ? item.content : []).flatMap((entry) => {
163
- if (!isJsonObject(entry)) return [];
164
- const type = readString$3(entry, "type");
165
- if (type !== "output_text" && type !== "text") return [];
166
- const value = readString$3(entry, "text");
167
- return value ? [value] : [];
168
- }).join("").trim() || void 0;
169
- }
170
- function readItemString(item, key) {
171
- const value = item[key];
172
- return typeof value === "string" ? value : void 0;
173
- }
174
- function readItem(value) {
175
- if (!isJsonObject(value)) return;
176
- const type = typeof value.type === "string" ? value.type : void 0;
177
- const id = typeof value.id === "string" ? value.id : void 0;
178
- if (!type || !id) return;
179
- return value;
180
- }
181
- //#endregion
182
20
  //#region extensions/codex/src/app-server/event-projector-items.ts
183
21
  function itemKind(item) {
184
22
  switch (item.type) {
@@ -218,1689 +56,76 @@ function unknownItemStatus(item) {
218
56
  case "completed":
219
57
  case "failed":
220
58
  case "error":
221
- case "declined":
222
- case "inProgress":
223
- case "in_progress":
224
- case "running": return;
225
- default: return status;
226
- }
227
- }
228
- function auditNativeToolTerminalStatus(item) {
229
- if (item.type === "imageView" || item.type === "sleep") return "completed";
230
- const status = readItemString(item, "status");
231
- if (status === "completed") return "completed";
232
- if (status === "failed" || status === "error") return "failed";
233
- if (status === "declined") return "blocked";
234
- return "unknown";
235
- }
236
- function auditNativeToolUnfinishedStatus(item) {
237
- return item.type === "webSearch" || item.type === "imageGeneration" ? "unknown" : "failed";
238
- }
239
- function isNonSuccessItemStatus(status) {
240
- return status === "failed" || status === "blocked";
241
- }
242
- function itemName(item) {
243
- if (item.type === "dynamicToolCall" && typeof item.tool === "string") return item.tool;
244
- if (item.type === "mcpToolCall" && typeof item.tool === "string") {
245
- const server = typeof item.server === "string" ? item.server : void 0;
246
- return server ? `${server}.${item.tool}` : item.tool;
247
- }
248
- if (item.type === "commandExecution") return "bash";
249
- if (item.type === "fileChange") return "apply_patch";
250
- if (item.type === "webSearch") return "web_search";
251
- }
252
- function auditNativeToolName(item) {
253
- if (item.type === "dynamicToolCall") return;
254
- const progressName = itemName(item);
255
- if (progressName) return progressName;
256
- if (item.type === "collabAgentToolCall") return typeof item.tool === "string" && item.tool.trim() ? `collab.${item.tool.trim()}` : "collab_agent";
257
- if (item.type === "imageGeneration") return "image_generation";
258
- if (item.type === "imageView") return "image_view";
259
- if (item.type === "sleep") return "sleep";
260
- }
261
- function isSideEffectingNativeToolItem(item) {
262
- return itemStatus(item) !== "blocked" && (isMutatingNativeToolItem(item) || item.type === "mcpToolCall");
263
- }
264
- function shouldSynthesizeToolProgressForItem(item) {
265
- switch (item.type) {
266
- case "commandExecution":
267
- case "fileChange":
268
- case "webSearch":
269
- case "mcpToolCall": return true;
270
- default: return false;
271
- }
272
- }
273
- function shouldRecordNativeToolTranscript(item) {
274
- return shouldSynthesizeToolProgressForItem(item) && item.type !== "webSearch";
275
- }
276
- function isMutatingNativeToolItem(item) {
277
- if (item.type === "commandExecution") return true;
278
- return item.type === "fileChange" || item.type === "collabAgentToolCall" || item.type === "imageGeneration";
279
- }
280
- function shouldClearTerminalPresentationForNativeItem(item) {
281
- switch (item.type) {
282
- case "collabAgentToolCall":
283
- case "commandExecution":
284
- case "fileChange":
285
- case "imageGeneration":
286
- case "imageView":
287
- case "mcpToolCall":
288
- case "webSearch": return true;
289
- default: return false;
290
- }
291
- }
292
- //#endregion
293
- //#region extensions/codex/src/app-server/event-projector-assistant.ts
294
- var CodexAssistantProjection = class {
295
- constructor(params, emitAgentEvent, matchesToolProgressEcho) {
296
- this.params = params;
297
- this.emitAgentEvent = emitAgentEvent;
298
- this.matchesToolProgressEcho = matchesToolProgressEcho;
299
- this.assistantTextByItem = /* @__PURE__ */ new Map();
300
- this.assistantItemOrder = [];
301
- this.assistantPhaseByItem = /* @__PURE__ */ new Map();
302
- this.latestTerminalAssistantCandidateSuperseded = false;
303
- this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
304
- this.terminalAssistantCandidateEarlierActiveItemIds = /* @__PURE__ */ new Set();
305
- this.lastCommentaryProgressTextByItem = /* @__PURE__ */ new Map();
306
- this.lastAnswerCandidateEventByItem = /* @__PURE__ */ new Map();
307
- this.pendingRawCommentaryEchoes = 0;
308
- this.rawPromotedAssistantItemIds = /* @__PURE__ */ new Set();
309
- this.assistantStarted = false;
310
- this.streamedPartialAssistantItemReplaceable = false;
311
- }
312
- hasCompletedTerminalAssistantText(completedItemIds) {
313
- const latestCompletedItemId = this.latestCompletedTerminalAssistantItemId;
314
- if (!latestCompletedItemId) return false;
315
- const finalItem = this.resolveFinalAssistantTextItem();
316
- return this.latestCompletedItemId === latestCompletedItemId && finalItem?.itemId === latestCompletedItemId && completedItemIds.has(latestCompletedItemId);
317
- }
318
- getLatestTerminalAssistantCandidate() {
319
- const itemId = this.latestTerminalAssistantCandidateItemId;
320
- if (!itemId) return;
321
- const text = this.assistantTextByItem.get(itemId)?.trim();
322
- return {
323
- itemId,
324
- hasText: Boolean(text && !this.isToolProgressEchoText(itemId, text))
325
- };
326
- }
327
- hasLatestTerminalAssistantCandidateText() {
328
- return !this.latestTerminalAssistantCandidateSuperseded && this.getLatestTerminalAssistantCandidate()?.hasText === true;
329
- }
330
- canReleaseLatestTerminalAssistantAfterToolHandoff() {
331
- return this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff && this.hasLatestTerminalAssistantCandidateText();
332
- }
333
- async handleAssistantDelta(params) {
334
- const itemId = readString$3(params, "itemId") ?? "assistant";
335
- const delta = readString$3(params, "delta") ?? "";
336
- if (!delta) return;
337
- if (itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
338
- const isCommentary = this.isCommentaryAssistantItem(itemId);
339
- if (!isCommentary && itemId !== this.latestTerminalAssistantCandidateItemId) this.markTerminalAssistantCandidateSupersededBy();
340
- if (!this.assistantStarted) {
341
- this.assistantStarted = true;
342
- await this.params.onAssistantMessageStart?.();
343
- }
344
- this.rememberAssistantItem(itemId);
345
- const text = `${this.assistantTextByItem.get(itemId) ?? ""}${delta}`;
346
- this.assistantTextByItem.set(itemId, text);
347
- if (isCommentary) {
348
- this.emitCommentaryProgress({
349
- itemId,
350
- text
351
- });
352
- return;
353
- }
354
- if (this.isFinalAnswerAssistantItem(itemId)) this.emitAnswerCandidate(itemId, "candidate");
355
- const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
356
- const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
357
- if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
358
- else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
359
- this.streamedPartialAssistantItemId = itemId;
360
- const replaceable = this.streamedPartialAssistantItemReplaceable;
361
- const replacement = replace && replaceable;
362
- const streamPayload = {
363
- text,
364
- delta: replacement ? "" : delta,
365
- ...replacement ? { replace: true } : {}
366
- };
367
- this.emitAgentEvent({
368
- stream: "assistant",
369
- data: {
370
- ...streamPayload,
371
- ...replaceable ? { replaceable: true } : {}
372
- }
373
- });
374
- if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
375
- }
376
- recordItemStarted(item, itemId) {
377
- if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
378
- this.rememberAssistantPhase(item);
379
- if (itemId && itemId !== this.latestTerminalAssistantCandidateItemId) {
380
- this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
381
- if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
382
- }
383
- }
384
- recordItemCompleted(item, itemId, activeItemIds) {
385
- if (item?.type === "agentMessage" && itemId && itemId !== this.pendingRawTerminalAssistantEchoItemId) this.pendingRawTerminalAssistantEchoItemId = void 0;
386
- if (itemId) this.latestCompletedItemId = itemId;
387
- this.rememberAssistantPhase(item);
388
- if (item?.type === "agentMessage" && !this.isCommentaryAssistantItem(item.id)) {
389
- this.latestCompletedTerminalAssistantItemId = item.id;
390
- this.markLatestTerminalAssistantCandidate(item.id, activeItemIds);
391
- this.pendingRawTerminalAssistantEchoItemId = item.id;
392
- } else if (itemId) {
393
- this.markTerminalAssistantCandidateSupersededBy(itemId, { preserveEarlierActiveItem: true });
394
- if (this.latestTerminalAssistantCandidateSuperseded) this.pendingRawTerminalAssistantEchoItemId = void 0;
395
- }
396
- if (item?.type === "agentMessage" && typeof item.text === "string") {
397
- this.rememberAssistantItem(item.id);
398
- this.assistantTextByItem.set(item.id, item.text);
399
- if (item.text && this.isCommentaryAssistantItem(item.id)) {
400
- this.emitCommentaryProgress({
401
- itemId: item.id,
402
- text: item.text
403
- });
404
- this.pendingRawCommentaryEchoes += 1;
405
- } else if (item.text && this.isFinalAnswerAssistantItem(item.id)) this.emitAnswerCandidate(item.id, "candidate");
406
- }
407
- }
408
- recordSnapshotItem(item) {
409
- this.rememberAssistantPhase(item);
410
- if (item.type === "agentMessage" && typeof item.text === "string") {
411
- this.rememberAssistantItem(item.id);
412
- this.assistantTextByItem.set(item.id, item.text);
413
- }
414
- }
415
- handleRawResponseItemCompleted(item, activeItemIds) {
416
- const role = readString$3(item, "role");
417
- const phase = readString$3(item, "phase");
418
- const rawItemId = readString$3(item, "id");
419
- const candidateWasSupersededBeforeRaw = this.latestTerminalAssistantCandidateSuperseded;
420
- const pendingTerminalAssistantEchoItemId = this.pendingRawTerminalAssistantEchoItemId;
421
- const isPendingTerminalAssistantEcho = role === "assistant" && phase !== "commentary" && pendingTerminalAssistantEchoItemId !== void 0 && (rawItemId === void 0 || rawItemId === pendingTerminalAssistantEchoItemId);
422
- if (pendingTerminalAssistantEchoItemId !== void 0 && !isPendingTerminalAssistantEcho) this.pendingRawTerminalAssistantEchoItemId = void 0;
423
- if (!isPendingTerminalAssistantEcho) {
424
- this.latestCompletedItemId = void 0;
425
- this.markTerminalAssistantCandidateSupersededBy(rawItemId);
426
- }
427
- if (role !== "assistant") return;
428
- if (phase === "commentary" && this.pendingRawCommentaryEchoes > 0) {
429
- this.pendingRawCommentaryEchoes -= 1;
430
- return;
431
- }
432
- const text = extractRawAssistantText(item);
433
- if (isPendingTerminalAssistantEcho) {
434
- const typedItemId = pendingTerminalAssistantEchoItemId;
435
- this.pendingRawTerminalAssistantEchoItemId = void 0;
436
- if (this.assistantTextByItem.get(typedItemId)?.trim() || !text) return;
437
- this.rememberAssistantItem(typedItemId);
438
- this.assistantTextByItem.set(typedItemId, text);
439
- return;
440
- }
441
- if (!text) return;
442
- const itemId = rawItemId ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
443
- const isIdlessTerminalAssistantAfterCompletedWork = candidateWasSupersededBeforeRaw && rawItemId === void 0 && pendingTerminalAssistantEchoItemId === void 0 && activeItemIds.size === 0;
444
- if (phase !== "commentary" && candidateWasSupersededBeforeRaw && itemId !== this.streamedPartialAssistantItemId && !isIdlessTerminalAssistantAfterCompletedWork) return;
445
- if (phase) this.assistantPhaseByItem.set(itemId, phase);
446
- this.rememberAssistantItem(itemId);
447
- this.assistantTextByItem.set(itemId, text);
448
- this.rawPromotedAssistantItemIds.add(itemId);
449
- if (phase === "commentary") this.emitCommentaryProgress({
450
- itemId,
451
- text
452
- });
453
- else this.markLatestTerminalAssistantCandidate(itemId, activeItemIds, { canReleaseAfterToolHandoff: isIdlessTerminalAssistantAfterCompletedWork });
454
- }
455
- collectAssistantTexts() {
456
- const finalText = this.resolveFinalAssistantTextItem()?.text;
457
- return finalText ? [finalText] : [];
458
- }
459
- finalizeAnswerCandidate(turn) {
460
- if (turn.status !== "completed") {
461
- this.supersedeVisibleAnswerCandidate();
462
- return;
463
- }
464
- const turnItems = turn.items ?? [];
465
- const authoritativeIndex = turnItems.findLastIndex((item) => item.type === "agentMessage" && readItemString(item, "phase") === "final_answer" && typeof item.text === "string" && item.text.trim().length > 0);
466
- const authoritative = authoritativeIndex >= 0 ? turnItems[authoritativeIndex] : void 0;
467
- if (turnItems.slice(authoritativeIndex + 1).some(shouldClearTerminalPresentationForNativeItem) || authoritative?.id === this.latestTerminalAssistantCandidateItemId && this.latestTerminalAssistantCandidateSuperseded) {
468
- this.supersedeVisibleAnswerCandidate();
469
- return;
470
- }
471
- const itemId = authoritative?.id ?? this.visibleAnswerCandidateItemId;
472
- if (!itemId) return;
473
- if (itemId !== this.visibleAnswerCandidateItemId) {
474
- this.supersedeVisibleAnswerCandidate();
475
- this.visibleAnswerCandidateItemId = itemId;
476
- }
477
- this.emitAnswerCandidate(itemId, "selected");
478
- }
479
- hasAssistantItemTextForSynthesis() {
480
- for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
481
- const itemId = this.assistantItemOrder[i];
482
- if (!itemId || this.assistantPhaseByItem.get(itemId) === "commentary") continue;
483
- const text = this.assistantTextByItem.get(itemId);
484
- if (text && text.length > 0) return true;
485
- }
486
- return false;
487
- }
488
- createCurrentAttemptAssistantMessage(options) {
489
- for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
490
- const itemId = this.assistantItemOrder[i];
491
- if (!itemId || this.isCommentaryAssistantItem(itemId) || !this.assistantTextByItem.has(itemId)) continue;
492
- const text = this.assistantTextByItem.get(itemId) ?? "";
493
- const normalizedText = text.trim();
494
- if (normalizedText && this.isToolProgressEchoText(itemId, normalizedText)) continue;
495
- return this.createAssistantMessage(text, options);
496
- }
497
- }
498
- createAssistantMessage(text, options) {
499
- return createAssistantMessage(this.params, text, options);
500
- }
501
- createAssistantMirrorMessage(title, text) {
502
- return createAssistantMirrorMessage(this.params, title, text);
503
- }
504
- rememberAssistantPhase(item) {
505
- if (item?.type !== "agentMessage") return;
506
- const phase = readItemString(item, "phase");
507
- if (phase) this.assistantPhaseByItem.set(item.id, phase);
508
- }
509
- isCommentaryAssistantItem(itemId) {
510
- return this.assistantPhaseByItem.get(itemId) === "commentary";
511
- }
512
- isFinalAnswerAssistantItem(itemId) {
513
- return this.assistantPhaseByItem.get(itemId) === "final_answer";
514
- }
515
- shouldStreamAssistantPartial(itemId) {
516
- return this.assistantPhaseByItem.get(itemId) === "final_answer";
517
- }
518
- emitCommentaryProgress(params) {
519
- const progressText = params.text.replace(/\s+/g, " ").trim();
520
- if (!progressText || this.lastCommentaryProgressTextByItem.get(params.itemId) === progressText) return;
521
- this.lastCommentaryProgressTextByItem.set(params.itemId, progressText);
522
- this.emitAgentEvent({
523
- stream: "item",
524
- data: {
525
- itemId: params.itemId,
526
- kind: "preamble",
527
- title: "Preamble",
528
- phase: "update",
529
- progressText,
530
- source: "codex-app-server"
531
- }
532
- });
533
- }
534
- emitAnswerCandidate(itemId, status) {
535
- const text = this.assistantTextByItem.get(itemId)?.trim();
536
- if (!text) return;
537
- if (status === "candidate" && this.visibleAnswerCandidateItemId !== itemId) {
538
- this.supersedeVisibleAnswerCandidate();
539
- this.visibleAnswerCandidateItemId = itemId;
540
- }
541
- const signature = `${status}\0${text}`;
542
- if (this.lastAnswerCandidateEventByItem.get(itemId) === signature) return;
543
- this.lastAnswerCandidateEventByItem.set(itemId, signature);
544
- this.emitAgentEvent({
545
- stream: "item",
546
- data: {
547
- itemId,
548
- kind: "answer_candidate",
549
- title: "Answer candidate",
550
- phase: "update",
551
- status,
552
- progressText: text,
553
- source: "codex-app-server",
554
- hideFromChannelProgress: true
555
- }
556
- });
557
- }
558
- supersedeVisibleAnswerCandidate() {
559
- const itemId = this.visibleAnswerCandidateItemId;
560
- if (!itemId) return;
561
- this.emitAnswerCandidate(itemId, "superseded");
562
- this.visibleAnswerCandidateItemId = void 0;
563
- }
564
- markLatestTerminalAssistantCandidate(itemId, activeItemIds, options) {
565
- this.latestTerminalAssistantCandidateItemId = itemId;
566
- this.latestTerminalAssistantCandidateSuperseded = false;
567
- this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = options?.canReleaseAfterToolHandoff === true;
568
- this.terminalAssistantCandidateEarlierActiveItemIds = new Set(activeItemIds);
569
- }
570
- markTerminalAssistantCandidateSupersededBy(itemId, options) {
571
- if (!this.latestTerminalAssistantCandidateItemId) return;
572
- if (itemId && this.terminalAssistantCandidateEarlierActiveItemIds.has(itemId)) {
573
- if (!options?.preserveEarlierActiveItem) this.terminalAssistantCandidateEarlierActiveItemIds.delete(itemId);
574
- return;
575
- }
576
- this.latestTerminalAssistantCandidateSuperseded = true;
577
- this.latestTerminalAssistantCandidateCanReleaseAfterToolHandoff = false;
578
- this.terminalAssistantCandidateEarlierActiveItemIds.clear();
579
- this.supersedeVisibleAnswerCandidate();
580
- }
581
- resolveFinalAssistantTextItem() {
582
- for (let i = this.assistantItemOrder.length - 1; i >= 0; i -= 1) {
583
- const itemId = this.assistantItemOrder[i];
584
- if (!itemId) continue;
585
- const text = this.assistantTextByItem.get(itemId)?.trim();
586
- if (this.assistantPhaseByItem.get(itemId) === "commentary") continue;
587
- if (text && !this.isToolProgressEchoText(itemId, text)) return {
588
- itemId,
589
- text
590
- };
591
- }
592
- }
593
- rememberAssistantItem(itemId) {
594
- if (!itemId || this.assistantItemOrder.includes(itemId)) return;
595
- this.assistantItemOrder.push(itemId);
596
- }
597
- isToolProgressEchoText(itemId, text) {
598
- return this.rawPromotedAssistantItemIds.has(itemId) && this.matchesToolProgressEcho(text);
599
- }
600
- };
601
- //#endregion
602
- //#region extensions/codex/src/app-server/event-projector-diagnostics.ts
603
- function redactCodexEventKind(method) {
604
- return redactSensitiveText(sanitizeTerminalText(method));
605
- }
606
- var CodexProjectionDiagnostics = class {
607
- constructor(threadId, turnId) {
608
- this.threadId = threadId;
609
- this.turnId = turnId;
610
- this.warningKeys = /* @__PURE__ */ new Set();
611
- }
612
- warnUnknownItemStatus(item) {
613
- if (!item) return;
614
- const status = unknownItemStatus(item);
615
- if (!status) return;
616
- const safeStatus = redactCodexEventKind(status);
617
- const safeItemType = redactCodexEventKind(item.type);
618
- this.warnOnce(JSON.stringify([
619
- "status",
620
- item.type,
621
- status
622
- ]), "codex app-server item reported unknown status; continuing projection", {
623
- itemId: item.id,
624
- itemType: safeItemType,
625
- status: safeStatus
626
- });
627
- }
628
- warnUnknownEvent(notification, params) {
629
- const notificationThreadId = readCodexNotificationThreadId(params);
630
- const notificationTurnId = readCodexNotificationTurnId(params);
631
- const eventKind = redactCodexEventKind(notification.method);
632
- this.warnOnce(JSON.stringify(["method", notification.method]), `codex app-server projector received unknown event kind; continuing: ${eventKind}`, {
633
- eventKind,
634
- activeThreadId: this.threadId,
635
- activeTurnId: this.turnId,
636
- threadId: notificationThreadId,
637
- turnId: notificationTurnId,
638
- matchesActiveThread: notificationThreadId === this.threadId,
639
- matchesActiveTurn: notificationTurnId === this.turnId
640
- });
641
- }
642
- warnOnce(key, message, context) {
643
- if (this.warningKeys.has(key)) return;
644
- this.warningKeys.add(key);
645
- embeddedAgentLog.warn(message, context);
646
- }
647
- };
648
- //#endregion
649
- //#region extensions/codex/src/app-server/event-projector-tool-output.ts
650
- const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 1e4;
651
- const TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX = "...(OpenClaw truncated Codex native tool output";
652
- var ToolOutputAccumulator = class {
653
- constructor() {
654
- this.prefixByItem = /* @__PURE__ */ new Map();
655
- this.originalLengthByItem = /* @__PURE__ */ new Map();
656
- this.normalizedLengthByItem = /* @__PURE__ */ new Map();
657
- this.trimStateByItem = /* @__PURE__ */ new Map();
658
- this.truncatedItemIds = /* @__PURE__ */ new Set();
659
- this.textByItem = /* @__PURE__ */ new Map();
660
- }
661
- append(itemId, delta) {
662
- const originalLength = (this.originalLengthByItem.get(itemId) ?? this.textByItem.get(itemId)?.length ?? 0) + delta.length;
663
- this.originalLengthByItem.set(itemId, originalLength);
664
- const normalizedLength = updateToolOutputTrimState(this.trimStateByItem, itemId, delta);
665
- this.normalizedLengthByItem.set(itemId, normalizedLength);
666
- if (this.truncatedItemIds.has(itemId)) {
667
- const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", "", originalLength);
668
- this.prefixByItem.set(itemId, next.rawPrefix);
669
- this.textByItem.set(itemId, next.text);
670
- return {
671
- text: next.text,
672
- originalLength,
673
- normalizedLength,
674
- rawPrefix: next.rawPrefix
675
- };
676
- }
677
- const next = appendBoundedToolTranscriptText(this.prefixByItem.get(itemId) ?? this.textByItem.get(itemId) ?? "", delta, originalLength);
678
- this.prefixByItem.set(itemId, next.rawPrefix);
679
- this.textByItem.set(itemId, next.text);
680
- if (originalLength > 1e4) this.truncatedItemIds.add(itemId);
681
- return {
682
- text: next.text,
683
- originalLength,
684
- normalizedLength,
685
- rawPrefix: next.rawPrefix
686
- };
687
- }
688
- };
689
- function updateToolOutputTrimState(trimStateByItem, itemId, delta) {
690
- const state = trimStateByItem.get(itemId) ?? {
691
- totalLength: 0,
692
- leadingWhitespaceLength: 0,
693
- trailingWhitespaceLength: 0,
694
- sawNonWhitespace: false
695
- };
696
- state.totalLength += delta.length;
697
- const firstNonWhitespace = delta.search(/\S/u);
698
- if (firstNonWhitespace === -1) {
699
- if (!state.sawNonWhitespace) state.leadingWhitespaceLength += delta.length;
700
- state.trailingWhitespaceLength += delta.length;
701
- trimStateByItem.set(itemId, state);
702
- return state.sawNonWhitespace ? state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength : 0;
703
- }
704
- if (!state.sawNonWhitespace) {
705
- state.leadingWhitespaceLength += firstNonWhitespace;
706
- state.sawNonWhitespace = true;
707
- }
708
- state.trailingWhitespaceLength = delta.match(/\s*$/u)?.[0].length ?? 0;
709
- trimStateByItem.set(itemId, state);
710
- return state.totalLength - state.leadingWhitespaceLength - state.trailingWhitespaceLength;
711
- }
712
- function toolOutputRawEchoSignature(text) {
713
- const trimmed = text.trim();
714
- if (!trimmed) return;
715
- return {
716
- rawLength: trimmed.length,
717
- rawPrefix: trimmed.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
718
- };
719
- }
720
- function normalizeToolTranscriptArguments(value) {
721
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
722
- return value;
723
- }
724
- function collectDynamicToolContentText(contentItems) {
725
- if (!Array.isArray(contentItems)) return "";
726
- return contentItems.flatMap((entry) => {
727
- if (!isJsonObject(entry)) return [];
728
- const text = readString$3(entry, "text");
729
- return text ? [text] : [];
730
- }).join("\n");
731
- }
732
- function appendBoundedToolTranscriptText(currentPrefix, delta, originalLength) {
733
- if (originalLength <= 1e4) {
734
- const rawPrefix = currentPrefix + delta;
735
- return {
736
- text: rawPrefix,
737
- rawPrefix
738
- };
739
- }
740
- const notice = toolTranscriptTruncationNotice(originalLength);
741
- if (notice.length >= 1e4) return {
742
- text: notice.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS),
743
- rawPrefix: ""
744
- };
745
- const textBudget = TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length;
746
- const remaining = Math.max(0, textBudget - currentPrefix.length);
747
- const rawPrefix = truncateUtf16Safe(remaining > 0 ? `${currentPrefix}${truncateUtf16Safe(delta, remaining)}` : currentPrefix, textBudget);
748
- return {
749
- text: `${rawPrefix}${notice}`,
750
- rawPrefix
751
- };
752
- }
753
- function toolTranscriptTruncationNotice(originalLength) {
754
- return `\n${`${TOOL_OUTPUT_TRUNCATION_NOTICE_PREFIX}: original ${originalLength} chars, showing ${TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS}; rerun with narrower args.)`}`;
755
- }
756
- function truncateToolTranscriptText(text, originalLength = text.length) {
757
- if (originalLength <= 1e4 && text.length <= 1e4) return text;
758
- const notice = toolTranscriptTruncationNotice(originalLength);
759
- if (notice.length >= 1e4) return notice.slice(1, 10001);
760
- return `${truncateUtf16Safe(text, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS - notice.length)}${notice}`;
761
- }
762
- function formatToolSummary(toolName, meta) {
763
- const trimmedMeta = meta?.trim();
764
- return formatToolAggregate(toolName, trimmedMeta ? [trimmedMeta] : void 0, { markdown: true });
765
- }
766
- function formatToolOutput(toolName, meta, output) {
767
- const formattedOutput = formatToolProgressOutput(output);
768
- if (!formattedOutput) return formatToolSummary(toolName, meta);
769
- const fence = markdownFenceForText(formattedOutput);
770
- return `${formatToolSummary(toolName, meta)}\n${fence}txt\n${formattedOutput}\n${fence}`;
771
- }
772
- function markdownFenceForText(text) {
773
- return "`".repeat(Math.max(3, longestBacktickRun(text) + 1));
774
- }
775
- function longestBacktickRun(value) {
776
- let longest = 0;
777
- let current = 0;
778
- for (const char of value) {
779
- if (char === "`") {
780
- current += 1;
781
- longest = Math.max(longest, current);
782
- continue;
783
- }
784
- current = 0;
785
- }
786
- return longest;
787
- }
788
- //#endregion
789
- //#region extensions/codex/src/app-server/tool-progress-normalization.ts
790
- /**
791
- * Normalizes and sanitizes Codex dynamic-tool progress payloads before they are
792
- * emitted into OpenClaw events or logs.
793
- */
794
- /** Maps OpenClaw tool-progress config to the mode used by Codex progress metadata. */
795
- function resolveCodexToolProgressDetailMode(value) {
796
- return value === "raw" ? "raw" : "explain";
797
- }
798
- /** Recursively redacts sensitive strings and handles circular values in event payloads. */
799
- function sanitizeCodexAgentEventValue(value, seen = /* @__PURE__ */ new WeakSet()) {
800
- if (typeof value === "string") return redactToolPayloadText(value);
801
- if (Array.isArray(value)) {
802
- if (seen.has(value)) return "[Circular]";
803
- seen.add(value);
804
- return value.map((entry) => sanitizeCodexAgentEventValue(entry, seen));
805
- }
806
- if (value && typeof value === "object") {
807
- if (seen.has(value)) return "[Circular]";
808
- seen.add(value);
809
- const out = {};
810
- for (const [key, child] of Object.entries(value)) out[key] = typeof child === "string" ? redactSensitiveFieldValue(key, child) : sanitizeCodexAgentEventValue(child, seen);
811
- return out;
812
- }
813
- return value;
814
- }
815
- /** Sanitizes a record-shaped Codex agent event payload. */
816
- function sanitizeCodexAgentEventRecord(value) {
817
- return sanitizeCodexAgentEventValue(value);
818
- }
819
- /** Sanitizes dynamic-tool arguments before diagnostic/event emission. */
820
- function sanitizeCodexToolArguments(value) {
821
- if (!isJsonObject(value)) return;
822
- return sanitizeCodexAgentEventRecord(value);
823
- }
824
- /** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
825
- function sanitizeCodexToolResponse(response) {
826
- return sanitizeCodexAgentEventRecord(response);
827
- }
828
- /** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
829
- function inferCodexDynamicToolMeta(call, detailMode) {
830
- return inferToolMetaFromArgs(call.tool, call.arguments, { detailMode });
831
- }
832
- //#endregion
833
- //#region extensions/codex/src/app-server/event-projector-tool-items.ts
834
- function nativeToolActionFingerprint(item) {
835
- if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
836
- type: item.type,
837
- command: item.command,
838
- cwd: typeof item.cwd === "string" ? item.cwd : ""
839
- });
840
- if (item.type === "fileChange") return JSON.stringify({
841
- type: item.type,
842
- changes: itemFileChanges(item)
843
- });
844
- }
845
- function isNativePostToolUseRelayItem(item) {
846
- switch (item.type) {
847
- case "commandExecution":
848
- case "fileChange":
849
- case "mcpToolCall": return true;
850
- default: return false;
851
- }
852
- }
853
- function shouldSuppressChannelProgressForItem(item) {
854
- if (shouldSynthesizeToolProgressForItem(item)) return true;
855
- return item.type === "dynamicToolCall";
856
- }
857
- function itemToolArgs(item) {
858
- if (item.type === "commandExecution") return sanitizeCodexAgentEventRecord({
859
- command: item.command,
860
- ...typeof item.cwd === "string" ? { cwd: item.cwd } : {}
861
- });
862
- if (item.type === "fileChange") return sanitizeCodexAgentEventRecord({ changes: itemFileChangesForTranscript(item) });
863
- if (item.type === "webSearch") return webSearchToolArgs(item);
864
- if (item.type === "dynamicToolCall" || item.type === "mcpToolCall") return sanitizeCodexToolArguments(item.arguments);
865
- }
866
- function webSearchToolArgs(item) {
867
- const action = isJsonObject(item.action) ? item.action : void 0;
868
- const actionType = action ? readNonEmptyString(action, "type") : void 0;
869
- const queries = action && actionType === "search" ? readNonEmptyStringArray(action, "queries") : [];
870
- const query = normalizeNonEmptyString(item.query) ?? (action && actionType === "search" ? readNonEmptyString(action, "query") : void 0) ?? queries[0];
871
- const url = action ? readNonEmptyString(action, "url") : void 0;
872
- const pattern = action ? readNonEmptyString(action, "pattern") : void 0;
873
- const args = {};
874
- if (query) args.query = query;
875
- if (queries.length > 0) args.queries = queries;
876
- if (actionType && actionType !== "search") args.action = actionType;
877
- if (url) args.url = url;
878
- if (pattern) args.pattern = pattern;
879
- if (!query && !url && !pattern) args.queryUnavailable = true;
880
- return sanitizeCodexAgentEventRecord(args);
881
- }
882
- function itemToolResult(item) {
883
- if (item.type === "commandExecution") return { result: sanitizeCodexAgentEventRecord({
884
- status: item.status,
885
- exitCode: item.exitCode,
886
- durationMs: item.durationMs
887
- }) };
888
- if (item.type === "fileChange") return { result: sanitizeCodexAgentEventRecord({
889
- status: item.status,
890
- changes: itemFileChanges(item)
891
- }) };
892
- if (item.type === "mcpToolCall") return { result: sanitizeCodexAgentEventRecord({
893
- status: item.status,
894
- durationMs: item.durationMs,
895
- ...item.error ? { error: item.error } : {},
896
- ...item.result ? { result: item.result } : {}
897
- }) };
898
- if (item.type === "webSearch") return { result: webSearchToolResult(item) };
899
- return {};
900
- }
901
- function webSearchToolResult(item) {
902
- return sanitizeCodexAgentEventRecord({
903
- status: itemStatus(item),
904
- ...typeof item.durationMs === "number" ? { durationMs: item.durationMs } : {},
905
- ...webSearchToolArgs(item)
906
- });
907
- }
908
- function itemFileChangeRecords(item) {
909
- const changes = item.changes;
910
- return Array.isArray(changes) ? changes.filter(isJsonObject) : [];
911
- }
912
- function itemFileChanges(item) {
913
- return itemFileChangeRecords(item).flatMap((change) => {
914
- const path = normalizeNonEmptyString(change.path);
915
- if (!path || change.kind === void 0) return [];
916
- return [{
917
- path,
918
- kind: change.kind
919
- }];
920
- });
921
- }
922
- function fileChangeKindType(kind) {
923
- if (typeof kind === "string") return kind;
924
- return isJsonObject(kind) ? normalizeNonEmptyString(kind.type) : void 0;
925
- }
926
- function countFileContentLines(content) {
927
- if (!content) return 0;
928
- const lines = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
929
- if (lines.length > 1 && lines.at(-1) === "") lines.pop();
930
- return lines.length;
931
- }
932
- function fileChangeDiffStat(diff, kind) {
933
- const kindType = fileChangeKindType(kind);
934
- if (kindType === "add") return {
935
- added: countFileContentLines(diff),
936
- removed: 0
937
- };
938
- if (kindType === "delete") return {
939
- added: 0,
940
- removed: countFileContentLines(diff)
941
- };
942
- let added = 0;
943
- let removed = 0;
944
- let inHunk = false;
945
- for (const line of diff.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n")) {
946
- if (line.startsWith("@@")) {
947
- inHunk = true;
948
- continue;
949
- }
950
- if (!inHunk) continue;
951
- if (line.startsWith("+")) added += 1;
952
- else if (line.startsWith("-")) removed += 1;
953
- }
954
- return {
955
- added,
956
- removed
957
- };
958
- }
959
- function truncateFileChangeDiffAtLineBoundary(diff, maxChars) {
960
- if (diff.length <= maxChars) return { diff };
961
- if (maxChars <= 0) return { diffTruncated: true };
962
- const boundary = diff.lastIndexOf("\n", maxChars - 1);
963
- return boundary >= 0 ? {
964
- diff: diff.slice(0, boundary + 1),
965
- diffTruncated: true
966
- } : { diffTruncated: true };
967
- }
968
- function itemFileChangesForTranscript(item) {
969
- let remainingDiffChars = 1e4;
970
- return itemFileChangeRecords(item).flatMap((change) => {
971
- const path = normalizeNonEmptyString(change.path);
972
- if (!path || change.kind === void 0) return [];
973
- const result = {
974
- path,
975
- kind: change.kind
976
- };
977
- if (typeof change.diff !== "string") return [result];
978
- result.stat = fileChangeDiffStat(change.diff, change.kind);
979
- const bounded = truncateFileChangeDiffAtLineBoundary(change.diff, remainingDiffChars);
980
- if (bounded.diff !== void 0) {
981
- result.diff = bounded.diff;
982
- remainingDiffChars -= bounded.diff.length;
983
- }
984
- if (bounded.diffTruncated) result.diffTruncated = true;
985
- return [result];
986
- });
987
- }
988
- function itemToolError(item, status, outputTextByItem) {
989
- if (status === "blocked") return "codex native tool blocked";
990
- if (status !== "failed") return;
991
- return itemOutputText(item, outputTextByItem) ?? "codex native tool failed";
992
- }
993
- function itemMeta(item, detailMode = "explain") {
994
- if (item.type === "commandExecution" && typeof item.command === "string") return inferToolMetaFromArgs("exec", {
995
- command: item.command,
996
- cwd: typeof item.cwd === "string" ? item.cwd : void 0
997
- }, { detailMode });
998
- if (item.type === "webSearch") return inferToolMetaFromArgs("web_search", webSearchToolArgs(item), { detailMode });
999
- const toolName = itemName(item);
1000
- if ((item.type === "dynamicToolCall" || item.type === "mcpToolCall") && toolName) return inferToolMetaFromArgs(toolName, item.arguments, { detailMode });
1001
- }
1002
- function itemOutputText(item, outputTextByItem) {
1003
- if (item.type === "commandExecution") {
1004
- const output = item.aggregatedOutput?.trim() || outputTextByItem?.get(item.id)?.trim();
1005
- return output ? truncateToolTranscriptText(output) : void 0;
1006
- }
1007
- if (item.type === "dynamicToolCall") {
1008
- const output = collectDynamicToolContentText(item.contentItems).trim();
1009
- return output ? truncateToolTranscriptText(output) : void 0;
1010
- }
1011
- if (item.type === "mcpToolCall") {
1012
- const output = item.error ? stringifyJsonValue(item.error) : item.result ? stringifyJsonValue(item.result) : void 0;
1013
- return output ? truncateToolTranscriptText(output) : void 0;
1014
- }
1015
- }
1016
- function itemTranscriptResultText(item, outputTextByItem) {
1017
- const output = itemOutputText(item, outputTextByItem);
1018
- if (output) return output;
1019
- const result = itemToolResult(item).result;
1020
- const resultText = result ? stringifyJsonValue(result) : void 0;
1021
- return resultText ? truncateToolTranscriptText(resultText) : itemStatus(item);
1022
- }
1023
- function stringifyJsonValue(value) {
1024
- try {
1025
- return JSON.stringify(value, null, 2);
1026
- } catch {
1027
- return;
1028
- }
1029
- }
1030
- //#endregion
1031
- //#region extensions/codex/src/app-server/event-projector-tool-progress.ts
1032
- const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
1033
- "message",
1034
- "messages",
1035
- "reply",
1036
- "send",
1037
- "reaction",
1038
- "react",
1039
- "typing"
1040
- ]);
1041
- function shouldEmitTranscriptToolProgress(toolName, _args) {
1042
- const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
1043
- return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
1044
- }
1045
- var CodexToolProgressProjection = class {
1046
- constructor(params) {
1047
- this.params = params;
1048
- this.echoesByItem = /* @__PURE__ */ new Map();
1049
- this.resultSummaryItemIds = /* @__PURE__ */ new Set();
1050
- this.resultOutputItemIds = /* @__PURE__ */ new Set();
1051
- this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
1052
- this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
1053
- this.transcriptArgumentsById = /* @__PURE__ */ new Map();
1054
- this.resultOutputDeltaState = /* @__PURE__ */ new Map();
1055
- this.output = new ToolOutputAccumulator();
1056
- this.metas = /* @__PURE__ */ new Map();
1057
- this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
1058
- this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
1059
- this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
1060
- }
1061
- get outputTextByItem() {
1062
- return this.output.textByItem;
1063
- }
1064
- get toolMetas() {
1065
- return [...this.metas.values()];
1066
- }
1067
- getToolMeta(itemId) {
1068
- return this.metas.get(itemId);
1069
- }
1070
- get lastToolError() {
1071
- return this.lastNativeToolError;
1072
- }
1073
- get hasPotentialSideEffects() {
1074
- return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
1075
- }
1076
- setLastToolError(error) {
1077
- if (!error) {
1078
- this.lastNativeToolError = void 0;
1079
- return;
1080
- }
1081
- const terminalResolution = this.params.observeToolTerminal?.({
1082
- toolName: error.toolName,
1083
- ...error.meta ? { meta: error.meta } : {},
1084
- outcome: "failure",
1085
- failure: {
1086
- ...error.errorCode ? { errorCode: error.errorCode } : {},
1087
- ...error.error ? { error: error.error } : {},
1088
- ...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
1089
- ...error.timedOut ? { timedOut: true } : {},
1090
- ...error.middlewareError ? { middlewareError: true } : {}
1091
- },
1092
- nativeMutation: {
1093
- mutatingAction: error.mutatingAction === true,
1094
- replaySafe: error.mutatingAction !== true,
1095
- ...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
1096
- ...error.fileTarget ? { fileTarget: error.fileTarget } : {}
1097
- }
1098
- });
1099
- this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
1100
- }
1101
- recordDynamicToolResult(params) {
1102
- const resultText = collectDynamicToolContentText(params.contentItems);
1103
- const existing = this.metas.get(params.callId);
1104
- this.metas.set(params.callId, {
1105
- toolName: existing?.toolName ?? params.tool,
1106
- ...existing?.meta ? { meta: existing.meta } : {},
1107
- ...params.asyncStarted === true ? { asyncStarted: true } : {},
1108
- ...!params.success ? { isError: true } : {}
1109
- });
1110
- if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
1111
- else if (!params.success) this.lastNativeToolError = {
1112
- toolName: params.tool,
1113
- error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
1114
- };
1115
- else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1116
- if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
1117
- }
1118
- handleOutputDelta(params, toolName) {
1119
- const itemId = readString$3(params, "itemId");
1120
- const delta = readString$3(params, "delta");
1121
- if (!itemId || !delta) return;
1122
- const storedOutput = this.output.append(itemId, delta);
1123
- this.rememberEcho(itemId, {
1124
- displayText: storedOutput.text,
1125
- rawLength: storedOutput.normalizedLength,
1126
- rawPrefix: storedOutput.rawPrefix,
1127
- streamedDisplay: true
1128
- });
1129
- if (!this.shouldEmitToolOutput()) return;
1130
- if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
1131
- const state = this.resultOutputDeltaState.get(itemId) ?? {
1132
- chars: 0,
1133
- messages: 0,
1134
- truncated: false
1135
- };
1136
- if (state.truncated) return;
1137
- const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
1138
- const remainingMessages = Math.max(0, 20 - state.messages);
1139
- if (remainingChars === 0 || remainingMessages === 0) {
1140
- state.truncated = true;
1141
- this.resultOutputDeltaState.set(itemId, state);
1142
- this.emitToolResultMessage({
1143
- itemId,
1144
- text: formatToolOutput(toolName, void 0, "(output truncated)")
1145
- });
1146
- return;
1147
- }
1148
- const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
1149
- state.chars += chunk.length;
1150
- state.messages += 1;
1151
- const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
1152
- if (reachedLimit) state.truncated = true;
1153
- this.resultOutputDeltaState.set(itemId, state);
1154
- this.resultOutputStreamedItemIds.add(itemId);
1155
- this.emitToolResultMessage({
1156
- itemId,
1157
- text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
1158
- });
1159
- }
1160
- recordNativeToolError(params) {
1161
- const executionStarted = params.status !== "blocked";
1162
- const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
1163
- const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
1164
- const isFailure = isNonSuccessItemStatus(params.status);
1165
- const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
1166
- const terminalResolution = this.params.observeToolTerminal?.({
1167
- toolCallId: params.item.id,
1168
- toolName: params.name,
1169
- arguments: itemToolArgs(params.item),
1170
- ...params.meta ? { meta: params.meta } : {},
1171
- executionStarted,
1172
- outcome: isFailure ? "failure" : "success",
1173
- ...isFailure ? { failure: error ? { error } : {} } : {},
1174
- nativeMutation: {
1175
- mutatingAction,
1176
- replaySafe: !mutatingAction,
1177
- ...actionFingerprint ? { actionFingerprint } : {}
1178
- }
1179
- });
1180
- if (terminalResolution) {
1181
- this.lastNativeToolError = terminalResolution.lastToolError;
1182
- return;
1183
- }
1184
- if (isFailure) this.lastNativeToolError = {
1185
- toolName: params.name,
1186
- ...params.meta ? { meta: params.meta } : {},
1187
- ...error ? { error } : {},
1188
- ...mutatingAction ? { mutatingAction: true } : {},
1189
- ...actionFingerprint ? { actionFingerprint } : {}
1190
- };
1191
- else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
1192
- }
1193
- emitToolResultSummary(item) {
1194
- if (!item || !this.params.onToolResult || !this.shouldEmitToolResult()) return;
1195
- if (this.resultSummaryItemIds.has(item.id)) return;
1196
- const toolName = itemName(item);
1197
- if (!toolName || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1198
- this.resultSummaryItemIds.add(item.id);
1199
- this.emitToolResultMessage({
1200
- itemId: item.id,
1201
- text: formatToolSummary(toolName, itemMeta(item, this.toolProgressDetailMode()))
1202
- });
1203
- }
1204
- emitToolResultOutput(item) {
1205
- if (!item || !this.params.onToolResult || !this.shouldEmitToolOutput()) return;
1206
- if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
1207
- const toolName = itemName(item);
1208
- const output = itemOutputText(item, this.output.textByItem);
1209
- if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
1210
- this.emitToolResultMessage({
1211
- itemId: item.id,
1212
- text: formatToolOutput(toolName, itemMeta(item, this.toolProgressDetailMode()), output),
1213
- finalOutput: true,
1214
- isError: isNonSuccessItemStatus(itemStatus(item))
1215
- });
1216
- }
1217
- recordToolMeta(item) {
1218
- if (!item) return;
1219
- if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
1220
- else this.sideEffectingNativeIds.delete(item.id);
1221
- const toolName = itemName(item);
1222
- if (!toolName) return;
1223
- const meta = itemMeta(item, this.toolProgressDetailMode());
1224
- const status = itemStatus(item);
1225
- const existing = this.metas.get(item.id);
1226
- this.metas.set(item.id, {
1227
- toolName,
1228
- ...meta ? { meta } : {},
1229
- ...existing?.asyncStarted ? { asyncStarted: true } : {},
1230
- ...status !== "running" && isNonSuccessItemStatus(status) ? { isError: true } : {}
1231
- });
1232
- }
1233
- recordTranscriptCall(params) {
1234
- this.transcriptArgumentsById.set(params.id, params.arguments);
1235
- if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
1236
- else this.transcriptProgressSuppressedIds.delete(params.id);
1237
- this.emitTranscriptToolCallProgress(params);
1238
- }
1239
- recordTranscriptResult(params) {
1240
- this.emitTranscriptToolResultProgress(params);
1241
- }
1242
- matchesEcho(text) {
1243
- for (const state of this.echoesByItem.values()) {
1244
- if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
1245
- if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
1246
- for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
1247
- }
1248
- return false;
1249
- }
1250
- rememberCommandAggregateOutputEcho(item) {
1251
- if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
1252
- const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
1253
- if (signature) this.rememberEcho(item.id, signature);
1254
- }
1255
- toolProgressDetailMode() {
1256
- return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
1257
- }
1258
- emitToolResultMessage(params) {
1259
- const rawText = params.text.trim();
1260
- const text = truncateToolTranscriptText(rawText);
1261
- if (!text) return;
1262
- this.rememberEcho(params.itemId, {
1263
- displayText: text,
1264
- rawText
1265
- });
1266
- if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
1267
- try {
1268
- Promise.resolve(this.params.onToolResult?.({
1269
- text,
1270
- ...params.isError === true ? { isError: true } : {}
1271
- })).catch(() => {});
1272
- } catch {}
1273
- }
1274
- shouldEmitToolResult() {
1275
- return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
1276
- }
1277
- shouldEmitToolOutput() {
1278
- return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
1279
- }
1280
- emitTranscriptToolCallProgress(params) {
1281
- if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
1282
- this.transcriptProgressCallIds.add(params.id);
1283
- const args = normalizeToolTranscriptArguments(params.arguments);
1284
- const meta = inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() });
1285
- if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1286
- this.resultSummaryItemIds.add(params.id);
1287
- this.emitToolResultMessage({
1288
- itemId: params.id,
1289
- text: formatToolSummary(params.name, meta)
1290
- });
1291
- }
1292
- emitTranscriptToolResultProgress(params) {
1293
- if (this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
1294
- if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
1295
- id: params.id,
1296
- name: params.name,
1297
- arguments: {}
1298
- });
1299
- if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
1300
- const text = params.text?.trim();
1301
- if (text) this.emitToolResultMessage({
1302
- itemId: params.id,
1303
- text: formatToolOutput(params.name, void 0, text),
1304
- finalOutput: true,
1305
- isError: params.isError
1306
- });
1307
- }
1308
- rememberEcho(itemId, signature) {
1309
- if (!itemId) return;
1310
- const existing = this.echoesByItem.get(itemId) ?? {
1311
- displayTexts: [],
1312
- rawSignatures: []
1313
- };
1314
- const displayText = signature.displayText?.trim();
1315
- if (displayText) {
1316
- if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
1317
- else if (!existing.displayTexts.includes(displayText)) {
1318
- if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
1319
- existing.displayTexts.push(displayText);
1320
- }
1321
- }
1322
- const rawText = signature.rawText?.trim();
1323
- const rawLength = signature.rawLength ?? rawText?.length;
1324
- const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
1325
- if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
1326
- const next = {
1327
- length: rawLength,
1328
- prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
1329
- };
1330
- if (signature.streamedDisplay) existing.streamedRawSignature = next;
1331
- else {
1332
- const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
1333
- if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
1334
- else {
1335
- if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
1336
- existing.rawSignatures.push(next);
1337
- }
1338
- }
1339
- }
1340
- this.echoesByItem.set(itemId, existing);
1341
- }
1342
- };
1343
- //#endregion
1344
- //#region extensions/codex/src/app-server/session-history.ts
1345
- /**
1346
- * Reads OpenClaw session history for Codex transcript mirroring and sanitizes
1347
- * image payloads before replaying messages into the app-server projector.
1348
- */
1349
- function isMissingFileError(error) {
1350
- return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
1351
- }
1352
- /** Returns sanitized session-context messages for a Codex mirrored session file. */
1353
- async function readCodexMirroredSessionHistoryMessages(target) {
1354
- try {
1355
- const entries = await readCodexMirroredSessionEntries(target);
1356
- if (entries.length === 0) return [];
1357
- const firstEntry = entries[0];
1358
- if (firstEntry?.type !== "session") return [];
1359
- if (typeof firstEntry.id !== "string") return;
1360
- migrateSessionEntries(entries);
1361
- return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
1362
- return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
1363
- })).messages, "codex mirrored history");
1364
- } catch (error) {
1365
- if (isMissingFileError(error)) return [];
1366
- return;
1367
- }
1368
- }
1369
- async function readCodexMirroredSessionEntries(target) {
1370
- const sqliteMarker = parseSqliteSessionFileMarker(target.sessionFile);
1371
- if (sqliteMarker) {
1372
- if (sqliteMarker.sessionId !== target.sessionId || target.agentId !== void 0 && sqliteMarker.agentId !== target.agentId) return [];
1373
- const sessionKey = resolveSqliteMarkerSessionKey(target, sqliteMarker);
1374
- if (!sessionKey) return [];
1375
- return await readSessionTranscriptEvents({
1376
- agentId: sqliteMarker.agentId,
1377
- sessionId: sqliteMarker.sessionId,
1378
- sessionKey,
1379
- storePath: sqliteMarker.storePath
1380
- });
1381
- }
1382
- return parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
1383
- }
1384
- function resolveSqliteMarkerSessionKey(target, marker) {
1385
- const explicitSessionKey = target.sessionKey?.trim();
1386
- if (explicitSessionKey) return explicitSessionKey;
1387
- const entries = listSessionEntries({
1388
- agentId: marker.agentId,
1389
- storePath: marker.storePath
1390
- });
1391
- return (entries.find(({ entry }) => {
1392
- return entry.sessionId === marker.sessionId && entry.sessionFile === target.sessionFile;
1393
- }) ?? entries.find(({ entry }) => {
1394
- return entry.sessionId === marker.sessionId;
1395
- }))?.sessionKey;
1396
- }
1397
- //#endregion
1398
- //#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
1399
- const ZERO_USAGE = {
1400
- input: 0,
1401
- output: 0,
1402
- cacheRead: 0,
1403
- cacheWrite: 0,
1404
- totalTokens: 0,
1405
- cost: {
1406
- input: 0,
1407
- output: 0,
1408
- cacheRead: 0,
1409
- cacheWrite: 0,
1410
- total: 0
1411
- }
1412
- };
1413
- const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
1414
- var CodexToolTranscriptProjection = class {
1415
- constructor(params, threadId, turnId, progress, options = {}) {
1416
- this.params = params;
1417
- this.threadId = threadId;
1418
- this.turnId = turnId;
1419
- this.progress = progress;
1420
- this.options = options;
1421
- this.messages = [];
1422
- this.callIds = /* @__PURE__ */ new Set();
1423
- this.resultIds = /* @__PURE__ */ new Set();
1424
- this.namesById = /* @__PURE__ */ new Map();
1425
- this.trajectoryCallIds = /* @__PURE__ */ new Set();
1426
- this.trajectoryResultIds = /* @__PURE__ */ new Set();
1427
- this.trajectoryNamesById = /* @__PURE__ */ new Map();
1428
- this.trajectoryItemsById = /* @__PURE__ */ new Map();
1429
- this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
1430
- }
1431
- get transcriptMessages() {
1432
- return this.messages;
1433
- }
1434
- recordDynamicToolCall(params) {
1435
- this.recordToolCall({
1436
- id: params.callId,
1437
- name: params.tool,
1438
- arguments: sanitizeCodexToolArguments(params.arguments)
1439
- });
1440
- }
1441
- recordDynamicToolResult(params) {
1442
- this.recordToolResult({
1443
- id: params.callId,
1444
- name: params.tool,
1445
- text: collectDynamicToolContentText(params.contentItems),
1446
- isError: !params.success
1447
- });
1448
- }
1449
- recordNativeToolCall(item) {
1450
- if (!item || !shouldRecordNativeToolTranscript(item)) return;
1451
- const name = itemName(item);
1452
- if (name) this.recordToolCall({
1453
- id: item.id,
1454
- name,
1455
- arguments: itemToolArgs(item)
1456
- });
1457
- }
1458
- recordNativeToolResult(item) {
1459
- if (!item || !shouldRecordNativeToolTranscript(item)) return;
1460
- const name = itemName(item);
1461
- if (name) this.recordToolResult({
1462
- id: item.id,
1463
- name,
1464
- text: itemTranscriptResultText(item, this.progress.outputTextByItem),
1465
- isError: isNonSuccessItemStatus(itemStatus(item))
1466
- });
1467
- }
1468
- recordTrajectoryEvent(params) {
1469
- if (params.phase === "start") {
1470
- this.trajectoryCallIds.add(params.item.id);
1471
- this.trajectoryNamesById.set(params.item.id, params.name);
1472
- this.trajectoryItemsById.set(params.item.id, params.item);
1473
- this.options.trajectoryRecorder?.recordEvent("tool.call", {
1474
- threadId: this.threadId,
1475
- turnId: this.turnId,
1476
- itemId: params.item.id,
1477
- toolCallId: params.item.id,
1478
- name: params.name,
1479
- arguments: params.args
1480
- });
1481
- return;
1482
- }
1483
- this.trajectoryResultIds.add(params.item.id);
1484
- const toolResult = itemToolResult(params.item).result;
1485
- const output = itemOutputText(params.item, this.progress.outputTextByItem);
1486
- this.options.trajectoryRecorder?.recordEvent("tool.result", {
1487
- threadId: this.threadId,
1488
- turnId: this.turnId,
1489
- itemId: params.item.id,
1490
- toolCallId: params.item.id,
1491
- name: params.name,
1492
- status: params.status,
1493
- isError: isNonSuccessItemStatus(params.status),
1494
- ...toolResult ? { result: toolResult } : {},
1495
- ...output ? { output } : {}
1496
- });
1497
- }
1498
- emitAfterToolCallObservation(item) {
1499
- if (!this.shouldEmitAfterToolCallObservation(item)) return;
1500
- const name = itemName(item);
1501
- const status = itemStatus(item);
1502
- if (!name || status === "running") return;
1503
- this.afterToolCallObservedItemIds.add(item.id);
1504
- const result = itemToolResult(item).result;
1505
- const error = itemToolError(item, status, this.progress.outputTextByItem);
1506
- const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
1507
- const hookParams = {
1508
- toolName: name,
1509
- toolCallId: item.id,
1510
- runId: this.params.runId,
1511
- agentId: this.params.agentId,
1512
- sessionId: this.params.sessionId,
1513
- sessionKey: this.params.sessionKey,
1514
- startArgs: itemToolArgs(item) ?? {},
1515
- ...result !== void 0 ? { result } : {},
1516
- ...error ? { error } : {},
1517
- ...startedAt !== void 0 ? { startedAt } : {}
1518
- };
1519
- setImmediate(() => {
1520
- runAgentHarnessAfterToolCallHook(hookParams);
1521
- });
1522
- }
1523
- synthesizeMissingToolResults(params) {
1524
- if (!params.synthesize) return;
1525
- const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
1526
- const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
1527
- if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
1528
- for (const id of missingTranscriptIds) {
1529
- const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
1530
- if (name) this.recordToolResult({
1531
- id,
1532
- name,
1533
- text: formatMissingToolResultError({
1534
- id,
1535
- name
1536
- }),
1537
- isError: true
1538
- });
1539
- }
1540
- for (const id of missingTrajectoryIds) {
1541
- const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
1542
- if (!name) continue;
1543
- this.trajectoryResultIds.add(id);
1544
- const text = formatMissingToolResultError({
1545
- id,
1546
- name
1547
- });
1548
- this.options.trajectoryRecorder?.recordEvent("tool.result", {
1549
- threadId: this.threadId,
1550
- turnId: this.turnId,
1551
- itemId: id,
1552
- toolCallId: id,
1553
- name,
1554
- status: "failed",
1555
- isError: true,
1556
- result: {
1557
- status: "failed",
1558
- reason: "missing_tool_result"
1559
- },
1560
- output: text
1561
- });
1562
- }
1563
- if (!params.recordPromptError) {
1564
- this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
1565
- return;
1566
- }
1567
- const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
1568
- return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
1569
- }
1570
- async readMirroredSessionMessages() {
1571
- return await readCodexMirroredSessionHistoryMessages({
1572
- agentId: this.params.agentId,
1573
- sessionFile: this.params.sessionFile,
1574
- sessionId: this.params.sessionId,
1575
- sessionKey: this.params.sessionKey
1576
- }) ?? [];
1577
- }
1578
- recordToolCall(params) {
1579
- if (!params.id || !params.name || this.callIds.has(params.id)) return;
1580
- this.callIds.add(params.id);
1581
- this.namesById.set(params.id, params.name);
1582
- this.progress.recordTranscriptCall(params);
1583
- this.messages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
1584
- }
1585
- recordToolResult(params) {
1586
- if (!params.id || !params.name || this.resultIds.has(params.id)) return;
1587
- this.resultIds.add(params.id);
1588
- this.progress.recordTranscriptResult(params);
1589
- this.messages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
1590
- }
1591
- recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
1592
- const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
1593
- if (!firstMissingId) return;
1594
- const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
1595
- if (!name) return;
1596
- const item = this.trajectoryItemsById.get(firstMissingId);
1597
- const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
1598
- const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
1599
- this.progress.setLastToolError({
1600
- toolName: name,
1601
- ...meta ? { meta } : {},
1602
- error: formatMissingToolResultError({
1603
- id: firstMissingId,
1604
- name
1605
- }),
1606
- ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
1607
- ...actionFingerprint ? { actionFingerprint } : {}
1608
- });
1609
- }
1610
- shouldEmitAfterToolCallObservation(item) {
1611
- if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
1612
- return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
1613
- }
1614
- createToolCallMessage(params) {
1615
- const args = normalizeToolTranscriptArguments(params.arguments);
1616
- const attribution = resolveCodexLocalRuntimeAttribution(this.params);
1617
- return {
1618
- role: "assistant",
1619
- content: [{
1620
- type: "toolCall",
1621
- id: params.id,
1622
- name: params.name,
1623
- arguments: args,
1624
- input: args
1625
- }],
1626
- api: attribution.api ?? "openai-chatgpt-responses",
1627
- provider: attribution.provider,
1628
- model: this.params.modelId,
1629
- usage: ZERO_USAGE,
1630
- stopReason: "toolUse",
1631
- timestamp: Date.now()
1632
- };
1633
- }
1634
- createToolResultMessage(params) {
1635
- const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
1636
- return {
1637
- role: "toolResult",
1638
- toolCallId: params.id,
1639
- toolName: params.name,
1640
- isError: params.isError,
1641
- content: [{
1642
- type: "toolResult",
1643
- id: params.id,
1644
- name: params.name,
1645
- toolName: params.name,
1646
- toolCallId: params.id,
1647
- toolUseId: params.id,
1648
- tool_use_id: params.id,
1649
- content: text,
1650
- text
1651
- }],
1652
- timestamp: Date.now()
1653
- };
1654
- }
1655
- };
1656
- function formatMissingToolResultError(params) {
1657
- return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
1658
- }
1659
- function toolResultStatusText(params) {
1660
- return params.isError ? `${params.name} failed` : `${params.name} completed`;
1661
- }
1662
- function resolveStartedAtFromDurationMs(durationMs) {
1663
- if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
1664
- return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
1665
- }
1666
- //#endregion
1667
- //#region extensions/codex/src/app-server/event-projector-events.ts
1668
- var CodexEventProjection = class {
1669
- constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
1670
- this.threadId = threadId;
1671
- this.turnId = turnId;
1672
- this.emitAgentEvent = emitAgentEvent;
1673
- this.toolProgress = toolProgress;
1674
- this.toolTranscript = toolTranscript;
1675
- this.onNativeToolResultRecorded = onNativeToolResultRecorded;
1676
- this.reviewCount = 0;
1677
- }
1678
- get guardianReviewCount() {
1679
- return this.reviewCount;
1680
- }
1681
- handleGuardianReview(method, params) {
1682
- this.reviewCount += 1;
1683
- const review = isJsonObject(params.review) ? params.review : void 0;
1684
- const action = isJsonObject(params.action) ? params.action : void 0;
1685
- this.emitAgentEvent({
1686
- stream: "codex_app_server.guardian",
1687
- data: {
1688
- method,
1689
- phase: method.endsWith("/started") ? "started" : "completed",
1690
- reviewId: readString$3(params, "reviewId"),
1691
- targetItemId: readNullableString(params, "targetItemId"),
1692
- decisionSource: readString$3(params, "decisionSource"),
1693
- status: review ? readString$3(review, "status") : void 0,
1694
- riskLevel: review ? readString$3(review, "riskLevel") : void 0,
1695
- userAuthorization: review ? readString$3(review, "userAuthorization") : void 0,
1696
- rationale: review ? readNullableString(review, "rationale") : void 0,
1697
- actionType: action ? readString$3(action, "type") : void 0
1698
- }
1699
- });
1700
- }
1701
- handleGuardianWarning(params) {
1702
- this.emitAgentEvent({
1703
- stream: "codex_app_server.guardian",
1704
- data: {
1705
- phase: "warning",
1706
- message: readString$3(params, "message")
1707
- }
1708
- });
1709
- }
1710
- handleHook(method, params) {
1711
- const run = isJsonObject(params.run) ? params.run : void 0;
1712
- if (!run) return;
1713
- const durationMs = readNumber(run, "durationMs");
1714
- const entries = readHookOutputEntries(run.entries);
1715
- const hookTurnId = readNullableString(params, "turnId");
1716
- this.emitAgentEvent({
1717
- stream: "codex_app_server.hook",
1718
- data: {
1719
- phase: method === "hook/started" ? "started" : "completed",
1720
- threadId: this.threadId,
1721
- turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
1722
- hookRunId: readString$3(run, "id"),
1723
- eventName: readString$3(run, "eventName"),
1724
- handlerType: readString$3(run, "handlerType"),
1725
- executionMode: readString$3(run, "executionMode"),
1726
- scope: readString$3(run, "scope"),
1727
- source: readString$3(run, "source"),
1728
- sourcePath: readString$3(run, "sourcePath"),
1729
- status: readString$3(run, "status"),
1730
- statusMessage: readNullableString(run, "statusMessage"),
1731
- ...durationMs !== void 0 ? { durationMs } : {},
1732
- ...entries.length > 0 ? { entries } : {}
1733
- }
1734
- });
1735
- }
1736
- emitStandardItemEvent(params) {
1737
- const { item } = params;
1738
- if (!item) return;
1739
- const kind = itemKind(item);
1740
- if (!kind) return;
1741
- const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1742
- const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
1743
- this.emitAgentEvent({
1744
- stream: "item",
1745
- data: {
1746
- itemId: item.id,
1747
- phase: params.phase,
1748
- kind,
1749
- title: itemTitle(item),
1750
- status: params.phase === "start" ? "running" : itemStatus(item),
1751
- ...itemName(item) ? { name: itemName(item) } : {},
1752
- ...meta ? { meta } : {},
1753
- ...suppressChannelProgress ? { suppressChannelProgress: true } : {}
1754
- }
1755
- });
1756
- }
1757
- async emitNormalizedToolItemEvent(params) {
1758
- const { item } = params;
1759
- if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
1760
- const name = itemName(item);
1761
- if (!name) return;
1762
- const status = params.phase === "result" ? itemStatus(item) : "running";
1763
- const args = itemToolArgs(item);
1764
- const meta = itemMeta(item, this.toolProgress.toolProgressDetailMode());
1765
- this.toolTranscript.recordTrajectoryEvent({
1766
- phase: params.phase,
1767
- item,
1768
- name,
1769
- args,
1770
- status
1771
- });
1772
- if (params.phase === "result") this.toolProgress.recordNativeToolError({
1773
- item,
1774
- name,
1775
- meta,
1776
- status
1777
- });
1778
- if (!shouldEmitTranscriptToolProgress(name, args)) {
1779
- if (params.phase === "result") {
1780
- this.toolTranscript.emitAfterToolCallObservation(item);
1781
- await this.onNativeToolResultRecorded?.();
1782
- }
1783
- return;
1784
- }
1785
- this.emitAgentEvent({
1786
- stream: "tool",
1787
- data: {
1788
- phase: params.phase,
1789
- name,
1790
- itemId: item.id,
1791
- toolCallId: item.id,
1792
- ...meta ? { meta } : {},
1793
- ...params.phase === "start" && args ? { args } : {},
1794
- ...params.phase === "result" ? {
1795
- status,
1796
- isError: isNonSuccessItemStatus(status),
1797
- ...itemToolResult(item)
1798
- } : {}
1799
- }
1800
- });
1801
- if (params.phase === "result") {
1802
- this.toolTranscript.emitAfterToolCallObservation(item);
1803
- await this.onNativeToolResultRecorded?.();
1804
- }
1805
- }
1806
- };
1807
- //#endregion
1808
- //#region extensions/codex/src/app-server/event-projector-media.ts
1809
- const GENERATED_IMAGE_MEDIA_SUBDIR = "tool-image-generation";
1810
- const BYTES_PER_MB = 1024 * 1024;
1811
- const DEFAULT_GENERATED_IMAGE_MAX_BYTES = 6 * BYTES_PER_MB;
1812
- var CodexGeneratedMediaProjection = class {
1813
- constructor(config) {
1814
- this.config = config;
1815
- this.itemIds = /* @__PURE__ */ new Set();
1816
- this.urlsByItemId = /* @__PURE__ */ new Map();
1817
- }
1818
- hasGeneratedMedia() {
1819
- return this.itemIds.size > 0;
1820
- }
1821
- recordNative(item) {
1822
- if (item?.type !== "imageGeneration") return;
1823
- const savedPath = readItemString(item, "savedPath")?.trim();
1824
- if (savedPath) this.recordUrl({
1825
- itemId: item.id,
1826
- mediaUrl: savedPath
1827
- });
1828
- }
1829
- async recordRaw(item) {
1830
- if (readString$3(item, "type") !== "image_generation_call") return;
1831
- const result = readString$3(item, "result");
1832
- if (!result) return;
1833
- const itemId = readString$3(item, "id") ?? `raw-image-${this.itemIds.size}`;
1834
- this.itemIds.add(itemId);
1835
- const maxBytes = resolveGeneratedImageMaxBytes(this.config);
1836
- const estimatedDecodedBytes = estimateBase64DecodedBytes(result);
1837
- if (estimatedDecodedBytes !== void 0 && estimatedDecodedBytes > maxBytes) {
1838
- embeddedAgentLog.warn("codex app-server raw image generation result exceeds media limit", {
1839
- itemId,
1840
- estimatedDecodedBytes,
1841
- maxBytes
1842
- });
1843
- return;
1844
- }
1845
- const asset = generatedImageAssetFromBase64({
1846
- base64: result,
1847
- index: this.itemIds.size,
1848
- revisedPrompt: readString$3(item, "revised_prompt") ?? readString$3(item, "revisedPrompt"),
1849
- fileNamePrefix: "codex-image-generation",
1850
- sniffMimeType: true
1851
- });
1852
- if (!asset) return;
1853
- try {
1854
- const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
1855
- this.recordUrl({
1856
- itemId,
1857
- mediaUrl: saved.path,
1858
- replaceExisting: true
1859
- });
1860
- } catch (error) {
1861
- embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
1862
- itemId,
1863
- error
1864
- });
1865
- }
1866
- }
1867
- buildToolMediaUrls(params) {
1868
- const mediaUrls = new Set(params.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
1869
- if ((params.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.urlsByItemId.values()) mediaUrls.add(mediaUrl);
1870
- return mediaUrls.size > 0 ? [...mediaUrls] : params.toolMediaUrls;
59
+ case "declined":
60
+ case "inProgress":
61
+ case "in_progress":
62
+ case "running": return;
63
+ default: return status;
1871
64
  }
1872
- recordUrl(params) {
1873
- if (this.urlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
1874
- this.itemIds.add(params.itemId);
1875
- return;
1876
- }
1877
- this.urlsByItemId.set(params.itemId, params.mediaUrl);
1878
- this.itemIds.add(params.itemId);
65
+ }
66
+ function auditNativeToolTerminalStatus(item) {
67
+ if (item.type === "imageView" || item.type === "sleep") return "completed";
68
+ const status = readItemString(item, "status");
69
+ if (status === "completed") return "completed";
70
+ if (status === "failed" || status === "error") return "failed";
71
+ if (status === "declined") return "blocked";
72
+ return "unknown";
73
+ }
74
+ function auditNativeToolUnfinishedStatus(item) {
75
+ return item.type === "webSearch" || item.type === "imageGeneration" ? "unknown" : "failed";
76
+ }
77
+ function isNonSuccessItemStatus(status) {
78
+ return status === "failed" || status === "blocked";
79
+ }
80
+ function itemName(item) {
81
+ if (item.type === "dynamicToolCall" && typeof item.tool === "string") return item.tool;
82
+ if (item.type === "mcpToolCall" && typeof item.tool === "string") {
83
+ const server = typeof item.server === "string" ? item.server : void 0;
84
+ return server ? `${server}.${item.tool}` : item.tool;
1879
85
  }
1880
- };
1881
- function estimateBase64DecodedBytes(base64) {
1882
- let nonWhitespaceLength = 0;
1883
- let previousCode = -1;
1884
- let lastCode = -1;
1885
- for (let i = 0; i < base64.length; i += 1) {
1886
- const code = base64.charCodeAt(i);
1887
- if (isBase64WhitespaceCode(code)) continue;
1888
- nonWhitespaceLength += 1;
1889
- previousCode = lastCode;
1890
- lastCode = code;
86
+ if (item.type === "commandExecution") return "bash";
87
+ if (item.type === "fileChange") return "apply_patch";
88
+ if (item.type === "webSearch") return "web_search";
89
+ }
90
+ function auditNativeToolName(item) {
91
+ if (item.type === "dynamicToolCall") return;
92
+ const progressName = itemName(item);
93
+ if (progressName) return progressName;
94
+ if (item.type === "collabAgentToolCall") return typeof item.tool === "string" && item.tool.trim() ? `collab.${item.tool.trim()}` : "collab_agent";
95
+ if (item.type === "imageGeneration") return "image_generation";
96
+ if (item.type === "imageView") return "image_view";
97
+ if (item.type === "sleep") return "sleep";
98
+ }
99
+ function isSideEffectingNativeToolItem(item) {
100
+ return itemStatus(item) !== "blocked" && (isMutatingNativeToolItem(item) || item.type === "mcpToolCall");
101
+ }
102
+ function shouldSynthesizeToolProgressForItem(item) {
103
+ switch (item.type) {
104
+ case "commandExecution":
105
+ case "fileChange":
106
+ case "webSearch":
107
+ case "mcpToolCall": return true;
108
+ default: return false;
1891
109
  }
1892
- if (nonWhitespaceLength === 0) return;
1893
- const equalsCode = "=".charCodeAt(0);
1894
- const padding = lastCode === equalsCode ? previousCode === equalsCode ? 2 : 1 : 0;
1895
- return Math.max(0, Math.floor(nonWhitespaceLength * 3 / 4) - padding);
1896
110
  }
1897
- function isBase64WhitespaceCode(code) {
1898
- return code === 32 || code === 9 || code === 10 || code === 13;
111
+ function shouldRecordNativeToolTranscript(item) {
112
+ return shouldSynthesizeToolProgressForItem(item) && item.type !== "webSearch";
113
+ }
114
+ function isMutatingNativeToolItem(item) {
115
+ if (item.type === "commandExecution") return true;
116
+ return item.type === "fileChange" || item.type === "collabAgentToolCall" || item.type === "imageGeneration";
1899
117
  }
1900
- function resolveGeneratedImageMaxBytes(config) {
1901
- const configured = config?.agents?.defaults?.mediaMaxMb;
1902
- if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) return Math.floor(configured * BYTES_PER_MB);
1903
- return DEFAULT_GENERATED_IMAGE_MAX_BYTES;
118
+ function shouldClearTerminalPresentationForNativeItem(item) {
119
+ switch (item.type) {
120
+ case "collabAgentToolCall":
121
+ case "commandExecution":
122
+ case "fileChange":
123
+ case "imageGeneration":
124
+ case "imageView":
125
+ case "mcpToolCall":
126
+ case "webSearch": return true;
127
+ default: return false;
128
+ }
1904
129
  }
1905
130
  //#endregion
1906
131
  //#region extensions/codex/src/app-server/dynamic-tool-response-state.ts
@@ -2029,7 +254,9 @@ const CODEX_DYNAMIC_COMPUTER_COMPLETION_GRACE_MS = 3e4;
2029
254
  /** Timeout for image-understanding style dynamic tool calls. */
2030
255
  const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
2031
256
  /** Timeout for message-delivery dynamic tool calls. */
2032
- const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS;
257
+ const CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS = 6e5;
258
+ /** Outer default for collector waits: full swarm budget plus completion grace. */
259
+ const CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS = 63e4;
2033
260
  const LOG_FIELD_MAX_LENGTH = 160;
2034
261
  function normalizeLogField(value) {
2035
262
  if (typeof value !== "string") return;
@@ -2270,6 +497,10 @@ function hasPendingDynamicToolTerminalDiagnostic(params) {
2270
497
  function resolveDynamicToolCallTimeoutMs(params) {
2271
498
  if (params.call.tool === "computer") return clampDynamicToolTimeoutMs(readComputerToolTimeoutMs(params.call.arguments));
2272
499
  if (params.call.tool === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
500
+ if (params.call.tool === "agents_wait") {
501
+ const requestedMs = readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_AGENTS_WAIT_TOOL_TIMEOUT_MS;
502
+ return Math.max(1, Math.min(63e4, Math.floor(requestedMs)));
503
+ }
2273
504
  return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
2274
505
  }
2275
506
  function readComputerToolTimeoutMs(value) {
@@ -2288,11 +519,15 @@ function readDynamicToolCallTimeoutMs(value) {
2288
519
  }
2289
520
  function readConfiguredDynamicToolTimeoutMs(toolName, config) {
2290
521
  if (toolName === "image_generate") {
2291
- const imageGenerationModel = config?.agents?.defaults?.imageGenerationModel;
2292
- if (!imageGenerationModel || typeof imageGenerationModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
2293
- return readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
522
+ const imageModel = config?.agents?.defaults?.mediaModels?.image;
523
+ if (!imageModel || typeof imageModel !== "object") return CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
524
+ return readPositiveFiniteTimeoutMs(imageModel.timeoutMs) ?? CODEX_DYNAMIC_IMAGE_GENERATION_TOOL_TIMEOUT_MS;
525
+ }
526
+ if (toolName === "image") {
527
+ const candidates = (config?.tools?.media?.models ?? []).filter((entry) => !entry.capabilities || entry.capabilities.includes("image"));
528
+ const capabilityTimeoutMs = readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds);
529
+ return Math.max(capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS, ...candidates.map((entry) => readTimeoutSecondsAsMs(entry.timeoutSeconds) ?? capabilityTimeoutMs ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS));
2294
530
  }
2295
- if (toolName === "image") return readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds) ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS;
2296
531
  if (toolName === "message") return CODEX_DYNAMIC_MESSAGE_TOOL_TIMEOUT_MS;
2297
532
  }
2298
533
  function readTimeoutSecondsAsMs(value) {
@@ -2412,6 +647,7 @@ function createCodexNativeHookRelay(params) {
2412
647
  ...params.config ? { config: params.config } : {},
2413
648
  runId: params.runId,
2414
649
  ...params.channelId ? { channelId: params.channelId } : {},
650
+ ...params.requester ? { requester: params.requester } : {},
2415
651
  allowedEvents: params.events,
2416
652
  preToolUseLoopDetection: params.loopDetectionPreToolUseRelay,
2417
653
  ttlMs: resolveCodexNativeHookRelayTtlMs({
@@ -2616,12 +852,12 @@ var CodexNativeToolLifecycleProjector = class {
2616
852
  this.preToolUseFailureByItem.set(failure.toolCallId, record);
2617
853
  }
2618
854
  recordRawWebSearchResult(item) {
2619
- if (readString$3(item, "type") !== "web_search_call") return;
2620
- const toolCallId = readString$3(item, "id");
855
+ if (readString$2(item, "type") !== "web_search_call") return;
856
+ const toolCallId = readString$2(item, "id");
2621
857
  if (!toolCallId || this.completedItemIds.has(toolCallId)) return;
2622
858
  const toolName = "web_search";
2623
859
  this.recordStarted(toolCallId, toolName, "unknown");
2624
- const rawStatus = readString$3(item, "status");
860
+ const rawStatus = readString$2(item, "status");
2625
861
  if (rawStatus === "in_progress" || rawStatus === "running") return;
2626
862
  const status = rawStatus === "completed" ? "completed" : rawStatus === "cancelled" ? "cancelled" : rawStatus === "failed" || rawStatus === "error" || rawStatus === "incomplete" ? "failed" : "unknown";
2627
863
  this.recordTerminal(toolCallId, toolName, status, { sourceTimestampMs: this.webSearchCompletionByItem.get(toolCallId)?.sourceTimestampMs });
@@ -2734,815 +970,6 @@ var CodexNativeToolLifecycleProjector = class {
2734
970
  }
2735
971
  };
2736
972
  //#endregion
2737
- //#region extensions/codex/src/app-server/event-projector-reasoning.ts
2738
- var CodexReasoningProjection = class {
2739
- constructor(params, emitAgentEvent) {
2740
- this.params = params;
2741
- this.emitAgentEvent = emitAgentEvent;
2742
- this.reasoningTextByGroup = /* @__PURE__ */ new Map();
2743
- this.reasoningItemOrder = /* @__PURE__ */ new Map();
2744
- this.planTextByItem = /* @__PURE__ */ new Map();
2745
- this.reasoningStarted = false;
2746
- this.reasoningEnded = false;
2747
- }
2748
- async handleReasoningDelta(method, params) {
2749
- const itemId = readString$3(params, "itemId") ?? "reasoning";
2750
- const delta = readString$3(params, "delta") ?? "";
2751
- if (!delta) return;
2752
- this.reasoningStarted = true;
2753
- if (!this.reasoningItemOrder.has(itemId)) this.reasoningItemOrder.set(itemId, this.reasoningItemOrder.size);
2754
- const groupIndex = method === "item/reasoning/textDelta" ? readNonNegativeInteger(params, "contentIndex") ?? 0 : readNonNegativeInteger(params, "summaryIndex") ?? 0;
2755
- const groupKey = `${method}\0${itemId}\0${groupIndex}`;
2756
- const current = this.reasoningTextByGroup.get(groupKey);
2757
- this.reasoningTextByGroup.set(groupKey, {
2758
- itemId,
2759
- method,
2760
- index: groupIndex,
2761
- text: `${current?.text ?? ""}${delta}`
2762
- });
2763
- await this.params.onReasoningStream?.({
2764
- text: this.reasoningText(),
2765
- isReasoningSnapshot: true
2766
- });
2767
- }
2768
- handlePlanDelta(params) {
2769
- const itemId = readString$3(params, "itemId") ?? "plan";
2770
- const delta = readString$3(params, "delta") ?? "";
2771
- if (!delta) return;
2772
- const text = `${this.planTextByItem.get(itemId) ?? ""}${delta}`;
2773
- this.planTextByItem.set(itemId, text);
2774
- this.emitPlanUpdate({
2775
- explanation: void 0,
2776
- steps: splitPlanText(text).map((step) => ({
2777
- step,
2778
- status: "pending"
2779
- }))
2780
- });
2781
- }
2782
- handleTurnPlanUpdated(params) {
2783
- const explanation = readNullableString(params, "explanation");
2784
- const plan = Array.isArray(params.plan) ? params.plan.flatMap((entry) => {
2785
- if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
2786
- const record = entry;
2787
- const step = readString$3(record, "step");
2788
- if (!step) return [];
2789
- return [{
2790
- step,
2791
- status: normalizePlanStepStatus(readString$3(record, "status"))
2792
- }];
2793
- }) : void 0;
2794
- const planText = [explanation, ...(plan ?? []).map(({ step, status }) => `- [${status}] ${step}`)].filter((part) => Boolean(part)).join("\n");
2795
- if (planText) this.turnPlanText = planText;
2796
- this.emitPlanUpdate({
2797
- explanation,
2798
- steps: plan
2799
- });
2800
- }
2801
- recordItem(item) {
2802
- if (item?.type === "plan" && typeof item.text === "string" && item.text) {
2803
- this.planTextByItem.set(item.id, item.text);
2804
- this.emitPlanUpdate({
2805
- explanation: void 0,
2806
- steps: splitPlanText(item.text).map((step) => ({
2807
- step,
2808
- status: "pending"
2809
- }))
2810
- });
2811
- }
2812
- }
2813
- async maybeEndReasoning() {
2814
- if (!this.reasoningStarted || this.reasoningEnded) return;
2815
- this.reasoningEnded = true;
2816
- await this.params.onReasoningEnd?.();
2817
- }
2818
- reasoningText() {
2819
- return collectReasoningTextValues(this.reasoningTextByGroup, this.reasoningItemOrder).join("\n\n");
2820
- }
2821
- planText() {
2822
- return this.turnPlanText ?? [...this.planTextByItem.values()].filter((text) => text.trim().length > 0).join("\n\n");
2823
- }
2824
- emitPlanUpdate(params) {
2825
- if (!params.explanation && (!params.steps || params.steps.length === 0)) return;
2826
- this.emitAgentEvent({
2827
- stream: "plan",
2828
- data: {
2829
- phase: "update",
2830
- title: "Plan updated",
2831
- source: "codex-app-server",
2832
- ...params.explanation ? { explanation: params.explanation } : {},
2833
- ...params.steps && params.steps.length > 0 ? { steps: params.steps } : {}
2834
- }
2835
- });
2836
- }
2837
- };
2838
- function normalizePlanStepStatus(status) {
2839
- if (status === "inProgress" || status === "in_progress") return "in_progress";
2840
- return status === "completed" ? "completed" : "pending";
2841
- }
2842
- function collectReasoningTextValues(groups, itemOrder) {
2843
- return [...groups.values()].toSorted((left, right) => {
2844
- const itemDelta = (itemOrder.get(left.itemId) ?? Number.MAX_SAFE_INTEGER) - (itemOrder.get(right.itemId) ?? Number.MAX_SAFE_INTEGER);
2845
- if (itemDelta !== 0) return itemDelta;
2846
- const methodDelta = reasoningMethodOrder(left.method) - reasoningMethodOrder(right.method);
2847
- return methodDelta !== 0 ? methodDelta : left.index - right.index;
2848
- }).map((group) => group.text).filter((text) => text.trim().length > 0);
2849
- }
2850
- function reasoningMethodOrder(method) {
2851
- return method === "item/reasoning/summaryTextDelta" ? 0 : 1;
2852
- }
2853
- //#endregion
2854
- //#region extensions/codex/src/app-server/event-projector-usage.ts
2855
- function readTokenCount(record, key) {
2856
- const value = readNonNegativeInteger(record, key);
2857
- return value !== void 0 && Number.isSafeInteger(value) ? value : void 0;
2858
- }
2859
- function readCodexThreadTokenUsage(params) {
2860
- const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
2861
- const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
2862
- return last ? normalizeCodexThreadTokenUsage(last) : void 0;
2863
- }
2864
- function normalizeCodexThreadTokenUsage(record) {
2865
- const inputTokens = readNumber(record, "inputTokens");
2866
- const cacheRead = readNumber(record, "cachedInputTokens");
2867
- const usage = normalizeUsage({
2868
- input: inputTokens !== void 0 && cacheRead !== void 0 ? Math.max(0, inputTokens - cacheRead) : inputTokens,
2869
- output: readNumber(record, "outputTokens"),
2870
- cacheRead,
2871
- total: readNumber(record, "totalTokens")
2872
- });
2873
- return usage ? {
2874
- ...usage,
2875
- contextUsage: { state: "unavailable" }
2876
- } : void 0;
2877
- }
2878
- function normalizeCodexResponseTokenUsage(record) {
2879
- const totalTokens = readTokenCount(record, "totalTokens");
2880
- const inputTokens = readTokenCount(record, "inputTokens");
2881
- const cacheRead = readTokenCount(record, "cachedInputTokens");
2882
- const output = readTokenCount(record, "outputTokens");
2883
- const reasoningOutput = readTokenCount(record, "reasoningOutputTokens");
2884
- const cacheWrite = record.cacheWriteInputTokens === void 0 ? 0 : readTokenCount(record, "cacheWriteInputTokens");
2885
- if (totalTokens === void 0 || inputTokens === void 0 || cacheRead === void 0 || cacheWrite === void 0 || output === void 0 || reasoningOutput === void 0 || cacheRead + cacheWrite > inputTokens || totalTokens !== inputTokens + output) return;
2886
- const usage = normalizeUsage({
2887
- input: inputTokens - cacheRead - cacheWrite,
2888
- output,
2889
- cacheRead,
2890
- cacheWrite,
2891
- total: totalTokens
2892
- });
2893
- if (!usage) return;
2894
- return {
2895
- ...usage,
2896
- contextUsage: {
2897
- state: "available",
2898
- promptTokens: inputTokens,
2899
- totalTokens
2900
- }
2901
- };
2902
- }
2903
- //#endregion
2904
- //#region extensions/codex/src/app-server/usage-limit-error.ts
2905
- /**
2906
- * Enriches Codex usage-limit failures with current rate-limit information and
2907
- * marks blocked auth profiles when Codex exposes a reset time.
2908
- */
2909
- const CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS = 5e3;
2910
- function createCodexUsageLimitPromptError(message) {
2911
- return Object.assign(new Error(message), { status: 429 });
2912
- }
2913
- function isCodexUsageLimitPromptError(error) {
2914
- return error instanceof Error && "status" in error && error.status === 429;
2915
- }
2916
- /** Marks a Codex auth profile blocked until the reset time advertised by rate limits. */
2917
- async function markCodexAuthProfileBlockedFromRateLimits(params) {
2918
- const authProfileId = params.authProfileId?.trim();
2919
- if (!authProfileId || !params.params.authProfileStore) return;
2920
- const blockedUntil = resolveCodexUsageLimitResetAtMs(params.rateLimits);
2921
- if (!blockedUntil) return;
2922
- try {
2923
- await markAuthProfileBlockedUntil({
2924
- store: params.params.authProfileStore,
2925
- profileId: authProfileId,
2926
- blockedUntil,
2927
- source: "codex_rate_limits",
2928
- agentDir: params.params.agentDir,
2929
- runId: params.params.runId,
2930
- modelId: params.params.modelId
2931
- });
2932
- } catch (error) {
2933
- embeddedAgentLog.debug("failed to mark Codex auth profile blocked from app-server limits", {
2934
- authProfileId,
2935
- error: formatErrorMessage(error)
2936
- });
2937
- }
2938
- }
2939
- /** Formats a turn-start usage-limit error, refreshing rate limits when needed. */
2940
- async function formatCodexTurnStartUsageLimitError(params) {
2941
- return refreshCodexUsageLimitError({
2942
- client: params.client,
2943
- source: readCodexTurnStartUsageLimitErrorSource(params.client, params.error, params.errorNotification, params.rateLimitsRevisionBeforeTurnStart),
2944
- timeoutMs: params.timeoutMs,
2945
- signal: params.signal
2946
- });
2947
- }
2948
- /** Refreshes a generic prompt usage-limit message into a reset-aware message. */
2949
- async function refreshCodexUsageLimitPromptError(params) {
2950
- if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(params.message)) return;
2951
- return refreshCodexUsageLimitError({
2952
- client: params.client,
2953
- source: {
2954
- message: params.message,
2955
- codexErrorInfo: "usageLimitExceeded",
2956
- rateLimits: readRecentCodexRateLimits(params.client)
2957
- },
2958
- timeoutMs: params.timeoutMs,
2959
- signal: params.signal
2960
- });
2961
- }
2962
- async function refreshCodexUsageLimitError(params) {
2963
- const initialMessage = formatCodexUsageLimitErrorMessage(params.source);
2964
- if (!shouldRefreshCodexRateLimitsForUsageLimitMessage(initialMessage)) return initialMessage ? {
2965
- message: initialMessage,
2966
- ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2967
- } : void 0;
2968
- const rateLimits = await readCodexRateLimitsFromAppServerForUsageLimitError({
2969
- client: params.client,
2970
- timeoutMs: params.timeoutMs,
2971
- signal: params.signal
2972
- });
2973
- if (!rateLimits) return initialMessage ? {
2974
- message: initialMessage,
2975
- ...params.source.rateLimitsTrustedForProfile ? { rateLimitsForProfile: params.source.rateLimits } : {}
2976
- } : void 0;
2977
- const message = formatCodexUsageLimitErrorMessage({
2978
- message: params.source.message,
2979
- codexErrorInfo: params.source.codexErrorInfo,
2980
- rateLimits,
2981
- rateLimitsAuthoritative: true
2982
- }) ?? initialMessage;
2983
- return message ? {
2984
- message,
2985
- rateLimitsForProfile: rateLimits
2986
- } : void 0;
2987
- }
2988
- async function readCodexRateLimitsFromAppServerForUsageLimitError(params) {
2989
- if (params.signal?.aborted) return;
2990
- try {
2991
- const rateLimits = await params.client.request(CODEX_CONTROL_METHODS.rateLimits, void 0, {
2992
- timeoutMs: resolveCodexUsageLimitRateLimitRefreshTimeoutMs(params.timeoutMs),
2993
- signal: params.signal
2994
- });
2995
- rememberCodexRateLimitsRead(params.client, rateLimits);
2996
- return rateLimits;
2997
- } catch (error) {
2998
- embeddedAgentLog.debug("codex app-server rate-limit refresh failed after usage-limit error", { error: formatErrorMessage(error) });
2999
- return;
3000
- }
3001
- }
3002
- function resolveCodexUsageLimitRateLimitRefreshTimeoutMs(timeoutMs) {
3003
- if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS;
3004
- return Math.max(100, Math.min(timeoutMs, CODEX_USAGE_LIMIT_RATE_LIMIT_REFRESH_TIMEOUT_MS));
3005
- }
3006
- function readCodexTurnStartUsageLimitErrorSource(client, error, errorNotification, rateLimitsRevisionBeforeTurnStart) {
3007
- const notificationError = readCodexErrorNotification(errorNotification);
3008
- const errorPayload = readCodexErrorPayload(error);
3009
- const rateLimits = errorPayload.rateLimits ?? readRecentCodexRateLimits(client);
3010
- const cacheUpdatedDuringTurnStart = rateLimitsRevisionBeforeTurnStart !== void 0 && readCodexRateLimitsRevision(client) > rateLimitsRevisionBeforeTurnStart;
3011
- return {
3012
- message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
3013
- codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
3014
- rateLimits,
3015
- rateLimitsTrustedForProfile: errorPayload.rateLimits !== void 0 || cacheUpdatedDuringTurnStart
3016
- };
3017
- }
3018
- function readCodexErrorNotification(notification) {
3019
- if (notification?.method !== "error" || !isJsonObject(notification.params)) return;
3020
- const error = notification.params.error;
3021
- return isJsonObject(error) ? {
3022
- message: readString$2(error, "message"),
3023
- codexErrorInfo: error.codexErrorInfo
3024
- } : void 0;
3025
- }
3026
- function readCodexErrorPayload(error) {
3027
- const message = error instanceof Error ? error.message : void 0;
3028
- if (!error || typeof error !== "object" || !("data" in error)) return { message };
3029
- const data = error.data;
3030
- if (!isJsonObject(data)) return { message };
3031
- const nestedError = isJsonObject(data.error) ? data.error : data;
3032
- const rateLimits = nestedError.rateLimits ?? data.rateLimits;
3033
- return {
3034
- message: readString$2(nestedError, "message") ?? message,
3035
- codexErrorInfo: nestedError.codexErrorInfo,
3036
- rateLimits
3037
- };
3038
- }
3039
- function readString$2(record, key) {
3040
- const value = record[key];
3041
- return typeof value === "string" ? value : void 0;
3042
- }
3043
- //#endregion
3044
- //#region extensions/codex/src/app-server/event-projector.ts
3045
- var CodexAppServerEventProjector = class {
3046
- constructor(params, threadId, turnId, options = {}) {
3047
- this.params = params;
3048
- this.threadId = threadId;
3049
- this.turnId = turnId;
3050
- this.options = options;
3051
- this.activeItemIds = /* @__PURE__ */ new Set();
3052
- this.completedItemIds = /* @__PURE__ */ new Set();
3053
- this.activeCompactionItemIds = /* @__PURE__ */ new Set();
3054
- this.terminalPresentationClearedItemIds = /* @__PURE__ */ new Set();
3055
- this.nativeToolOutcomeOrdinals = /* @__PURE__ */ new Map();
3056
- this.promptErrorSource = null;
3057
- this.synthesizedMissingToolResultError = null;
3058
- this.aborted = false;
3059
- this.completedCompactionCount = 0;
3060
- this.diagnostics = new CodexProjectionDiagnostics(threadId, turnId);
3061
- this.nativeToolLifecycleProjector = new CodexNativeToolLifecycleProjector(params, threadId, turnId, { runAbortSignal: options.runAbortSignal });
3062
- this.generatedMediaProjection = new CodexGeneratedMediaProjection(params.config);
3063
- this.toolProgressProjection = new CodexToolProgressProjection(params);
3064
- this.toolTranscriptProjection = new CodexToolTranscriptProjection(params, threadId, turnId, this.toolProgressProjection, {
3065
- nativePostToolUseRelayEnabled: options.nativePostToolUseRelayEnabled,
3066
- trajectoryRecorder: options.trajectoryRecorder
3067
- });
3068
- this.eventProjection = new CodexEventProjection(threadId, turnId, (event) => this.emitAgentEvent(event), this.toolProgressProjection, this.toolTranscriptProjection, options.onNativeToolResultRecorded);
3069
- this.assistantProjection = new CodexAssistantProjection(params, (event) => this.emitAgentEvent(event), (text) => this.toolProgressProjection.matchesEcho(text));
3070
- this.reasoningProjection = new CodexReasoningProjection(params, (event) => this.emitAgentEvent(event));
3071
- }
3072
- getCompletedTurnStatus() {
3073
- return this.completedTurn?.status;
3074
- }
3075
- hasCompletedTerminalAssistantText() {
3076
- return this.assistantProjection.hasCompletedTerminalAssistantText(this.completedItemIds);
3077
- }
3078
- getLatestTerminalAssistantCandidate() {
3079
- return this.assistantProjection.getLatestTerminalAssistantCandidate();
3080
- }
3081
- hasLatestTerminalAssistantCandidateText() {
3082
- return this.assistantProjection.hasLatestTerminalAssistantCandidateText();
3083
- }
3084
- canReleaseLatestTerminalAssistantAfterToolHandoff() {
3085
- return this.assistantProjection.canReleaseLatestTerminalAssistantAfterToolHandoff();
3086
- }
3087
- /** Restores a completed final item after only the enclosing turn timeout fired. */
3088
- recoverCompletedTerminalAssistantAfterTurnWatchTimeout() {
3089
- if (!this.aborted || this.promptError !== "codex app-server attempt timed out" || !this.hasCompletedTerminalAssistantText()) return false;
3090
- this.aborted = false;
3091
- this.promptError = void 0;
3092
- this.promptErrorSource = null;
3093
- return true;
3094
- }
3095
- /** Resolves the shared model-order position for a native tool item. */
3096
- recordNativeToolOutcome(item) {
3097
- if (!item || this.nativeToolOutcomeOrdinals.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
3098
- const ordinal = this.params.allocateToolOutcomeOrdinal?.(item.id);
3099
- if (ordinal !== void 0) this.nativeToolOutcomeOrdinals.set(item.id, ordinal);
3100
- }
3101
- recordNativeToolApprovalFailure(toolCallId, disposition) {
3102
- this.nativeToolLifecycleProjector.recordApprovalFailureDisposition(toolCallId, disposition);
3103
- }
3104
- recordNativeToolPreToolUseFailure(failure) {
3105
- this.nativeToolLifecycleProjector.recordPreToolUseFailure(failure);
3106
- }
3107
- async handleNotification(notification) {
3108
- const params = isJsonObject(notification.params) ? notification.params : void 0;
3109
- if (!params) return;
3110
- if (isHookNotificationMethod(notification.method)) {
3111
- if (!this.isHookNotificationForCurrentThread(params)) return;
3112
- } else if (notification.method === "guardianWarning") {
3113
- if (readCodexNotificationThreadId(params) !== this.threadId) return;
3114
- } else if (!this.isNotificationForTurn(params)) return;
3115
- this.nativeToolLifecycleProjector.handleNotification(notification);
3116
- switch (notification.method) {
3117
- case "item/agentMessage/delta":
3118
- await this.assistantProjection.handleAssistantDelta(params);
3119
- break;
3120
- case "item/reasoning/summaryTextDelta":
3121
- case "item/reasoning/textDelta":
3122
- await this.reasoningProjection.handleReasoningDelta(notification.method, params);
3123
- break;
3124
- case "item/plan/delta":
3125
- this.reasoningProjection.handlePlanDelta(params);
3126
- break;
3127
- case "turn/plan/updated":
3128
- this.reasoningProjection.handleTurnPlanUpdated(params);
3129
- break;
3130
- case "item/started":
3131
- await this.handleItemStarted(params);
3132
- break;
3133
- case "item/completed":
3134
- await this.handleItemCompleted(params);
3135
- break;
3136
- case "item/commandExecution/outputDelta":
3137
- this.toolProgressProjection.handleOutputDelta(params, "bash");
3138
- break;
3139
- case "item/autoApprovalReview/started":
3140
- case "item/autoApprovalReview/completed":
3141
- this.eventProjection.handleGuardianReview(notification.method, params);
3142
- break;
3143
- case "guardianWarning":
3144
- this.eventProjection.handleGuardianWarning(params);
3145
- break;
3146
- case "hook/started":
3147
- case "hook/completed":
3148
- this.eventProjection.handleHook(notification.method, params);
3149
- break;
3150
- case "thread/tokenUsage/updated":
3151
- this.tokenUsage = readCodexThreadTokenUsage(params) ?? this.tokenUsage;
3152
- break;
3153
- case "turn/completed":
3154
- await this.handleTurnCompleted(params);
3155
- break;
3156
- case "rawResponse/completed":
3157
- this.handleRawResponseCompleted(params);
3158
- break;
3159
- case "rawResponseItem/completed":
3160
- await this.handleRawResponseItemCompleted(params);
3161
- break;
3162
- case "error":
3163
- this.responseUsage = void 0;
3164
- if (params.willRetry === true) break;
3165
- this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
3166
- this.promptErrorSource = "prompt";
3167
- break;
3168
- case "thread/compacted":
3169
- case "turn/started":
3170
- case "turn/diff/updated":
3171
- case "item/reasoning/summaryPartAdded":
3172
- case "item/commandExecution/terminalInteraction":
3173
- case "item/fileChange/outputDelta":
3174
- case "item/fileChange/patchUpdated":
3175
- case "item/mcpToolCall/progress":
3176
- case "model/rerouted":
3177
- case "model/verification":
3178
- case "turn/moderationMetadata":
3179
- case "model/safetyBuffering/updated": break;
3180
- default:
3181
- this.diagnostics.warnUnknownEvent(notification, params);
3182
- break;
3183
- }
3184
- }
3185
- buildResult(toolTelemetry, options) {
3186
- this.nativeToolLifecycleProjector.finalizeActive();
3187
- const assistantTexts = this.assistantProjection.collectAssistantTexts();
3188
- const reasoningText = this.reasoningProjection.reasoningText();
3189
- const planText = this.reasoningProjection.planText();
3190
- const projectedUsage = this.aborted ? this.tokenUsage : this.responseUsage ?? this.tokenUsage;
3191
- const hasAssistantItemText = this.assistantProjection.hasAssistantItemTextForSynthesis();
3192
- const legacyFailClosed = !this.completedTurn || this.completedTurn.status !== "completed" || hasAssistantItemText;
3193
- const hasDeliverableAssistantOnCompletedTurn = this.completedTurn?.status === "completed" && assistantTexts.some((text) => text.trim().length > 0);
3194
- const synthesizedMissingToolResultError = this.toolTranscriptProjection.synthesizeMissingToolResults({
3195
- synthesize: legacyFailClosed,
3196
- recordPromptError: legacyFailClosed && !hasDeliverableAssistantOnCompletedTurn && !this.aborted
3197
- });
3198
- if (synthesizedMissingToolResultError) {
3199
- this.synthesizedMissingToolResultError = synthesizedMissingToolResultError;
3200
- this.promptErrorSource = this.promptErrorSource ?? "prompt";
3201
- }
3202
- const assistantMessageOptions = {
3203
- tokenUsage: projectedUsage,
3204
- aborted: this.aborted,
3205
- promptError: this.promptError
3206
- };
3207
- const lastAssistant = assistantTexts.length ? this.assistantProjection.createAssistantMessage(assistantTexts.join("\n\n"), assistantMessageOptions) : void 0;
3208
- const currentAttemptAssistant = this.assistantProjection.createCurrentAttemptAssistantMessage(assistantMessageOptions);
3209
- const turnId = this.turnId;
3210
- const messagesSnapshot = promptSnapshot(this.params, turnId, this.options.upstreamUserText);
3211
- if (reasoningText) messagesSnapshot.push(attachCodexMirrorIdentity(this.assistantProjection.createAssistantMirrorMessage("Codex reasoning", reasoningText), `${turnId}:reasoning`));
3212
- if (planText) messagesSnapshot.push(attachCodexMirrorIdentity(this.assistantProjection.createAssistantMirrorMessage("Codex plan", planText), `${turnId}:plan`));
3213
- messagesSnapshot.push(...this.toolTranscriptProjection.transcriptMessages);
3214
- if (lastAssistant) messagesSnapshot.push(attachCodexMirrorIdentity(lastAssistant, `${turnId}:assistant`));
3215
- const turnFailed = this.completedTurn?.status === "failed";
3216
- const promptError = this.promptError ?? this.synthesizedMissingToolResultError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
3217
- const agentHarnessResultClassification = classifyAgentHarnessTerminalOutcome({
3218
- assistantTexts,
3219
- reasoningText,
3220
- planText,
3221
- promptError,
3222
- turnCompleted: Boolean(this.completedTurn)
3223
- });
3224
- const toolMetas = this.toolProgressProjection.toolMetas;
3225
- const hadPotentialSideEffects = toolTelemetry.didSendViaMessagingTool || (toolTelemetry.successfulCronAdds ?? 0) > 0 || this.generatedMediaProjection.hasGeneratedMedia() || this.toolProgressProjection.hasPotentialSideEffects;
3226
- return {
3227
- aborted: this.aborted,
3228
- externalAbort: false,
3229
- timedOut: false,
3230
- idleTimedOut: false,
3231
- timedOutDuringCompaction: false,
3232
- timedOutDuringToolExecution: false,
3233
- promptError,
3234
- promptErrorSource: promptError ? this.promptErrorSource || "prompt" : null,
3235
- sessionIdUsed: this.params.sessionId,
3236
- ...agentHarnessResultClassification ? { agentHarnessResultClassification } : {},
3237
- bootstrapPromptWarningSignaturesSeen: this.params.bootstrapPromptWarningSignaturesSeen,
3238
- bootstrapPromptWarningSignature: this.params.bootstrapPromptWarningSignature,
3239
- messagesSnapshot,
3240
- assistantTexts,
3241
- toolMetas,
3242
- lastAssistant,
3243
- currentAttemptAssistant,
3244
- ...this.toolProgressProjection.lastToolError ? { lastToolError: this.toolProgressProjection.lastToolError } : {},
3245
- didSendViaMessagingTool: toolTelemetry.didSendViaMessagingTool,
3246
- didDeliverSourceReplyViaMessageTool: toolTelemetry.didDeliverSourceReplyViaMessageTool === true,
3247
- messagingToolSentTexts: toolTelemetry.messagingToolSentTexts,
3248
- messagingToolSentMediaUrls: toolTelemetry.messagingToolSentMediaUrls,
3249
- messagingToolSentTargets: toolTelemetry.messagingToolSentTargets,
3250
- messagingToolSourceReplyPayloads: toolTelemetry.messagingToolSourceReplyPayloads ?? [],
3251
- heartbeatToolResponse: toolTelemetry.heartbeatToolResponse,
3252
- toolMediaUrls: this.generatedMediaProjection.buildToolMediaUrls(toolTelemetry),
3253
- toolAudioAsVoice: toolTelemetry.toolAudioAsVoice,
3254
- successfulCronAdds: toolTelemetry.successfulCronAdds,
3255
- cloudCodeAssistFormatError: false,
3256
- attemptUsage: projectedUsage,
3257
- ...this.completedCompactionCount > 0 ? { compactionCount: this.completedCompactionCount } : {},
3258
- replayMetadata: {
3259
- hadPotentialSideEffects,
3260
- replaySafe: !hadPotentialSideEffects
3261
- },
3262
- itemLifecycle: {
3263
- startedCount: this.activeItemIds.size + this.completedItemIds.size,
3264
- completedCount: this.completedItemIds.size,
3265
- activeCount: this.activeItemIds.size
3266
- },
3267
- yieldDetected: options?.yieldDetected || false,
3268
- didSendDeterministicApprovalPrompt: this.eventProjection.guardianReviewCount > 0 ? false : void 0
3269
- };
3270
- }
3271
- recordDynamicToolCall(params) {
3272
- this.toolTranscriptProjection.recordDynamicToolCall(params);
3273
- }
3274
- recordDynamicToolResult(params) {
3275
- this.toolProgressProjection.recordDynamicToolResult(params);
3276
- this.toolTranscriptProjection.recordDynamicToolResult(params);
3277
- }
3278
- markTimedOut() {
3279
- this.aborted = true;
3280
- this.promptError = "codex app-server attempt timed out";
3281
- this.promptErrorSource = "prompt";
3282
- }
3283
- markAborted() {
3284
- this.aborted = true;
3285
- this.responseUsage = void 0;
3286
- }
3287
- isCompacting() {
3288
- return this.activeCompactionItemIds.size > 0;
3289
- }
3290
- async handleItemStarted(params) {
3291
- const item = readItem(params.item);
3292
- const itemId = item?.id ?? readString$3(params, "itemId");
3293
- this.assistantProjection.recordItemStarted(item, itemId);
3294
- if (itemId) this.activeItemIds.add(itemId);
3295
- this.recordNativeToolOutcome(item);
3296
- if (item?.type === "contextCompaction" && itemId) {
3297
- this.activeCompactionItemIds.add(itemId);
3298
- await runAgentHarnessBeforeCompactionHook({
3299
- sessionFile: this.params.sessionFile,
3300
- messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
3301
- ctx: {
3302
- runId: this.params.runId,
3303
- agentId: this.params.agentId,
3304
- sessionKey: this.params.sessionKey,
3305
- sessionId: this.params.sessionId,
3306
- workspaceDir: this.params.workspaceDir,
3307
- messageProvider: this.params.messageProvider ?? void 0,
3308
- trigger: this.params.trigger,
3309
- channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
3310
- }
3311
- });
3312
- this.emitAgentEvent({
3313
- stream: "compaction",
3314
- data: {
3315
- phase: "start",
3316
- backend: "codex-app-server",
3317
- threadId: this.threadId,
3318
- turnId: this.turnId,
3319
- itemId
3320
- }
3321
- });
3322
- }
3323
- this.toolProgressProjection.recordToolMeta(item);
3324
- this.eventProjection.emitStandardItemEvent({
3325
- phase: "start",
3326
- item
3327
- });
3328
- await this.eventProjection.emitNormalizedToolItemEvent({
3329
- phase: "start",
3330
- item
3331
- });
3332
- this.toolTranscriptProjection.recordNativeToolCall(item);
3333
- this.toolProgressProjection.emitToolResultSummary(item);
3334
- this.emitAgentEvent({
3335
- stream: "codex_app_server.item",
3336
- data: {
3337
- phase: "started",
3338
- itemId,
3339
- type: item?.type
3340
- }
3341
- });
3342
- }
3343
- async handleItemCompleted(params) {
3344
- const item = readItem(params.item);
3345
- this.diagnostics.warnUnknownItemStatus(item);
3346
- this.recordNativeToolOutcome(item);
3347
- this.clearTerminalPresentationForNativeItem(item);
3348
- const itemId = item?.id ?? readString$3(params, "itemId");
3349
- if (itemId) {
3350
- this.activeItemIds.delete(itemId);
3351
- this.completedItemIds.add(itemId);
3352
- }
3353
- this.assistantProjection.recordItemCompleted(item, itemId, this.activeItemIds);
3354
- this.reasoningProjection.recordItem(item);
3355
- this.generatedMediaProjection.recordNative(item);
3356
- if (item?.type === "contextCompaction" && itemId) {
3357
- this.activeCompactionItemIds.delete(itemId);
3358
- this.completedCompactionCount += 1;
3359
- this.options.onContextCompacted?.();
3360
- await runAgentHarnessAfterCompactionHook({
3361
- sessionFile: this.params.sessionFile,
3362
- messages: await this.toolTranscriptProjection.readMirroredSessionMessages(),
3363
- compactedCount: -1,
3364
- ctx: {
3365
- runId: this.params.runId,
3366
- agentId: this.params.agentId,
3367
- sessionKey: this.params.sessionKey,
3368
- sessionId: this.params.sessionId,
3369
- workspaceDir: this.params.workspaceDir,
3370
- messageProvider: this.params.messageProvider ?? void 0,
3371
- trigger: this.params.trigger,
3372
- channelId: this.params.messageChannel ?? this.params.messageProvider ?? void 0
3373
- }
3374
- });
3375
- this.emitAgentEvent({
3376
- stream: "compaction",
3377
- data: {
3378
- phase: "end",
3379
- backend: "codex-app-server",
3380
- completed: true,
3381
- threadId: this.threadId,
3382
- turnId: this.turnId,
3383
- itemId
3384
- }
3385
- });
3386
- }
3387
- this.toolProgressProjection.recordToolMeta(item);
3388
- this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
3389
- this.eventProjection.emitStandardItemEvent({
3390
- phase: "end",
3391
- item
3392
- });
3393
- await this.eventProjection.emitNormalizedToolItemEvent({
3394
- phase: "result",
3395
- item
3396
- });
3397
- this.toolTranscriptProjection.recordNativeToolCall(item);
3398
- this.toolTranscriptProjection.recordNativeToolResult(item);
3399
- this.toolProgressProjection.emitToolResultSummary(item);
3400
- this.toolProgressProjection.emitToolResultOutput(item);
3401
- this.emitAgentEvent({
3402
- stream: "codex_app_server.item",
3403
- data: {
3404
- phase: "completed",
3405
- itemId,
3406
- type: item?.type
3407
- }
3408
- });
3409
- }
3410
- handleRawResponseCompleted(params) {
3411
- const usage = isJsonObject(params.usage) ? params.usage : void 0;
3412
- this.responseUsage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
3413
- }
3414
- async handleTurnCompleted(params) {
3415
- const turn = readCodexTurn(params.turn);
3416
- if (!turn || turn.id !== this.turnId) return;
3417
- this.completedTurn = turn;
3418
- if (turn.status !== "completed") this.responseUsage = void 0;
3419
- if (turn.status === "failed") {
3420
- const usageLimitMessage = formatCodexUsageLimitErrorMessage({
3421
- message: turn.error?.message,
3422
- codexErrorInfo: turn.error?.codexErrorInfo,
3423
- rateLimits: this.options.readRecentRateLimits?.()
3424
- });
3425
- this.promptError = usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : turn.error?.message ?? "codex app-server turn failed";
3426
- this.promptErrorSource = "prompt";
3427
- }
3428
- const turnItems = turn.items ?? [];
3429
- for (let index = turnItems.length - 1; index >= 0; index -= 1) {
3430
- const item = turnItems[index];
3431
- if (!item || !this.isCurrentTurnSnapshotItem(item)) continue;
3432
- if (item?.type === "dynamicToolCall") break;
3433
- if (shouldClearTerminalPresentationForNativeItem(item)) {
3434
- this.clearTerminalPresentationForNativeItem(item);
3435
- break;
3436
- }
3437
- }
3438
- for (const item of turnItems) {
3439
- this.diagnostics.warnUnknownItemStatus(item);
3440
- this.assistantProjection.recordSnapshotItem(item);
3441
- this.reasoningProjection.recordItem(item);
3442
- this.generatedMediaProjection.recordNative(item);
3443
- this.toolProgressProjection.recordToolMeta(item);
3444
- this.toolProgressProjection.rememberCommandAggregateOutputEcho(item);
3445
- await this.emitSnapshotOnlyNativeToolProgress(item);
3446
- this.toolTranscriptProjection.recordNativeToolCall(item);
3447
- this.toolTranscriptProjection.recordNativeToolResult(item);
3448
- this.toolTranscriptProjection.emitAfterToolCallObservation(item);
3449
- this.toolProgressProjection.emitToolResultSummary(item);
3450
- this.toolProgressProjection.emitToolResultOutput(item);
3451
- }
3452
- this.assistantProjection.finalizeAnswerCandidate(turn);
3453
- this.activeCompactionItemIds.clear();
3454
- await this.reasoningProjection.maybeEndReasoning();
3455
- }
3456
- async emitSnapshotOnlyNativeToolProgress(item) {
3457
- if (!shouldSynthesizeToolProgressForItem(item) || !this.isCurrentTurnSnapshotItem(item) || this.completedItemIds.has(item.id) || itemStatus(item) === "running") return;
3458
- if (!this.activeItemIds.has(item.id)) {
3459
- this.eventProjection.emitStandardItemEvent({
3460
- phase: "start",
3461
- item
3462
- });
3463
- await this.eventProjection.emitNormalizedToolItemEvent({
3464
- phase: "start",
3465
- item
3466
- });
3467
- }
3468
- this.activeItemIds.delete(item.id);
3469
- this.eventProjection.emitStandardItemEvent({
3470
- phase: "end",
3471
- item
3472
- });
3473
- await this.eventProjection.emitNormalizedToolItemEvent({
3474
- phase: "result",
3475
- item
3476
- });
3477
- this.completedItemIds.add(item.id);
3478
- }
3479
- isCurrentTurnSnapshotItem(item) {
3480
- const itemTurnId = readItemString(item, "turnId");
3481
- return itemTurnId === void 0 || itemTurnId === this.turnId;
3482
- }
3483
- async handleRawResponseItemCompleted(params) {
3484
- const item = isJsonObject(params.item) ? params.item : void 0;
3485
- if (!item) return;
3486
- this.assistantProjection.handleRawResponseItemCompleted(item, this.activeItemIds);
3487
- await this.generatedMediaProjection.recordRaw(item);
3488
- }
3489
- clearTerminalPresentationForNativeItem(item) {
3490
- if (!item || this.terminalPresentationClearedItemIds.has(item.id) || !shouldClearTerminalPresentationForNativeItem(item)) return;
3491
- const toolCallOrdinal = this.nativeToolOutcomeOrdinals.get(item.id);
3492
- this.terminalPresentationClearedItemIds.add(item.id);
3493
- this.params.onToolOutcome?.({
3494
- toolName: itemName(item) ?? item.type,
3495
- argsHash: "",
3496
- resultHash: "",
3497
- ...toolCallOrdinal !== void 0 ? { toolCallOrdinal } : {},
3498
- terminalPresentation: void 0,
3499
- presentationOnly: true
3500
- });
3501
- }
3502
- formatCodexErrorMessage(params) {
3503
- const error = isJsonObject(params.error) ? params.error : void 0;
3504
- const usageLimitMessage = formatCodexUsageLimitErrorMessage({
3505
- message: error ? readString$3(error, "message") : void 0,
3506
- codexErrorInfo: error?.codexErrorInfo,
3507
- rateLimits: this.options.readRecentRateLimits?.()
3508
- });
3509
- return usageLimitMessage ? createCodexUsageLimitPromptError(usageLimitMessage) : readCodexErrorNotificationMessage(params);
3510
- }
3511
- emitAgentEvent(event) {
3512
- try {
3513
- emitAgentEvent({
3514
- runId: this.params.runId,
3515
- stream: event.stream,
3516
- data: event.data,
3517
- ...this.params.sessionKey ? { sessionKey: this.params.sessionKey } : {}
3518
- });
3519
- } catch (error) {
3520
- embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
3521
- }
3522
- try {
3523
- const maybePromise = this.params.onAgentEvent?.(event);
3524
- Promise.resolve(maybePromise).catch((error) => {
3525
- embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
3526
- });
3527
- } catch (error) {
3528
- embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
3529
- }
3530
- }
3531
- isNotificationForTurn(params) {
3532
- const threadId = readCodexNotificationThreadId(params);
3533
- const turnId = readCodexNotificationTurnId(params);
3534
- return threadId === this.threadId && turnId === this.turnId;
3535
- }
3536
- isHookNotificationForCurrentThread(params) {
3537
- const threadId = readString$3(params, "threadId");
3538
- const turnId = params.turnId;
3539
- return threadId === this.threadId && (turnId === this.turnId || turnId === null);
3540
- }
3541
- };
3542
- function isHookNotificationMethod(method) {
3543
- return method === "hook/started" || method === "hook/completed";
3544
- }
3545
- //#endregion
3546
973
  //#region extensions/codex/src/app-server/dynamic-tool-build-state.ts
3547
974
  /** Mutable dependency seam shared by dynamic-tool construction and its behavioral tests. */
3548
975
  const dynamicToolBuildState = {};
@@ -3785,6 +1212,8 @@ async function buildDynamicTools(input) {
3785
1212
  senderUsername: params.senderUsername,
3786
1213
  senderE164: params.senderE164,
3787
1214
  senderIsOwner: params.senderIsOwner,
1215
+ inputProvenance: params.inputProvenance,
1216
+ trustedInternalHandoff: params.trustedInternalHandoff,
3788
1217
  allowGatewaySubagentBinding: params.allowGatewaySubagentBinding || isForcedPrivateQaCodexRuntime(),
3789
1218
  ...sessionKeys,
3790
1219
  sessionId: params.sessionId,
@@ -3877,7 +1306,9 @@ async function buildDynamicTools(input) {
3877
1306
  senderId: params.senderId,
3878
1307
  senderName: params.senderName,
3879
1308
  senderUsername: params.senderUsername,
3880
- senderE164: params.senderE164
1309
+ senderE164: params.senderE164,
1310
+ inputProvenance: params.inputProvenance,
1311
+ trustedInternalHandoff: params.trustedInternalHandoff
3881
1312
  });
3882
1313
  const transientWebSearchRestriction = !webSearchPolicy.allowed && webSearchPolicy.persistentAllowed || isCodexMemoryFlushRun(params);
3883
1314
  const persistentCodexWebSearchSurface = params.config?.tools?.web?.search?.enabled !== false && !(input.pluginConfig.codexDynamicToolsExclude ?? []).some((name) => normalizeCodexDynamicToolName(name) === "web_search");
@@ -3943,6 +1374,7 @@ function includeForcedCodexDynamicToolAllow(toolsAllow, params) {
3943
1374
  /** Decides whether Codex native code mode can own shell/file tools for this turn. */
3944
1375
  function shouldEnableCodexAppServerNativeToolSurface(params, sandbox, options = {}) {
3945
1376
  if (isCodexMemoryFlushRun(params)) return false;
1377
+ if (params.disableTools) return false;
3946
1378
  const toolsAllow = includeForcedCodexDynamicToolAllow(params.toolsAllow, params);
3947
1379
  if (toolsAllow === void 0) return canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
3948
1380
  return hasWildcardCodexToolsAllow(toolsAllow) && canCodexAppServerNativeToolSurfaceHonorSandbox(sandbox, options);
@@ -4303,8 +1735,11 @@ function approvalRequestExplicitlyUnavailable(result) {
4303
1735
  }
4304
1736
  /** Waits for the gateway's final approval decision, respecting turn aborts. */
4305
1737
  async function waitForPluginApprovalDecision(params) {
4306
- const waitPromise = callGatewayTool("plugin.approval.waitDecision", { timeoutMs: resolveCodexGatewayTimeoutWithGraceMs(DEFAULT_CODEX_APPROVAL_TIMEOUT_MS) }, { id: params.approvalId });
4307
- const bindDecision = (result) => result?.id === params.approvalId ? result.decision : void 0;
1738
+ const waitPromise = callGatewayTool("plugin.approval.waitDecision", { timeoutMs: resolveCodexGatewayTimeoutWithGraceMs(DEFAULT_CODEX_APPROVAL_TIMEOUT_MS) }, { id: params.approvalId }).catch((error) => {
1739
+ if (isApprovalNotFoundError(error)) return null;
1740
+ throw error;
1741
+ });
1742
+ const bindDecision = (result) => result === null ? null : result?.id === params.approvalId ? result.decision : void 0;
4308
1743
  if (!params.signal) return bindDecision(await waitPromise);
4309
1744
  let onAbort;
4310
1745
  const abortPromise = new Promise((_, reject) => {
@@ -6691,4 +4126,4 @@ function isCronAddAction(args) {
6691
4126
  return typeof action === "string" && action.trim().toLowerCase() === "add";
6692
4127
  }
6693
4128
  //#endregion
6694
- export { resolveCodexToolProgressDetailMode as $, CODEX_NATIVE_HOOK_RELAY_EVENTS as A, hasPendingDynamicToolTerminalDiagnostic as B, CodexAppServerEventProjector as C, markCodexAuthProfileBlockedFromRateLimits as D, isCodexUsageLimitPromptError as E, emitCodexNativePreToolUseFailureDiagnostic as F, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as G, isMatchingDynamicToolTerminalDiagnostic as H, resolveCodexNativeHookRelayEvents as I, toCodexDynamicToolProtocolResponse as J, shouldReleaseTurnAfterTerminalDynamicTool as K, resolveCodexNativeHookRelayTtlMs as L, buildCodexNativeHookRelayConfig as M, buildCodexNativeHookRelayDisabledConfig as N, refreshCodexUsageLimitPromptError as O, createCodexNativeHookRelay as P, inferCodexDynamicToolMeta as Q, scheduleCodexNativeHookRelayUnregister as R, filterToolsForVisionInputs as S, formatCodexTurnStartUsageLimitError as T, resolveDynamicToolCallTimeoutMs as U, isDynamicToolTerminalDiagnosticEvent as V, resolveTerminalDynamicToolBatchAction as W, readCodexMirroredSessionHistoryMessages as X, resolveCodexToolAbortTerminalReason as Y, shouldEmitTranscriptToolProgress as Z, resolveCodexMessageToolProvider as _, emitDynamicToolStartedDiagnostic as a, shouldRequireCodexSandboxExecServerEnvironment as b, resolveCodexProviderWebSearchSupportForClient as c, createCodexDynamicToolBuildStageTracker as d, sanitizeCodexToolArguments as et, disableCodexPluginThreadConfig as f, resolveCodexExternalSandboxPolicyForOpenClawSandbox as g, resolveCodexAppServerHookChannelId as h, emitDynamicToolErrorDiagnostic as i, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as j, CodexNativeToolLifecycleProjector as k, settleCodexSourceReplyFinality as l, resolveCodexAppServerExecutionCwd as m, handleCodexAppServerApprovalRequest as n, redactCodexEventKind as nt, emitDynamicToolTerminalDiagnostic as o, formatCodexDynamicToolBuildStageSummary as p, toCodexDynamicToolProgressResponse as q, handleCodexAppServerElicitationRequest as r, resolveCodexLocalRuntimeAttribution as rt, resolveCodexProviderWebSearchSupport as s, createCodexDynamicToolBridge as t, sanitizeCodexToolResponse as tt, buildDynamicTools as u, resolveCodexSandboxEnvironmentSelection as v, createCodexUsageLimitPromptError as w, shouldWarnCodexDynamicToolBuildStageSummary as x, shouldEnableCodexAppServerNativeToolSurface as y, handleDynamicToolCallWithTimeout as z };
4129
+ export { shouldSynthesizeToolProgressForItem as $, resolveCodexNativeHookRelayEvents as A, shouldReleaseTurnAfterTerminalDynamicTool as B, CodexNativeToolLifecycleProjector as C, buildCodexNativeHookRelayDisabledConfig as D, buildCodexNativeHookRelayConfig as E, isDynamicToolTerminalDiagnosticEvent as F, isNonSuccessItemStatus as G, toCodexDynamicToolProtocolResponse as H, isMatchingDynamicToolTerminalDiagnostic as I, itemName as J, isSideEffectingNativeToolItem as K, resolveDynamicToolCallTimeoutMs as L, scheduleCodexNativeHookRelayUnregister as M, handleDynamicToolCallWithTimeout as N, createCodexNativeHookRelay as O, hasPendingDynamicToolTerminalDiagnostic as P, shouldRecordNativeToolTranscript as Q, resolveTerminalDynamicToolBatchAction as R, filterToolsForVisionInputs as S, CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS as T, resolveCodexToolAbortTerminalReason as U, toCodexDynamicToolProgressResponse as V, isMutatingNativeToolItem as W, itemTitle as X, itemStatus as Y, shouldClearTerminalPresentationForNativeItem as Z, resolveCodexMessageToolProvider as _, emitDynamicToolStartedDiagnostic as a, shouldRequireCodexSandboxExecServerEnvironment as b, resolveCodexProviderWebSearchSupportForClient as c, createCodexDynamicToolBuildStageTracker as d, unknownItemStatus as et, disableCodexPluginThreadConfig as f, resolveCodexExternalSandboxPolicyForOpenClawSandbox as g, resolveCodexAppServerHookChannelId as h, emitDynamicToolErrorDiagnostic as i, resolveCodexNativeHookRelayTtlMs as j, emitCodexNativePreToolUseFailureDiagnostic as k, settleCodexSourceReplyFinality as l, resolveCodexAppServerExecutionCwd as m, handleCodexAppServerApprovalRequest as n, emitDynamicToolTerminalDiagnostic as o, formatCodexDynamicToolBuildStageSummary as p, itemKind as q, handleCodexAppServerElicitationRequest as r, resolveCodexProviderWebSearchSupport as s, createCodexDynamicToolBridge as t, buildDynamicTools as u, resolveCodexSandboxEnvironmentSelection as v, CODEX_NATIVE_HOOK_RELAY_EVENTS as w, shouldWarnCodexDynamicToolBuildStageSummary as x, shouldEnableCodexAppServerNativeToolSurface as y, shouldBlockTerminalReleaseForNonTerminalDynamicToolResult as z };