@openclaw/codex 2026.5.7 → 2026.5.10-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{client-BGbqC7jk.js → client-CTzy3Y6M.js} +7 -7
- package/dist/{client-factory--cll1Fba.js → client-factory-BJL_efz4.js} +1 -1
- package/dist/{command-handlers-DiH-D13x.js → command-handlers-BJ0GpaPa.js} +7 -7
- package/dist/{compact-DcR5aTxd.js → compact-4FVe6NwI.js} +3 -3
- package/dist/config-CT01BBDc.js +496 -0
- package/dist/{conversation-binding-CtHkMJfG.js → conversation-binding-FqeYliIk.js} +10 -8
- package/dist/doctor-contract-api.js +35 -1
- package/dist/harness.js +4 -4
- package/dist/index.js +406 -33
- package/dist/media-understanding-provider.js +4 -4
- package/dist/{models-CkowdYbm.js → models-OtCFiaj_.js} +2 -2
- package/dist/plugin-activation-CweAZa7r.js +389 -0
- package/dist/{protocol-validators-Dky2yV4W.js → protocol-validators-CbqWfY5M.js} +147 -14
- package/dist/provider.js +2 -2
- package/dist/{rate-limit-cache-t6ebYmfS.js → rate-limit-cache-DbZvmrAD.js} +3 -17
- package/dist/{command-formatters-PiJcdUbu.js → request-DC1Dz3iZ.js} +16 -2
- package/dist/{run-attempt-BaT_FcTv.js → run-attempt-DsO-3wqp.js} +542 -136
- package/dist/{session-binding-DuJYTJQy.js → session-binding-B44KIZM2.js} +44 -5
- package/dist/{shared-client-Dfk3Enm-.js → shared-client-p-TvEiNL.js} +77 -22
- package/dist/test-api.js +8 -5
- package/dist/{thread-lifecycle-CzllX4PU.js → thread-lifecycle-DtD_qoMW.js} +329 -18
- package/openclaw.plugin.json +75 -9
- package/package.json +7 -8
- package/dist/config-ByrA30No.js +0 -242
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as readCodexDynamicToolCallParams, r as assertCodexTurnStartResponse, s as readCodexTurn } from "./protocol-validators-
|
|
1
|
+
import { l as resolveCodexPluginsPolicy, o as readCodexPluginConfig, s as resolveCodexAppServerRuntimeOptions, u as withMcpElicitationsApprovalPolicy } from "./config-CT01BBDc.js";
|
|
2
|
+
import { i as readCodexDynamicToolCallParams, r as assertCodexTurnStartResponse, s as readCodexTurn } from "./protocol-validators-CbqWfY5M.js";
|
|
3
3
|
import { t as isJsonObject } from "./protocol-C9UWI98H.js";
|
|
4
|
-
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-
|
|
5
|
-
import {
|
|
6
|
-
import { a as refreshCodexAppServerAuthTokens, o as
|
|
7
|
-
import { i as readCodexAppServerBinding } from "./session-binding-
|
|
8
|
-
import {
|
|
9
|
-
import { n as
|
|
10
|
-
import { n as
|
|
4
|
+
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-CTzy3Y6M.js";
|
|
5
|
+
import { d as formatCodexUsageLimitErrorMessage, i as formatCodexDisplayText } from "./request-DC1Dz3iZ.js";
|
|
6
|
+
import { a as refreshCodexAppServerAuthTokens, c as resolveCodexAppServerAuthProfileIdForAgent, l as resolveCodexAppServerEnvApiKeyCacheKey, o as resolveCodexAppServerAuthAccountCacheKey, s as resolveCodexAppServerAuthProfileId, t as clearSharedCodexAppServerClientIfCurrent, u as resolveCodexAppServerHomeDir } from "./shared-client-p-TvEiNL.js";
|
|
7
|
+
import { i as readCodexAppServerBinding } from "./session-binding-B44KIZM2.js";
|
|
8
|
+
import { i as defaultCodexAppInventoryCache, r as buildCodexAppInventoryCacheKey } from "./plugin-activation-CweAZa7r.js";
|
|
9
|
+
import { a as buildTurnStartParams, c as buildCodexPluginThreadConfig, d as createCodexDynamicToolBridge, f as filterCodexDynamicTools, l as buildCodexPluginThreadConfigInputFingerprint, n as buildDeveloperInstructions, o as codexDynamicToolsFingerprint, p as normalizeCodexDynamicToolName, s as startOrResumeThread, t as areCodexDynamicToolFingerprintsCompatible, u as shouldBuildCodexPluginThreadConfig } from "./thread-lifecycle-DtD_qoMW.js";
|
|
10
|
+
import { n as defaultCodexAppServerClientFactory } from "./client-factory-BJL_efz4.js";
|
|
11
|
+
import { n as rememberCodexRateLimits, r as ensureCodexComputerUse, t as readRecentCodexRateLimits } from "./rate-limit-cache-DbZvmrAD.js";
|
|
11
12
|
import { createHash } from "node:crypto";
|
|
12
|
-
import
|
|
13
|
+
import nodeFs from "node:fs";
|
|
14
|
+
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, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockAcquireTimeoutMs, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
13
15
|
import fs from "node:fs/promises";
|
|
14
16
|
import path from "node:path";
|
|
15
|
-
import
|
|
17
|
+
import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
|
|
18
|
+
import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
19
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
16
20
|
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
17
21
|
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@mariozechner/pi-coding-agent";
|
|
18
22
|
import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/text-runtime";
|
|
19
|
-
import { resolveUserPath as resolveUserPath$1 } from "openclaw/plugin-sdk/agent-harness";
|
|
20
23
|
//#region extensions/codex/src/app-server/plugin-approval-roundtrip.ts
|
|
21
24
|
const DEFAULT_CODEX_APPROVAL_TIMEOUT_MS = 12e4;
|
|
22
25
|
const MAX_PLUGIN_APPROVAL_TITLE_LENGTH = 80;
|
|
@@ -92,7 +95,7 @@ const INVISIBLE_FORMATTING_CONTROL_RE$1 = new RegExp(String.raw`[\u00ad\u034f\u0
|
|
|
92
95
|
const DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE$1 = new RegExp(String.raw`(?:\u001b\][^\u001b\u009c\u0007]*|\u009d[^\u001b\u009c\u0007]*|\u001b\[[0-?]*[ -/]*|\u009b[0-?]*[ -/]*|\u001b)$`);
|
|
93
96
|
async function handleCodexAppServerApprovalRequest(params) {
|
|
94
97
|
const requestParams = isJsonObject(params.requestParams) ? params.requestParams : void 0;
|
|
95
|
-
if (!matchesCurrentTurn
|
|
98
|
+
if (!matchesCurrentTurn(requestParams, params.threadId, params.turnId)) return;
|
|
96
99
|
if (!isSupportedAppServerApprovalMethod(params.method)) return unsupportedApprovalResponse();
|
|
97
100
|
const context = buildApprovalContext({
|
|
98
101
|
method: params.method,
|
|
@@ -176,7 +179,7 @@ function buildApprovalResponse(method, requestParams, outcome) {
|
|
|
176
179
|
}
|
|
177
180
|
return unsupportedApprovalResponse();
|
|
178
181
|
}
|
|
179
|
-
function matchesCurrentTurn
|
|
182
|
+
function matchesCurrentTurn(requestParams, threadId, turnId) {
|
|
180
183
|
if (!requestParams) return false;
|
|
181
184
|
const requestThreadId = readString$4(requestParams, "threadId") ?? readString$4(requestParams, "conversationId");
|
|
182
185
|
const requestTurnId = readString$4(requestParams, "turnId");
|
|
@@ -636,6 +639,29 @@ const MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY = "connector_name";
|
|
|
636
639
|
const MCP_TOOL_APPROVAL_TOOL_TITLE_KEY = "tool_title";
|
|
637
640
|
const MCP_TOOL_APPROVAL_TOOL_DESCRIPTION_KEY = "tool_description";
|
|
638
641
|
const MCP_TOOL_APPROVAL_TOOL_PARAMS_DISPLAY_KEY = "tool_params_display";
|
|
642
|
+
const PLUGIN_APP_ID_META_KEYS = [
|
|
643
|
+
"app_id",
|
|
644
|
+
"appId",
|
|
645
|
+
"codex_app_id",
|
|
646
|
+
"codexAppId"
|
|
647
|
+
];
|
|
648
|
+
const PLUGIN_NAME_META_KEYS = [
|
|
649
|
+
"plugin_name",
|
|
650
|
+
"pluginName",
|
|
651
|
+
"codex_plugin_name",
|
|
652
|
+
"codexPluginName"
|
|
653
|
+
];
|
|
654
|
+
const PLUGIN_CONFIG_KEY_META_KEYS = [
|
|
655
|
+
"config_key",
|
|
656
|
+
"configKey",
|
|
657
|
+
"codex_config_key"
|
|
658
|
+
];
|
|
659
|
+
const PLUGIN_MARKETPLACE_NAME_META_KEYS = [
|
|
660
|
+
"marketplace_name",
|
|
661
|
+
"marketplaceName",
|
|
662
|
+
"codex_marketplace_name",
|
|
663
|
+
"codexMarketplaceName"
|
|
664
|
+
];
|
|
639
665
|
const MAX_DISPLAY_PARAM_ENTRIES = 8;
|
|
640
666
|
const MAX_DISPLAY_PARAM_VALUE_LENGTH = 120;
|
|
641
667
|
const MAX_DISPLAY_VALUE_ARRAY_ITEMS = 8;
|
|
@@ -649,7 +675,24 @@ const INVISIBLE_FORMATTING_CONTROL_RE = new RegExp(String.raw`[\u00ad\u034f\u061
|
|
|
649
675
|
const DANGLING_TERMINAL_SEQUENCE_SUFFIX_RE = new RegExp(String.raw`(?:\u001b\][^\u001b\u009c\u0007]*|\u009d[^\u001b\u009c\u0007]*|\u001b\[[0-?]*[ -/]*|\u009b[0-?]*[ -/]*|\u001b)$`);
|
|
650
676
|
async function handleCodexAppServerElicitationRequest(params) {
|
|
651
677
|
const requestParams = isJsonObject(params.requestParams) ? params.requestParams : void 0;
|
|
652
|
-
if (!
|
|
678
|
+
if (!requestParams) return;
|
|
679
|
+
if (!matchesCurrentThread(requestParams, params.threadId)) return;
|
|
680
|
+
if (turnIdMismatches(requestParams, params.turnId)) return;
|
|
681
|
+
const pluginResolution = resolvePluginElicitation({
|
|
682
|
+
requestParams,
|
|
683
|
+
pluginAppPolicyContext: params.pluginAppPolicyContext
|
|
684
|
+
});
|
|
685
|
+
if (pluginResolution.kind !== "not_plugin") {
|
|
686
|
+
if (pluginResolution.kind === "decline") {
|
|
687
|
+
logPluginElicitationDecline(pluginResolution.reason, requestParams);
|
|
688
|
+
return declineElicitationResponse();
|
|
689
|
+
}
|
|
690
|
+
if (!hasExactTurnId(requestParams, params.turnId)) {
|
|
691
|
+
logPluginElicitationDecline("missing_active_turn", requestParams);
|
|
692
|
+
return declineElicitationResponse();
|
|
693
|
+
}
|
|
694
|
+
return buildPluginPolicyElicitationResponse(pluginResolution.entry, requestParams);
|
|
695
|
+
}
|
|
653
696
|
const approvalPrompt = readBridgeableApprovalElicitation(requestParams);
|
|
654
697
|
if (!approvalPrompt) return;
|
|
655
698
|
const outcome = await requestPluginApprovalOutcome({
|
|
@@ -660,12 +703,113 @@ async function handleCodexAppServerElicitationRequest(params) {
|
|
|
660
703
|
});
|
|
661
704
|
return buildElicitationResponse(approvalPrompt.requestedSchema, approvalPrompt.meta, outcome);
|
|
662
705
|
}
|
|
663
|
-
function
|
|
706
|
+
function matchesCurrentThread(requestParams, threadId) {
|
|
664
707
|
if (!requestParams) return false;
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
708
|
+
return readString$3(requestParams, "threadId") === threadId;
|
|
709
|
+
}
|
|
710
|
+
function turnIdMismatches(requestParams, turnId) {
|
|
711
|
+
const rawTurnId = requestParams?.turnId;
|
|
712
|
+
return rawTurnId !== null && rawTurnId !== void 0 && rawTurnId !== turnId;
|
|
713
|
+
}
|
|
714
|
+
function hasExactTurnId(requestParams, turnId) {
|
|
715
|
+
return requestParams?.turnId === turnId;
|
|
716
|
+
}
|
|
717
|
+
function resolvePluginElicitation(params) {
|
|
718
|
+
const requestParams = params.requestParams;
|
|
719
|
+
if (!requestParams) return { kind: "not_plugin" };
|
|
720
|
+
const meta = isJsonObject(requestParams._meta) ? requestParams._meta : {};
|
|
721
|
+
const context = params.pluginAppPolicyContext;
|
|
722
|
+
const entries = context ? Object.values(context.apps) : [];
|
|
723
|
+
const appId = readFirstString(meta, PLUGIN_APP_ID_META_KEYS) ?? readFirstString(requestParams, PLUGIN_APP_ID_META_KEYS);
|
|
724
|
+
if (appId) {
|
|
725
|
+
if (!context) return {
|
|
726
|
+
kind: "decline",
|
|
727
|
+
reason: "missing_policy_context"
|
|
728
|
+
};
|
|
729
|
+
const entry = context.apps[appId];
|
|
730
|
+
return uniquePluginMatch(entry ? [entry] : [], "app_id");
|
|
731
|
+
}
|
|
732
|
+
const serverName = readString$3(requestParams, "serverName");
|
|
733
|
+
if (serverName && context) {
|
|
734
|
+
const matches = entries.filter((entry) => entry.mcpServerNames.includes(serverName));
|
|
735
|
+
if (matches.length > 0) return uniquePluginMatch(matches, "server_name");
|
|
736
|
+
}
|
|
737
|
+
const metadataResolution = resolvePluginStableMetadataMatch({
|
|
738
|
+
meta,
|
|
739
|
+
requestParams,
|
|
740
|
+
entries,
|
|
741
|
+
context
|
|
742
|
+
});
|
|
743
|
+
if (metadataResolution.kind !== "not_plugin") return metadataResolution;
|
|
744
|
+
if (context && hasDisplayNameOnlyPluginMatch(meta, entries)) return {
|
|
745
|
+
kind: "decline",
|
|
746
|
+
reason: "display_name_only"
|
|
747
|
+
};
|
|
748
|
+
return { kind: "not_plugin" };
|
|
749
|
+
}
|
|
750
|
+
function resolvePluginStableMetadataMatch(params) {
|
|
751
|
+
const pluginName = readFirstString(params.meta, PLUGIN_NAME_META_KEYS) ?? readFirstString(params.requestParams, PLUGIN_NAME_META_KEYS);
|
|
752
|
+
const configKey = readFirstString(params.meta, PLUGIN_CONFIG_KEY_META_KEYS) ?? readFirstString(params.requestParams, PLUGIN_CONFIG_KEY_META_KEYS);
|
|
753
|
+
const marketplaceName = readFirstString(params.meta, PLUGIN_MARKETPLACE_NAME_META_KEYS) ?? readFirstString(params.requestParams, PLUGIN_MARKETPLACE_NAME_META_KEYS);
|
|
754
|
+
if (!pluginName && !configKey) return { kind: "not_plugin" };
|
|
755
|
+
if (!params.context) return {
|
|
756
|
+
kind: "decline",
|
|
757
|
+
reason: "missing_policy_context"
|
|
758
|
+
};
|
|
759
|
+
return uniquePluginMatch(params.entries.filter((entry) => {
|
|
760
|
+
if (marketplaceName && entry.marketplaceName !== marketplaceName) return false;
|
|
761
|
+
if (pluginName && entry.pluginName !== pluginName) return false;
|
|
762
|
+
if (configKey && entry.configKey !== configKey) return false;
|
|
763
|
+
return true;
|
|
764
|
+
}), "metadata");
|
|
765
|
+
}
|
|
766
|
+
function uniquePluginMatch(matches, source) {
|
|
767
|
+
if (matches.length === 1 && matches[0]) return {
|
|
768
|
+
kind: "matched",
|
|
769
|
+
entry: matches[0]
|
|
770
|
+
};
|
|
771
|
+
return {
|
|
772
|
+
kind: "decline",
|
|
773
|
+
reason: matches.length === 0 ? `${source}_not_enabled` : `${source}_ambiguous`
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function hasDisplayNameOnlyPluginMatch(meta, entries) {
|
|
777
|
+
const connectorName = readString$3(meta, MCP_TOOL_APPROVAL_CONNECTOR_NAME_KEY);
|
|
778
|
+
if (!connectorName) return false;
|
|
779
|
+
const normalized = normalizePluginIdentityText(connectorName);
|
|
780
|
+
return entries.some((entry) => normalizePluginIdentityText(entry.pluginName) === normalized || normalizePluginIdentityText(entry.configKey) === normalized);
|
|
781
|
+
}
|
|
782
|
+
function normalizePluginIdentityText(value) {
|
|
783
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
784
|
+
}
|
|
785
|
+
function buildPluginPolicyElicitationResponse(entry, requestParams) {
|
|
786
|
+
if (!entry.allowDestructiveActions) {
|
|
787
|
+
logPluginElicitationDecline("destructive_actions_disabled", requestParams);
|
|
788
|
+
return declineElicitationResponse();
|
|
789
|
+
}
|
|
790
|
+
if (readString$3(requestParams, "mode") !== "form" || !isJsonObject(requestParams.requestedSchema)) {
|
|
791
|
+
logPluginElicitationDecline("unsupported_schema", requestParams);
|
|
792
|
+
return declineElicitationResponse();
|
|
793
|
+
}
|
|
794
|
+
const meta = isJsonObject(requestParams._meta) ? requestParams._meta : {};
|
|
795
|
+
const response = buildElicitationResponse(requestParams.requestedSchema, meta, "approved-once");
|
|
796
|
+
if (isJsonObject(response) && response.action === "accept") return response;
|
|
797
|
+
logPluginElicitationDecline("unmappable_schema", requestParams);
|
|
798
|
+
return declineElicitationResponse();
|
|
799
|
+
}
|
|
800
|
+
function declineElicitationResponse() {
|
|
801
|
+
return {
|
|
802
|
+
action: "decline",
|
|
803
|
+
content: null,
|
|
804
|
+
_meta: null
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function logPluginElicitationDecline(reason, requestParams) {
|
|
808
|
+
embeddedAgentLog.debug("codex plugin elicitation declined", {
|
|
809
|
+
reason,
|
|
810
|
+
serverName: readString$3(requestParams, "serverName"),
|
|
811
|
+
mode: readString$3(requestParams, "mode")
|
|
812
|
+
});
|
|
669
813
|
}
|
|
670
814
|
function readBridgeableApprovalElicitation(requestParams) {
|
|
671
815
|
if (!requestParams || readString$3(requestParams, "mode") !== "form" || !isJsonObject(requestParams._meta) || requestParams._meta[MCP_TOOL_APPROVAL_KIND_KEY] !== MCP_TOOL_APPROVAL_KIND || !isJsonObject(requestParams.requestedSchema)) return;
|
|
@@ -944,6 +1088,12 @@ function readString$3(record, key) {
|
|
|
944
1088
|
const value = record?.[key];
|
|
945
1089
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
946
1090
|
}
|
|
1091
|
+
function readFirstString(record, keys) {
|
|
1092
|
+
for (const key of keys) {
|
|
1093
|
+
const value = readString$3(record, key);
|
|
1094
|
+
if (value) return value;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
947
1097
|
//#endregion
|
|
948
1098
|
//#region extensions/codex/src/app-server/session-history.ts
|
|
949
1099
|
function isMissingFileError(error) {
|
|
@@ -1038,7 +1188,7 @@ function buildMirrorDedupeIdentity(message) {
|
|
|
1038
1188
|
return `${message.role}:${fingerprintMirrorMessageContent(message)}`;
|
|
1039
1189
|
}
|
|
1040
1190
|
async function mirrorCodexAppServerTranscript(params) {
|
|
1041
|
-
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant");
|
|
1191
|
+
const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant" || message.role === "toolResult");
|
|
1042
1192
|
if (messages.length === 0) return;
|
|
1043
1193
|
const lock = await acquireSessionWriteLock({
|
|
1044
1194
|
sessionFile: params.sessionFile,
|
|
@@ -1130,6 +1280,7 @@ const CODEX_PROMPT_TOTAL_INPUT_KEYS = [
|
|
|
1130
1280
|
"prompt_tokens"
|
|
1131
1281
|
];
|
|
1132
1282
|
const MAX_TOOL_OUTPUT_DELTA_MESSAGES_PER_ITEM = 20;
|
|
1283
|
+
const TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS = 12e3;
|
|
1133
1284
|
var CodexAppServerEventProjector = class {
|
|
1134
1285
|
constructor(params, threadId, turnId) {
|
|
1135
1286
|
this.params = params;
|
|
@@ -1147,6 +1298,9 @@ var CodexAppServerEventProjector = class {
|
|
|
1147
1298
|
this.toolResultOutputStreamedItemIds = /* @__PURE__ */ new Set();
|
|
1148
1299
|
this.toolResultOutputDeltaState = /* @__PURE__ */ new Map();
|
|
1149
1300
|
this.toolMetas = /* @__PURE__ */ new Map();
|
|
1301
|
+
this.toolTranscriptMessages = [];
|
|
1302
|
+
this.toolTranscriptCallIds = /* @__PURE__ */ new Set();
|
|
1303
|
+
this.toolTranscriptResultIds = /* @__PURE__ */ new Set();
|
|
1150
1304
|
this.assistantStarted = false;
|
|
1151
1305
|
this.reasoningStarted = false;
|
|
1152
1306
|
this.reasoningEnded = false;
|
|
@@ -1230,6 +1384,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1230
1384
|
}, `${turnId}:prompt`)];
|
|
1231
1385
|
if (reasoningText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex reasoning", reasoningText), `${turnId}:reasoning`));
|
|
1232
1386
|
if (planText) messagesSnapshot.push(attachCodexMirrorIdentity(this.createAssistantMirrorMessage("Codex plan", planText), `${turnId}:plan`));
|
|
1387
|
+
messagesSnapshot.push(...this.toolTranscriptMessages);
|
|
1233
1388
|
if (lastAssistant) messagesSnapshot.push(attachCodexMirrorIdentity(lastAssistant, `${turnId}:assistant`));
|
|
1234
1389
|
const turnFailed = this.completedTurn?.status === "failed";
|
|
1235
1390
|
const turnInterrupted = this.completedTurn?.status === "interrupted";
|
|
@@ -1282,6 +1437,21 @@ var CodexAppServerEventProjector = class {
|
|
|
1282
1437
|
didSendDeterministicApprovalPrompt: this.guardianReviewCount > 0 ? false : void 0
|
|
1283
1438
|
};
|
|
1284
1439
|
}
|
|
1440
|
+
recordDynamicToolCall(params) {
|
|
1441
|
+
this.recordToolTranscriptCall({
|
|
1442
|
+
id: params.callId,
|
|
1443
|
+
name: params.tool,
|
|
1444
|
+
arguments: sanitizeCodexToolArguments(params.arguments)
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
recordDynamicToolResult(params) {
|
|
1448
|
+
this.recordToolTranscriptResult({
|
|
1449
|
+
id: params.callId,
|
|
1450
|
+
name: params.tool,
|
|
1451
|
+
text: collectDynamicToolContentText(params.contentItems),
|
|
1452
|
+
isError: !params.success
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1285
1455
|
markTimedOut() {
|
|
1286
1456
|
this.aborted = true;
|
|
1287
1457
|
this.promptError = "codex app-server attempt timed out";
|
|
@@ -1373,6 +1543,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1373
1543
|
phase: "start",
|
|
1374
1544
|
item
|
|
1375
1545
|
});
|
|
1546
|
+
this.recordNativeToolTranscriptCall(item);
|
|
1376
1547
|
this.emitToolResultSummary(item);
|
|
1377
1548
|
this.emitAgentEvent({
|
|
1378
1549
|
stream: "codex_app_server.item",
|
|
@@ -1439,6 +1610,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1439
1610
|
phase: "result",
|
|
1440
1611
|
item
|
|
1441
1612
|
});
|
|
1613
|
+
this.recordNativeToolTranscriptCall(item);
|
|
1614
|
+
this.recordNativeToolTranscriptResult(item);
|
|
1442
1615
|
this.emitToolResultSummary(item);
|
|
1443
1616
|
this.emitToolResultOutput(item);
|
|
1444
1617
|
this.emitAgentEvent({
|
|
@@ -1529,6 +1702,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1529
1702
|
});
|
|
1530
1703
|
}
|
|
1531
1704
|
this.recordToolMeta(item);
|
|
1705
|
+
this.recordNativeToolTranscriptCall(item);
|
|
1706
|
+
this.recordNativeToolTranscriptResult(item);
|
|
1532
1707
|
this.emitToolResultSummary(item);
|
|
1533
1708
|
this.emitToolResultOutput(item);
|
|
1534
1709
|
}
|
|
@@ -1693,6 +1868,37 @@ var CodexAppServerEventProjector = class {
|
|
|
1693
1868
|
...meta ? { meta } : {}
|
|
1694
1869
|
});
|
|
1695
1870
|
}
|
|
1871
|
+
recordNativeToolTranscriptCall(item) {
|
|
1872
|
+
if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
|
|
1873
|
+
const name = itemName(item);
|
|
1874
|
+
if (!name) return;
|
|
1875
|
+
this.recordToolTranscriptCall({
|
|
1876
|
+
id: item.id,
|
|
1877
|
+
name,
|
|
1878
|
+
arguments: itemToolArgs(item)
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
recordNativeToolTranscriptResult(item) {
|
|
1882
|
+
if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
|
|
1883
|
+
const name = itemName(item);
|
|
1884
|
+
if (!name) return;
|
|
1885
|
+
this.recordToolTranscriptResult({
|
|
1886
|
+
id: item.id,
|
|
1887
|
+
name,
|
|
1888
|
+
text: itemTranscriptResultText(item),
|
|
1889
|
+
isError: isNonSuccessItemStatus(itemStatus(item))
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
recordToolTranscriptCall(params) {
|
|
1893
|
+
if (!params.id || !params.name || this.toolTranscriptCallIds.has(params.id)) return;
|
|
1894
|
+
this.toolTranscriptCallIds.add(params.id);
|
|
1895
|
+
this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`));
|
|
1896
|
+
}
|
|
1897
|
+
recordToolTranscriptResult(params) {
|
|
1898
|
+
if (!params.id || !params.name || this.toolTranscriptResultIds.has(params.id)) return;
|
|
1899
|
+
this.toolTranscriptResultIds.add(params.id);
|
|
1900
|
+
this.toolTranscriptMessages.push(attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`));
|
|
1901
|
+
}
|
|
1696
1902
|
formatCodexErrorMessage(params) {
|
|
1697
1903
|
const error = isJsonObject(params.error) ? params.error : void 0;
|
|
1698
1904
|
return formatCodexUsageLimitErrorMessage({
|
|
@@ -1779,6 +1985,41 @@ var CodexAppServerEventProjector = class {
|
|
|
1779
1985
|
timestamp: Date.now()
|
|
1780
1986
|
};
|
|
1781
1987
|
}
|
|
1988
|
+
createToolCallMessage(params) {
|
|
1989
|
+
return {
|
|
1990
|
+
role: "assistant",
|
|
1991
|
+
content: [{
|
|
1992
|
+
type: "toolCall",
|
|
1993
|
+
id: params.id,
|
|
1994
|
+
name: params.name,
|
|
1995
|
+
arguments: normalizeToolTranscriptArguments(params.arguments)
|
|
1996
|
+
}],
|
|
1997
|
+
api: this.params.model.api ?? "openai-codex-responses",
|
|
1998
|
+
provider: this.params.provider,
|
|
1999
|
+
model: this.params.modelId,
|
|
2000
|
+
usage: ZERO_USAGE,
|
|
2001
|
+
stopReason: "toolUse",
|
|
2002
|
+
timestamp: Date.now()
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
createToolResultMessage(params) {
|
|
2006
|
+
const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
|
|
2007
|
+
return {
|
|
2008
|
+
role: "toolResult",
|
|
2009
|
+
toolCallId: params.id,
|
|
2010
|
+
toolName: params.name,
|
|
2011
|
+
isError: params.isError,
|
|
2012
|
+
content: [{
|
|
2013
|
+
type: "toolResult",
|
|
2014
|
+
toolCallId: params.id,
|
|
2015
|
+
toolUseId: params.id,
|
|
2016
|
+
tool_use_id: params.id,
|
|
2017
|
+
content: text,
|
|
2018
|
+
text
|
|
2019
|
+
}],
|
|
2020
|
+
timestamp: Date.now()
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
1782
2023
|
isNotificationForTurn(params) {
|
|
1783
2024
|
const threadId = readString$2(params, "threadId");
|
|
1784
2025
|
const turnId = readNotificationTurnId$1(params);
|
|
@@ -1813,13 +2054,13 @@ function readNumber(record, key) {
|
|
|
1813
2054
|
const value = record[key];
|
|
1814
2055
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1815
2056
|
}
|
|
1816
|
-
function readBoolean(record, key) {
|
|
2057
|
+
function readBoolean$1(record, key) {
|
|
1817
2058
|
const value = record[key];
|
|
1818
2059
|
return typeof value === "boolean" ? value : void 0;
|
|
1819
2060
|
}
|
|
1820
2061
|
function readBooleanAlias(record, keys) {
|
|
1821
2062
|
for (const key of keys) {
|
|
1822
|
-
const value = readBoolean(record, key);
|
|
2063
|
+
const value = readBoolean$1(record, key);
|
|
1823
2064
|
if (value !== void 0) return value;
|
|
1824
2065
|
}
|
|
1825
2066
|
}
|
|
@@ -2003,6 +2244,16 @@ function itemOutputText(item) {
|
|
|
2003
2244
|
return item.result ? stringifyJsonValue(item.result) : void 0;
|
|
2004
2245
|
}
|
|
2005
2246
|
}
|
|
2247
|
+
function itemTranscriptResultText(item) {
|
|
2248
|
+
const output = itemOutputText(item);
|
|
2249
|
+
if (output) return output;
|
|
2250
|
+
const result = itemToolResult(item).result;
|
|
2251
|
+
return result ? stringifyJsonValue(result) : itemStatus(item);
|
|
2252
|
+
}
|
|
2253
|
+
function normalizeToolTranscriptArguments(value) {
|
|
2254
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2255
|
+
return value;
|
|
2256
|
+
}
|
|
2006
2257
|
function collectDynamicToolContentText(contentItems) {
|
|
2007
2258
|
if (!Array.isArray(contentItems)) return "";
|
|
2008
2259
|
return contentItems.flatMap((entry) => {
|
|
@@ -2011,6 +2262,13 @@ function collectDynamicToolContentText(contentItems) {
|
|
|
2011
2262
|
return text ? [text] : [];
|
|
2012
2263
|
}).join("\n");
|
|
2013
2264
|
}
|
|
2265
|
+
function truncateToolTranscriptText(text) {
|
|
2266
|
+
if (text.length <= TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS) return text;
|
|
2267
|
+
return `${text.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)}\n...(truncated)...`;
|
|
2268
|
+
}
|
|
2269
|
+
function toolResultStatusText(params) {
|
|
2270
|
+
return params.isError ? `${params.name} failed` : `${params.name} completed`;
|
|
2271
|
+
}
|
|
2014
2272
|
function stringifyJsonValue(value) {
|
|
2015
2273
|
try {
|
|
2016
2274
|
return JSON.stringify(value, null, 2);
|
|
@@ -2111,62 +2369,17 @@ const JWT_VALUE_RE = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]
|
|
|
2111
2369
|
const COOKIE_PAIR_RE = /\b([A-Za-z][A-Za-z0-9_.-]{1,64})=([A-Za-z0-9+/._~%=-]{16,})(?=;|\s|$)/gu;
|
|
2112
2370
|
const TRAJECTORY_RUNTIME_FILE_MAX_BYTES = 50 * 1024 * 1024;
|
|
2113
2371
|
const TRAJECTORY_RUNTIME_EVENT_MAX_BYTES = 256 * 1024;
|
|
2114
|
-
function resolveCodexTrajectoryAppendFlags(constants = nodeFs.constants) {
|
|
2115
|
-
const noFollow = constants.O_NOFOLLOW;
|
|
2116
|
-
return constants.O_CREAT | constants.O_APPEND | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
|
|
2117
|
-
}
|
|
2118
2372
|
function resolveCodexTrajectoryPointerFlags(constants = nodeFs.constants) {
|
|
2119
2373
|
const noFollow = constants.O_NOFOLLOW;
|
|
2120
2374
|
return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY | (typeof noFollow === "number" ? noFollow : 0);
|
|
2121
2375
|
}
|
|
2122
|
-
async function assertNoSymlinkParents(filePath) {
|
|
2123
|
-
const resolvedDir = path.resolve(path.dirname(filePath));
|
|
2124
|
-
const parsed = path.parse(resolvedDir);
|
|
2125
|
-
const relativeParts = path.relative(parsed.root, resolvedDir).split(path.sep).filter(Boolean);
|
|
2126
|
-
let current = parsed.root;
|
|
2127
|
-
for (const part of relativeParts) {
|
|
2128
|
-
current = path.join(current, part);
|
|
2129
|
-
const stat = await fs.lstat(current);
|
|
2130
|
-
if (stat.isSymbolicLink()) {
|
|
2131
|
-
if (path.dirname(current) === parsed.root) continue;
|
|
2132
|
-
throw new Error(`Refusing to write trajectory under symlinked directory: ${current}`);
|
|
2133
|
-
}
|
|
2134
|
-
if (!stat.isDirectory()) throw new Error(`Refusing to write trajectory under non-directory: ${current}`);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
function verifyStableOpenedTrajectoryFile(params) {
|
|
2138
|
-
if (!params.postOpenStat.isFile()) throw new Error(`Refusing to write trajectory to non-file: ${params.filePath}`);
|
|
2139
|
-
if (params.postOpenStat.nlink > 1) throw new Error(`Refusing to write trajectory to hardlinked file: ${params.filePath}`);
|
|
2140
|
-
const pre = params.preOpenStat;
|
|
2141
|
-
if (pre && (pre.dev !== params.postOpenStat.dev || pre.ino !== params.postOpenStat.ino)) throw new Error(`Refusing to write trajectory after file changed: ${params.filePath}`);
|
|
2142
|
-
}
|
|
2143
2376
|
async function safeAppendTrajectoryFile(filePath, line) {
|
|
2144
|
-
await
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
preOpenStat = stat;
|
|
2151
|
-
} catch (err) {
|
|
2152
|
-
if (err.code !== "ENOENT") throw err;
|
|
2153
|
-
}
|
|
2154
|
-
const lineBytes = Buffer.byteLength(line, "utf8");
|
|
2155
|
-
if ((preOpenStat?.size ?? 0) + lineBytes > TRAJECTORY_RUNTIME_FILE_MAX_BYTES) return;
|
|
2156
|
-
const handle = await fs.open(filePath, resolveCodexTrajectoryAppendFlags(), 384);
|
|
2157
|
-
try {
|
|
2158
|
-
const stat = await handle.stat();
|
|
2159
|
-
verifyStableOpenedTrajectoryFile({
|
|
2160
|
-
preOpenStat,
|
|
2161
|
-
postOpenStat: stat,
|
|
2162
|
-
filePath
|
|
2163
|
-
});
|
|
2164
|
-
if (stat.size + lineBytes > TRAJECTORY_RUNTIME_FILE_MAX_BYTES) return;
|
|
2165
|
-
await handle.chmod(384);
|
|
2166
|
-
await handle.appendFile(line, "utf8");
|
|
2167
|
-
} finally {
|
|
2168
|
-
await handle.close();
|
|
2169
|
-
}
|
|
2377
|
+
await appendRegularFile({
|
|
2378
|
+
filePath,
|
|
2379
|
+
content: line,
|
|
2380
|
+
maxFileBytes: TRAJECTORY_RUNTIME_FILE_MAX_BYTES,
|
|
2381
|
+
rejectSymlinkParents: true
|
|
2382
|
+
});
|
|
2170
2383
|
}
|
|
2171
2384
|
function boundedTrajectoryLine(event) {
|
|
2172
2385
|
const line = JSON.stringify(event);
|
|
@@ -2289,7 +2502,7 @@ function parseTrajectoryEnabled(env) {
|
|
|
2289
2502
|
}
|
|
2290
2503
|
function resolveTrajectoryFilePath(params) {
|
|
2291
2504
|
const dirOverride = params.env.OPENCLAW_TRAJECTORY_DIR?.trim();
|
|
2292
|
-
if (dirOverride) return resolveContainedPath(resolveUserPath
|
|
2505
|
+
if (dirOverride) return resolveContainedPath(resolveUserPath(dirOverride), `${safeTrajectorySessionFileName(params.sessionId)}.jsonl`);
|
|
2293
2506
|
return params.sessionFile.endsWith(".jsonl") ? `${params.sessionFile.slice(0, -6)}.trajectory.jsonl` : `${params.sessionFile}.trajectory.jsonl`;
|
|
2294
2507
|
}
|
|
2295
2508
|
function safeTrajectorySessionFileName(sessionId) {
|
|
@@ -2528,9 +2741,14 @@ function filterToolsForVisionInputs(tools, params) {
|
|
|
2528
2741
|
//#endregion
|
|
2529
2742
|
//#region extensions/codex/src/app-server/run-attempt.ts
|
|
2530
2743
|
const CODEX_DYNAMIC_TOOL_TIMEOUT_MS = 3e4;
|
|
2744
|
+
const CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS = 6e5;
|
|
2745
|
+
const CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS = 6e4;
|
|
2531
2746
|
const CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS = 3;
|
|
2747
|
+
const CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS = 100;
|
|
2532
2748
|
const CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS = 6e4;
|
|
2533
2749
|
const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
2750
|
+
const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
|
|
2751
|
+
const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
|
|
2534
2752
|
const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
|
|
2535
2753
|
const LOG_FIELD_MAX_LENGTH = 160;
|
|
2536
2754
|
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
|
|
@@ -2544,7 +2762,12 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
|
|
|
2544
2762
|
["memory.md", 60],
|
|
2545
2763
|
["heartbeat.md", 70]
|
|
2546
2764
|
]);
|
|
2547
|
-
|
|
2765
|
+
const testClientFactoryStorage = new AsyncLocalStorage();
|
|
2766
|
+
const clientFactory = defaultCodexAppServerClientFactory;
|
|
2767
|
+
let openClawCodingToolsFactoryForTests;
|
|
2768
|
+
function resolveCodexAppServerClientFactory() {
|
|
2769
|
+
return testClientFactoryStorage.getStore() ?? clientFactory;
|
|
2770
|
+
}
|
|
2548
2771
|
function emitCodexAppServerEvent(params, event) {
|
|
2549
2772
|
try {
|
|
2550
2773
|
emitAgentEvent({
|
|
@@ -2680,11 +2903,42 @@ function toCodexTextInput(text) {
|
|
|
2680
2903
|
text_elements: []
|
|
2681
2904
|
};
|
|
2682
2905
|
}
|
|
2906
|
+
function resolveCodexPluginAppCacheEndpoint(appServer) {
|
|
2907
|
+
return JSON.stringify({
|
|
2908
|
+
transport: appServer.start.transport,
|
|
2909
|
+
command: appServer.start.command,
|
|
2910
|
+
args: appServer.start.args,
|
|
2911
|
+
url: appServer.start.url ?? null,
|
|
2912
|
+
credentialFingerprint: fingerprintCodexPluginAppCacheCredentials(appServer.start)
|
|
2913
|
+
});
|
|
2914
|
+
}
|
|
2915
|
+
function fingerprintCodexPluginAppCacheCredentials(startOptions) {
|
|
2916
|
+
const authToken = startOptions.authToken ?? "";
|
|
2917
|
+
const headers = Object.entries(startOptions.headers).map(([key, value]) => [key.toLowerCase(), value]).toSorted(([left], [right]) => left.localeCompare(right));
|
|
2918
|
+
if (!authToken && headers.length === 0) return null;
|
|
2919
|
+
const hash = createHash("sha256");
|
|
2920
|
+
hash.update("openclaw:codex:plugin-app-cache-credentials:v1");
|
|
2921
|
+
hash.update("\0");
|
|
2922
|
+
hash.update(authToken);
|
|
2923
|
+
for (const [key, value] of headers) {
|
|
2924
|
+
hash.update("\0");
|
|
2925
|
+
hash.update(key);
|
|
2926
|
+
hash.update("\0");
|
|
2927
|
+
hash.update(value);
|
|
2928
|
+
}
|
|
2929
|
+
return `sha256:${hash.digest("hex")}`;
|
|
2930
|
+
}
|
|
2931
|
+
function resolveCodexPluginAppCacheCodexHome(appServer, agentDir) {
|
|
2932
|
+
const configuredCodexHome = appServer.start.env?.CODEX_HOME?.trim();
|
|
2933
|
+
if (configuredCodexHome) return configuredCodexHome;
|
|
2934
|
+
return appServer.start.transport === "stdio" ? resolveCodexAppServerHomeDir(agentDir) : void 0;
|
|
2935
|
+
}
|
|
2683
2936
|
async function runCodexAppServerAttempt(params, options = {}) {
|
|
2684
2937
|
const attemptStartedAt = Date.now();
|
|
2685
|
-
const attemptClientFactory =
|
|
2938
|
+
const attemptClientFactory = resolveCodexAppServerClientFactory();
|
|
2686
2939
|
const pluginConfig = readCodexPluginConfig(options.pluginConfig);
|
|
2687
2940
|
const appServer = resolveCodexAppServerRuntimeOptions({ pluginConfig });
|
|
2941
|
+
let pluginAppServer = appServer;
|
|
2688
2942
|
const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
|
|
2689
2943
|
configuredEvents: options.nativeHookRelay?.events,
|
|
2690
2944
|
appServer
|
|
@@ -2710,7 +2964,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2710
2964
|
config: params.config,
|
|
2711
2965
|
agentId: params.agentId
|
|
2712
2966
|
});
|
|
2713
|
-
const agentDir = params.agentDir ??
|
|
2967
|
+
const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, sessionAgentId);
|
|
2714
2968
|
const startupBinding = await readCodexAppServerBinding(params.sessionFile);
|
|
2715
2969
|
const startupAuthProfileCandidate = params.runtimePlan?.auth.forwardedAuthProfileId ?? params.authProfileId ?? startupBinding?.authProfileId;
|
|
2716
2970
|
const startupAuthProfileId = params.authProfileStore ? resolveCodexAppServerAuthProfileId({
|
|
@@ -2727,6 +2981,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2727
2981
|
sessionKey: sandboxSessionKey,
|
|
2728
2982
|
...startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}
|
|
2729
2983
|
};
|
|
2984
|
+
const startupAuthAccountCacheKey = await resolveCodexAppServerAuthAccountCacheKey({
|
|
2985
|
+
authProfileId: startupAuthProfileId,
|
|
2986
|
+
authProfileStore: params.authProfileStore,
|
|
2987
|
+
agentDir,
|
|
2988
|
+
config: params.config
|
|
2989
|
+
});
|
|
2990
|
+
const startupEnvApiKeyCacheKey = startupAuthProfileId ? void 0 : resolveCodexAppServerEnvApiKeyCacheKey({ startOptions: appServer.start });
|
|
2730
2991
|
const activeContextEngine = isActiveHarnessContextEngine(params.contextEngine) ? params.contextEngine : void 0;
|
|
2731
2992
|
let yieldDetected = false;
|
|
2732
2993
|
const toolBridge = createCodexDynamicToolBridge({
|
|
@@ -2744,6 +3005,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2744
3005
|
}
|
|
2745
3006
|
}),
|
|
2746
3007
|
signal: runAbortController.signal,
|
|
3008
|
+
loading: pluginConfig.codexDynamicToolsLoading ?? "searchable",
|
|
3009
|
+
directToolNames: shouldForceMessageTool(params) ? ["message"] : [],
|
|
2747
3010
|
hookContext: {
|
|
2748
3011
|
agentId: sessionAgentId,
|
|
2749
3012
|
config: params.config,
|
|
@@ -2752,7 +3015,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2752
3015
|
runId: params.runId
|
|
2753
3016
|
}
|
|
2754
3017
|
});
|
|
2755
|
-
const hadSessionFile = await
|
|
3018
|
+
const hadSessionFile = await pathExists(params.sessionFile);
|
|
2756
3019
|
let historyMessages = await readMirroredSessionHistoryMessages(params.sessionFile) ?? [];
|
|
2757
3020
|
const hookContext = {
|
|
2758
3021
|
runId: params.runId,
|
|
@@ -2784,8 +3047,15 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2784
3047
|
historyMessages = await readMirroredSessionHistoryMessages(params.sessionFile) ?? historyMessages;
|
|
2785
3048
|
}
|
|
2786
3049
|
const baseDeveloperInstructions = buildDeveloperInstructions(params);
|
|
3050
|
+
const workspaceBootstrapInstructions = await buildCodexWorkspaceBootstrapInstructions({
|
|
3051
|
+
params,
|
|
3052
|
+
resolvedWorkspace,
|
|
3053
|
+
effectiveWorkspace,
|
|
3054
|
+
sessionKey: sandboxSessionKey,
|
|
3055
|
+
sessionAgentId
|
|
3056
|
+
});
|
|
2787
3057
|
let promptText = params.prompt;
|
|
2788
|
-
let developerInstructions = baseDeveloperInstructions;
|
|
3058
|
+
let developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
|
|
2789
3059
|
let prePromptMessageCount = historyMessages.length;
|
|
2790
3060
|
if (activeContextEngine) try {
|
|
2791
3061
|
const assembled = await assembleHarnessContextEngine({
|
|
@@ -2807,7 +3077,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2807
3077
|
systemPromptAddition: assembled.systemPromptAddition
|
|
2808
3078
|
});
|
|
2809
3079
|
promptText = projection.promptText;
|
|
2810
|
-
developerInstructions = joinPresentSections(baseDeveloperInstructions, projection.developerInstructionAddition);
|
|
3080
|
+
developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions, projection.developerInstructionAddition);
|
|
2811
3081
|
prePromptMessageCount = projection.prePromptMessageCount;
|
|
2812
3082
|
} catch (assembleErr) {
|
|
2813
3083
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
@@ -2831,13 +3101,6 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2831
3101
|
messages: historyMessages,
|
|
2832
3102
|
ctx: hookContext
|
|
2833
3103
|
});
|
|
2834
|
-
const workspaceBootstrapInstructions = await buildCodexWorkspaceBootstrapInstructions({
|
|
2835
|
-
params,
|
|
2836
|
-
resolvedWorkspace,
|
|
2837
|
-
effectiveWorkspace,
|
|
2838
|
-
sessionKey: sandboxSessionKey,
|
|
2839
|
-
sessionAgentId
|
|
2840
|
-
});
|
|
2841
3104
|
const trajectoryRecorder = createCodexTrajectoryRecorder({
|
|
2842
3105
|
attempt: params,
|
|
2843
3106
|
cwd: effectiveWorkspace,
|
|
@@ -2850,6 +3113,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2850
3113
|
let trajectoryEndRecorded = false;
|
|
2851
3114
|
let nativeHookRelay;
|
|
2852
3115
|
let startupClientForCleanup;
|
|
3116
|
+
const startupTimeoutMs = resolveCodexStartupTimeoutMs({
|
|
3117
|
+
timeoutMs: params.timeoutMs,
|
|
3118
|
+
timeoutFloorMs: options.startupTimeoutFloorMs
|
|
3119
|
+
});
|
|
2853
3120
|
try {
|
|
2854
3121
|
emitCodexAppServerEvent(params, {
|
|
2855
3122
|
stream: "codex_app_server.lifecycle",
|
|
@@ -2863,16 +3130,36 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2863
3130
|
sessionKey: sandboxSessionKey,
|
|
2864
3131
|
config: params.config,
|
|
2865
3132
|
runId: params.runId,
|
|
3133
|
+
attemptTimeoutMs: params.timeoutMs,
|
|
3134
|
+
startupTimeoutMs,
|
|
3135
|
+
turnStartTimeoutMs: params.timeoutMs,
|
|
2866
3136
|
signal: runAbortController.signal
|
|
2867
3137
|
});
|
|
2868
|
-
const threadConfig =
|
|
3138
|
+
const threadConfig = nativeHookRelay ? buildCodexNativeHookRelayConfig({
|
|
2869
3139
|
relay: nativeHookRelay,
|
|
2870
3140
|
events: nativeHookRelayEvents,
|
|
2871
3141
|
hookTimeoutSec: options.nativeHookRelay?.hookTimeoutSec
|
|
2872
|
-
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0
|
|
3142
|
+
}) : options.nativeHookRelay?.enabled === false ? buildCodexNativeHookRelayDisabledConfig() : void 0;
|
|
3143
|
+
const pluginThreadConfigEnabled = shouldBuildCodexPluginThreadConfig(pluginConfig);
|
|
3144
|
+
const pluginAppCacheKey = buildCodexAppInventoryCacheKey({
|
|
3145
|
+
codexHome: resolveCodexPluginAppCacheCodexHome(appServer, agentDir),
|
|
3146
|
+
endpoint: resolveCodexPluginAppCacheEndpoint(appServer),
|
|
3147
|
+
authProfileId: startupAuthProfileId,
|
|
3148
|
+
accountId: startupAuthAccountCacheKey,
|
|
3149
|
+
envApiKeyFingerprint: startupEnvApiKeyCacheKey
|
|
3150
|
+
});
|
|
3151
|
+
const pluginThreadConfigInputFingerprint = pluginThreadConfigEnabled ? buildCodexPluginThreadConfigInputFingerprint({
|
|
3152
|
+
pluginConfig,
|
|
3153
|
+
appCacheKey: pluginAppCacheKey
|
|
3154
|
+
}) : void 0;
|
|
3155
|
+
const resolvedPluginPolicy = pluginThreadConfigEnabled ? resolveCodexPluginsPolicy(pluginConfig) : void 0;
|
|
3156
|
+
const enabledPluginConfigKeys = resolvedPluginPolicy ? resolvedPluginPolicy.pluginPolicies.filter((plugin) => plugin.enabled).map((plugin) => plugin.configKey).toSorted() : void 0;
|
|
3157
|
+
pluginAppServer = resolvedPluginPolicy?.enabled === true ? {
|
|
3158
|
+
...appServer,
|
|
3159
|
+
approvalPolicy: withMcpElicitationsApprovalPolicy(appServer.approvalPolicy)
|
|
3160
|
+
} : appServer;
|
|
2873
3161
|
({client, thread} = await withCodexStartupTimeout({
|
|
2874
|
-
timeoutMs:
|
|
2875
|
-
timeoutFloorMs: options.startupTimeoutFloorMs,
|
|
3162
|
+
timeoutMs: startupTimeoutMs,
|
|
2876
3163
|
signal: runAbortController.signal,
|
|
2877
3164
|
operation: async () => {
|
|
2878
3165
|
let attemptedClient;
|
|
@@ -2893,9 +3180,23 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2893
3180
|
params: runtimeParams,
|
|
2894
3181
|
cwd: effectiveWorkspace,
|
|
2895
3182
|
dynamicTools: toolBridge.specs,
|
|
2896
|
-
appServer,
|
|
3183
|
+
appServer: pluginAppServer,
|
|
2897
3184
|
developerInstructions: promptBuild.developerInstructions,
|
|
2898
|
-
config: threadConfig
|
|
3185
|
+
config: threadConfig,
|
|
3186
|
+
pluginThreadConfig: pluginThreadConfigEnabled ? {
|
|
3187
|
+
enabled: true,
|
|
3188
|
+
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
3189
|
+
enabledPluginConfigKeys,
|
|
3190
|
+
build: () => buildCodexPluginThreadConfig({
|
|
3191
|
+
pluginConfig,
|
|
3192
|
+
request: (method, requestParams) => startupClient.request(method, requestParams, {
|
|
3193
|
+
timeoutMs: appServer.requestTimeoutMs,
|
|
3194
|
+
signal: runAbortController.signal
|
|
3195
|
+
}),
|
|
3196
|
+
appCache: defaultCodexAppInventoryCache,
|
|
3197
|
+
appCacheKey: pluginAppCacheKey
|
|
3198
|
+
})
|
|
3199
|
+
} : void 0
|
|
2899
3200
|
})
|
|
2900
3201
|
};
|
|
2901
3202
|
};
|
|
@@ -2971,14 +3272,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2971
3272
|
resolveCompletion = resolve;
|
|
2972
3273
|
});
|
|
2973
3274
|
let notificationQueue = Promise.resolve();
|
|
2974
|
-
const turnCompletionIdleTimeoutMs = resolveCodexTurnCompletionIdleTimeoutMs(options.turnCompletionIdleTimeoutMs);
|
|
3275
|
+
const turnCompletionIdleTimeoutMs = resolveCodexTurnCompletionIdleTimeoutMs(options.turnCompletionIdleTimeoutMs ?? appServer.turnCompletionIdleTimeoutMs);
|
|
2975
3276
|
const turnTerminalIdleTimeoutMs = resolveCodexTurnTerminalIdleTimeoutMs(options.turnTerminalIdleTimeoutMs);
|
|
2976
3277
|
let turnCompletionIdleTimer;
|
|
2977
3278
|
let turnCompletionIdleWatchArmed = false;
|
|
3279
|
+
let turnCompletionIdleWatchPinnedByTerminalError = false;
|
|
2978
3280
|
let turnTerminalIdleTimer;
|
|
2979
3281
|
let turnTerminalIdleWatchArmed = false;
|
|
2980
3282
|
let turnCompletionLastActivityAt = Date.now();
|
|
2981
3283
|
let turnCompletionLastActivityReason = "startup";
|
|
3284
|
+
let turnCompletionLastActivityDetails;
|
|
2982
3285
|
let activeAppServerTurnRequests = 0;
|
|
2983
3286
|
const clearTurnCompletionIdleTimer = () => {
|
|
2984
3287
|
if (turnCompletionIdleTimer) {
|
|
@@ -3008,14 +3311,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3008
3311
|
turnId,
|
|
3009
3312
|
idleMs,
|
|
3010
3313
|
timeoutMs: turnCompletionIdleTimeoutMs,
|
|
3011
|
-
lastActivityReason: turnCompletionLastActivityReason
|
|
3314
|
+
lastActivityReason: turnCompletionLastActivityReason,
|
|
3315
|
+
...turnCompletionLastActivityDetails
|
|
3012
3316
|
});
|
|
3013
3317
|
embeddedAgentLog.warn("codex app-server turn idle timed out waiting for completion", {
|
|
3014
3318
|
threadId: thread.threadId,
|
|
3015
3319
|
turnId,
|
|
3016
3320
|
idleMs,
|
|
3017
3321
|
timeoutMs: turnCompletionIdleTimeoutMs,
|
|
3018
|
-
lastActivityReason: turnCompletionLastActivityReason
|
|
3322
|
+
lastActivityReason: turnCompletionLastActivityReason,
|
|
3323
|
+
...turnCompletionLastActivityDetails
|
|
3019
3324
|
});
|
|
3020
3325
|
runAbortController.abort("turn_completion_idle_timeout");
|
|
3021
3326
|
};
|
|
@@ -3035,14 +3340,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3035
3340
|
turnId,
|
|
3036
3341
|
idleMs,
|
|
3037
3342
|
timeoutMs: turnTerminalIdleTimeoutMs,
|
|
3038
|
-
lastActivityReason: turnCompletionLastActivityReason
|
|
3343
|
+
lastActivityReason: turnCompletionLastActivityReason,
|
|
3344
|
+
...turnCompletionLastActivityDetails
|
|
3039
3345
|
});
|
|
3040
3346
|
embeddedAgentLog.warn("codex app-server turn idle timed out waiting for terminal event", {
|
|
3041
3347
|
threadId: thread.threadId,
|
|
3042
3348
|
turnId,
|
|
3043
3349
|
idleMs,
|
|
3044
3350
|
timeoutMs: turnTerminalIdleTimeoutMs,
|
|
3045
|
-
lastActivityReason: turnCompletionLastActivityReason
|
|
3351
|
+
lastActivityReason: turnCompletionLastActivityReason,
|
|
3352
|
+
...turnCompletionLastActivityDetails
|
|
3046
3353
|
});
|
|
3047
3354
|
runAbortController.abort("turn_terminal_idle_timeout");
|
|
3048
3355
|
};
|
|
@@ -3065,6 +3372,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3065
3372
|
const touchTurnCompletionActivity = (reason, options) => {
|
|
3066
3373
|
turnCompletionLastActivityAt = Date.now();
|
|
3067
3374
|
turnCompletionLastActivityReason = reason;
|
|
3375
|
+
turnCompletionLastActivityDetails = options?.details;
|
|
3068
3376
|
emitTrustedDiagnosticEvent({
|
|
3069
3377
|
type: "run.progress",
|
|
3070
3378
|
runId: params.runId,
|
|
@@ -3072,10 +3380,23 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3072
3380
|
sessionKey: params.sessionKey,
|
|
3073
3381
|
reason: `codex_app_server:${reason}`
|
|
3074
3382
|
});
|
|
3075
|
-
if (options?.arm)
|
|
3383
|
+
if (options?.arm) {
|
|
3384
|
+
turnCompletionIdleWatchArmed = true;
|
|
3385
|
+
turnCompletionIdleWatchPinnedByTerminalError = false;
|
|
3386
|
+
}
|
|
3076
3387
|
scheduleTurnCompletionIdleWatch();
|
|
3077
3388
|
scheduleTurnTerminalIdleWatch();
|
|
3078
3389
|
};
|
|
3390
|
+
const disarmTurnCompletionIdleWatch = () => {
|
|
3391
|
+
turnCompletionIdleWatchArmed = false;
|
|
3392
|
+
turnCompletionIdleWatchPinnedByTerminalError = false;
|
|
3393
|
+
clearTurnCompletionIdleTimer();
|
|
3394
|
+
};
|
|
3395
|
+
const armTurnCompletionIdleWatch = (options) => {
|
|
3396
|
+
turnCompletionIdleWatchArmed = true;
|
|
3397
|
+
turnCompletionIdleWatchPinnedByTerminalError = options?.pinnedByTerminalError === true;
|
|
3398
|
+
scheduleTurnCompletionIdleWatch();
|
|
3399
|
+
};
|
|
3079
3400
|
const emitLifecycleStart = () => {
|
|
3080
3401
|
emitCodexAppServerEvent(params, {
|
|
3081
3402
|
stream: "lifecycle",
|
|
@@ -3099,13 +3420,17 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3099
3420
|
lifecycleTerminalEmitted = true;
|
|
3100
3421
|
};
|
|
3101
3422
|
const handleNotification = async (notification) => {
|
|
3102
|
-
touchTurnCompletionActivity(`notification:${notification.method}`);
|
|
3103
3423
|
userInputBridge?.handleNotification(notification);
|
|
3104
3424
|
if (!projector || !turnId) {
|
|
3105
3425
|
pendingNotifications.push(notification);
|
|
3106
3426
|
return;
|
|
3107
3427
|
}
|
|
3108
|
-
const
|
|
3428
|
+
const isCurrentTurnNotification = isTurnNotification(notification.params, thread.threadId, turnId);
|
|
3429
|
+
if (isCurrentTurnNotification) touchTurnCompletionActivity(`notification:${notification.method}`, { details: describeNotificationActivity(notification) });
|
|
3430
|
+
if (isCurrentTurnNotification && notification.method === "error") if (isRetryableErrorNotification(notification.params)) disarmTurnCompletionIdleWatch();
|
|
3431
|
+
else armTurnCompletionIdleWatch({ pinnedByTerminalError: true });
|
|
3432
|
+
else if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification) disarmTurnCompletionIdleWatch();
|
|
3433
|
+
const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
|
|
3109
3434
|
try {
|
|
3110
3435
|
await projector.handleNotification(notification);
|
|
3111
3436
|
} catch (error) {
|
|
@@ -3136,7 +3461,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3136
3461
|
try {
|
|
3137
3462
|
if (request.method === "account/chatgptAuthTokens/refresh") return refreshCodexAppServerAuthTokens({
|
|
3138
3463
|
agentDir,
|
|
3139
|
-
authProfileId: startupAuthProfileId
|
|
3464
|
+
authProfileId: startupAuthProfileId,
|
|
3465
|
+
config: params.config
|
|
3140
3466
|
});
|
|
3141
3467
|
if (!turnId) return;
|
|
3142
3468
|
if (request.method === "mcpServer/elicitation/request") {
|
|
@@ -3146,6 +3472,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3146
3472
|
paramsForRun: params,
|
|
3147
3473
|
threadId: thread.threadId,
|
|
3148
3474
|
turnId,
|
|
3475
|
+
pluginAppPolicyContext: thread.pluginAppPolicyContext,
|
|
3149
3476
|
signal: runAbortController.signal
|
|
3150
3477
|
});
|
|
3151
3478
|
}
|
|
@@ -3180,6 +3507,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3180
3507
|
name: call.tool,
|
|
3181
3508
|
arguments: call.arguments
|
|
3182
3509
|
});
|
|
3510
|
+
projector?.recordDynamicToolCall({
|
|
3511
|
+
callId: call.callId,
|
|
3512
|
+
tool: call.tool,
|
|
3513
|
+
arguments: call.arguments
|
|
3514
|
+
});
|
|
3183
3515
|
const toolMeta = inferCodexDynamicToolMeta(call, resolveCodexToolProgressDetailMode(params.toolProgressDetail));
|
|
3184
3516
|
const toolArgs = sanitizeCodexToolArguments(call.arguments);
|
|
3185
3517
|
emitCodexAppServerEvent(params, {
|
|
@@ -3192,18 +3524,22 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3192
3524
|
...toolArgs ? { args: toolArgs } : {}
|
|
3193
3525
|
}
|
|
3194
3526
|
});
|
|
3527
|
+
const dynamicToolTimeoutMs = resolveDynamicToolCallTimeoutMs({
|
|
3528
|
+
call,
|
|
3529
|
+
config: params.config
|
|
3530
|
+
});
|
|
3195
3531
|
const response = await handleDynamicToolCallWithTimeout({
|
|
3196
3532
|
call,
|
|
3197
3533
|
toolBridge,
|
|
3198
3534
|
signal: runAbortController.signal,
|
|
3199
|
-
timeoutMs:
|
|
3535
|
+
timeoutMs: dynamicToolTimeoutMs,
|
|
3200
3536
|
onTimeout: () => {
|
|
3201
3537
|
trajectoryRecorder?.recordEvent("tool.timeout", {
|
|
3202
3538
|
threadId: call.threadId,
|
|
3203
3539
|
turnId: call.turnId,
|
|
3204
3540
|
toolCallId: call.callId,
|
|
3205
3541
|
name: call.tool,
|
|
3206
|
-
timeoutMs:
|
|
3542
|
+
timeoutMs: dynamicToolTimeoutMs
|
|
3207
3543
|
});
|
|
3208
3544
|
}
|
|
3209
3545
|
});
|
|
@@ -3215,6 +3551,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3215
3551
|
success: response.success,
|
|
3216
3552
|
contentItems: response.contentItems
|
|
3217
3553
|
});
|
|
3554
|
+
projector?.recordDynamicToolResult({
|
|
3555
|
+
callId: call.callId,
|
|
3556
|
+
tool: call.tool,
|
|
3557
|
+
success: response.success,
|
|
3558
|
+
contentItems: response.contentItems
|
|
3559
|
+
});
|
|
3218
3560
|
emitCodexAppServerEvent(params, {
|
|
3219
3561
|
stream: "tool",
|
|
3220
3562
|
data: {
|
|
@@ -3265,7 +3607,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3265
3607
|
turn = assertCodexTurnStartResponse(await client.request("turn/start", buildTurnStartParams(params, {
|
|
3266
3608
|
threadId: thread.threadId,
|
|
3267
3609
|
cwd: effectiveWorkspace,
|
|
3268
|
-
appServer,
|
|
3610
|
+
appServer: pluginAppServer,
|
|
3269
3611
|
promptText: promptBuild.prompt
|
|
3270
3612
|
}), {
|
|
3271
3613
|
timeoutMs: params.timeoutMs,
|
|
@@ -3535,7 +3877,7 @@ async function handleDynamicToolCallWithTimeout(params) {
|
|
|
3535
3877
|
resolveAbort = resolve;
|
|
3536
3878
|
});
|
|
3537
3879
|
const timeoutPromise = new Promise((resolve) => {
|
|
3538
|
-
const timeoutMs =
|
|
3880
|
+
const timeoutMs = clampDynamicToolTimeoutMs(params.timeoutMs);
|
|
3539
3881
|
timeout = setTimeout(() => {
|
|
3540
3882
|
timedOut = true;
|
|
3541
3883
|
const timeoutDetails = formatDynamicToolTimeoutDetails({
|
|
@@ -3578,6 +3920,31 @@ function failedDynamicToolResponse(message) {
|
|
|
3578
3920
|
}]
|
|
3579
3921
|
};
|
|
3580
3922
|
}
|
|
3923
|
+
function resolveDynamicToolCallTimeoutMs(params) {
|
|
3924
|
+
return clampDynamicToolTimeoutMs(readDynamicToolCallTimeoutMs(params.call.arguments) ?? readConfiguredDynamicToolTimeoutMs(params.call.tool, params.config) ?? CODEX_DYNAMIC_TOOL_TIMEOUT_MS);
|
|
3925
|
+
}
|
|
3926
|
+
function readDynamicToolCallTimeoutMs(value) {
|
|
3927
|
+
if (!isJsonObject(value)) return;
|
|
3928
|
+
return readPositiveFiniteTimeoutMs(value.timeoutMs);
|
|
3929
|
+
}
|
|
3930
|
+
function readConfiguredDynamicToolTimeoutMs(toolName, config) {
|
|
3931
|
+
if (toolName === "image_generate") {
|
|
3932
|
+
const imageGenerationModel = config?.agents?.defaults?.imageGenerationModel;
|
|
3933
|
+
if (!imageGenerationModel || typeof imageGenerationModel !== "object") return;
|
|
3934
|
+
return readPositiveFiniteTimeoutMs(imageGenerationModel.timeoutMs);
|
|
3935
|
+
}
|
|
3936
|
+
if (toolName === "image") return readTimeoutSecondsAsMs(config?.tools?.media?.image?.timeoutSeconds) ?? CODEX_DYNAMIC_IMAGE_TOOL_TIMEOUT_MS;
|
|
3937
|
+
}
|
|
3938
|
+
function readTimeoutSecondsAsMs(value) {
|
|
3939
|
+
const seconds = readPositiveFiniteTimeoutMs(value);
|
|
3940
|
+
return seconds === void 0 ? void 0 : seconds * 1e3;
|
|
3941
|
+
}
|
|
3942
|
+
function readPositiveFiniteTimeoutMs(value) {
|
|
3943
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : void 0;
|
|
3944
|
+
}
|
|
3945
|
+
function clampDynamicToolTimeoutMs(timeoutMs) {
|
|
3946
|
+
return Math.max(1, Math.min(CODEX_DYNAMIC_TOOL_MAX_TIMEOUT_MS, Math.floor(timeoutMs)));
|
|
3947
|
+
}
|
|
3581
3948
|
function createCodexNativeHookRelay(params) {
|
|
3582
3949
|
if (params.options?.enabled === false) return;
|
|
3583
3950
|
return registerNativeHookRelay({
|
|
@@ -3593,7 +3960,12 @@ function createCodexNativeHookRelay(params) {
|
|
|
3593
3960
|
...params.config ? { config: params.config } : {},
|
|
3594
3961
|
runId: params.runId,
|
|
3595
3962
|
allowedEvents: params.events,
|
|
3596
|
-
ttlMs:
|
|
3963
|
+
ttlMs: resolveCodexNativeHookRelayTtlMs({
|
|
3964
|
+
explicitTtlMs: params.options?.ttlMs,
|
|
3965
|
+
attemptTimeoutMs: params.attemptTimeoutMs,
|
|
3966
|
+
startupTimeoutMs: params.startupTimeoutMs,
|
|
3967
|
+
turnStartTimeoutMs: params.turnStartTimeoutMs
|
|
3968
|
+
}),
|
|
3597
3969
|
signal: params.signal,
|
|
3598
3970
|
command: { timeoutMs: params.options?.gatewayTimeoutMs }
|
|
3599
3971
|
});
|
|
@@ -3602,6 +3974,11 @@ function resolveCodexNativeHookRelayEvents(params) {
|
|
|
3602
3974
|
if (params.configuredEvents?.length) return params.configuredEvents;
|
|
3603
3975
|
return params.appServer.approvalPolicy === "never" ? CODEX_NATIVE_HOOK_RELAY_EVENTS : CODEX_NATIVE_HOOK_RELAY_EVENTS_WITH_APP_SERVER_APPROVALS;
|
|
3604
3976
|
}
|
|
3977
|
+
function resolveCodexNativeHookRelayTtlMs(params) {
|
|
3978
|
+
if (params.explicitTtlMs !== void 0) return params.explicitTtlMs;
|
|
3979
|
+
const relayBudgetMs = params.attemptTimeoutMs + params.startupTimeoutMs + params.turnStartTimeoutMs + CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
|
|
3980
|
+
return Math.max(CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS, Math.floor(relayBudgetMs));
|
|
3981
|
+
}
|
|
3605
3982
|
function buildCodexNativeHookRelayId(params) {
|
|
3606
3983
|
const hash = createHash("sha256");
|
|
3607
3984
|
hash.update("openclaw:codex:native-hook-relay:v1");
|
|
@@ -3616,13 +3993,20 @@ function interruptCodexTurnBestEffort(client, params) {
|
|
|
3616
3993
|
embeddedAgentLog.debug("codex app-server turn interrupt failed during abort", { error });
|
|
3617
3994
|
});
|
|
3618
3995
|
}
|
|
3996
|
+
function resolveOpenClawCodingToolsSessionKeys(params, sandboxSessionKey) {
|
|
3997
|
+
return {
|
|
3998
|
+
sessionKey: sandboxSessionKey,
|
|
3999
|
+
runSessionKey: params.sessionKey && params.sessionKey !== sandboxSessionKey ? params.sessionKey : void 0
|
|
4000
|
+
};
|
|
4001
|
+
}
|
|
3619
4002
|
async function buildDynamicTools(input) {
|
|
3620
4003
|
const { params } = input;
|
|
3621
4004
|
if (params.disableTools || !supportsModelTools(params.model)) return [];
|
|
3622
4005
|
const modelHasVision = params.model.input?.includes("image") ?? false;
|
|
3623
|
-
const agentDir = params.agentDir ??
|
|
3624
|
-
const
|
|
3625
|
-
const
|
|
4006
|
+
const agentDir = params.agentDir ?? resolveAgentDir(params.config ?? {}, input.sessionAgentId);
|
|
4007
|
+
const createOpenClawCodingTools = openClawCodingToolsFactoryForTests ?? (await import("openclaw/plugin-sdk/agent-harness")).createOpenClawCodingTools;
|
|
4008
|
+
const sessionKeys = resolveOpenClawCodingToolsSessionKeys(params, input.sandboxSessionKey);
|
|
4009
|
+
const filteredTools = filterCodexDynamicToolsForAllowlist(filterToolsForVisionInputs(filterCodexDynamicTools(createOpenClawCodingTools({
|
|
3626
4010
|
agentId: input.sessionAgentId,
|
|
3627
4011
|
...buildEmbeddedAttemptToolRunContext(params),
|
|
3628
4012
|
exec: {
|
|
@@ -3644,8 +4028,7 @@ async function buildDynamicTools(input) {
|
|
|
3644
4028
|
senderE164: params.senderE164,
|
|
3645
4029
|
senderIsOwner: params.senderIsOwner,
|
|
3646
4030
|
allowGatewaySubagentBinding: params.allowGatewaySubagentBinding,
|
|
3647
|
-
|
|
3648
|
-
runSessionKey: params.sessionKey && params.sessionKey !== input.sandboxSessionKey ? params.sessionKey : void 0,
|
|
4031
|
+
...sessionKeys,
|
|
3649
4032
|
sessionId: params.sessionId,
|
|
3650
4033
|
runId: params.runId,
|
|
3651
4034
|
agentDir,
|
|
@@ -3670,8 +4053,9 @@ async function buildDynamicTools(input) {
|
|
|
3670
4053
|
hasRepliedRef: params.hasRepliedRef,
|
|
3671
4054
|
modelHasVision,
|
|
3672
4055
|
requireExplicitMessageTarget: params.requireExplicitMessageTarget ?? isSubagentSessionKey(params.sessionKey),
|
|
4056
|
+
sourceReplyDeliveryMode: params.sourceReplyDeliveryMode,
|
|
3673
4057
|
disableMessageTool: params.disableMessageTool,
|
|
3674
|
-
forceMessageTool: params
|
|
4058
|
+
forceMessageTool: shouldForceMessageTool(params),
|
|
3675
4059
|
enableHeartbeatTool: params.trigger === "heartbeat",
|
|
3676
4060
|
forceHeartbeatTool: params.trigger === "heartbeat",
|
|
3677
4061
|
onYield: (message) => {
|
|
@@ -3688,8 +4072,7 @@ async function buildDynamicTools(input) {
|
|
|
3688
4072
|
}), input.pluginConfig), {
|
|
3689
4073
|
modelHasVision,
|
|
3690
4074
|
hasInboundImages: (params.images?.length ?? 0) > 0
|
|
3691
|
-
});
|
|
3692
|
-
const filteredTools = params.toolsAllow && params.toolsAllow.length > 0 ? visionFilteredTools.filter((tool) => params.toolsAllow?.includes(tool.name)) : visionFilteredTools;
|
|
4075
|
+
}), params.toolsAllow);
|
|
3693
4076
|
return normalizeAgentRuntimeTools({
|
|
3694
4077
|
runtimePlan: params.runtimePlan,
|
|
3695
4078
|
tools: filteredTools,
|
|
@@ -3702,6 +4085,14 @@ async function buildDynamicTools(input) {
|
|
|
3702
4085
|
model: params.model
|
|
3703
4086
|
});
|
|
3704
4087
|
}
|
|
4088
|
+
function filterCodexDynamicToolsForAllowlist(tools, toolsAllow) {
|
|
4089
|
+
if (!toolsAllow || toolsAllow.length === 0) return tools;
|
|
4090
|
+
const allowSet = new Set(toolsAllow.map((name) => normalizeCodexDynamicToolName(name)).filter(Boolean));
|
|
4091
|
+
return tools.filter((tool) => allowSet.has(normalizeCodexDynamicToolName(tool.name)));
|
|
4092
|
+
}
|
|
4093
|
+
function shouldForceMessageTool(params) {
|
|
4094
|
+
return params.sourceReplyDeliveryMode === "message_tool_only";
|
|
4095
|
+
}
|
|
3705
4096
|
function shouldProjectMirroredHistoryForCodexStart(params) {
|
|
3706
4097
|
if (!params.historyMessages.some((message) => message.role === "user")) return false;
|
|
3707
4098
|
if (!params.startupBinding?.threadId) return true;
|
|
@@ -3723,10 +4114,9 @@ async function withCodexStartupTimeout(params) {
|
|
|
3723
4114
|
}
|
|
3724
4115
|
reject(error);
|
|
3725
4116
|
};
|
|
3726
|
-
const timeoutMs = Math.max(params.timeoutFloorMs ?? 100, params.timeoutMs);
|
|
3727
4117
|
timeout = setTimeout(() => {
|
|
3728
4118
|
rejectOnce(/* @__PURE__ */ new Error("codex app-server startup timed out"));
|
|
3729
|
-
}, timeoutMs);
|
|
4119
|
+
}, params.timeoutMs);
|
|
3730
4120
|
const abortListener = () => rejectOnce(/* @__PURE__ */ new Error("codex app-server startup aborted"));
|
|
3731
4121
|
params.signal.addEventListener("abort", abortListener, { once: true });
|
|
3732
4122
|
abortCleanup = () => params.signal.removeEventListener("abort", abortListener);
|
|
@@ -3736,6 +4126,9 @@ async function withCodexStartupTimeout(params) {
|
|
|
3736
4126
|
abortCleanup?.();
|
|
3737
4127
|
}
|
|
3738
4128
|
}
|
|
4129
|
+
function resolveCodexStartupTimeoutMs(params) {
|
|
4130
|
+
return Math.max(params.timeoutFloorMs ?? CODEX_APP_SERVER_STARTUP_TIMEOUT_FLOOR_MS, params.timeoutMs);
|
|
4131
|
+
}
|
|
3739
4132
|
function resolveCodexTurnCompletionIdleTimeoutMs(value) {
|
|
3740
4133
|
if (value === void 0) return CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS;
|
|
3741
4134
|
if (!Number.isFinite(value)) return CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS;
|
|
@@ -3791,10 +4184,37 @@ function readCodexErrorPayload(error) {
|
|
|
3791
4184
|
rateLimits: nestedError.rateLimits ?? data.rateLimits
|
|
3792
4185
|
};
|
|
3793
4186
|
}
|
|
4187
|
+
function describeNotificationActivity(notification) {
|
|
4188
|
+
if (!isJsonObject(notification.params)) return { lastNotificationMethod: notification.method };
|
|
4189
|
+
if (notification.method !== "rawResponseItem/completed") return { lastNotificationMethod: notification.method };
|
|
4190
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
4191
|
+
if (!item) return { lastNotificationMethod: notification.method };
|
|
4192
|
+
return {
|
|
4193
|
+
lastNotificationMethod: notification.method,
|
|
4194
|
+
lastNotificationItemId: readString(item, "id"),
|
|
4195
|
+
lastNotificationItemType: readString(item, "type"),
|
|
4196
|
+
lastNotificationItemRole: readString(item, "role"),
|
|
4197
|
+
lastAssistantTextPreview: readRawAssistantTextPreview(item)
|
|
4198
|
+
};
|
|
4199
|
+
}
|
|
4200
|
+
function readRawAssistantTextPreview(item) {
|
|
4201
|
+
if (readString(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
|
|
4202
|
+
const text = item.content.flatMap((content) => {
|
|
4203
|
+
if (!isJsonObject(content)) return [];
|
|
4204
|
+
const contentText = readString(content, "text");
|
|
4205
|
+
return contentText ? [contentText] : [];
|
|
4206
|
+
}).join("\n").trim();
|
|
4207
|
+
if (!text) return;
|
|
4208
|
+
return text.length > 240 ? `${text.slice(0, 237)}...` : text;
|
|
4209
|
+
}
|
|
3794
4210
|
function isTurnNotification(value, threadId, turnId) {
|
|
3795
4211
|
if (!isJsonObject(value)) return false;
|
|
3796
4212
|
return readString(value, "threadId") === threadId && readNotificationTurnId(value) === turnId;
|
|
3797
4213
|
}
|
|
4214
|
+
function isRetryableErrorNotification(value) {
|
|
4215
|
+
if (!isJsonObject(value)) return false;
|
|
4216
|
+
return readBoolean(value, "willRetry") === true || readBoolean(value, "will_retry") === true;
|
|
4217
|
+
}
|
|
3798
4218
|
function isTerminalTurnStatus(status) {
|
|
3799
4219
|
return status === "completed" || status === "interrupted" || status === "failed";
|
|
3800
4220
|
}
|
|
@@ -3809,6 +4229,10 @@ function readString(record, key) {
|
|
|
3809
4229
|
const value = record[key];
|
|
3810
4230
|
return typeof value === "string" ? value : void 0;
|
|
3811
4231
|
}
|
|
4232
|
+
function readBoolean(record, key) {
|
|
4233
|
+
const value = record[key];
|
|
4234
|
+
return typeof value === "boolean" ? value : void 0;
|
|
4235
|
+
}
|
|
3812
4236
|
async function readMirroredSessionHistoryMessages(sessionFile) {
|
|
3813
4237
|
const messages = await readCodexMirroredSessionHistoryMessages(sessionFile);
|
|
3814
4238
|
if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
|
|
@@ -3855,12 +4279,6 @@ function renderCodexWorkspaceBootstrapInstructions(contextFiles) {
|
|
|
3855
4279
|
for (const file of files) lines.push(`## ${file.path}`, "", file.content, "");
|
|
3856
4280
|
return lines.join("\n").trim();
|
|
3857
4281
|
}
|
|
3858
|
-
function mergeCodexConfigInstructions(config, instructions) {
|
|
3859
|
-
if (!instructions?.trim()) return config;
|
|
3860
|
-
const merged = { ...config };
|
|
3861
|
-
merged.instructions = joinPresentSections(typeof merged.instructions === "string" ? merged.instructions.trim() : void 0, instructions);
|
|
3862
|
-
return merged;
|
|
3863
|
-
}
|
|
3864
4282
|
function remapCodexContextFilePath(params) {
|
|
3865
4283
|
const relativePath = path.relative(params.sourceWorkspaceDir, params.file.path);
|
|
3866
4284
|
if (!relativePath || relativePath.startsWith("..") || path.isAbsolute(relativePath) || params.sourceWorkspaceDir === params.targetWorkspaceDir) return params.file;
|
|
@@ -3900,15 +4318,6 @@ async function mirrorTranscriptBestEffort(params) {
|
|
|
3900
4318
|
embeddedAgentLog.warn("failed to mirror codex app-server transcript", { error });
|
|
3901
4319
|
}
|
|
3902
4320
|
}
|
|
3903
|
-
async function fileExists(filePath) {
|
|
3904
|
-
try {
|
|
3905
|
-
await fs.stat(filePath);
|
|
3906
|
-
return true;
|
|
3907
|
-
} catch (error) {
|
|
3908
|
-
if (error.code === "ENOENT") return false;
|
|
3909
|
-
throw error;
|
|
3910
|
-
}
|
|
3911
|
-
}
|
|
3912
4321
|
function isNonEmptyString(value) {
|
|
3913
4322
|
return typeof value === "string" && value.length > 0;
|
|
3914
4323
|
}
|
|
@@ -3925,8 +4334,5 @@ function handleApprovalRequest(params) {
|
|
|
3925
4334
|
signal: params.signal
|
|
3926
4335
|
});
|
|
3927
4336
|
}
|
|
3928
|
-
({ ...createCodexAppServerClientFactoryTestHooks((factory) => {
|
|
3929
|
-
clientFactory = factory;
|
|
3930
|
-
}) });
|
|
3931
4337
|
//#endregion
|
|
3932
4338
|
export { runCodexAppServerAttempt };
|