@openclaw/codex 2026.5.16-beta.1 → 2026.5.16-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-CoctX13d.js → client-CA7amCZ8.js} +1 -1
- package/dist/{client-factory-Be6RD28K.js → client-factory-DwzPofwS.js} +1 -1
- package/dist/{command-handlers-CbJPJwK_.js → command-handlers-C4F8BChC.js} +6 -6
- package/dist/{compact-CKWfgifa.js → compact-96QPqIAu.js} +97 -3
- package/dist/{computer-use-DsJxRRtm.js → computer-use-BX02ojP4.js} +2 -2
- package/dist/{config-0rd3LnKg.js → config-3ATInASk.js} +7 -1
- package/dist/harness.js +9 -6
- package/dist/index.js +6 -6
- package/dist/media-understanding-provider.js +4 -4
- package/dist/{models-GCYf5s8J.js → models-BZLMz9WS.js} +2 -2
- package/dist/{node-cli-sessions-xstpFJmx.js → node-cli-sessions-BLDFnUEF.js} +4 -4
- package/dist/{plugin-activation-aQOmRQwA.js → plugin-activation-BDU4e-NA.js} +1 -1
- package/dist/{protocol-validators-CSY0BFBo.js → protocol-validators-BGBspNmF.js} +12 -40
- package/dist/provider.js +2 -2
- package/dist/{request-CKYiRqsN.js → request-Czoa60Nt.js} +3 -3
- package/dist/{run-attempt-frGYsF9Y.js → run-attempt-B3nk5oT1.js} +501 -89
- package/dist/{session-binding-CMTXuyoz.js → session-binding-DbdVqMzW.js} +14 -2
- package/dist/{shared-client-BwUqd3lh.js → shared-client-CnbrvEfV.js} +2 -2
- package/dist/{side-question-CDcvaIKA.js → side-question-D3nH-Jk1.js} +7 -7
- package/dist/test-api.js +2 -2
- package/dist/{thread-lifecycle-BzY-GLGu.js → thread-lifecycle-D2sxRPdz.js} +157 -36
- package/dist/{vision-tools-CyhFwJIY.js → vision-tools-Cm_YicZb.js} +106 -6
- package/package.json +4 -4
|
@@ -1,28 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-
|
|
1
|
+
import { c as resolveCodexAppServerRuntimeOptions, d as withMcpElicitationsApprovalPolicy, i as isCodexAppServerApprovalPolicyAllowedByRequirements, s as readCodexPluginConfig, u as resolveCodexPluginsPolicy } from "./config-3ATInASk.js";
|
|
2
|
+
import { a as readCodexDynamicToolCallParams, c as readCodexTurn, i as assertCodexTurnStartResponse } from "./protocol-validators-BGBspNmF.js";
|
|
3
3
|
import { t as isJsonObject } from "./protocol-C9UWI98H.js";
|
|
4
|
-
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-
|
|
5
|
-
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-
|
|
4
|
+
import { i as isCodexAppServerConnectionClosedError, r as isCodexAppServerApprovalRequest } from "./client-CA7amCZ8.js";
|
|
5
|
+
import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS } from "./request-Czoa60Nt.js";
|
|
6
6
|
import { d as resolveCodexUsageLimitResetAtMs, f as shouldRefreshCodexRateLimitsForUsageLimitMessage, r as formatCodexDisplayText, u as formatCodexUsageLimitErrorMessage } from "./command-formatters-BRW7_Nu7.js";
|
|
7
|
-
import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, n as clearSharedCodexAppServerClientIfCurrent, s as refreshCodexAppServerAuthTokens, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-
|
|
8
|
-
import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-
|
|
9
|
-
import { a as defaultCodexAppInventoryCache } from "./plugin-activation-
|
|
10
|
-
import { _ as
|
|
11
|
-
import { t as defaultCodexAppServerClientFactory } from "./client-factory-
|
|
12
|
-
import { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-
|
|
13
|
-
import { t as ensureCodexComputerUse } from "./computer-use-
|
|
7
|
+
import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, l as resolveCodexAppServerAuthProfileId, n as clearSharedCodexAppServerClientIfCurrent, s as refreshCodexAppServerAuthTokens, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-CnbrvEfV.js";
|
|
8
|
+
import { i as readCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DbdVqMzW.js";
|
|
9
|
+
import { a as defaultCodexAppInventoryCache } from "./plugin-activation-BDU4e-NA.js";
|
|
10
|
+
import { S as normalizeCodexDynamicToolName, _ as projectContextEngineAssemblyForCodex, b as createCodexDynamicToolBridge, c as codexDynamicToolsFingerprint, f as startOrResumeThread, g as shouldBuildCodexPluginThreadConfig, h as mergeCodexThreadConfigs, i as buildDeveloperInstructions, l as isContextEngineBindingCompatible, m as buildCodexPluginThreadConfigInputFingerprint, p as buildCodexPluginThreadConfig, r as buildContextEngineBinding, s as buildTurnStartParams, t as areCodexDynamicToolFingerprintsCompatible, v as resolveCodexContextEngineProjectionMaxChars, x as filterCodexDynamicTools, y as resolveCodexContextEngineProjectionReserveTokens } from "./thread-lifecycle-D2sxRPdz.js";
|
|
11
|
+
import { t as defaultCodexAppServerClientFactory } from "./client-factory-DwzPofwS.js";
|
|
12
|
+
import { n as handleCodexAppServerElicitationRequest, r as handleCodexAppServerApprovalRequest, t as filterToolsForVisionInputs } from "./vision-tools-Cm_YicZb.js";
|
|
13
|
+
import { t as ensureCodexComputerUse } from "./computer-use-BX02ojP4.js";
|
|
14
14
|
import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import nodeFs from "node:fs";
|
|
17
|
-
import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockAcquireTimeoutMs, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
17
|
+
import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, bootstrapHarnessContextEngine, buildEmbeddedAttemptToolRunContext, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatToolAggregate, formatToolProgressOutput, hasBeforeToolCallPolicy, inferToolMetaFromArgs, isActiveHarnessContextEngine, isSubagentSessionKey, loadCodexBundleMcpThreadConfig, normalizeAgentRuntimeTools, normalizeUsage, registerNativeHookRelay, resolveAgentHarnessBeforePromptBuildResult, resolveAttemptSpawnWorkspaceDir, resolveBootstrapContextForRun, resolveContextEngineOwnerPluginId, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, resolveSessionWriteLockAcquireTimeoutMs, resolveUserPath, runAgentCleanupStep, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessAgentEndHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
18
18
|
import fs from "node:fs/promises";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import { markAuthProfileBlockedUntil, resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
|
|
21
21
|
import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
|
|
22
|
+
import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
|
|
22
23
|
import { emitTrustedDiagnosticEvent } from "openclaw/plugin-sdk/diagnostic-runtime";
|
|
23
24
|
import { createRunningTaskRun, finalizeTaskRunByRunId, recordTaskRunProgressByRunId } from "openclaw/plugin-sdk/codex-native-task-runtime";
|
|
24
25
|
import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "@earendil-works/pi-coding-agent";
|
|
25
|
-
|
|
26
|
+
//#region extensions/codex/src/app-server/local-runtime-attribution.ts
|
|
27
|
+
const OPENAI_PROVIDER_ID = "openai";
|
|
28
|
+
const OPENAI_RESPONSES_API = "openai-responses";
|
|
29
|
+
const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
|
|
30
|
+
const OPENAI_CODEX_RESPONSES_API = "openai-codex-responses";
|
|
31
|
+
function normalizeRuntimeId(value) {
|
|
32
|
+
return value?.trim().toLowerCase() ?? "";
|
|
33
|
+
}
|
|
34
|
+
function resolveCodexLocalRuntimeAttribution(params) {
|
|
35
|
+
const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
|
|
36
|
+
if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
|
|
37
|
+
provider: OPENAI_CODEX_PROVIDER_ID,
|
|
38
|
+
api: OPENAI_CODEX_RESPONSES_API
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
provider: params.provider,
|
|
42
|
+
api: params.model.api
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
26
46
|
//#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
|
|
27
47
|
const CODEX_NATIVE_SUBAGENT_RUNTIME = "subagent";
|
|
28
48
|
const CODEX_NATIVE_SUBAGENT_TASK_KIND = "codex-native";
|
|
@@ -860,6 +880,7 @@ var CodexAppServerEventProjector = class {
|
|
|
860
880
|
data: {
|
|
861
881
|
phase: "end",
|
|
862
882
|
backend: "codex-app-server",
|
|
883
|
+
completed: true,
|
|
863
884
|
threadId: this.threadId,
|
|
864
885
|
turnId: this.turnId,
|
|
865
886
|
itemId
|
|
@@ -1017,8 +1038,14 @@ var CodexAppServerEventProjector = class {
|
|
|
1017
1038
|
const text = extractRawAssistantText(item);
|
|
1018
1039
|
if (!text) return;
|
|
1019
1040
|
const itemId = readString$2(item, "id") ?? `raw-assistant-${this.assistantItemOrder.length + 1}`;
|
|
1041
|
+
const phase = readString$2(item, "phase");
|
|
1042
|
+
if (phase) this.assistantPhaseByItem.set(itemId, phase);
|
|
1020
1043
|
this.rememberAssistantItem(itemId);
|
|
1021
1044
|
this.assistantTextByItem.set(itemId, text);
|
|
1045
|
+
if (phase === "commentary") this.emitCommentaryProgress({
|
|
1046
|
+
itemId,
|
|
1047
|
+
text
|
|
1048
|
+
});
|
|
1022
1049
|
}
|
|
1023
1050
|
recordNativeGeneratedMedia(item) {
|
|
1024
1051
|
if (item?.type !== "imageGeneration") return;
|
|
@@ -1327,6 +1354,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1327
1354
|
return await readCodexMirroredSessionHistoryMessages(this.params.sessionFile) ?? [];
|
|
1328
1355
|
}
|
|
1329
1356
|
createAssistantMessage(text) {
|
|
1357
|
+
const attribution = resolveCodexLocalRuntimeAttribution(this.params);
|
|
1330
1358
|
const usage = this.tokenUsage ? {
|
|
1331
1359
|
input: this.tokenUsage.input ?? 0,
|
|
1332
1360
|
output: this.tokenUsage.output ?? 0,
|
|
@@ -1341,8 +1369,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1341
1369
|
type: "text",
|
|
1342
1370
|
text
|
|
1343
1371
|
}],
|
|
1344
|
-
api:
|
|
1345
|
-
provider:
|
|
1372
|
+
api: attribution.api ?? "openai-codex-responses",
|
|
1373
|
+
provider: attribution.provider,
|
|
1346
1374
|
model: this.params.modelId,
|
|
1347
1375
|
usage,
|
|
1348
1376
|
stopReason: this.aborted ? "aborted" : this.promptError ? "error" : "stop",
|
|
@@ -1351,14 +1379,15 @@ var CodexAppServerEventProjector = class {
|
|
|
1351
1379
|
};
|
|
1352
1380
|
}
|
|
1353
1381
|
createAssistantMirrorMessage(title, text) {
|
|
1382
|
+
const attribution = resolveCodexLocalRuntimeAttribution(this.params);
|
|
1354
1383
|
return {
|
|
1355
1384
|
role: "assistant",
|
|
1356
1385
|
content: [{
|
|
1357
1386
|
type: "text",
|
|
1358
1387
|
text: `${title}:\n${text}`
|
|
1359
1388
|
}],
|
|
1360
|
-
api:
|
|
1361
|
-
provider:
|
|
1389
|
+
api: attribution.api ?? "openai-codex-responses",
|
|
1390
|
+
provider: attribution.provider,
|
|
1362
1391
|
model: this.params.modelId,
|
|
1363
1392
|
usage: ZERO_USAGE,
|
|
1364
1393
|
stopReason: "stop",
|
|
@@ -1367,6 +1396,7 @@ var CodexAppServerEventProjector = class {
|
|
|
1367
1396
|
}
|
|
1368
1397
|
createToolCallMessage(params) {
|
|
1369
1398
|
const args = normalizeToolTranscriptArguments(params.arguments);
|
|
1399
|
+
const attribution = resolveCodexLocalRuntimeAttribution(this.params);
|
|
1370
1400
|
return {
|
|
1371
1401
|
role: "assistant",
|
|
1372
1402
|
content: [{
|
|
@@ -1376,8 +1406,8 @@ var CodexAppServerEventProjector = class {
|
|
|
1376
1406
|
arguments: args,
|
|
1377
1407
|
input: args
|
|
1378
1408
|
}],
|
|
1379
|
-
api:
|
|
1380
|
-
provider:
|
|
1409
|
+
api: attribution.api ?? "openai-codex-responses",
|
|
1410
|
+
provider: attribution.provider,
|
|
1381
1411
|
model: this.params.modelId,
|
|
1382
1412
|
usage: ZERO_USAGE,
|
|
1383
1413
|
stopReason: "toolUse",
|
|
@@ -1732,22 +1762,40 @@ const CODEX_HOOK_EVENT_BY_NATIVE_EVENT = {
|
|
|
1732
1762
|
permission_request: "PermissionRequest",
|
|
1733
1763
|
before_agent_finalize: "Stop"
|
|
1734
1764
|
};
|
|
1765
|
+
const CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT = {
|
|
1766
|
+
pre_tool_use: "pre_tool_use",
|
|
1767
|
+
post_tool_use: "post_tool_use",
|
|
1768
|
+
permission_request: "permission_request",
|
|
1769
|
+
before_agent_finalize: "stop"
|
|
1770
|
+
};
|
|
1771
|
+
const CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS = ["/<session-flags>/config.toml", "<session-flags>/config.toml"];
|
|
1735
1772
|
function buildCodexNativeHookRelayConfig(params) {
|
|
1736
1773
|
const events = params.events?.length ? params.events : CODEX_NATIVE_HOOK_RELAY_EVENTS;
|
|
1737
1774
|
const config = { "features.hooks": true };
|
|
1775
|
+
const hookState = {};
|
|
1738
1776
|
for (const event of events) {
|
|
1739
1777
|
const codexEvent = CODEX_HOOK_EVENT_BY_NATIVE_EVENT[event];
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1778
|
+
const command = params.relay.commandForEvent(event);
|
|
1779
|
+
const timeout = normalizeHookTimeoutSec(params.hookTimeoutSec);
|
|
1780
|
+
config[`hooks.${codexEvent}`] = [{ hooks: [{
|
|
1781
|
+
type: "command",
|
|
1782
|
+
command,
|
|
1783
|
+
timeout,
|
|
1784
|
+
async: false,
|
|
1785
|
+
statusMessage: "OpenClaw native hook relay"
|
|
1786
|
+
}] }];
|
|
1787
|
+
const state = {
|
|
1788
|
+
enabled: true,
|
|
1789
|
+
trusted_hash: codexCommandHookTrustedHash({
|
|
1790
|
+
event,
|
|
1791
|
+
command,
|
|
1792
|
+
timeout,
|
|
1747
1793
|
statusMessage: "OpenClaw native hook relay"
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1794
|
+
})
|
|
1795
|
+
};
|
|
1796
|
+
for (const sourcePath of CODEX_SESSION_FLAGS_HOOK_SOURCE_PATHS) hookState[`${sourcePath}:${CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[event]}:0:0`] = state;
|
|
1750
1797
|
}
|
|
1798
|
+
config["hooks.state"] = hookState;
|
|
1751
1799
|
return config;
|
|
1752
1800
|
}
|
|
1753
1801
|
function buildCodexNativeHookRelayDisabledConfig() {
|
|
@@ -1762,6 +1810,26 @@ function buildCodexNativeHookRelayDisabledConfig() {
|
|
|
1762
1810
|
function normalizeHookTimeoutSec(value) {
|
|
1763
1811
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.ceil(value) : 5;
|
|
1764
1812
|
}
|
|
1813
|
+
function codexCommandHookTrustedHash(params) {
|
|
1814
|
+
const identity = {
|
|
1815
|
+
event_name: CODEX_HOOK_KEY_LABEL_BY_NATIVE_EVENT[params.event],
|
|
1816
|
+
hooks: [{
|
|
1817
|
+
async: false,
|
|
1818
|
+
command: params.command,
|
|
1819
|
+
statusMessage: params.statusMessage,
|
|
1820
|
+
timeout: params.timeout,
|
|
1821
|
+
type: "command"
|
|
1822
|
+
}]
|
|
1823
|
+
};
|
|
1824
|
+
return `sha256:${createHash("sha256").update(JSON.stringify(sortJsonValue(identity))).digest("hex")}`;
|
|
1825
|
+
}
|
|
1826
|
+
function sortJsonValue(value) {
|
|
1827
|
+
if (!value || typeof value !== "object") return value;
|
|
1828
|
+
if (Array.isArray(value)) return value.map(sortJsonValue);
|
|
1829
|
+
const sorted = {};
|
|
1830
|
+
for (const key of Object.keys(value).toSorted()) sorted[key] = sortJsonValue(value[key]);
|
|
1831
|
+
return sorted;
|
|
1832
|
+
}
|
|
1765
1833
|
//#endregion
|
|
1766
1834
|
//#region extensions/codex/src/app-server/trajectory.ts
|
|
1767
1835
|
const SENSITIVE_FIELD_RE = /(?:authorization|cookie|credential|key|password|passwd|secret|token)/iu;
|
|
@@ -1844,6 +1912,7 @@ function createCodexTrajectoryRecorder(params) {
|
|
|
1844
1912
|
});
|
|
1845
1913
|
let queue = Promise.resolve();
|
|
1846
1914
|
let seq = 0;
|
|
1915
|
+
const attribution = resolveCodexLocalRuntimeAttribution(params.attempt);
|
|
1847
1916
|
return {
|
|
1848
1917
|
filePath,
|
|
1849
1918
|
recordEvent: (type, data) => {
|
|
@@ -1860,9 +1929,9 @@ function createCodexTrajectoryRecorder(params) {
|
|
|
1860
1929
|
sessionKey: params.attempt.sessionKey,
|
|
1861
1930
|
runId: params.attempt.runId,
|
|
1862
1931
|
workspaceDir: params.cwd,
|
|
1863
|
-
provider:
|
|
1932
|
+
provider: attribution.provider,
|
|
1864
1933
|
modelId: params.attempt.modelId,
|
|
1865
|
-
modelApi:
|
|
1934
|
+
modelApi: attribution.api,
|
|
1866
1935
|
data: data ? sanitizeValue(data) : void 0
|
|
1867
1936
|
});
|
|
1868
1937
|
if (!line) return;
|
|
@@ -2148,6 +2217,7 @@ const CODEX_TURN_ASSISTANT_COMPLETION_IDLE_TIMEOUT_MS = 1e4;
|
|
|
2148
2217
|
const CODEX_TURN_TERMINAL_IDLE_TIMEOUT_MS = 30 * 6e4;
|
|
2149
2218
|
const CODEX_NATIVE_HOOK_RELAY_MIN_TTL_MS = 30 * 6e4;
|
|
2150
2219
|
const CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS = 5 * 6e4;
|
|
2220
|
+
const CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS = 6e4;
|
|
2151
2221
|
const CODEX_STEER_ALL_DEBOUNCE_MS = 500;
|
|
2152
2222
|
const LOG_FIELD_MAX_LENGTH = 160;
|
|
2153
2223
|
const CODEX_NATIVE_PROJECT_DOC_BASENAMES = new Set(["agents.md"]);
|
|
@@ -2315,6 +2385,22 @@ function restrictCodexAppServerSandboxForOpenClawSandbox(appServer, sandbox) {
|
|
|
2315
2385
|
sandbox: "workspace-write"
|
|
2316
2386
|
};
|
|
2317
2387
|
}
|
|
2388
|
+
function resolveCodexAppServerForOpenClawToolPolicy(params) {
|
|
2389
|
+
if (!params.shouldPromote || !params.canUseUntrustedApprovalPolicy || params.appServer.approvalPolicy !== "never") return params.appServer;
|
|
2390
|
+
const explicitMode = params.pluginConfig.appServer?.mode !== void 0 || isCodexAppServerPolicyMode(params.env.OPENCLAW_CODEX_APP_SERVER_MODE);
|
|
2391
|
+
const explicitApprovalPolicy = params.pluginConfig.appServer?.approvalPolicy !== void 0 || isCodexAppServerApprovalPolicy(params.env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY);
|
|
2392
|
+
if (explicitMode || explicitApprovalPolicy) return params.appServer;
|
|
2393
|
+
return {
|
|
2394
|
+
...params.appServer,
|
|
2395
|
+
approvalPolicy: "untrusted"
|
|
2396
|
+
};
|
|
2397
|
+
}
|
|
2398
|
+
function isCodexAppServerPolicyMode(value) {
|
|
2399
|
+
return value === "guardian" || value === "yolo";
|
|
2400
|
+
}
|
|
2401
|
+
function isCodexAppServerApprovalPolicy(value) {
|
|
2402
|
+
return value === "never" || value === "on-request" || value === "on-failure" || value === "untrusted";
|
|
2403
|
+
}
|
|
2318
2404
|
async function runCodexAppServerAttempt(params, options = {}) {
|
|
2319
2405
|
const attemptStartedAt = Date.now();
|
|
2320
2406
|
const attemptClientFactory = options.clientFactory ?? defaultCodexAppServerClientFactory;
|
|
@@ -2330,7 +2416,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2330
2416
|
});
|
|
2331
2417
|
const effectiveWorkspace = sandbox?.enabled ? sandbox.workspaceAccess === "rw" ? resolvedWorkspace : sandbox.workspaceDir : resolvedWorkspace;
|
|
2332
2418
|
await fs.mkdir(effectiveWorkspace, { recursive: true });
|
|
2333
|
-
const appServer =
|
|
2419
|
+
const appServer = resolveCodexAppServerForOpenClawToolPolicy({
|
|
2420
|
+
appServer: restrictCodexAppServerSandboxForOpenClawSandbox(configuredAppServer, sandbox),
|
|
2421
|
+
pluginConfig,
|
|
2422
|
+
env: process.env,
|
|
2423
|
+
shouldPromote: hasBeforeToolCallPolicy(),
|
|
2424
|
+
canUseUntrustedApprovalPolicy: configuredAppServer.start.transport !== "stdio" || isCodexAppServerApprovalPolicyAllowedByRequirements("untrusted")
|
|
2425
|
+
});
|
|
2334
2426
|
let pluginAppServer = appServer;
|
|
2335
2427
|
const nativeHookRelayEvents = resolveCodexNativeHookRelayEvents({
|
|
2336
2428
|
configuredEvents: options.nativeHookRelay?.events,
|
|
@@ -2364,6 +2456,17 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2364
2456
|
sessionKey: sandboxSessionKey,
|
|
2365
2457
|
...startupAuthProfileId ? { authProfileId: startupAuthProfileId } : {}
|
|
2366
2458
|
};
|
|
2459
|
+
let activeSessionId = params.sessionId;
|
|
2460
|
+
let activeSessionFile = params.sessionFile;
|
|
2461
|
+
const buildActiveRunAttemptParams = () => ({
|
|
2462
|
+
...runtimeParams,
|
|
2463
|
+
sessionId: activeSessionId,
|
|
2464
|
+
sessionFile: activeSessionFile
|
|
2465
|
+
});
|
|
2466
|
+
const adoptContextEngineCompactionTranscript = (compactResult) => {
|
|
2467
|
+
if (compactResult.result?.sessionId) activeSessionId = compactResult.result.sessionId;
|
|
2468
|
+
if (compactResult.result?.sessionFile) activeSessionFile = compactResult.result.sessionFile;
|
|
2469
|
+
};
|
|
2367
2470
|
const startupAuthAccountCacheKey = await resolveCodexAppServerAuthAccountCacheKey({
|
|
2368
2471
|
authProfileId: startupAuthProfileId,
|
|
2369
2472
|
authProfileStore: params.authProfileStore,
|
|
@@ -2406,8 +2509,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2406
2509
|
runId: params.runId
|
|
2407
2510
|
}
|
|
2408
2511
|
});
|
|
2409
|
-
const hadSessionFile = await pathExists(
|
|
2410
|
-
let historyMessages = await readMirroredSessionHistoryMessages(
|
|
2512
|
+
const hadSessionFile = await pathExists(activeSessionFile);
|
|
2513
|
+
let historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? [];
|
|
2411
2514
|
const hookContextWindowFields = {
|
|
2412
2515
|
...params.contextWindowInfo?.tokens ? { contextTokenBudget: params.contextWindowInfo.tokens } : params.contextTokenBudget ? { contextTokenBudget: params.contextTokenBudget } : {},
|
|
2413
2516
|
...params.contextWindowInfo?.source ? { contextWindowSource: params.contextWindowInfo.source } : {},
|
|
@@ -2424,27 +2527,28 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2424
2527
|
channelId: params.messageChannel ?? params.messageProvider ?? void 0,
|
|
2425
2528
|
...hookContextWindowFields
|
|
2426
2529
|
};
|
|
2530
|
+
const activeContextEnginePluginId = activeContextEngine ? resolveContextEngineOwnerPluginId(activeContextEngine) : void 0;
|
|
2531
|
+
const buildActiveContextEngineRuntimeContext = () => buildHarnessContextEngineRuntimeContext({
|
|
2532
|
+
attempt: buildActiveRunAttemptParams(),
|
|
2533
|
+
workspaceDir: effectiveWorkspace,
|
|
2534
|
+
agentDir,
|
|
2535
|
+
activeAgentId: sessionAgentId,
|
|
2536
|
+
contextEnginePluginId: activeContextEnginePluginId,
|
|
2537
|
+
tokenBudget: params.contextTokenBudget
|
|
2538
|
+
});
|
|
2427
2539
|
if (activeContextEngine) {
|
|
2428
|
-
const activeContextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
|
|
2429
2540
|
await bootstrapHarnessContextEngine({
|
|
2430
2541
|
hadSessionFile,
|
|
2431
2542
|
contextEngine: activeContextEngine,
|
|
2432
|
-
sessionId:
|
|
2543
|
+
sessionId: activeSessionId,
|
|
2433
2544
|
sessionKey: sandboxSessionKey,
|
|
2434
|
-
sessionFile:
|
|
2435
|
-
runtimeContext:
|
|
2436
|
-
attempt: runtimeParams,
|
|
2437
|
-
workspaceDir: effectiveWorkspace,
|
|
2438
|
-
agentDir,
|
|
2439
|
-
activeAgentId: sessionAgentId,
|
|
2440
|
-
contextEnginePluginId: activeContextEnginePluginId,
|
|
2441
|
-
tokenBudget: params.contextTokenBudget
|
|
2442
|
-
}),
|
|
2545
|
+
sessionFile: activeSessionFile,
|
|
2546
|
+
runtimeContext: buildActiveContextEngineRuntimeContext(),
|
|
2443
2547
|
runMaintenance: runHarnessContextEngineMaintenance,
|
|
2444
2548
|
config: params.config,
|
|
2445
2549
|
warn: (message) => embeddedAgentLog.warn(message)
|
|
2446
2550
|
});
|
|
2447
|
-
historyMessages = await readMirroredSessionHistoryMessages(
|
|
2551
|
+
historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
|
|
2448
2552
|
}
|
|
2449
2553
|
const baseDeveloperInstructions = buildDeveloperInstructions(params);
|
|
2450
2554
|
const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
|
|
@@ -2458,10 +2562,18 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2458
2562
|
let promptText = params.prompt;
|
|
2459
2563
|
let developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
|
|
2460
2564
|
let prePromptMessageCount = historyMessages.length;
|
|
2461
|
-
|
|
2565
|
+
let contextEngineProjection;
|
|
2566
|
+
const resetCodexPromptInputs = () => {
|
|
2567
|
+
promptText = params.prompt;
|
|
2568
|
+
developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions);
|
|
2569
|
+
prePromptMessageCount = historyMessages.length;
|
|
2570
|
+
contextEngineProjection = void 0;
|
|
2571
|
+
};
|
|
2572
|
+
const applyActiveContextEngineProjection = async (decisionStartupBinding) => {
|
|
2573
|
+
if (!activeContextEngine) return;
|
|
2462
2574
|
const assembled = await assembleHarnessContextEngine({
|
|
2463
2575
|
contextEngine: activeContextEngine,
|
|
2464
|
-
sessionId:
|
|
2576
|
+
sessionId: activeSessionId,
|
|
2465
2577
|
sessionKey: sandboxSessionKey,
|
|
2466
2578
|
messages: historyMessages,
|
|
2467
2579
|
tokenBudget: params.contextTokenBudget,
|
|
@@ -2471,6 +2583,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2471
2583
|
prompt: params.prompt
|
|
2472
2584
|
});
|
|
2473
2585
|
if (!assembled) throw new Error("context engine assemble returned no result");
|
|
2586
|
+
contextEngineProjection = readContextEngineThreadBootstrapProjection(assembled.contextProjection);
|
|
2474
2587
|
const projection = projectContextEngineAssemblyForCodex({
|
|
2475
2588
|
assembledMessages: assembled.messages,
|
|
2476
2589
|
originalHistoryMessages: historyMessages,
|
|
@@ -2479,11 +2592,41 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2479
2592
|
maxRenderedContextChars: resolveCodexContextEngineProjectionMaxChars({
|
|
2480
2593
|
contextTokenBudget: params.contextTokenBudget,
|
|
2481
2594
|
reserveTokens: resolveCodexContextEngineProjectionReserveTokens({ config: params.config })
|
|
2482
|
-
})
|
|
2595
|
+
}),
|
|
2596
|
+
toolPayloadMode: contextEngineProjection ? "preserve" : "elide"
|
|
2483
2597
|
});
|
|
2484
|
-
|
|
2598
|
+
const projectionDecision = contextEngineProjection ? resolveContextEngineBootstrapProjectionDecision({
|
|
2599
|
+
startupBinding: decisionStartupBinding,
|
|
2600
|
+
expectedBinding: buildContextEngineBinding(buildActiveRunAttemptParams(), contextEngineProjection),
|
|
2601
|
+
projection: contextEngineProjection,
|
|
2602
|
+
dynamicToolsFingerprint: codexDynamicToolsFingerprint(toolBridge.specs)
|
|
2603
|
+
}) : {
|
|
2604
|
+
project: true,
|
|
2605
|
+
reason: "per-turn-projection"
|
|
2606
|
+
};
|
|
2607
|
+
embeddedAgentLog.info("codex app-server context-engine projection decision", {
|
|
2608
|
+
sessionId: params.sessionId,
|
|
2609
|
+
sessionKey: sandboxSessionKey,
|
|
2610
|
+
engineId: activeContextEngine.info.id,
|
|
2611
|
+
mode: contextEngineProjection?.mode ?? assembled.contextProjection?.mode ?? "per_turn",
|
|
2612
|
+
epoch: contextEngineProjection?.epoch,
|
|
2613
|
+
fingerprint: contextEngineProjection?.fingerprint,
|
|
2614
|
+
previousThreadId: decisionStartupBinding?.threadId,
|
|
2615
|
+
previousEpoch: decisionStartupBinding?.contextEngine?.projection?.epoch,
|
|
2616
|
+
previousFingerprint: decisionStartupBinding?.contextEngine?.projection?.fingerprint,
|
|
2617
|
+
projected: projectionDecision.project,
|
|
2618
|
+
reason: projectionDecision.reason,
|
|
2619
|
+
assembledMessages: assembled.messages.length,
|
|
2620
|
+
originalHistoryMessages: historyMessages.length,
|
|
2621
|
+
projectedPromptChars: projection.promptText.length,
|
|
2622
|
+
developerInstructionAdditionChars: projection.developerInstructionAddition?.length ?? 0
|
|
2623
|
+
});
|
|
2624
|
+
promptText = projectionDecision.project ? projection.promptText : params.prompt;
|
|
2485
2625
|
developerInstructions = joinPresentSections(baseDeveloperInstructions, workspaceBootstrapInstructions, projection.developerInstructionAddition);
|
|
2486
2626
|
prePromptMessageCount = projection.prePromptMessageCount;
|
|
2627
|
+
};
|
|
2628
|
+
if (activeContextEngine) try {
|
|
2629
|
+
await applyActiveContextEngineProjection(startupBinding);
|
|
2487
2630
|
} catch (assembleErr) {
|
|
2488
2631
|
embeddedAgentLog.warn("context engine assemble failed; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
2489
2632
|
}
|
|
@@ -2500,13 +2643,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2500
2643
|
promptText = projection.promptText;
|
|
2501
2644
|
prePromptMessageCount = projection.prePromptMessageCount;
|
|
2502
2645
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
prompt: promptText,
|
|
2646
|
+
const buildPromptFromCurrentInputs = () => resolveAgentHarnessBeforePromptBuildResult({
|
|
2647
|
+
prompt: prependCurrentTurnContext(promptText, params.currentTurnContext),
|
|
2506
2648
|
developerInstructions,
|
|
2507
2649
|
messages: historyMessages,
|
|
2508
2650
|
ctx: hookContext
|
|
2509
2651
|
});
|
|
2652
|
+
let promptBuild = await buildPromptFromCurrentInputs();
|
|
2510
2653
|
const systemPromptReport = buildCodexSystemPromptReport({
|
|
2511
2654
|
attempt: params,
|
|
2512
2655
|
sessionKey: sandboxSessionKey,
|
|
@@ -2588,9 +2731,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2588
2731
|
timeoutMs: appServer.requestTimeoutMs,
|
|
2589
2732
|
signal: runAbortController.signal
|
|
2590
2733
|
});
|
|
2591
|
-
const
|
|
2734
|
+
const buildThreadLifecycleParams = () => ({
|
|
2592
2735
|
client: startupClient,
|
|
2593
|
-
params:
|
|
2736
|
+
params: buildActiveRunAttemptParams(),
|
|
2594
2737
|
agentId: sessionAgentId,
|
|
2595
2738
|
cwd: effectiveWorkspace,
|
|
2596
2739
|
dynamicTools: toolBridge.specs,
|
|
@@ -2599,6 +2742,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2599
2742
|
config: threadConfig,
|
|
2600
2743
|
mcpServersFingerprint: bundleMcpThreadConfig.fingerprint,
|
|
2601
2744
|
mcpServersFingerprintEvaluated: bundleMcpThreadConfig.evaluated,
|
|
2745
|
+
contextEngineProjection,
|
|
2602
2746
|
pluginThreadConfig: pluginThreadConfigEnabled ? {
|
|
2603
2747
|
enabled: true,
|
|
2604
2748
|
inputFingerprint: pluginThreadConfigInputFingerprint,
|
|
@@ -2613,11 +2757,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2613
2757
|
appCacheKey: pluginAppCacheKey
|
|
2614
2758
|
})
|
|
2615
2759
|
} : void 0
|
|
2616
|
-
};
|
|
2617
|
-
restartContextEngineCodexThread = () => startOrResumeThread(
|
|
2760
|
+
});
|
|
2761
|
+
restartContextEngineCodexThread = () => startOrResumeThread(buildThreadLifecycleParams());
|
|
2618
2762
|
return {
|
|
2619
2763
|
client: startupClient,
|
|
2620
|
-
thread: await startOrResumeThread(
|
|
2764
|
+
thread: await startOrResumeThread(buildThreadLifecycleParams())
|
|
2621
2765
|
};
|
|
2622
2766
|
};
|
|
2623
2767
|
for (let attempt = 1; attempt <= CODEX_APP_SERVER_STARTUP_CONNECTION_CLOSE_MAX_ATTEMPTS; attempt += 1) try {
|
|
@@ -2702,14 +2846,22 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2702
2846
|
let turnAssistantCompletionIdleWatchArmed = false;
|
|
2703
2847
|
let turnAssistantCompletionLastActivityAt = Date.now();
|
|
2704
2848
|
let turnAssistantCompletionLastActivityDetails;
|
|
2849
|
+
const turnAttemptIdleTimeoutMs = Math.max(100, Math.floor(params.timeoutMs));
|
|
2850
|
+
let turnAttemptIdleTimer;
|
|
2851
|
+
let turnAttemptIdleWatchArmed = false;
|
|
2705
2852
|
let turnTerminalIdleTimer;
|
|
2706
2853
|
let turnTerminalIdleWatchArmed = false;
|
|
2707
2854
|
let turnCompletionLastActivityAt = Date.now();
|
|
2708
2855
|
let turnCompletionLastActivityReason = "startup";
|
|
2709
2856
|
let turnCompletionLastActivityDetails;
|
|
2857
|
+
let turnAttemptLastProgressAt = Date.now();
|
|
2858
|
+
let turnAttemptLastProgressReason = "startup";
|
|
2859
|
+
let turnAttemptLastProgressDetails;
|
|
2860
|
+
let nativeHookRelayLastRenewedAt = 0;
|
|
2710
2861
|
let activeAppServerTurnRequests = 0;
|
|
2711
2862
|
const activeOpenClawDynamicToolCallIds = /* @__PURE__ */ new Set();
|
|
2712
2863
|
const activeTurnItemIds = /* @__PURE__ */ new Set();
|
|
2864
|
+
let turnCrossedToolHandoff = false;
|
|
2713
2865
|
const clearTurnCompletionIdleTimer = () => {
|
|
2714
2866
|
if (turnCompletionIdleTimer) {
|
|
2715
2867
|
clearTimeout(turnCompletionIdleTimer);
|
|
@@ -2728,6 +2880,12 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2728
2880
|
turnAssistantCompletionIdleTimer = void 0;
|
|
2729
2881
|
}
|
|
2730
2882
|
};
|
|
2883
|
+
const clearTurnAttemptIdleTimer = () => {
|
|
2884
|
+
if (turnAttemptIdleTimer) {
|
|
2885
|
+
clearTimeout(turnAttemptIdleTimer);
|
|
2886
|
+
turnAttemptIdleTimer = void 0;
|
|
2887
|
+
}
|
|
2888
|
+
};
|
|
2731
2889
|
const fireTurnAssistantCompletionIdleRelease = () => {
|
|
2732
2890
|
if (completed || runAbortController.signal.aborted || !turnAssistantCompletionIdleWatchArmed) return;
|
|
2733
2891
|
if (activeAppServerTurnRequests > 0 || activeTurnItemIds.size > 0) {
|
|
@@ -2764,6 +2922,35 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2764
2922
|
completed = true;
|
|
2765
2923
|
resolveCompletion?.();
|
|
2766
2924
|
};
|
|
2925
|
+
const fireTurnAttemptIdleTimeout = () => {
|
|
2926
|
+
if (completed || runAbortController.signal.aborted || !turnAttemptIdleWatchArmed) return;
|
|
2927
|
+
const idleMs = Math.max(0, Date.now() - turnAttemptLastProgressAt);
|
|
2928
|
+
if (idleMs < turnAttemptIdleTimeoutMs) {
|
|
2929
|
+
scheduleTurnAttemptIdleWatch();
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
timedOut = true;
|
|
2933
|
+
turnCompletionIdleTimedOut = true;
|
|
2934
|
+
turnCompletionIdleTimeoutMessage = "codex app-server turn idle timed out waiting for turn/completed";
|
|
2935
|
+
projector?.markTimedOut();
|
|
2936
|
+
trajectoryRecorder?.recordEvent("turn.progress_idle_timeout", {
|
|
2937
|
+
threadId: thread.threadId,
|
|
2938
|
+
turnId,
|
|
2939
|
+
idleMs,
|
|
2940
|
+
timeoutMs: turnAttemptIdleTimeoutMs,
|
|
2941
|
+
lastActivityReason: turnAttemptLastProgressReason,
|
|
2942
|
+
...turnAttemptLastProgressDetails
|
|
2943
|
+
});
|
|
2944
|
+
embeddedAgentLog.warn("codex app-server turn idle timed out waiting for progress", {
|
|
2945
|
+
threadId: thread.threadId,
|
|
2946
|
+
turnId,
|
|
2947
|
+
idleMs,
|
|
2948
|
+
timeoutMs: turnAttemptIdleTimeoutMs,
|
|
2949
|
+
lastActivityReason: turnAttemptLastProgressReason,
|
|
2950
|
+
...turnAttemptLastProgressDetails
|
|
2951
|
+
});
|
|
2952
|
+
runAbortController.abort("turn_progress_idle_timeout");
|
|
2953
|
+
};
|
|
2767
2954
|
const fireTurnCompletionIdleTimeout = () => {
|
|
2768
2955
|
if (completed || runAbortController.signal.aborted || !turnCompletionIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
2769
2956
|
const idleMs = Math.max(0, Date.now() - turnCompletionLastActivityAt);
|
|
@@ -2838,6 +3025,14 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2838
3025
|
turnAssistantCompletionIdleTimer = setTimeout(fireTurnAssistantCompletionIdleRelease, delayMs);
|
|
2839
3026
|
turnAssistantCompletionIdleTimer.unref?.();
|
|
2840
3027
|
}
|
|
3028
|
+
function scheduleTurnAttemptIdleWatch() {
|
|
3029
|
+
clearTurnAttemptIdleTimer();
|
|
3030
|
+
if (completed || runAbortController.signal.aborted || !turnAttemptIdleWatchArmed) return;
|
|
3031
|
+
const elapsedMs = Math.max(0, Date.now() - turnAttemptLastProgressAt);
|
|
3032
|
+
const delayMs = Math.max(1, turnAttemptIdleTimeoutMs - elapsedMs);
|
|
3033
|
+
turnAttemptIdleTimer = setTimeout(fireTurnAttemptIdleTimeout, delayMs);
|
|
3034
|
+
turnAttemptIdleTimer.unref?.();
|
|
3035
|
+
}
|
|
2841
3036
|
function scheduleTurnTerminalIdleWatch() {
|
|
2842
3037
|
clearTurnTerminalIdleTimer();
|
|
2843
3038
|
if (completed || runAbortController.signal.aborted || !turnTerminalIdleWatchArmed || activeAppServerTurnRequests > 0) return;
|
|
@@ -2846,10 +3041,41 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2846
3041
|
turnTerminalIdleTimer = setTimeout(fireTurnTerminalIdleTimeout, delayMs);
|
|
2847
3042
|
turnTerminalIdleTimer.unref?.();
|
|
2848
3043
|
}
|
|
3044
|
+
function scheduleTurnProgressWatches() {
|
|
3045
|
+
scheduleTurnAttemptIdleWatch();
|
|
3046
|
+
scheduleTurnCompletionIdleWatch();
|
|
3047
|
+
scheduleTurnTerminalIdleWatch();
|
|
3048
|
+
}
|
|
3049
|
+
const renewNativeHookRelayForTurnProgress = () => {
|
|
3050
|
+
if (!nativeHookRelay || options.nativeHookRelay?.ttlMs !== void 0) return;
|
|
3051
|
+
const now = Date.now();
|
|
3052
|
+
const renewsRecently = now - nativeHookRelayLastRenewedAt < CODEX_NATIVE_HOOK_RELAY_RENEW_INTERVAL_MS;
|
|
3053
|
+
const expiresSoon = now >= nativeHookRelay.expiresAtMs - CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS;
|
|
3054
|
+
if (renewsRecently && !expiresSoon) return;
|
|
3055
|
+
nativeHookRelayLastRenewedAt = now;
|
|
3056
|
+
nativeHookRelay.renew(resolveCodexNativeHookRelayTtlMs({
|
|
3057
|
+
explicitTtlMs: void 0,
|
|
3058
|
+
attemptTimeoutMs: turnAttemptIdleTimeoutMs,
|
|
3059
|
+
startupTimeoutMs,
|
|
3060
|
+
turnStartTimeoutMs: params.timeoutMs
|
|
3061
|
+
}));
|
|
3062
|
+
};
|
|
2849
3063
|
const touchTurnCompletionActivity = (reason, options) => {
|
|
2850
3064
|
turnCompletionLastActivityAt = Date.now();
|
|
2851
3065
|
turnCompletionLastActivityReason = reason;
|
|
2852
3066
|
turnCompletionLastActivityDetails = options?.details;
|
|
3067
|
+
if (options?.attemptProgress) {
|
|
3068
|
+
turnAttemptLastProgressAt = turnCompletionLastActivityAt;
|
|
3069
|
+
turnAttemptLastProgressReason = reason;
|
|
3070
|
+
turnAttemptLastProgressDetails = options.details;
|
|
3071
|
+
renewNativeHookRelayForTurnProgress();
|
|
3072
|
+
params.onRunProgress?.({
|
|
3073
|
+
reason,
|
|
3074
|
+
provider: params.provider,
|
|
3075
|
+
model: params.modelId,
|
|
3076
|
+
backend: "codex-app-server"
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
2853
3079
|
emitTrustedDiagnosticEvent({
|
|
2854
3080
|
type: "run.progress",
|
|
2855
3081
|
runId: params.runId,
|
|
@@ -2861,8 +3087,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2861
3087
|
turnCompletionIdleWatchArmed = true;
|
|
2862
3088
|
turnCompletionIdleWatchPinnedByTerminalError = false;
|
|
2863
3089
|
}
|
|
2864
|
-
|
|
2865
|
-
scheduleTurnTerminalIdleWatch();
|
|
3090
|
+
scheduleTurnProgressWatches();
|
|
2866
3091
|
};
|
|
2867
3092
|
const disarmTurnCompletionIdleWatch = () => {
|
|
2868
3093
|
turnCompletionIdleWatchArmed = false;
|
|
@@ -2946,26 +3171,34 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2946
3171
|
const isCurrentTurnNotification = isTurnNotification(notification.params, thread.threadId, turnId);
|
|
2947
3172
|
const isTurnCompletion = notification.method === "turn/completed" && isCurrentTurnNotification;
|
|
2948
3173
|
if (isCurrentTurnNotification) {
|
|
2949
|
-
touchTurnCompletionActivity(`notification:${notification.method}`, {
|
|
3174
|
+
touchTurnCompletionActivity(`notification:${notification.method}`, {
|
|
3175
|
+
details: describeNotificationActivity(notification),
|
|
3176
|
+
attemptProgress: true
|
|
3177
|
+
});
|
|
2950
3178
|
reportCodexExecutionNotification(notification);
|
|
2951
3179
|
}
|
|
2952
3180
|
if (isCurrentTurnNotification) updateActiveTurnItemIds(notification, activeTurnItemIds);
|
|
2953
3181
|
const unblockedAssistantCompletionRelease = isCurrentTurnNotification && turnAssistantCompletionIdleWatchArmed && notification.method === "item/completed" && activeTurnItemIds.size === 0;
|
|
2954
3182
|
const trackedDynamicToolCompletion = isTrackedOpenClawDynamicToolCompletionNotification(notification, activeOpenClawDynamicToolCallIds);
|
|
2955
|
-
const
|
|
3183
|
+
const rawToolOutputCompletion = isRawToolOutputCompletionNotification(notification);
|
|
3184
|
+
if (isCurrentTurnNotification && (rawToolOutputCompletion || isNativeToolProgressNotification(notification))) turnCrossedToolHandoff = true;
|
|
3185
|
+
const assistantCompletionCanRelease = isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff);
|
|
3186
|
+
const shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem = isCurrentTurnNotification && notification.method === "item/completed" && activeTurnItemIds.size === 0 && !trackedDynamicToolCompletion && !assistantCompletionCanRelease;
|
|
2956
3187
|
if (isCurrentTurnNotification && notification.method === "error") {
|
|
2957
3188
|
if (isRetryableErrorNotification(notification.params)) disarmTurnCompletionIdleWatch();
|
|
2958
3189
|
else armTurnCompletionIdleWatch({ pinnedByTerminalError: true });
|
|
2959
3190
|
disarmTurnAssistantCompletionIdleWatch();
|
|
2960
3191
|
} else if (isTurnCompletion) disarmTurnAssistantCompletionIdleWatch();
|
|
2961
|
-
else if (isCurrentTurnNotification &&
|
|
3192
|
+
else if (isCurrentTurnNotification && assistantCompletionCanRelease) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
2962
3193
|
else if (unblockedAssistantCompletionRelease) armTurnAssistantCompletionIdleWatch(describeNotificationActivity(notification));
|
|
2963
3194
|
else if (shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) armTurnCompletionIdleWatch();
|
|
3195
|
+
else if (isCurrentTurnNotification && rawToolOutputCompletion) armTurnCompletionIdleWatch();
|
|
2964
3196
|
else if (isCurrentTurnNotification && shouldDisarmAssistantCompletionIdleWatch(notification)) disarmTurnAssistantCompletionIdleWatch();
|
|
2965
|
-
if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
|
|
3197
|
+
if (turnCompletionIdleWatchArmed && !turnCompletionIdleWatchPinnedByTerminalError && notification.method !== "turn/completed" && isCurrentTurnNotification && !trackedDynamicToolCompletion && !rawToolOutputCompletion && !shouldRearmCompletionIdleWatchAfterLastCurrentTurnItem) disarmTurnCompletionIdleWatch();
|
|
2966
3198
|
const isTurnAbortMarker = isCurrentTurnNotification && isCodexTurnAbortMarkerNotification(notification, { currentPromptText: promptBuild.prompt });
|
|
2967
3199
|
const isTurnTerminal = isTurnCompletion || isTurnAbortMarker;
|
|
2968
3200
|
try {
|
|
3201
|
+
await waitForCodexNotificationDispatchTurn();
|
|
2969
3202
|
await projector.handleNotification(notification);
|
|
2970
3203
|
} catch (error) {
|
|
2971
3204
|
embeddedAgentLog.debug("codex app-server projector notification threw", {
|
|
@@ -2985,16 +3218,25 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
2985
3218
|
}
|
|
2986
3219
|
};
|
|
2987
3220
|
const enqueueNotification = (notification) => {
|
|
3221
|
+
if (!projector || !turnId) {
|
|
3222
|
+
userInputBridge?.handleNotification(notification);
|
|
3223
|
+
pendingNotifications.push(notification);
|
|
3224
|
+
return Promise.resolve();
|
|
3225
|
+
}
|
|
2988
3226
|
notificationQueue = notificationQueue.then(() => handleNotification(notification), () => handleNotification(notification));
|
|
2989
3227
|
return notificationQueue;
|
|
2990
3228
|
};
|
|
2991
3229
|
const notificationCleanup = client.addNotificationHandler(enqueueNotification);
|
|
2992
3230
|
const requestCleanup = client.addRequestHandler(async (request) => {
|
|
2993
|
-
activeAppServerTurnRequests += 1;
|
|
2994
|
-
clearTurnCompletionIdleTimer();
|
|
2995
|
-
disarmTurnAssistantCompletionIdleWatch();
|
|
2996
|
-
touchTurnCompletionActivity(`request:${request.method}`);
|
|
2997
3231
|
let armCompletionWatchOnResponse = false;
|
|
3232
|
+
let requestCountsAsTurnActivity = false;
|
|
3233
|
+
const markCurrentTurnRequestProgress = () => {
|
|
3234
|
+
activeAppServerTurnRequests += 1;
|
|
3235
|
+
clearTurnCompletionIdleTimer();
|
|
3236
|
+
disarmTurnAssistantCompletionIdleWatch();
|
|
3237
|
+
requestCountsAsTurnActivity = true;
|
|
3238
|
+
touchTurnCompletionActivity(`request:${request.method}:start`, { attemptProgress: true });
|
|
3239
|
+
};
|
|
2998
3240
|
try {
|
|
2999
3241
|
if (request.method === "account/chatgptAuthTokens/refresh") return refreshCodexAppServerAuthTokens({
|
|
3000
3242
|
agentDir,
|
|
@@ -3003,7 +3245,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3003
3245
|
});
|
|
3004
3246
|
if (!turnId) return;
|
|
3005
3247
|
if (request.method === "mcpServer/elicitation/request") {
|
|
3006
|
-
|
|
3248
|
+
if (isCurrentThreadOptionalTurnRequestParams(request.params, thread.threadId, turnId)) {
|
|
3249
|
+
armCompletionWatchOnResponse = true;
|
|
3250
|
+
markCurrentTurnRequestProgress();
|
|
3251
|
+
}
|
|
3007
3252
|
return handleCodexAppServerElicitationRequest({
|
|
3008
3253
|
requestParams: request.params,
|
|
3009
3254
|
paramsForRun: params,
|
|
@@ -3014,7 +3259,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3014
3259
|
});
|
|
3015
3260
|
}
|
|
3016
3261
|
if (request.method === "item/tool/requestUserInput") {
|
|
3017
|
-
|
|
3262
|
+
if (isCurrentThreadTurnRequestParams(request.params, thread.threadId, turnId)) {
|
|
3263
|
+
armCompletionWatchOnResponse = true;
|
|
3264
|
+
markCurrentTurnRequestProgress();
|
|
3265
|
+
}
|
|
3018
3266
|
return userInputBridge?.handleRequest({
|
|
3019
3267
|
id: request.id,
|
|
3020
3268
|
params: request.params
|
|
@@ -3022,7 +3270,10 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3022
3270
|
}
|
|
3023
3271
|
if (request.method !== "item/tool/call") {
|
|
3024
3272
|
if (isCodexAppServerApprovalRequest(request.method)) {
|
|
3025
|
-
|
|
3273
|
+
if (isCurrentApprovalTurnRequestParams(request.params, thread.threadId, turnId)) {
|
|
3274
|
+
armCompletionWatchOnResponse = true;
|
|
3275
|
+
markCurrentTurnRequestProgress();
|
|
3276
|
+
}
|
|
3026
3277
|
return handleApprovalRequest({
|
|
3027
3278
|
method: request.method,
|
|
3028
3279
|
params: request.params,
|
|
@@ -3037,6 +3288,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3037
3288
|
const call = readDynamicToolCallParams(request.params);
|
|
3038
3289
|
if (!call || call.threadId !== thread.threadId || call.turnId !== turnId) return;
|
|
3039
3290
|
armCompletionWatchOnResponse = true;
|
|
3291
|
+
markCurrentTurnRequestProgress();
|
|
3292
|
+
turnCrossedToolHandoff = true;
|
|
3040
3293
|
activeOpenClawDynamicToolCallIds.add(call.callId);
|
|
3041
3294
|
trajectoryRecorder?.recordEvent("tool.call", {
|
|
3042
3295
|
threadId: call.threadId,
|
|
@@ -3113,11 +3366,85 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3113
3366
|
});
|
|
3114
3367
|
return response;
|
|
3115
3368
|
} finally {
|
|
3116
|
-
|
|
3117
|
-
|
|
3369
|
+
if (requestCountsAsTurnActivity) {
|
|
3370
|
+
activeAppServerTurnRequests = Math.max(0, activeAppServerTurnRequests - 1);
|
|
3371
|
+
touchTurnCompletionActivity(`request:${request.method}:response`, {
|
|
3372
|
+
arm: armCompletionWatchOnResponse,
|
|
3373
|
+
attemptProgress: true
|
|
3374
|
+
});
|
|
3375
|
+
} else scheduleTurnProgressWatches();
|
|
3118
3376
|
}
|
|
3119
3377
|
});
|
|
3120
|
-
const
|
|
3378
|
+
const forceContextEngineCompactionForCodexOverflow = async (error) => {
|
|
3379
|
+
if (!activeContextEngine?.info.ownsCompaction) return false;
|
|
3380
|
+
embeddedAgentLog.warn("codex app-server context-engine turn overflowed; forcing context-engine compaction", {
|
|
3381
|
+
sessionId: activeSessionId,
|
|
3382
|
+
sessionKey: sandboxSessionKey,
|
|
3383
|
+
threadId: thread.threadId,
|
|
3384
|
+
engineId: activeContextEngine.info.id,
|
|
3385
|
+
tokenBudget: params.contextTokenBudget,
|
|
3386
|
+
error: formatErrorMessage(error)
|
|
3387
|
+
});
|
|
3388
|
+
try {
|
|
3389
|
+
const runtimeContext = buildActiveContextEngineRuntimeContext();
|
|
3390
|
+
const overflowTokenCount = params.contextTokenBudget ?? params.contextWindowInfo?.tokens;
|
|
3391
|
+
const compactResult = await activeContextEngine.compact({
|
|
3392
|
+
sessionId: activeSessionId,
|
|
3393
|
+
sessionKey: sandboxSessionKey,
|
|
3394
|
+
sessionFile: activeSessionFile,
|
|
3395
|
+
tokenBudget: params.contextTokenBudget,
|
|
3396
|
+
force: true,
|
|
3397
|
+
...overflowTokenCount ? { currentTokenCount: overflowTokenCount } : {},
|
|
3398
|
+
compactionTarget: "threshold",
|
|
3399
|
+
runtimeContext: overflowTokenCount ? {
|
|
3400
|
+
...runtimeContext,
|
|
3401
|
+
currentTokenCount: overflowTokenCount
|
|
3402
|
+
} : runtimeContext
|
|
3403
|
+
});
|
|
3404
|
+
embeddedAgentLog.info("codex app-server context-engine forced compaction result", {
|
|
3405
|
+
sessionId: activeSessionId,
|
|
3406
|
+
sessionKey: sandboxSessionKey,
|
|
3407
|
+
engineId: activeContextEngine.info.id,
|
|
3408
|
+
ok: compactResult.ok,
|
|
3409
|
+
compacted: compactResult.compacted,
|
|
3410
|
+
reason: compactResult.reason,
|
|
3411
|
+
tokensBefore: compactResult.result?.tokensBefore,
|
|
3412
|
+
tokensAfter: compactResult.result?.tokensAfter
|
|
3413
|
+
});
|
|
3414
|
+
if (!compactResult.ok || !compactResult.compacted) return false;
|
|
3415
|
+
adoptContextEngineCompactionTranscript(compactResult);
|
|
3416
|
+
const maintenanceRuntimeContext = buildActiveContextEngineRuntimeContext();
|
|
3417
|
+
await runHarnessContextEngineMaintenance({
|
|
3418
|
+
contextEngine: activeContextEngine,
|
|
3419
|
+
sessionId: activeSessionId,
|
|
3420
|
+
sessionKey: sandboxSessionKey,
|
|
3421
|
+
sessionFile: activeSessionFile,
|
|
3422
|
+
reason: "compaction",
|
|
3423
|
+
runtimeContext: maintenanceRuntimeContext,
|
|
3424
|
+
config: params.config
|
|
3425
|
+
});
|
|
3426
|
+
return true;
|
|
3427
|
+
} catch (compactErr) {
|
|
3428
|
+
embeddedAgentLog.warn("codex app-server context-engine forced compaction failed", {
|
|
3429
|
+
sessionId: params.sessionId,
|
|
3430
|
+
sessionKey: sandboxSessionKey,
|
|
3431
|
+
engineId: activeContextEngine.info.id,
|
|
3432
|
+
error: formatErrorMessage(compactErr)
|
|
3433
|
+
});
|
|
3434
|
+
return false;
|
|
3435
|
+
}
|
|
3436
|
+
};
|
|
3437
|
+
const rebuildPromptAfterContextEngineCompaction = async () => {
|
|
3438
|
+
historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
|
|
3439
|
+
resetCodexPromptInputs();
|
|
3440
|
+
try {
|
|
3441
|
+
await applyActiveContextEngineProjection(void 0);
|
|
3442
|
+
} catch (assembleErr) {
|
|
3443
|
+
embeddedAgentLog.warn("context engine assemble failed after forced compaction; using Codex baseline prompt", { error: formatErrorMessage(assembleErr) });
|
|
3444
|
+
}
|
|
3445
|
+
promptBuild = await buildPromptFromCurrentInputs();
|
|
3446
|
+
};
|
|
3447
|
+
const buildLlmInputEvent = () => ({
|
|
3121
3448
|
runId: params.runId,
|
|
3122
3449
|
sessionId: params.sessionId,
|
|
3123
3450
|
provider: params.provider,
|
|
@@ -3126,8 +3453,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3126
3453
|
prompt: promptBuild.prompt,
|
|
3127
3454
|
historyMessages,
|
|
3128
3455
|
imagesCount: params.images?.length ?? 0
|
|
3129
|
-
};
|
|
3130
|
-
const
|
|
3456
|
+
});
|
|
3457
|
+
const buildTurnStartFailureMessages = () => [...historyMessages, buildCodexUserPromptMessage({
|
|
3131
3458
|
...params,
|
|
3132
3459
|
prompt: promptBuild.prompt
|
|
3133
3460
|
})];
|
|
@@ -3143,7 +3470,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3143
3470
|
}));
|
|
3144
3471
|
try {
|
|
3145
3472
|
runAgentHarnessLlmInputHook({
|
|
3146
|
-
event:
|
|
3473
|
+
event: buildLlmInputEvent(),
|
|
3147
3474
|
ctx: hookContext
|
|
3148
3475
|
});
|
|
3149
3476
|
emitCodexAppServerEvent(params, {
|
|
@@ -3165,7 +3492,11 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3165
3492
|
threadId: thread.threadId,
|
|
3166
3493
|
error: formatErrorMessage(turnStartError)
|
|
3167
3494
|
});
|
|
3168
|
-
|
|
3495
|
+
const preRetrySessionFile = activeSessionFile;
|
|
3496
|
+
const compactedForRetry = await forceContextEngineCompactionForCodexOverflow(turnStartError);
|
|
3497
|
+
await clearCodexAppServerBinding(preRetrySessionFile);
|
|
3498
|
+
if (activeSessionFile !== preRetrySessionFile) await clearCodexAppServerBinding(activeSessionFile);
|
|
3499
|
+
if (compactedForRetry) await rebuildPromptAfterContextEngineCompaction();
|
|
3169
3500
|
thread = await restartContextEngineCodexThread();
|
|
3170
3501
|
emitCodexAppServerEvent(params, {
|
|
3171
3502
|
stream: "codex_app_server.lifecycle",
|
|
@@ -3219,7 +3550,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3219
3550
|
});
|
|
3220
3551
|
runAgentHarnessAgentEndHook({
|
|
3221
3552
|
event: {
|
|
3222
|
-
messages:
|
|
3553
|
+
messages: buildTurnStartFailureMessages(),
|
|
3223
3554
|
success: false,
|
|
3224
3555
|
error: turnStartErrorMessage,
|
|
3225
3556
|
durationMs: Date.now() - attemptStartedAt
|
|
@@ -3248,7 +3579,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3248
3579
|
return buildCodexTurnStartFailureResult({
|
|
3249
3580
|
params,
|
|
3250
3581
|
message: usageLimitError.message,
|
|
3251
|
-
messagesSnapshot:
|
|
3582
|
+
messagesSnapshot: buildTurnStartFailureMessages(),
|
|
3252
3583
|
systemPromptReport
|
|
3253
3584
|
});
|
|
3254
3585
|
}
|
|
@@ -3302,11 +3633,9 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3302
3633
|
abort: () => runAbortController.abort("aborted")
|
|
3303
3634
|
};
|
|
3304
3635
|
setActiveEmbeddedRun(params.sessionId, handle, params.sessionKey);
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
runAbortController.abort("timeout");
|
|
3309
|
-
}, Math.max(100, params.timeoutMs));
|
|
3636
|
+
turnAttemptIdleWatchArmed = true;
|
|
3637
|
+
turnTerminalIdleWatchArmed = true;
|
|
3638
|
+
touchTurnCompletionActivity("turn:start", { attemptProgress: true });
|
|
3310
3639
|
const abortListener = () => {
|
|
3311
3640
|
const shouldRetireClient = timedOut;
|
|
3312
3641
|
interruptCodexTurnBestEffort(client, {
|
|
@@ -3380,20 +3709,20 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3380
3709
|
});
|
|
3381
3710
|
if (activeContextEngine) {
|
|
3382
3711
|
const activeContextEnginePluginId = resolveContextEngineOwnerPluginId(activeContextEngine);
|
|
3383
|
-
const finalMessages = await readMirroredSessionHistoryMessages(
|
|
3712
|
+
const finalMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages.concat(result.messagesSnapshot);
|
|
3384
3713
|
await finalizeHarnessContextEngineTurn({
|
|
3385
3714
|
contextEngine: activeContextEngine,
|
|
3386
3715
|
promptError: Boolean(finalPromptError),
|
|
3387
3716
|
aborted: finalAborted,
|
|
3388
3717
|
yieldAborted: Boolean(result.yieldDetected),
|
|
3389
|
-
sessionIdUsed:
|
|
3718
|
+
sessionIdUsed: activeSessionId,
|
|
3390
3719
|
sessionKey: sandboxSessionKey,
|
|
3391
|
-
sessionFile:
|
|
3720
|
+
sessionFile: activeSessionFile,
|
|
3392
3721
|
messagesSnapshot: finalMessages,
|
|
3393
3722
|
prePromptMessageCount,
|
|
3394
3723
|
tokenBudget: params.contextTokenBudget,
|
|
3395
3724
|
runtimeContext: buildHarnessContextEngineRuntimeContextFromUsage({
|
|
3396
|
-
attempt:
|
|
3725
|
+
attempt: buildActiveRunAttemptParams(),
|
|
3397
3726
|
workspaceDir: effectiveWorkspace,
|
|
3398
3727
|
agentDir,
|
|
3399
3728
|
activeAgentId: sessionAgentId,
|
|
@@ -3462,7 +3791,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
|
|
|
3462
3791
|
});
|
|
3463
3792
|
if (!timedOut && !runAbortController.signal.aborted) await steeringQueue?.flushPending();
|
|
3464
3793
|
userInputBridge?.cancelPending();
|
|
3465
|
-
|
|
3794
|
+
clearTurnAttemptIdleTimer();
|
|
3466
3795
|
clearTurnCompletionIdleTimer();
|
|
3467
3796
|
clearTurnAssistantCompletionIdleTimer();
|
|
3468
3797
|
clearTurnTerminalIdleTimer();
|
|
@@ -3804,6 +4133,45 @@ function shouldProjectMirroredHistoryForCodexStart(params) {
|
|
|
3804
4133
|
next: params.dynamicToolsFingerprint
|
|
3805
4134
|
});
|
|
3806
4135
|
}
|
|
4136
|
+
function readContextEngineThreadBootstrapProjection(projection) {
|
|
4137
|
+
if (projection?.mode !== "thread_bootstrap") return;
|
|
4138
|
+
const epoch = projection.epoch?.trim();
|
|
4139
|
+
if (!epoch) {
|
|
4140
|
+
embeddedAgentLog.warn("context engine requested Codex thread-bootstrap projection without an epoch; using per-turn projection");
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
const fingerprint = projection.fingerprint?.trim();
|
|
4144
|
+
return {
|
|
4145
|
+
mode: "thread_bootstrap",
|
|
4146
|
+
epoch,
|
|
4147
|
+
...fingerprint ? { fingerprint } : {}
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
function resolveContextEngineBootstrapProjectionDecision(params) {
|
|
4151
|
+
const bindingProjection = params.startupBinding?.contextEngine?.projection;
|
|
4152
|
+
if (!params.startupBinding?.threadId || !bindingProjection) return {
|
|
4153
|
+
project: true,
|
|
4154
|
+
reason: !params.startupBinding?.threadId ? "missing-thread-binding" : "missing-projection-binding"
|
|
4155
|
+
};
|
|
4156
|
+
if (!params.expectedBinding || !isContextEngineBindingCompatible(params.startupBinding.contextEngine, params.expectedBinding)) return {
|
|
4157
|
+
project: true,
|
|
4158
|
+
reason: "context-engine-binding-mismatch"
|
|
4159
|
+
};
|
|
4160
|
+
if (!areCodexDynamicToolFingerprintsCompatible({
|
|
4161
|
+
previous: params.startupBinding.dynamicToolsFingerprint,
|
|
4162
|
+
next: params.dynamicToolsFingerprint
|
|
4163
|
+
})) return {
|
|
4164
|
+
project: true,
|
|
4165
|
+
reason: "dynamic-tools-mismatch"
|
|
4166
|
+
};
|
|
4167
|
+
return bindingProjection.mode !== "thread_bootstrap" || bindingProjection.epoch !== params.projection.epoch || bindingProjection.fingerprint !== params.projection.fingerprint ? {
|
|
4168
|
+
project: true,
|
|
4169
|
+
reason: "projection-mismatch"
|
|
4170
|
+
} : {
|
|
4171
|
+
project: false,
|
|
4172
|
+
reason: "matching-thread-bootstrap-binding"
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
3807
4175
|
async function withCodexStartupTimeout(params) {
|
|
3808
4176
|
if (params.signal.aborted) throw new Error("codex app-server startup aborted");
|
|
3809
4177
|
let timeout;
|
|
@@ -3985,6 +4353,10 @@ function isCompletedAssistantNotification(notification) {
|
|
|
3985
4353
|
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
3986
4354
|
return Boolean(item && readString(item, "type") === "agentMessage" && readString(item, "phase") !== "commentary");
|
|
3987
4355
|
}
|
|
4356
|
+
function isAssistantCompletionReleaseNotification(notification, turnCrossedToolHandoff) {
|
|
4357
|
+
if (isCompletedAssistantNotification(notification)) return true;
|
|
4358
|
+
return !turnCrossedToolHandoff && isRawAssistantCompletionNotification(notification);
|
|
4359
|
+
}
|
|
3988
4360
|
function shouldDisarmAssistantCompletionIdleWatch(notification) {
|
|
3989
4361
|
if (!isJsonObject(notification.params)) return false;
|
|
3990
4362
|
if (notification.method === "item/started") return true;
|
|
@@ -4004,6 +4376,28 @@ function isTrackedOpenClawDynamicToolCompletionNotification(notification, active
|
|
|
4004
4376
|
const itemType = item ? readString(item, "type") : void 0;
|
|
4005
4377
|
return itemType === void 0 || itemType === "dynamicToolCall";
|
|
4006
4378
|
}
|
|
4379
|
+
function isRawToolOutputCompletionNotification(notification) {
|
|
4380
|
+
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
4381
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
4382
|
+
return item ? readString(item, "type") === "custom_tool_call_output" : false;
|
|
4383
|
+
}
|
|
4384
|
+
function isNativeToolProgressNotification(notification) {
|
|
4385
|
+
if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "item/updated") return false;
|
|
4386
|
+
if (!isJsonObject(notification.params)) return false;
|
|
4387
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
4388
|
+
switch (item ? readString(item, "type") : void 0) {
|
|
4389
|
+
case "commandExecution":
|
|
4390
|
+
case "fileChange":
|
|
4391
|
+
case "mcpToolCall":
|
|
4392
|
+
case "webSearch": return true;
|
|
4393
|
+
default: return false;
|
|
4394
|
+
}
|
|
4395
|
+
}
|
|
4396
|
+
function isRawAssistantCompletionNotification(notification) {
|
|
4397
|
+
if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
|
|
4398
|
+
const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
|
|
4399
|
+
return Boolean(item && readString(item, "type") === "message" && readString(item, "role") === "assistant" && readString(item, "phase") !== "commentary" && readRawAssistantTextPreview(item));
|
|
4400
|
+
}
|
|
4007
4401
|
function readRawAssistantTextPreview(item) {
|
|
4008
4402
|
if (readString(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
|
|
4009
4403
|
const text = item.content.flatMap((content) => {
|
|
@@ -4018,6 +4412,19 @@ function isTurnNotification(value, threadId, turnId) {
|
|
|
4018
4412
|
if (!isJsonObject(value)) return false;
|
|
4019
4413
|
return readString(value, "threadId") === threadId && readNotificationTurnId(value) === turnId;
|
|
4020
4414
|
}
|
|
4415
|
+
function isCurrentThreadTurnRequestParams(value, threadId, turnId) {
|
|
4416
|
+
if (!isJsonObject(value)) return false;
|
|
4417
|
+
return readString(value, "threadId") === threadId && readString(value, "turnId") === turnId;
|
|
4418
|
+
}
|
|
4419
|
+
function isCurrentApprovalTurnRequestParams(value, threadId, turnId) {
|
|
4420
|
+
if (!isJsonObject(value)) return false;
|
|
4421
|
+
return (readString(value, "threadId") ?? readString(value, "conversationId")) === threadId && readString(value, "turnId") === turnId;
|
|
4422
|
+
}
|
|
4423
|
+
function isCurrentThreadOptionalTurnRequestParams(value, threadId, turnId) {
|
|
4424
|
+
if (!isJsonObject(value) || readString(value, "threadId") !== threadId) return false;
|
|
4425
|
+
const requestTurnId = value.turnId;
|
|
4426
|
+
return requestTurnId === null || requestTurnId === void 0 || requestTurnId === turnId;
|
|
4427
|
+
}
|
|
4021
4428
|
function isRetryableErrorNotification(value) {
|
|
4022
4429
|
if (!isJsonObject(value)) return false;
|
|
4023
4430
|
return readBoolean(value, "willRetry") === true || readBoolean(value, "will_retry") === true;
|
|
@@ -4289,6 +4696,11 @@ function prependCurrentTurnContext(prompt, context) {
|
|
|
4289
4696
|
const text = context?.text.trim();
|
|
4290
4697
|
return text ? [text, prompt].filter(Boolean).join("\n\n") : prompt;
|
|
4291
4698
|
}
|
|
4699
|
+
function waitForCodexNotificationDispatchTurn() {
|
|
4700
|
+
return new Promise((resolve) => {
|
|
4701
|
+
setImmediate(resolve);
|
|
4702
|
+
});
|
|
4703
|
+
}
|
|
4292
4704
|
function handleApprovalRequest(params) {
|
|
4293
4705
|
return handleCodexAppServerApprovalRequest({
|
|
4294
4706
|
method: params.method,
|