@openclaw/codex 2026.5.4-beta.1 → 2026.5.4-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-chGfNrq5.js → client-BGbqC7jk.js} +2 -2
- package/dist/{client-factory-ClSvDfKC.js → client-factory--cll1Fba.js} +1 -1
- package/dist/command-formatters-PiJcdUbu.js +337 -0
- package/dist/{command-handlers-DsknA9lT.js → command-handlers-DiH-D13x.js} +154 -163
- package/dist/{compact-CCKeE8zJ.js → compact-DcR5aTxd.js} +2 -2
- package/dist/{config-CkkoMeqF.js → config-ByrA30No.js} +0 -2
- package/dist/{conversation-binding-LXwwffvV.js → conversation-binding-CtHkMJfG.js} +128 -61
- package/dist/doctor-contract-api.js +19 -0
- package/dist/harness.js +3 -3
- package/dist/index.js +8 -3
- package/dist/media-understanding-provider.js +4 -4
- package/dist/{models-B-1qT9nX.js → models-CkowdYbm.js} +2 -2
- package/dist/{protocol-validators-Cpopom3_.js → protocol-validators-Dky2yV4W.js} +2354 -2258
- package/dist/provider.js +2 -2
- package/dist/{computer-use-DtCrnbLb.js → rate-limit-cache-t6ebYmfS.js} +27 -4
- package/dist/{run-attempt-DdEBxgoj.js → run-attempt-CFL1BFBl.js} +345 -120
- package/dist/{shared-client-B7LbV3PF.js → shared-client-Dfk3Enm-.js} +2 -2
- package/dist/test-api.js +2 -2
- package/dist/{thread-lifecycle-C2MSeIjn.js → thread-lifecycle-CzllX4PU.js} +56 -21
- package/package.json +6 -6
- package/dist/capabilities-BmhO5h8O.js +0 -22
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { i as resolveCodexAppServerRuntimeOptions, r as readCodexPluginConfig } from "./config-
|
|
2
|
-
import { i as readCodexDynamicToolCallParams, r as assertCodexTurnStartResponse, s as readCodexTurn } from "./protocol-validators-
|
|
1
|
+
import { i as resolveCodexAppServerRuntimeOptions, r as readCodexPluginConfig } from "./config-ByrA30No.js";
|
|
2
|
+
import { i as readCodexDynamicToolCallParams, r as assertCodexTurnStartResponse, s as readCodexTurn } from "./protocol-validators-Dky2yV4W.js";
|
|
3
3
|
import { t as isJsonObject } from "./protocol-C9UWI98H.js";
|
|
4
|
-
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-
|
|
5
|
-
import {
|
|
4
|
+
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-BGbqC7jk.js";
|
|
5
|
+
import { r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-PiJcdUbu.js";
|
|
6
|
+
import { a as refreshCodexAppServerAuthTokens, o as resolveCodexAppServerAuthProfileId, s as resolveCodexAppServerAuthProfileIdForAgent, t as clearSharedCodexAppServerClientIfCurrent } from "./shared-client-Dfk3Enm-.js";
|
|
6
7
|
import { i as readCodexAppServerBinding } from "./session-binding-DuJYTJQy.js";
|
|
7
|
-
import { a as
|
|
8
|
-
import { n as defaultCodexAppServerClientFactory, t as createCodexAppServerClientFactoryTestHooks } from "./client-factory
|
|
9
|
-
import {
|
|
8
|
+
import { a as buildTurnStartParams, c as createCodexDynamicToolBridge, l as applyCodexDynamicToolProfile, n as buildDeveloperInstructions, o as codexDynamicToolsFingerprint, s as startOrResumeThread, t as areCodexDynamicToolFingerprintsCompatible } from "./thread-lifecycle-CzllX4PU.js";
|
|
9
|
+
import { n as defaultCodexAppServerClientFactory, t as createCodexAppServerClientFactoryTestHooks } from "./client-factory--cll1Fba.js";
|
|
10
|
+
import { n as rememberCodexRateLimits, r as ensureCodexComputerUse, t as readRecentCodexRateLimits } from "./rate-limit-cache-t6ebYmfS.js";
|
|
10
11
|
import { createHash } from "node:crypto";
|
|
11
12
|
import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, callGatewayTool, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatApprovalDisplayPath, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveModelAuthMode, resolveOpenClawAgentDir, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockAcquireTimeoutMs, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
12
13
|
import fs from "node:fs/promises";
|
|
@@ -80,6 +81,7 @@ function truncateForGateway(value, maxLength) {
|
|
|
80
81
|
const PERMISSION_DESCRIPTION_MAX_LENGTH = 700;
|
|
81
82
|
const PERMISSION_SAMPLE_LIMIT = 2;
|
|
82
83
|
const PERMISSION_VALUE_MAX_LENGTH = 48;
|
|
84
|
+
const COMMAND_PREVIEW_WITH_DETAILS_MAX_LENGTH = 80;
|
|
83
85
|
const APPROVAL_PREVIEW_SCAN_MAX_LENGTH = 4096;
|
|
84
86
|
const APPROVAL_PREVIEW_OMITTED = "[preview truncated or unsafe content omitted]";
|
|
85
87
|
const ANSI_OSC_SEQUENCE_RE$1 = new RegExp(String.raw`(?:\u001b]|\u009d)[^\u001b\u009c\u0007]*(?:\u0007|\u001b\\|\u009c)`, "g");
|
|
@@ -153,7 +155,7 @@ async function handleCodexAppServerApprovalRequest(params) {
|
|
|
153
155
|
title: context.title,
|
|
154
156
|
...context.eventDetails,
|
|
155
157
|
...approvalEventScope(params.method, cancelled ? "cancelled" : "denied"),
|
|
156
|
-
message: cancelled ? "Codex app-server approval cancelled because the run stopped." : `Codex app-server approval route failed: ${formatErrorMessage$1(error)}`
|
|
158
|
+
message: cancelled ? "Codex app-server approval cancelled because the run stopped." : `Codex app-server approval route failed: ${formatCodexDisplayText(formatErrorMessage$1(error))}`
|
|
157
159
|
});
|
|
158
160
|
return buildApprovalResponse(params.method, context.requestParams, cancelled ? "cancelled" : "denied");
|
|
159
161
|
}
|
|
@@ -181,7 +183,8 @@ function matchesCurrentTurn$1(requestParams, threadId, turnId) {
|
|
|
181
183
|
}
|
|
182
184
|
function buildApprovalContext(params) {
|
|
183
185
|
const itemId = readString$4(params.requestParams, "itemId") ?? readString$4(params.requestParams, "callId") ?? readString$4(params.requestParams, "approvalId");
|
|
184
|
-
const
|
|
186
|
+
const commandDetailLines = params.method === "item/commandExecution/requestApproval" ? describeCommandApprovalDetails(params.requestParams) : [];
|
|
187
|
+
const commandPreview = sanitizeApprovalPreview(readDisplayCommandPreview(params.requestParams), commandDetailLines.length > 0 ? COMMAND_PREVIEW_WITH_DETAILS_MAX_LENGTH : 180);
|
|
185
188
|
const reasonPreview = sanitizeApprovalPreview(readStringPreview(params.requestParams, "reason"), 180);
|
|
186
189
|
const command = commandPreview.text;
|
|
187
190
|
const reason = reasonPreview.text;
|
|
@@ -192,7 +195,11 @@ function buildApprovalContext(params) {
|
|
|
192
195
|
return {
|
|
193
196
|
kind,
|
|
194
197
|
title,
|
|
195
|
-
description: permissionLines.length > 0 ? joinDescriptionLinesWithinLimit(permissionLines, PERMISSION_DESCRIPTION_MAX_LENGTH) : [
|
|
198
|
+
description: permissionLines.length > 0 ? joinDescriptionLinesWithinLimit(permissionLines, PERMISSION_DESCRIPTION_MAX_LENGTH) : [
|
|
199
|
+
subject,
|
|
200
|
+
...commandDetailLines,
|
|
201
|
+
params.paramsForRun.sessionKey && `Session: ${params.paramsForRun.sessionKey}`
|
|
202
|
+
].filter(Boolean).join("\n"),
|
|
196
203
|
severity: kind === "exec" ? "warning" : "info",
|
|
197
204
|
toolName: kind === "exec" ? "codex_command_approval" : params.method === "item/permissions/requestApproval" ? "codex_permission_approval" : "codex_file_approval",
|
|
198
205
|
itemId,
|
|
@@ -235,46 +242,101 @@ function unsupportedApprovalResponse() {
|
|
|
235
242
|
};
|
|
236
243
|
}
|
|
237
244
|
function describeRequestedPermissions(requestParams) {
|
|
238
|
-
|
|
245
|
+
return describePermissionProfile(requestedPermissions(requestParams), "Permissions");
|
|
246
|
+
}
|
|
247
|
+
function describeCommandApprovalDetails(requestParams) {
|
|
248
|
+
const lines = [];
|
|
249
|
+
const additionalPermissions = isJsonObject(requestParams?.additionalPermissions) ? requestParams.additionalPermissions : void 0;
|
|
250
|
+
if (additionalPermissions) lines.push(...describePermissionProfile(additionalPermissions, "Additional permissions"));
|
|
251
|
+
const execpolicySummary = summarizeStringArray(requestParams?.proposedExecpolicyAmendment, "Proposed exec policy", sanitizePermissionScalar);
|
|
252
|
+
if (execpolicySummary) lines.push(execpolicySummary);
|
|
253
|
+
const networkAmendmentSummary = summarizeNetworkPolicyAmendments(requestParams?.proposedNetworkPolicyAmendments);
|
|
254
|
+
if (networkAmendmentSummary) lines.push(networkAmendmentSummary);
|
|
255
|
+
return lines;
|
|
256
|
+
}
|
|
257
|
+
function describePermissionProfile(permissions, label) {
|
|
239
258
|
const lines = [];
|
|
240
259
|
const kinds = [];
|
|
241
260
|
const risks = /* @__PURE__ */ new Set();
|
|
242
261
|
if (isJsonObject(permissions.network)) kinds.push("network");
|
|
243
262
|
if (isJsonObject(permissions.fileSystem)) kinds.push("fileSystem");
|
|
244
|
-
if (kinds.length > 0) lines.push(
|
|
263
|
+
if (kinds.length > 0) lines.push(`${label}: ${kinds.join(", ")}`);
|
|
245
264
|
let networkSummary;
|
|
246
|
-
if (isJsonObject(permissions.network))
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
265
|
+
if (isJsonObject(permissions.network)) {
|
|
266
|
+
const summaries = [summarizeNetworkEnabledPermission(permissions.network, risks), summarizePermissionRecord(permissions.network, risks, [{
|
|
267
|
+
key: "allowHosts",
|
|
268
|
+
label: "allowHosts",
|
|
269
|
+
sanitize: sanitizePermissionHostValue,
|
|
270
|
+
risksFor: permissionHostRisks
|
|
271
|
+
}])].filter((summary) => Boolean(summary));
|
|
272
|
+
networkSummary = summaries.length > 0 ? summaries.join("; ") : void 0;
|
|
273
|
+
}
|
|
252
274
|
let fileSystemSummary;
|
|
253
|
-
if (isJsonObject(permissions.fileSystem))
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
if (isJsonObject(permissions.fileSystem)) {
|
|
276
|
+
const summaries = [summarizePermissionRecord(permissions.fileSystem, risks, [
|
|
277
|
+
{
|
|
278
|
+
key: "read",
|
|
279
|
+
label: "read",
|
|
280
|
+
sanitize: sanitizePermissionPathValue,
|
|
281
|
+
risksFor: permissionPathRisks
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
key: "write",
|
|
285
|
+
label: "write",
|
|
286
|
+
sanitize: sanitizePermissionPathValue,
|
|
287
|
+
risksFor: permissionPathRisks
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
key: "roots",
|
|
291
|
+
label: "roots",
|
|
292
|
+
sanitize: sanitizePermissionPathValue,
|
|
293
|
+
risksFor: permissionPathRisks
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
key: "readPaths",
|
|
297
|
+
label: "readPaths",
|
|
298
|
+
sanitize: sanitizePermissionPathValue,
|
|
299
|
+
risksFor: permissionPathRisks
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
key: "writePaths",
|
|
303
|
+
label: "writePaths",
|
|
304
|
+
sanitize: sanitizePermissionPathValue,
|
|
305
|
+
risksFor: permissionPathRisks
|
|
306
|
+
}
|
|
307
|
+
]), summarizeFileSystemEntries(permissions.fileSystem, risks)].filter((summary) => Boolean(summary));
|
|
308
|
+
fileSystemSummary = summaries.length > 0 ? summaries.join("; ") : void 0;
|
|
309
|
+
}
|
|
273
310
|
if (risks.size > 0) lines.push(`High-risk targets: ${[...risks].join(", ")}`);
|
|
274
311
|
if (networkSummary) lines.push(`Network ${networkSummary}`);
|
|
275
312
|
if (fileSystemSummary) lines.push(`File system ${fileSystemSummary}`);
|
|
276
313
|
return lines;
|
|
277
314
|
}
|
|
315
|
+
function summarizeNetworkEnabledPermission(permission, risks) {
|
|
316
|
+
const enabled = permission.enabled;
|
|
317
|
+
if (typeof enabled !== "boolean") return;
|
|
318
|
+
if (enabled) risks.add("network access");
|
|
319
|
+
return `enabled: ${enabled}`;
|
|
320
|
+
}
|
|
321
|
+
function summarizeFileSystemEntries(permission, risks) {
|
|
322
|
+
const entries = permission.entries;
|
|
323
|
+
if (!Array.isArray(entries)) return;
|
|
324
|
+
const samples = [];
|
|
325
|
+
let count = 0;
|
|
326
|
+
for (const entry of entries) {
|
|
327
|
+
const item = isJsonObject(entry) ? entry : void 0;
|
|
328
|
+
const path = typeof item?.path === "string" ? item.path.trim() : "";
|
|
329
|
+
const access = typeof item?.access === "string" ? item.access.trim() : "";
|
|
330
|
+
if (!path || !access) continue;
|
|
331
|
+
count += 1;
|
|
332
|
+
if (access !== "none") for (const risk of permissionPathRisks(path)) risks.add(risk);
|
|
333
|
+
if (samples.length < PERMISSION_SAMPLE_LIMIT) samples.push(`${sanitizePermissionScalar(access)} ${sanitizePermissionPathValue(path)}`);
|
|
334
|
+
}
|
|
335
|
+
if (count === 0) return;
|
|
336
|
+
const remaining = count - samples.length;
|
|
337
|
+
const remainderSuffix = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
338
|
+
return `entries: ${samples.join(", ")}${remainderSuffix}`;
|
|
339
|
+
}
|
|
278
340
|
function summarizePermissionRecord(permission, risks, descriptors) {
|
|
279
341
|
const details = [];
|
|
280
342
|
for (const descriptor of descriptors) {
|
|
@@ -293,6 +355,32 @@ function summarizePermissionArray(record, descriptor, risks) {
|
|
|
293
355
|
const remainderSuffix = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
294
356
|
return `${descriptor.label}: ${sampleValues.join(", ")}${remainderSuffix}`;
|
|
295
357
|
}
|
|
358
|
+
function summarizeStringArray(value, label, sanitize) {
|
|
359
|
+
if (!Array.isArray(value)) return;
|
|
360
|
+
const values = value.filter((entry) => typeof entry === "string").map((entry) => sanitize(entry)).filter(Boolean);
|
|
361
|
+
if (values.length === 0) return;
|
|
362
|
+
const samples = values.slice(0, PERMISSION_SAMPLE_LIMIT);
|
|
363
|
+
const remaining = values.length - samples.length;
|
|
364
|
+
const remainderSuffix = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
365
|
+
return `${label}: ${samples.join(", ")}${remainderSuffix}`;
|
|
366
|
+
}
|
|
367
|
+
function summarizeNetworkPolicyAmendments(value) {
|
|
368
|
+
if (!Array.isArray(value)) return;
|
|
369
|
+
const samples = [];
|
|
370
|
+
let count = 0;
|
|
371
|
+
for (const entry of value) {
|
|
372
|
+
const amendment = isJsonObject(entry) ? entry : void 0;
|
|
373
|
+
const host = typeof amendment?.host === "string" ? amendment.host : "";
|
|
374
|
+
const action = typeof amendment?.action === "string" ? amendment.action : "";
|
|
375
|
+
if (!host || !action) continue;
|
|
376
|
+
count += 1;
|
|
377
|
+
if (samples.length < PERMISSION_SAMPLE_LIMIT) samples.push(`${sanitizePermissionScalar(action)} ${sanitizePermissionHostValue(host)}`);
|
|
378
|
+
}
|
|
379
|
+
if (count === 0) return;
|
|
380
|
+
const remaining = count - samples.length;
|
|
381
|
+
const remainderSuffix = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
382
|
+
return `Proposed network policy: ${samples.join(", ")}${remainderSuffix}`;
|
|
383
|
+
}
|
|
296
384
|
function readStringArray(record, key) {
|
|
297
385
|
const value = record[key];
|
|
298
386
|
return Array.isArray(value) ? value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean) : [];
|
|
@@ -433,7 +521,7 @@ function sanitizeApprovalPreview(source, maxLength) {
|
|
|
433
521
|
const sanitized = sanitizeVisibleScalar(source.value.replace(DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE$1, ""));
|
|
434
522
|
if (!sanitized) return { omitted: true };
|
|
435
523
|
return {
|
|
436
|
-
text: truncate(sanitized, maxLength),
|
|
524
|
+
text: formatCodexDisplayText(truncate(sanitized, maxLength)),
|
|
437
525
|
omitted: source.clipped
|
|
438
526
|
};
|
|
439
527
|
}
|
|
@@ -679,7 +767,8 @@ function sanitizeDisplayText(value) {
|
|
|
679
767
|
const scanned = value.slice(0, DISPLAY_TEXT_SCAN_MAX_LENGTH);
|
|
680
768
|
const clipped = value.length > DISPLAY_TEXT_SCAN_MAX_LENGTH;
|
|
681
769
|
const sanitized = scanned.replace(ANSI_OSC_SEQUENCE_RE, "").replace(ANSI_CONTROL_SEQUENCE_RE, "").replace(DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE, "").replace(INVISIBLE_FORMATTING_CONTROL_RE, " ").replace(CONTROL_CHARACTER_RE, " ").replace(/\s+/g, " ").trim();
|
|
682
|
-
|
|
770
|
+
const escaped = sanitized ? formatCodexDisplayText(sanitized) : "";
|
|
771
|
+
return clipped && escaped ? `${escaped}...` : escaped;
|
|
683
772
|
}
|
|
684
773
|
function truncateDisplayText(value, maxLength) {
|
|
685
774
|
return value.length <= maxLength ? value : `${value.slice(0, Math.max(0, maxLength - 3))}...`;
|
|
@@ -872,6 +961,110 @@ async function readCodexMirroredSessionHistoryMessages(sessionFile) {
|
|
|
872
961
|
}
|
|
873
962
|
}
|
|
874
963
|
//#endregion
|
|
964
|
+
//#region extensions/codex/src/app-server/transcript-mirror.ts
|
|
965
|
+
const MIRROR_IDENTITY_META_KEY = "mirrorIdentity";
|
|
966
|
+
/**
|
|
967
|
+
* Tag a message with a stable logical identity for mirror dedupe. Callers
|
|
968
|
+
* should use a value that is invariant for the same logical message across
|
|
969
|
+
* re-emits (e.g. `${turnId}:prompt`, `${turnId}:assistant`) but distinct
|
|
970
|
+
* for genuinely-distinct messages (different turns, different kinds). When
|
|
971
|
+
* present this identity replaces the role/content fingerprint in the
|
|
972
|
+
* idempotency key, so the dedupe survives caller-scope rotation without
|
|
973
|
+
* collapsing distinct same-content turns.
|
|
974
|
+
*/
|
|
975
|
+
function attachCodexMirrorIdentity(message, identity) {
|
|
976
|
+
const record = message;
|
|
977
|
+
const existing = record.__openclaw;
|
|
978
|
+
const baseMeta = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
|
|
979
|
+
return {
|
|
980
|
+
...record,
|
|
981
|
+
__openclaw: {
|
|
982
|
+
...baseMeta,
|
|
983
|
+
[MIRROR_IDENTITY_META_KEY]: identity
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
function readMirrorIdentity(message) {
|
|
988
|
+
const meta = message.__openclaw;
|
|
989
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return;
|
|
990
|
+
const id = meta[MIRROR_IDENTITY_META_KEY];
|
|
991
|
+
return typeof id === "string" && id.length > 0 ? id : void 0;
|
|
992
|
+
}
|
|
993
|
+
function fingerprintMirrorMessageContent(message) {
|
|
994
|
+
const payload = JSON.stringify({
|
|
995
|
+
role: message.role,
|
|
996
|
+
content: message.content
|
|
997
|
+
});
|
|
998
|
+
return createHash("sha256").update(payload).digest("hex").slice(0, 16);
|
|
999
|
+
}
|
|
1000
|
+
function buildMirrorDedupeIdentity(message) {
|
|
1001
|
+
const explicit = readMirrorIdentity(message);
|
|
1002
|
+
if (explicit) return explicit;
|
|
1003
|
+
return `${message.role}:${fingerprintMirrorMessageContent(message)}`;
|
|
1004
|
+
}
|
|
1005
|
+
async function mirrorCodexAppServerTranscript(params) {
|
|
1006
|
+
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant");
|
|
1007
|
+
if (messages.length === 0) return;
|
|
1008
|
+
const lock = await acquireSessionWriteLock({
|
|
1009
|
+
sessionFile: params.sessionFile,
|
|
1010
|
+
timeoutMs: resolveSessionWriteLockAcquireTimeoutMs(params.config)
|
|
1011
|
+
});
|
|
1012
|
+
try {
|
|
1013
|
+
const existingIdempotencyKeys = await readTranscriptIdempotencyKeys(params.sessionFile);
|
|
1014
|
+
for (const message of messages) {
|
|
1015
|
+
const dedupeIdentity = buildMirrorDedupeIdentity(message);
|
|
1016
|
+
const idempotencyKey = params.idempotencyScope ? `${params.idempotencyScope}:${dedupeIdentity}` : void 0;
|
|
1017
|
+
if (idempotencyKey && existingIdempotencyKeys.has(idempotencyKey)) continue;
|
|
1018
|
+
const nextMessage = runAgentHarnessBeforeMessageWriteHook({
|
|
1019
|
+
message: {
|
|
1020
|
+
...message,
|
|
1021
|
+
...idempotencyKey ? { idempotencyKey } : {}
|
|
1022
|
+
},
|
|
1023
|
+
agentId: params.agentId,
|
|
1024
|
+
sessionKey: params.sessionKey
|
|
1025
|
+
});
|
|
1026
|
+
if (!nextMessage) continue;
|
|
1027
|
+
const messageToAppend = idempotencyKey ? {
|
|
1028
|
+
...nextMessage,
|
|
1029
|
+
idempotencyKey
|
|
1030
|
+
} : nextMessage;
|
|
1031
|
+
await appendSessionTranscriptMessage({
|
|
1032
|
+
transcriptPath: params.sessionFile,
|
|
1033
|
+
message: messageToAppend,
|
|
1034
|
+
config: params.config
|
|
1035
|
+
});
|
|
1036
|
+
if (idempotencyKey) existingIdempotencyKeys.add(idempotencyKey);
|
|
1037
|
+
}
|
|
1038
|
+
} finally {
|
|
1039
|
+
await lock.release();
|
|
1040
|
+
}
|
|
1041
|
+
if (params.sessionKey) emitSessionTranscriptUpdate({
|
|
1042
|
+
sessionFile: params.sessionFile,
|
|
1043
|
+
sessionKey: params.sessionKey
|
|
1044
|
+
});
|
|
1045
|
+
else emitSessionTranscriptUpdate(params.sessionFile);
|
|
1046
|
+
}
|
|
1047
|
+
async function readTranscriptIdempotencyKeys(sessionFile) {
|
|
1048
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1049
|
+
let raw;
|
|
1050
|
+
try {
|
|
1051
|
+
raw = await fs.readFile(sessionFile, "utf8");
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
if (error.code !== "ENOENT") throw error;
|
|
1054
|
+
return keys;
|
|
1055
|
+
}
|
|
1056
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
1057
|
+
if (!line.trim()) continue;
|
|
1058
|
+
try {
|
|
1059
|
+
const parsed = JSON.parse(line);
|
|
1060
|
+
if (typeof parsed.message?.idempotencyKey === "string") keys.add(parsed.message.idempotencyKey);
|
|
1061
|
+
} catch {
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
return keys;
|
|
1066
|
+
}
|
|
1067
|
+
//#endregion
|
|
875
1068
|
//#region extensions/codex/src/app-server/event-projector.ts
|
|
876
1069
|
const ZERO_USAGE = {
|
|
877
1070
|
input: 0,
|
|
@@ -930,6 +1123,11 @@ var CodexAppServerEventProjector = class {
|
|
|
930
1123
|
async handleNotification(notification) {
|
|
931
1124
|
const params = isJsonObject(notification.params) ? notification.params : void 0;
|
|
932
1125
|
if (!params) return;
|
|
1126
|
+
if (notification.method === "account/rateLimits/updated") {
|
|
1127
|
+
this.latestRateLimits = params;
|
|
1128
|
+
rememberCodexRateLimits(params);
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
933
1131
|
if (isHookNotificationMethod(notification.method)) {
|
|
934
1132
|
if (!this.isHookNotificationForCurrentThread(params)) return;
|
|
935
1133
|
} else if (!this.isNotificationForTurn(params)) return;
|
|
@@ -978,7 +1176,7 @@ var CodexAppServerEventProjector = class {
|
|
|
978
1176
|
break;
|
|
979
1177
|
case "error":
|
|
980
1178
|
if (readBooleanAlias(params, ["willRetry", "will_retry"]) === true) break;
|
|
981
|
-
this.promptError =
|
|
1179
|
+
this.promptError = this.formatCodexErrorMessage(params) ?? "codex app-server error";
|
|
982
1180
|
this.promptErrorSource = "prompt";
|
|
983
1181
|
break;
|
|
984
1182
|
default: break;
|
|
@@ -989,14 +1187,15 @@ var CodexAppServerEventProjector = class {
|
|
|
989
1187
|
const reasoningText = collectTextValues(this.reasoningTextByItem).join("\n\n");
|
|
990
1188
|
const planText = collectTextValues(this.planTextByItem).join("\n\n");
|
|
991
1189
|
const lastAssistant = assistantTexts.length > 0 ? this.createAssistantMessage(assistantTexts.join("\n\n")) : void 0;
|
|
992
|
-
const
|
|
1190
|
+
const turnId = this.turnId;
|
|
1191
|
+
const messagesSnapshot = [attachCodexMirrorIdentity({
|
|
993
1192
|
role: "user",
|
|
994
1193
|
content: this.params.prompt,
|
|
995
1194
|
timestamp: Date.now()
|
|
996
|
-
}];
|
|
997
|
-
if (reasoningText) messagesSnapshot.push(this.createAssistantMirrorMessage("Codex reasoning", reasoningText));
|
|
998
|
-
if (planText) messagesSnapshot.push(this.createAssistantMirrorMessage("Codex plan", planText));
|
|
999
|
-
if (lastAssistant) messagesSnapshot.push(lastAssistant);
|
|
1195
|
+
}, `${turnId}:prompt`)];
|
|
1196
|
+
if (reasoningText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex reasoning", reasoningText), `${turnId}:reasoning`));
|
|
1197
|
+
if (planText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex plan", planText), `${turnId}:plan`));
|
|
1198
|
+
if (lastAssistant) messagesSnapshot.push(attachCodexMirrorIdentity(lastAssistant, `${turnId}:assistant`));
|
|
1000
1199
|
const turnFailed = this.completedTurn?.status === "failed";
|
|
1001
1200
|
const turnInterrupted = this.completedTurn?.status === "interrupted";
|
|
1002
1201
|
const promptError = this.promptError ?? (turnFailed ? this.completedTurn?.error?.message ?? "codex app-server turn failed" : null);
|
|
@@ -1267,7 +1466,11 @@ var CodexAppServerEventProjector = class {
|
|
|
1267
1466
|
this.completedTurn = turn;
|
|
1268
1467
|
if (turn.status === "interrupted") this.aborted = true;
|
|
1269
1468
|
if (turn.status === "failed") {
|
|
1270
|
-
this.promptError =
|
|
1469
|
+
this.promptError = formatCodexUsageLimitErrorMessage({
|
|
1470
|
+
message: turn.error?.message,
|
|
1471
|
+
codexErrorInfo: turn.error?.codexErrorInfo,
|
|
1472
|
+
rateLimits: this.latestRateLimits ?? readRecentCodexRateLimits()
|
|
1473
|
+
}) ?? turn.error?.message ?? "codex app-server turn failed";
|
|
1271
1474
|
this.promptErrorSource = "prompt";
|
|
1272
1475
|
}
|
|
1273
1476
|
for (const item of turn.items ?? []) {
|
|
@@ -1420,6 +1623,14 @@ var CodexAppServerEventProjector = class {
|
|
|
1420
1623
|
...meta ? { meta } : {}
|
|
1421
1624
|
});
|
|
1422
1625
|
}
|
|
1626
|
+
formatCodexErrorMessage(params) {
|
|
1627
|
+
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
1628
|
+
return formatCodexUsageLimitErrorMessage({
|
|
1629
|
+
message: error ? readString$2(error, "message") : void 0,
|
|
1630
|
+
codexErrorInfo: error?.codexErrorInfo,
|
|
1631
|
+
rateLimits: this.latestRateLimits ?? readRecentCodexRateLimits()
|
|
1632
|
+
}) ?? readCodexErrorNotificationMessage(params);
|
|
1633
|
+
}
|
|
1423
1634
|
emitAgentEvent(event) {
|
|
1424
1635
|
try {
|
|
1425
1636
|
emitAgentEvent({
|
|
@@ -2019,69 +2230,6 @@ function normalizeCodexTrajectoryError(value) {
|
|
|
2019
2230
|
}
|
|
2020
2231
|
}
|
|
2021
2232
|
//#endregion
|
|
2022
|
-
//#region extensions/codex/src/app-server/transcript-mirror.ts
|
|
2023
|
-
async function mirrorCodexAppServerTranscript(params) {
|
|
2024
|
-
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant");
|
|
2025
|
-
if (messages.length === 0) return;
|
|
2026
|
-
const lock = await acquireSessionWriteLock({
|
|
2027
|
-
sessionFile: params.sessionFile,
|
|
2028
|
-
timeoutMs: resolveSessionWriteLockAcquireTimeoutMs(params.config)
|
|
2029
|
-
});
|
|
2030
|
-
try {
|
|
2031
|
-
const existingIdempotencyKeys = await readTranscriptIdempotencyKeys(params.sessionFile);
|
|
2032
|
-
for (const [index, message] of messages.entries()) {
|
|
2033
|
-
const idempotencyKey = params.idempotencyScope ? `${params.idempotencyScope}:${message.role}:${index}` : void 0;
|
|
2034
|
-
if (idempotencyKey && existingIdempotencyKeys.has(idempotencyKey)) continue;
|
|
2035
|
-
const nextMessage = runAgentHarnessBeforeMessageWriteHook({
|
|
2036
|
-
message: {
|
|
2037
|
-
...message,
|
|
2038
|
-
...idempotencyKey ? { idempotencyKey } : {}
|
|
2039
|
-
},
|
|
2040
|
-
agentId: params.agentId,
|
|
2041
|
-
sessionKey: params.sessionKey
|
|
2042
|
-
});
|
|
2043
|
-
if (!nextMessage) continue;
|
|
2044
|
-
const messageToAppend = idempotencyKey ? {
|
|
2045
|
-
...nextMessage,
|
|
2046
|
-
idempotencyKey
|
|
2047
|
-
} : nextMessage;
|
|
2048
|
-
await appendSessionTranscriptMessage({
|
|
2049
|
-
transcriptPath: params.sessionFile,
|
|
2050
|
-
message: messageToAppend,
|
|
2051
|
-
config: params.config
|
|
2052
|
-
});
|
|
2053
|
-
if (idempotencyKey) existingIdempotencyKeys.add(idempotencyKey);
|
|
2054
|
-
}
|
|
2055
|
-
} finally {
|
|
2056
|
-
await lock.release();
|
|
2057
|
-
}
|
|
2058
|
-
if (params.sessionKey) emitSessionTranscriptUpdate({
|
|
2059
|
-
sessionFile: params.sessionFile,
|
|
2060
|
-
sessionKey: params.sessionKey
|
|
2061
|
-
});
|
|
2062
|
-
else emitSessionTranscriptUpdate(params.sessionFile);
|
|
2063
|
-
}
|
|
2064
|
-
async function readTranscriptIdempotencyKeys(sessionFile) {
|
|
2065
|
-
const keys = /* @__PURE__ */ new Set();
|
|
2066
|
-
let raw;
|
|
2067
|
-
try {
|
|
2068
|
-
raw = await fs.readFile(sessionFile, "utf8");
|
|
2069
|
-
} catch (error) {
|
|
2070
|
-
if (error.code !== "ENOENT") throw error;
|
|
2071
|
-
return keys;
|
|
2072
|
-
}
|
|
2073
|
-
for (const line of raw.split(/\r?\n/)) {
|
|
2074
|
-
if (!line.trim()) continue;
|
|
2075
|
-
try {
|
|
2076
|
-
const parsed = JSON.parse(line);
|
|
2077
|
-
if (typeof parsed.message?.idempotencyKey === "string") keys.add(parsed.message.idempotencyKey);
|
|
2078
|
-
} catch {
|
|
2079
|
-
continue;
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
|
-
return keys;
|
|
2083
|
-
}
|
|
2084
|
-
//#endregion
|
|
2085
2233
|
//#region extensions/codex/src/app-server/user-input-bridge.ts
|
|
2086
2234
|
function createCodexUserInputBridge(params) {
|
|
2087
2235
|
let pending;
|
|
@@ -2097,6 +2245,7 @@ function createCodexUserInputBridge(params) {
|
|
|
2097
2245
|
const requestParams = readUserInputParams(request.params);
|
|
2098
2246
|
if (!requestParams) return;
|
|
2099
2247
|
if (requestParams.threadId !== params.threadId || requestParams.turnId !== params.turnId) return;
|
|
2248
|
+
if (requestParams.questions.length === 0) return emptyUserInputResponse();
|
|
2100
2249
|
resolvePending(emptyUserInputResponse());
|
|
2101
2250
|
return new Promise((resolve) => {
|
|
2102
2251
|
const abortListener = () => resolvePending(emptyUserInputResponse());
|
|
@@ -2191,11 +2340,11 @@ async function deliverUserInputPrompt(params, questions) {
|
|
|
2191
2340
|
function formatUserInputPrompt(questions) {
|
|
2192
2341
|
const lines = ["Codex needs input:"];
|
|
2193
2342
|
questions.forEach((question, index) => {
|
|
2194
|
-
if (questions.length > 1) lines.push("", `${index + 1}. ${question.header}`, question.question);
|
|
2195
|
-
else lines.push("", question.header, question.question);
|
|
2343
|
+
if (questions.length > 1) lines.push("", `${index + 1}. ${formatCodexDisplayText(question.header)}`, formatCodexDisplayText(question.question));
|
|
2344
|
+
else lines.push("", formatCodexDisplayText(question.header), formatCodexDisplayText(question.question));
|
|
2196
2345
|
if (question.isSecret) lines.push("This channel may show your reply to other participants.");
|
|
2197
2346
|
question.options?.forEach((option, optionIndex) => {
|
|
2198
|
-
lines.push(`${optionIndex + 1}. ${option.label}${option.description ? ` - ${option.description}` : ""}`);
|
|
2347
|
+
lines.push(`${optionIndex + 1}. ${formatCodexDisplayText(option.label)}${option.description ? ` - ${formatCodexDisplayText(option.description)}` : ""}`);
|
|
2199
2348
|
});
|
|
2200
2349
|
if (question.isOther) lines.push("Other: reply with your own answer.");
|
|
2201
2350
|
});
|
|
@@ -2205,14 +2354,18 @@ function buildUserInputResponse(questions, inputText) {
|
|
|
2205
2354
|
const answers = {};
|
|
2206
2355
|
if (questions.length === 1) {
|
|
2207
2356
|
const question = questions[0];
|
|
2208
|
-
if (question)
|
|
2357
|
+
if (question) {
|
|
2358
|
+
const answer = normalizeAnswer(inputText, question);
|
|
2359
|
+
answers[question.id] = { answers: answer ? [answer] : [] };
|
|
2360
|
+
}
|
|
2209
2361
|
return { answers };
|
|
2210
2362
|
}
|
|
2211
2363
|
const keyed = parseKeyedAnswers(inputText);
|
|
2212
2364
|
const fallbackLines = inputText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2213
2365
|
questions.forEach((question, index) => {
|
|
2214
2366
|
const answer = keyed.get(question.id.toLowerCase()) ?? keyed.get(question.header.toLowerCase()) ?? keyed.get(question.question.toLowerCase()) ?? keyed.get(String(index + 1)) ?? fallbackLines[index] ?? "";
|
|
2215
|
-
|
|
2367
|
+
const normalized = answer ? normalizeAnswer(answer, question) : void 0;
|
|
2368
|
+
answers[question.id] = { answers: normalized ? [normalized] : [] };
|
|
2216
2369
|
});
|
|
2217
2370
|
return { answers };
|
|
2218
2371
|
}
|
|
@@ -2222,7 +2375,10 @@ function normalizeAnswer(answer, question) {
|
|
|
2222
2375
|
const optionIndex = /^\d+$/.test(trimmed) ? Number(trimmed) - 1 : -1;
|
|
2223
2376
|
const indexed = optionIndex >= 0 ? options[optionIndex] : void 0;
|
|
2224
2377
|
if (indexed) return indexed.label;
|
|
2225
|
-
|
|
2378
|
+
const exact = options.find((option) => option.label.toLowerCase() === trimmed.toLowerCase());
|
|
2379
|
+
if (exact) return exact.label;
|
|
2380
|
+
if (options.length > 0 && !question.isOther) return;
|
|
2381
|
+
return trimmed || void 0;
|
|
2226
2382
|
}
|
|
2227
2383
|
function parseKeyedAnswers(inputText) {
|
|
2228
2384
|
const answers = /* @__PURE__ */ new Map();
|
|
@@ -2468,6 +2624,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2468
2624
|
signal: runAbortController.signal,
|
|
2469
2625
|
hookContext: {
|
|
2470
2626
|
agentId: sessionAgentId,
|
|
2627
|
+
config: params.config,
|
|
2471
2628
|
sessionId: params.sessionId,
|
|
2472
2629
|
sessionKey: sandboxSessionKey,
|
|
2473
2630
|
runId: params.runId
|
|
@@ -2533,6 +2690,19 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2533
2690
|
} catch (assembleErr) {
|
|
2534
2691
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
2535
2692
|
}
|
|
2693
|
+
else if (shouldProjectMirroredHistoryForCodexStart({
|
|
2694
|
+
startupBinding,
|
|
2695
|
+
dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs),
|
|
2696
|
+
historyMessages
|
|
2697
|
+
})) {
|
|
2698
|
+
const projection = projectContextEngineAssemblyForCodex({
|
|
2699
|
+
assembledMessages: historyMessages,
|
|
2700
|
+
originalHistoryMessages: historyMessages,
|
|
2701
|
+
prompt: params.prompt
|
|
2702
|
+
});
|
|
2703
|
+
promptText = projection.promptText;
|
|
2704
|
+
prePromptMessageCount = projection.prePromptMessageCount;
|
|
2705
|
+
}
|
|
2536
2706
|
const promptBuild = await resolveAgentHarnessBeforePromptBuildResult({
|
|
2537
2707
|
prompt: promptText,
|
|
2538
2708
|
developerInstructions,
|
|
@@ -2568,6 +2738,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2568
2738
|
agentId: sessionAgentId,
|
|
2569
2739
|
sessionId: params.sessionId,
|
|
2570
2740
|
sessionKey: sandboxSessionKey,
|
|
2741
|
+
config: params.config,
|
|
2571
2742
|
runId: params.runId,
|
|
2572
2743
|
signal: runAbortController.signal
|
|
2573
2744
|
});
|
|
@@ -2955,11 +3126,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2955
3126
|
signal: runAbortController.signal
|
|
2956
3127
|
}));
|
|
2957
3128
|
} catch (error) {
|
|
3129
|
+
const usageLimitError = formatCodexTurnStartUsageLimitError(error, pendingNotifications);
|
|
3130
|
+
const turnStartErrorMessage = usageLimitError ?? formatErrorMessage(error);
|
|
2958
3131
|
emitCodexAppServerEvent(params, {
|
|
2959
3132
|
stream: "codex_app_server.lifecycle",
|
|
2960
3133
|
data: {
|
|
2961
3134
|
phase: "turn_start_failed",
|
|
2962
|
-
error:
|
|
3135
|
+
error: turnStartErrorMessage
|
|
2963
3136
|
}
|
|
2964
3137
|
});
|
|
2965
3138
|
trajectoryRecorder?.recordEvent("session.ended", {
|
|
@@ -2967,7 +3140,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2967
3140
|
threadId: thread.threadId,
|
|
2968
3141
|
timedOut,
|
|
2969
3142
|
aborted: runAbortController.signal.aborted,
|
|
2970
|
-
promptError:
|
|
3143
|
+
promptError: turnStartErrorMessage
|
|
2971
3144
|
});
|
|
2972
3145
|
trajectoryEndRecorded = true;
|
|
2973
3146
|
runAgentHarnessLlmOutputHook({
|
|
@@ -2986,7 +3159,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2986
3159
|
event: {
|
|
2987
3160
|
messages: turnStartFailureMessages,
|
|
2988
3161
|
success: false,
|
|
2989
|
-
error:
|
|
3162
|
+
error: turnStartErrorMessage,
|
|
2990
3163
|
durationMs: Date.now() - attemptStartedAt
|
|
2991
3164
|
},
|
|
2992
3165
|
ctx: hookContext
|
|
@@ -3004,6 +3177,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3004
3177
|
}
|
|
3005
3178
|
});
|
|
3006
3179
|
params.abortSignal?.removeEventListener("abort", abortFromUpstream);
|
|
3180
|
+
if (usageLimitError) throw new Error(usageLimitError, { cause: error });
|
|
3007
3181
|
throw error;
|
|
3008
3182
|
}
|
|
3009
3183
|
turnId = turn.turn.id;
|
|
@@ -3270,6 +3444,7 @@ function createCodexNativeHookRelay(params) {
|
|
|
3270
3444
|
...params.agentId ? { agentId: params.agentId } : {},
|
|
3271
3445
|
sessionId: params.sessionId,
|
|
3272
3446
|
...params.sessionKey ? { sessionKey: params.sessionKey } : {},
|
|
3447
|
+
...params.config ? { config: params.config } : {},
|
|
3273
3448
|
runId: params.runId,
|
|
3274
3449
|
allowedEvents: params.options?.events ?? CODEX_NATIVE_HOOK_RELAY_EVENTS,
|
|
3275
3450
|
ttlMs: params.options?.ttlMs,
|
|
@@ -3377,6 +3552,14 @@ async function buildDynamicTools(input) {
|
|
|
3377
3552
|
model: params.model
|
|
3378
3553
|
});
|
|
3379
3554
|
}
|
|
3555
|
+
function shouldProjectMirroredHistoryForCodexStart(params) {
|
|
3556
|
+
if (!params.historyMessages.some((message) => message.role === "user")) return false;
|
|
3557
|
+
if (!params.startupBinding?.threadId) return true;
|
|
3558
|
+
return !areCodexDynamicToolFingerprintsCompatible({
|
|
3559
|
+
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
3560
|
+
next: params.dynamicToolsFingerprint
|
|
3561
|
+
});
|
|
3562
|
+
}
|
|
3380
3563
|
async function withCodexStartupTimeout(params) {
|
|
3381
3564
|
if (params.signal.aborted) throw new Error("codex app-server startup aborted");
|
|
3382
3565
|
let timeout;
|
|
@@ -3416,6 +3599,48 @@ function resolveCodexTurnTerminalIdleTimeoutMs(value) {
|
|
|
3416
3599
|
function readDynamicToolCallParams(value) {
|
|
3417
3600
|
return readCodexDynamicToolCallParams(value);
|
|
3418
3601
|
}
|
|
3602
|
+
function formatCodexTurnStartUsageLimitError(error, pendingNotifications) {
|
|
3603
|
+
const notificationError = readLatestCodexErrorNotification(pendingNotifications);
|
|
3604
|
+
const errorPayload = readCodexErrorPayload(error);
|
|
3605
|
+
return formatCodexUsageLimitErrorMessage({
|
|
3606
|
+
message: notificationError?.message ?? errorPayload.message ?? formatErrorMessage(error),
|
|
3607
|
+
codexErrorInfo: notificationError?.codexErrorInfo ?? errorPayload.codexErrorInfo,
|
|
3608
|
+
rateLimits: readLatestRateLimitNotificationPayload(pendingNotifications) ?? errorPayload.rateLimits ?? readRecentCodexRateLimits()
|
|
3609
|
+
});
|
|
3610
|
+
}
|
|
3611
|
+
function readLatestRateLimitNotificationPayload(notifications) {
|
|
3612
|
+
for (let index = notifications.length - 1; index >= 0; index -= 1) {
|
|
3613
|
+
const notification = notifications[index];
|
|
3614
|
+
if (notification?.method === "account/rateLimits/updated") {
|
|
3615
|
+
rememberCodexRateLimits(notification.params);
|
|
3616
|
+
return notification.params;
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
}
|
|
3620
|
+
function readLatestCodexErrorNotification(notifications) {
|
|
3621
|
+
for (let index = notifications.length - 1; index >= 0; index -= 1) {
|
|
3622
|
+
const notification = notifications[index];
|
|
3623
|
+
if (notification?.method !== "error" || !isJsonObject(notification.params)) continue;
|
|
3624
|
+
const error = notification.params.error;
|
|
3625
|
+
if (!isJsonObject(error)) continue;
|
|
3626
|
+
return {
|
|
3627
|
+
message: readString(error, "message"),
|
|
3628
|
+
codexErrorInfo: error.codexErrorInfo
|
|
3629
|
+
};
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
function readCodexErrorPayload(error) {
|
|
3633
|
+
const message = error instanceof Error ? error.message : void 0;
|
|
3634
|
+
if (!error || typeof error !== "object" || !("data" in error)) return { message };
|
|
3635
|
+
const data = error.data;
|
|
3636
|
+
if (!isJsonObject(data)) return { message };
|
|
3637
|
+
const nestedError = isJsonObject(data.error) ? data.error : data;
|
|
3638
|
+
return {
|
|
3639
|
+
message: readString(nestedError, "message") ?? message,
|
|
3640
|
+
codexErrorInfo: nestedError.codexErrorInfo,
|
|
3641
|
+
rateLimits: nestedError.rateLimits ?? data.rateLimits
|
|
3642
|
+
};
|
|
3643
|
+
}
|
|
3419
3644
|
function isTurnNotification(value, threadId, turnId) {
|
|
3420
3645
|
if (!isJsonObject(value)) return false;
|
|
3421
3646
|
return readString(value, "threadId") === threadId && readNotificationTurnId(value) === turnId;
|
|
@@ -3518,7 +3743,7 @@ async function mirrorTranscriptBestEffort(params) {
|
|
|
3518
3743
|
agentId: params.agentId,
|
|
3519
3744
|
sessionKey: params.sessionKey,
|
|
3520
3745
|
messages: params.result.messagesSnapshot,
|
|
3521
|
-
idempotencyScope: `codex-app-server:${params.threadId}
|
|
3746
|
+
idempotencyScope: `codex-app-server:${params.threadId}`,
|
|
3522
3747
|
config: params.params.config
|
|
3523
3748
|
});
|
|
3524
3749
|
} catch (error) {
|