@agentconnect.md/codex-acp 1.10.0-agentconnect.2 → 1.12.0-agentconnect.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/README.md +11 -0
- package/dist/index.js +973 -863
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -22782,6 +22782,111 @@ function reversePatch(structuredPatch) {
|
|
|
22782
22782
|
return reversed;
|
|
22783
22783
|
}
|
|
22784
22784
|
|
|
22785
|
+
// src/DiffStats.ts
|
|
22786
|
+
var DiffStatsCalculator = class {
|
|
22787
|
+
addedFile(text) {
|
|
22788
|
+
return { version: 1, added: this.lineCount(text), removed: 0 };
|
|
22789
|
+
}
|
|
22790
|
+
deletedFile(text) {
|
|
22791
|
+
return { version: 1, added: 0, removed: this.lineCount(text) };
|
|
22792
|
+
}
|
|
22793
|
+
update(patch) {
|
|
22794
|
+
if (patch.isBinary || patch.hunks.length === 0) return null;
|
|
22795
|
+
let added = 0;
|
|
22796
|
+
let removed = 0;
|
|
22797
|
+
let previousOldEnd = 1;
|
|
22798
|
+
let previousNewEnd = 1;
|
|
22799
|
+
for (const hunk of patch.hunks) {
|
|
22800
|
+
const { oldStart, oldLines, newStart, newLines } = hunk;
|
|
22801
|
+
if (![oldStart, oldLines, newStart, newLines].every(Number.isSafeInteger) || oldStart < previousOldEnd || newStart < previousNewEnd || oldLines < 0 || newLines < 0 || newStart - oldStart !== added - removed) return null;
|
|
22802
|
+
let oldConsumed = 0;
|
|
22803
|
+
let newConsumed = 0;
|
|
22804
|
+
let previousWasContent = false;
|
|
22805
|
+
for (const line of hunk.lines) {
|
|
22806
|
+
switch (line[0]) {
|
|
22807
|
+
case "+":
|
|
22808
|
+
added++;
|
|
22809
|
+
newConsumed++;
|
|
22810
|
+
previousWasContent = true;
|
|
22811
|
+
break;
|
|
22812
|
+
case "-":
|
|
22813
|
+
removed++;
|
|
22814
|
+
oldConsumed++;
|
|
22815
|
+
previousWasContent = true;
|
|
22816
|
+
break;
|
|
22817
|
+
case " ":
|
|
22818
|
+
case void 0:
|
|
22819
|
+
oldConsumed++;
|
|
22820
|
+
newConsumed++;
|
|
22821
|
+
previousWasContent = true;
|
|
22822
|
+
break;
|
|
22823
|
+
case "\\":
|
|
22824
|
+
if (!previousWasContent || line.replace(/\r$/, "") !== "\") return null;
|
|
22825
|
+
previousWasContent = false;
|
|
22826
|
+
break;
|
|
22827
|
+
default:
|
|
22828
|
+
return null;
|
|
22829
|
+
}
|
|
22830
|
+
}
|
|
22831
|
+
if (oldConsumed !== oldLines || newConsumed !== newLines) return null;
|
|
22832
|
+
previousOldEnd = oldStart + oldLines;
|
|
22833
|
+
previousNewEnd = newStart + newLines;
|
|
22834
|
+
}
|
|
22835
|
+
return { version: 1, added, removed };
|
|
22836
|
+
}
|
|
22837
|
+
lineCount(text) {
|
|
22838
|
+
let count = 0;
|
|
22839
|
+
for (let offset = text.indexOf("\n"); offset >= 0; offset = text.indexOf("\n", offset + 1)) count++;
|
|
22840
|
+
for (let offset = text.indexOf("\r"); offset >= 0; offset = text.indexOf("\r", offset + 1)) {
|
|
22841
|
+
if (text[offset + 1] !== "\n") count++;
|
|
22842
|
+
}
|
|
22843
|
+
if (text.length > 0 && !text.endsWith("\n") && !text.endsWith("\r")) count++;
|
|
22844
|
+
return count;
|
|
22845
|
+
}
|
|
22846
|
+
};
|
|
22847
|
+
|
|
22848
|
+
// src/AirExtension.ts
|
|
22849
|
+
var JETBRAINS_META_KEY = "jetbrains";
|
|
22850
|
+
var AIR_META_KEY = "air";
|
|
22851
|
+
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
22852
|
+
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
22853
|
+
var AIR_DIFF_STATS_KEY = "diffStats";
|
|
22854
|
+
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
22855
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
22856
|
+
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
22857
|
+
var AIR_ASYNC_TASKS_KEY = "asyncTasks";
|
|
22858
|
+
var AIR_RECOMMENDED_CONFIG_VALUE_KEY = "recommendedValue";
|
|
22859
|
+
var AIR_ASYNC_TASKS_BACKGROUNDED_KEY = "backgrounded";
|
|
22860
|
+
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
22861
|
+
var AIR_EXTENSION_VERSION = 1;
|
|
22862
|
+
function withAirMeta(meta3, key, value) {
|
|
22863
|
+
const root = asRecord(meta3);
|
|
22864
|
+
const jetbrains = asRecord(root[JETBRAINS_META_KEY]);
|
|
22865
|
+
const air = asRecord(jetbrains[AIR_META_KEY]);
|
|
22866
|
+
return {
|
|
22867
|
+
...root,
|
|
22868
|
+
[JETBRAINS_META_KEY]: {
|
|
22869
|
+
...jetbrains,
|
|
22870
|
+
[AIR_META_KEY]: {
|
|
22871
|
+
...air,
|
|
22872
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
22873
|
+
[key]: value
|
|
22874
|
+
}
|
|
22875
|
+
}
|
|
22876
|
+
};
|
|
22877
|
+
}
|
|
22878
|
+
function clientSupportsAirCapability(capabilities, capability) {
|
|
22879
|
+
const meta3 = asRecord(capabilities?._meta);
|
|
22880
|
+
const jetbrains = asRecord(meta3[JETBRAINS_META_KEY]);
|
|
22881
|
+
const air = asRecord(jetbrains[AIR_META_KEY]);
|
|
22882
|
+
const version2 = air[AIR_EXTENSION_VERSION_KEY];
|
|
22883
|
+
const supported = air[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
22884
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
22885
|
+
}
|
|
22886
|
+
function asRecord(value) {
|
|
22887
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
22888
|
+
}
|
|
22889
|
+
|
|
22785
22890
|
// src/CodexToolCallMapper.ts
|
|
22786
22891
|
import { readFile } from "node:fs/promises";
|
|
22787
22892
|
import path2 from "node:path";
|
|
@@ -22834,8 +22939,26 @@ function createContextCompactionMeta(metadata = {}) {
|
|
|
22834
22939
|
};
|
|
22835
22940
|
}
|
|
22836
22941
|
|
|
22942
|
+
// src/ToolCallName.ts
|
|
22943
|
+
function functionToolName(name, namespace) {
|
|
22944
|
+
return `${namespace ?? ""}${name}`;
|
|
22945
|
+
}
|
|
22946
|
+
function commandToolName(source) {
|
|
22947
|
+
switch (source) {
|
|
22948
|
+
case "unifiedExecStartup":
|
|
22949
|
+
return "exec_command";
|
|
22950
|
+
case "unifiedExecInteraction":
|
|
22951
|
+
return "write_stdin";
|
|
22952
|
+
// These sources do not identify a unique model tool.
|
|
22953
|
+
case "agent":
|
|
22954
|
+
case "userShell":
|
|
22955
|
+
return void 0;
|
|
22956
|
+
}
|
|
22957
|
+
}
|
|
22958
|
+
|
|
22837
22959
|
// src/CodexToolCallMapper.ts
|
|
22838
22960
|
var CONTEXT_COMPACTION_META = createContextCompactionMeta();
|
|
22961
|
+
var DIFF_STATS = new DiffStatsCalculator();
|
|
22839
22962
|
function toAcpStatus(status) {
|
|
22840
22963
|
switch (status) {
|
|
22841
22964
|
case "inProgress":
|
|
@@ -22864,14 +22987,19 @@ async function createFileChangeUpdate(item) {
|
|
|
22864
22987
|
};
|
|
22865
22988
|
}
|
|
22866
22989
|
async function createCommandExecutionUpdate(item) {
|
|
22990
|
+
const name = commandToolName(item.source);
|
|
22867
22991
|
const commandAction = item.commandActions.length === 1 ? item.commandActions[0] : void 0;
|
|
22868
22992
|
if (commandAction) {
|
|
22869
|
-
return
|
|
22993
|
+
return {
|
|
22994
|
+
...createCommandActionEvent(item.id, item.status, item.cwd, commandAction),
|
|
22995
|
+
...name === void 0 ? {} : { name }
|
|
22996
|
+
};
|
|
22870
22997
|
}
|
|
22871
22998
|
const command = stripShellPrefix(item.command);
|
|
22872
22999
|
return createTerminalCommandEvent({
|
|
22873
23000
|
sessionUpdate: "tool_call",
|
|
22874
23001
|
toolCallId: item.id,
|
|
23002
|
+
...name === void 0 ? {} : { name },
|
|
22875
23003
|
kind: "execute",
|
|
22876
23004
|
title: command,
|
|
22877
23005
|
status: toAcpStatus(item.status),
|
|
@@ -22926,7 +23054,10 @@ async function createMcpToolCallUpdate(item) {
|
|
|
22926
23054
|
};
|
|
22927
23055
|
}
|
|
22928
23056
|
async function createDynamicToolCallUpdate(item) {
|
|
22929
|
-
return
|
|
23057
|
+
return {
|
|
23058
|
+
...await createExecuteToolCallUpdate(item, item.tool, { arguments: item.arguments }),
|
|
23059
|
+
name: functionToolName(item.tool, item.namespace)
|
|
23060
|
+
};
|
|
22930
23061
|
}
|
|
22931
23062
|
function createImageViewUpdate(item) {
|
|
22932
23063
|
const displayPath = item.path;
|
|
@@ -22934,6 +23065,7 @@ function createImageViewUpdate(item) {
|
|
|
22934
23065
|
sessionUpdate: "tool_call",
|
|
22935
23066
|
toolCallId: item.id,
|
|
22936
23067
|
kind: "read",
|
|
23068
|
+
name: "view_image",
|
|
22937
23069
|
title: `View Image ${displayPath}`,
|
|
22938
23070
|
status: "completed",
|
|
22939
23071
|
content: [createContent({
|
|
@@ -23491,53 +23623,43 @@ async function createAddFileContent(change) {
|
|
|
23491
23623
|
newText: change.diff,
|
|
23492
23624
|
// app-server always returns file content instead of diff
|
|
23493
23625
|
path: change.path,
|
|
23494
|
-
_meta: {
|
|
23495
|
-
kind: "add"
|
|
23496
|
-
}
|
|
23626
|
+
_meta: withAirMeta({ kind: "add" }, AIR_DIFF_STATS_KEY, DIFF_STATS.addedFile(change.diff))
|
|
23497
23627
|
};
|
|
23498
23628
|
}
|
|
23499
23629
|
async function createUpdateFileContent(change) {
|
|
23500
23630
|
if (change.kind.type !== "update") return null;
|
|
23501
23631
|
const unifiedDiff = recoverCorruptedDiff(change.diff);
|
|
23632
|
+
const patches = parsePatch(unifiedDiff);
|
|
23633
|
+
if (patches.length !== 1) return null;
|
|
23634
|
+
const patch = patches[0];
|
|
23502
23635
|
const movePath = change.kind.move_path;
|
|
23503
23636
|
const oldContent = await readFileContent(change.path);
|
|
23504
23637
|
if (oldContent !== null) {
|
|
23505
|
-
const patchedContent = applyPatch(oldContent,
|
|
23638
|
+
const patchedContent = applyPatch(oldContent, patch);
|
|
23506
23639
|
if (patchedContent === false) {
|
|
23507
|
-
const
|
|
23508
|
-
if (
|
|
23509
|
-
|
|
23510
|
-
if (revertedContent2 !== false) {
|
|
23511
|
-
return createUpdateDiffContent(change.path, revertedContent2, oldContent);
|
|
23512
|
-
}
|
|
23640
|
+
const revertedContent2 = applyPatch(oldContent, reversePatch(patch));
|
|
23641
|
+
if (revertedContent2 !== false) {
|
|
23642
|
+
return createUpdateDiffContent(change.path, revertedContent2, oldContent, patch);
|
|
23513
23643
|
}
|
|
23514
23644
|
return null;
|
|
23515
23645
|
}
|
|
23516
|
-
return createUpdateDiffContent(movePath ?? change.path, oldContent, patchedContent);
|
|
23646
|
+
return createUpdateDiffContent(movePath ?? change.path, oldContent, patchedContent, patch);
|
|
23517
23647
|
}
|
|
23518
23648
|
if (!movePath) return null;
|
|
23519
23649
|
const newContent = await readFileContent(movePath);
|
|
23520
23650
|
if (newContent === null) return null;
|
|
23521
|
-
const
|
|
23522
|
-
if (!revertedPatch) return null;
|
|
23523
|
-
const revertedContent = applyPatch(newContent, revertedPatch);
|
|
23651
|
+
const revertedContent = applyPatch(newContent, reversePatch(patch));
|
|
23524
23652
|
if (revertedContent === false) return null;
|
|
23525
|
-
return createUpdateDiffContent(movePath, revertedContent, newContent);
|
|
23526
|
-
}
|
|
23527
|
-
function revertPatch(unifiedDiff) {
|
|
23528
|
-
const [patch] = parsePatch(unifiedDiff);
|
|
23529
|
-
if (!patch) return null;
|
|
23530
|
-
return reversePatch(patch);
|
|
23653
|
+
return createUpdateDiffContent(movePath, revertedContent, newContent, patch);
|
|
23531
23654
|
}
|
|
23532
|
-
function createUpdateDiffContent(path9, oldText, newText) {
|
|
23655
|
+
function createUpdateDiffContent(path9, oldText, newText, patch) {
|
|
23656
|
+
const stats = DIFF_STATS.update(patch);
|
|
23533
23657
|
return {
|
|
23534
23658
|
type: "diff",
|
|
23535
23659
|
oldText,
|
|
23536
23660
|
newText,
|
|
23537
23661
|
path: path9,
|
|
23538
|
-
_meta: {
|
|
23539
|
-
kind: "update"
|
|
23540
|
-
}
|
|
23662
|
+
_meta: stats ? withAirMeta({ kind: "update" }, AIR_DIFF_STATS_KEY, stats) : { kind: "update" }
|
|
23541
23663
|
};
|
|
23542
23664
|
}
|
|
23543
23665
|
async function createDeleteFileContent(change) {
|
|
@@ -23547,9 +23669,7 @@ async function createDeleteFileContent(change) {
|
|
|
23547
23669
|
// app-server always returns file content instead of diff
|
|
23548
23670
|
newText: "",
|
|
23549
23671
|
path: change.path,
|
|
23550
|
-
_meta: {
|
|
23551
|
-
kind: "delete"
|
|
23552
|
-
}
|
|
23672
|
+
_meta: withAirMeta({ kind: "delete" }, AIR_DIFF_STATS_KEY, DIFF_STATS.deletedFile(change.diff))
|
|
23553
23673
|
};
|
|
23554
23674
|
}
|
|
23555
23675
|
async function readFileContent(filePath) {
|
|
@@ -23661,26 +23781,6 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23661
23781
|
// src/CodexEventHandler.ts
|
|
23662
23782
|
import { randomUUID } from "node:crypto";
|
|
23663
23783
|
|
|
23664
|
-
// src/AirExtension.ts
|
|
23665
|
-
var JETBRAINS_META_KEY = "jetbrains";
|
|
23666
|
-
var AIR_META_KEY = "air";
|
|
23667
|
-
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
23668
|
-
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
23669
|
-
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
23670
|
-
var AIR_AGENT_FILE_CHANGE_REPORT_KEY = "agentFileChangeReport";
|
|
23671
|
-
var AIR_NATIVE_SUBAGENT_SESSIONS_KEY = "nativeSubagentSessions";
|
|
23672
|
-
var AIR_ASYNC_TASKS_KEY = "asyncTasks";
|
|
23673
|
-
var AIR_ASYNC_TASKS_BACKGROUNDED_KEY = "backgrounded";
|
|
23674
|
-
var AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY = "agentFileChangeReportRequest";
|
|
23675
|
-
var AIR_EXTENSION_VERSION = 1;
|
|
23676
|
-
function clientSupportsAirCapability(capabilities, capability) {
|
|
23677
|
-
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
23678
|
-
const air = jetbrains?.[AIR_META_KEY];
|
|
23679
|
-
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
23680
|
-
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
23681
|
-
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(capability);
|
|
23682
|
-
}
|
|
23683
|
-
|
|
23684
23784
|
// src/subagents/CodexAgentPath.ts
|
|
23685
23785
|
function normalizeAgentPath(path9) {
|
|
23686
23786
|
const normalized = path9.trim().replace(/\/+$/, "");
|
|
@@ -24110,153 +24210,462 @@ function mergeRateLimitSnapshot(previous, update) {
|
|
|
24110
24210
|
};
|
|
24111
24211
|
}
|
|
24112
24212
|
|
|
24113
|
-
// src/
|
|
24114
|
-
|
|
24115
|
-
|
|
24116
|
-
|
|
24117
|
-
|
|
24118
|
-
|
|
24119
|
-
|
|
24120
|
-
|
|
24121
|
-
|
|
24122
|
-
|
|
24123
|
-
|
|
24124
|
-
|
|
24125
|
-
|
|
24126
|
-
|
|
24127
|
-
|
|
24128
|
-
|
|
24129
|
-
|
|
24130
|
-
|
|
24131
|
-
|
|
24132
|
-
|
|
24133
|
-
|
|
24134
|
-
|
|
24135
|
-
|
|
24136
|
-
context_exhausted: {
|
|
24137
|
-
category: "limit",
|
|
24138
|
-
actions: ["new_session"]
|
|
24139
|
-
},
|
|
24140
|
-
budget_exhausted: {
|
|
24141
|
-
category: "limit",
|
|
24142
|
-
actions: ["new_session"]
|
|
24143
|
-
},
|
|
24144
|
-
policy_denied: {
|
|
24145
|
-
category: "request",
|
|
24146
|
-
actions: []
|
|
24147
|
-
},
|
|
24148
|
-
bad_request: {
|
|
24149
|
-
category: "request",
|
|
24150
|
-
actions: []
|
|
24151
|
-
},
|
|
24152
|
-
provider_error: {
|
|
24153
|
-
category: "service",
|
|
24154
|
-
actions: ["retry"]
|
|
24155
|
-
},
|
|
24156
|
-
internal_error: {
|
|
24157
|
-
category: "service",
|
|
24158
|
-
actions: ["retry", "new_session"]
|
|
24213
|
+
// src/AgentFileChangeReport.ts
|
|
24214
|
+
import fs2 from "node:fs";
|
|
24215
|
+
import path3 from "node:path";
|
|
24216
|
+
var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
|
|
24217
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
|
|
24218
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH = 4096;
|
|
24219
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES = 256 * 1024;
|
|
24220
|
+
var AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES = 8 * 1024 * 1024;
|
|
24221
|
+
var TURN_DIFF_UNCERTAINTY = "Codex turn diffs may omit same-content renames and changes made outside apply_patch, including shell commands, version-control commands, generators, and child processes.";
|
|
24222
|
+
function captureAgentFileChangeWorkspace(cwd, additionalDirectories) {
|
|
24223
|
+
const lexicalCwd = parseWorkspaceRoot(cwd);
|
|
24224
|
+
return {
|
|
24225
|
+
cwd,
|
|
24226
|
+
additionalDirectories: [...additionalDirectories],
|
|
24227
|
+
diffRoot: lexicalCwd === null ? cwd : findDiffDisplayRoot(lexicalCwd).value
|
|
24228
|
+
};
|
|
24229
|
+
}
|
|
24230
|
+
function parseAgentFileChangeReportRequest(meta3) {
|
|
24231
|
+
const jetbrains = asRecord2(meta3?.[JETBRAINS_META_KEY]);
|
|
24232
|
+
const air = asRecord2(jetbrains?.[AIR_META_KEY]);
|
|
24233
|
+
const request = asRecord2(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
|
|
24234
|
+
if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
|
|
24235
|
+
return null;
|
|
24159
24236
|
}
|
|
24160
|
-
|
|
24161
|
-
|
|
24162
|
-
|
|
24163
|
-
|
|
24164
|
-
};
|
|
24165
|
-
function nextSessionFailureRevision(previous, id) {
|
|
24166
|
-
return previous?.id === id ? previous.revision + 1 : 1;
|
|
24237
|
+
const requestId = request["requestId"];
|
|
24238
|
+
if (typeof requestId !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId)) {
|
|
24239
|
+
return null;
|
|
24240
|
+
}
|
|
24241
|
+
return { version: AGENT_FILE_CHANGE_REPORT_VERSION, requestId };
|
|
24167
24242
|
}
|
|
24168
|
-
|
|
24169
|
-
|
|
24170
|
-
|
|
24171
|
-
usageLimitExceeded: "quota_exhausted",
|
|
24172
|
-
rateLimitExceeded: "rate_limited",
|
|
24173
|
-
serverOverloaded: "overloaded",
|
|
24174
|
-
cyberPolicy: "policy_denied",
|
|
24175
|
-
misalignmentPolicyViolation: "policy_denied",
|
|
24176
|
-
internalServerError: "internal_error",
|
|
24177
|
-
unauthorized: "auth_required",
|
|
24178
|
-
badRequest: "bad_request",
|
|
24179
|
-
threadRollbackFailed: "provider_error",
|
|
24180
|
-
sandboxError: "provider_error",
|
|
24181
|
-
other: "provider_error"
|
|
24182
|
-
};
|
|
24183
|
-
var STRUCTURED_CODEX_ERROR_CATEGORIES = {
|
|
24184
|
-
httpConnectionFailed: "transport_lost",
|
|
24185
|
-
responseStreamConnectionFailed: "transport_lost",
|
|
24186
|
-
responseStreamDisconnected: "transport_lost",
|
|
24187
|
-
responseTooManyFailedAttempts: "transport_lost",
|
|
24188
|
-
activeTurnNotSteerable: "provider_error"
|
|
24189
|
-
};
|
|
24190
|
-
var CodexEventHandler = class _CodexEventHandler {
|
|
24191
|
-
static PLAN_UPDATE_INTERVAL_MS = 150;
|
|
24192
|
-
sessionState;
|
|
24193
|
-
supportsPlanUpdates;
|
|
24194
|
-
supportsTypedSessionFailures;
|
|
24195
|
-
sessionFailureEpoch;
|
|
24196
|
-
pendingErrors = [];
|
|
24197
|
-
failuresById = /* @__PURE__ */ new Map();
|
|
24198
|
-
activeFailureIdByScope = /* @__PURE__ */ new Map();
|
|
24199
|
-
failureTurnIdById = /* @__PURE__ */ new Map();
|
|
24200
|
-
allocatedFailureScopes = /* @__PURE__ */ new Set();
|
|
24201
|
-
lastSessionNotice;
|
|
24202
|
-
nextNoticeId = 1;
|
|
24203
|
-
failure = null;
|
|
24204
|
-
completedPlan = null;
|
|
24205
|
-
activeFuzzyFileSearchSessions = /* @__PURE__ */ new Set();
|
|
24206
|
-
activeGuardianApprovalReviews = /* @__PURE__ */ new Set();
|
|
24207
|
-
activeImageGenerationItems = /* @__PURE__ */ new Set();
|
|
24208
|
-
emittedImageViewItems = /* @__PURE__ */ new Set();
|
|
24209
|
-
planDeltaTextByItemId = /* @__PURE__ */ new Map();
|
|
24210
|
-
pendingPlanItemIds = /* @__PURE__ */ new Set();
|
|
24211
|
-
lastEmittedPlanTextByItemId = /* @__PURE__ */ new Map();
|
|
24212
|
-
session;
|
|
24213
|
-
planUpdateTimer = null;
|
|
24214
|
-
planUpdateChain = Promise.resolve();
|
|
24215
|
-
disposed = false;
|
|
24216
|
-
seenReasoningDeltaItemIds = /* @__PURE__ */ new Set();
|
|
24217
|
-
terminalCommandIds = /* @__PURE__ */ new Set();
|
|
24218
|
-
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
24219
|
-
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
24220
|
-
subagents;
|
|
24221
|
-
/** Connection-level `authStatus` sink; the app-server account push feeds it. */
|
|
24222
|
-
onAccountUpdated;
|
|
24223
|
-
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID(), subagents = new CodexSubagentEventRouter(
|
|
24224
|
-
sessionState.sessionId,
|
|
24225
|
-
false,
|
|
24226
|
-
new ACPSessionConnection(connection, sessionState.sessionId)
|
|
24227
|
-
), onAccountUpdated) {
|
|
24228
|
-
this.onAccountUpdated = onAccountUpdated;
|
|
24229
|
-
this.sessionState = sessionState;
|
|
24230
|
-
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
24231
|
-
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
24232
|
-
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
24233
|
-
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
24234
|
-
this.subagents = subagents;
|
|
24235
|
-
if (sessionState.sessionFailure !== void 0) {
|
|
24236
|
-
this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
|
|
24237
|
-
}
|
|
24243
|
+
function createReportedAgentFileChangeReport(requestId, diff, workspace) {
|
|
24244
|
+
if (Buffer.byteLength(diff, "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES) {
|
|
24245
|
+
throw new AgentFileChangeReportError("invalidOutput", "The turn diff exceeds the parser input limit");
|
|
24238
24246
|
}
|
|
24239
|
-
|
|
24240
|
-
|
|
24247
|
+
const parsedReport = parseTurnDiff(diff);
|
|
24248
|
+
const normalized = normalizeFileChangeReport(parsedReport, workspace);
|
|
24249
|
+
return fitReportedAgentFileChangeReport({
|
|
24250
|
+
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
24251
|
+
requestId,
|
|
24252
|
+
status: "reported",
|
|
24253
|
+
...normalized
|
|
24254
|
+
});
|
|
24255
|
+
}
|
|
24256
|
+
function createUnavailableAgentFileChangeReport(requestId, reason) {
|
|
24257
|
+
return {
|
|
24258
|
+
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
24259
|
+
requestId,
|
|
24260
|
+
status: "unavailable",
|
|
24261
|
+
reason
|
|
24262
|
+
};
|
|
24263
|
+
}
|
|
24264
|
+
var AgentFileChangeReportError = class extends Error {
|
|
24265
|
+
reason;
|
|
24266
|
+
constructor(reason, message) {
|
|
24267
|
+
super(message);
|
|
24268
|
+
this.name = "AgentFileChangeReportError";
|
|
24269
|
+
this.reason = reason;
|
|
24241
24270
|
}
|
|
24242
|
-
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
}
|
|
24247
|
-
return this.createSessionFailureMeta(failure);
|
|
24271
|
+
};
|
|
24272
|
+
function parseTurnDiff(diff) {
|
|
24273
|
+
if (diff.trim() === "") {
|
|
24274
|
+
return { paths: [], complete: false, uncertainty: TURN_DIFF_UNCERTAINTY };
|
|
24248
24275
|
}
|
|
24249
|
-
|
|
24250
|
-
|
|
24276
|
+
let patches;
|
|
24277
|
+
try {
|
|
24278
|
+
patches = parsePatch(diff);
|
|
24279
|
+
} catch (error51) {
|
|
24280
|
+
throw new AgentFileChangeReportError(
|
|
24281
|
+
"invalidOutput",
|
|
24282
|
+
`The turn diff is not valid unified diff: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
24283
|
+
);
|
|
24251
24284
|
}
|
|
24252
|
-
|
|
24253
|
-
|
|
24254
|
-
|
|
24255
|
-
|
|
24256
|
-
|
|
24257
|
-
|
|
24258
|
-
|
|
24259
|
-
|
|
24285
|
+
if (patches.length === 0) {
|
|
24286
|
+
throw new AgentFileChangeReportError("invalidOutput", "The turn diff contains no parseable file patches");
|
|
24287
|
+
}
|
|
24288
|
+
const rawFileHeaders = extractRawFileHeaders(diff);
|
|
24289
|
+
const paths = [];
|
|
24290
|
+
for (const [index, patch] of patches.entries()) {
|
|
24291
|
+
const rawHeaders = rawFileHeaders[index];
|
|
24292
|
+
const oldPath = normalizeDiffPath(selectLosslessFileName(rawHeaders?.oldFileName, patch.oldFileName));
|
|
24293
|
+
const newPath = normalizeDiffPath(selectLosslessFileName(rawHeaders?.newFileName, patch.newFileName));
|
|
24294
|
+
if (oldPath === null && newPath === null) {
|
|
24295
|
+
throw new AgentFileChangeReportError("invalidOutput", "The turn diff contains a patch without a file path");
|
|
24296
|
+
}
|
|
24297
|
+
if (oldPath !== null) paths.push(oldPath);
|
|
24298
|
+
if (newPath !== null) paths.push(newPath);
|
|
24299
|
+
}
|
|
24300
|
+
return { paths, complete: false, uncertainty: TURN_DIFF_UNCERTAINTY };
|
|
24301
|
+
}
|
|
24302
|
+
function extractRawFileHeaders(diff) {
|
|
24303
|
+
return diff.split(/(?=^diff --git )/m).filter((section) => section.trim() !== "").map((section) => {
|
|
24304
|
+
const lines = section.split(/\r?\n/);
|
|
24305
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
24306
|
+
const line = lines[index];
|
|
24307
|
+
if (line?.startsWith("@@ ")) return null;
|
|
24308
|
+
const nextLine = lines[index + 1];
|
|
24309
|
+
if (line?.startsWith("--- ") && nextLine?.startsWith("+++ ")) {
|
|
24310
|
+
return {
|
|
24311
|
+
oldFileName: line.slice(4),
|
|
24312
|
+
newFileName: nextLine.slice(4)
|
|
24313
|
+
};
|
|
24314
|
+
}
|
|
24315
|
+
}
|
|
24316
|
+
return null;
|
|
24317
|
+
});
|
|
24318
|
+
}
|
|
24319
|
+
function selectLosslessFileName(rawFileName, parsedFileName) {
|
|
24320
|
+
return rawFileName === void 0 || rawFileName.startsWith('"') ? parsedFileName : rawFileName;
|
|
24321
|
+
}
|
|
24322
|
+
function normalizeDiffPath(value) {
|
|
24323
|
+
if (value === void 0 || value === "/dev/null") return null;
|
|
24324
|
+
return value.startsWith("a/") || value.startsWith("b/") ? value.slice(2) : value;
|
|
24325
|
+
}
|
|
24326
|
+
function fitReportedAgentFileChangeReport(report) {
|
|
24327
|
+
const paths = [...report.paths];
|
|
24328
|
+
let truncated = report.truncated;
|
|
24329
|
+
let fitted = report;
|
|
24330
|
+
while (Buffer.byteLength(JSON.stringify(fitted), "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
24331
|
+
if (paths.length === 0) {
|
|
24332
|
+
throw new AgentFileChangeReportError("invalidOutput", "The audit report exceeds the wire limit");
|
|
24333
|
+
}
|
|
24334
|
+
paths.pop();
|
|
24335
|
+
truncated = true;
|
|
24336
|
+
fitted = {
|
|
24337
|
+
...report,
|
|
24338
|
+
paths: [...paths],
|
|
24339
|
+
declaredComplete: false,
|
|
24340
|
+
truncated
|
|
24341
|
+
};
|
|
24342
|
+
}
|
|
24343
|
+
return fitted;
|
|
24344
|
+
}
|
|
24345
|
+
function normalizeFileChangeReport(report, workspace) {
|
|
24346
|
+
const lexicalCwd = parseWorkspaceRoot(workspace.cwd);
|
|
24347
|
+
if (lexicalCwd === null) {
|
|
24348
|
+
throw new AgentFileChangeReportError("providerError", "The session working directory is not absolute");
|
|
24349
|
+
}
|
|
24350
|
+
const cwd = canonicalizeWorkspaceRoot(lexicalCwd);
|
|
24351
|
+
const diffRoot = parseWorkspaceRoot(workspace.diffRoot);
|
|
24352
|
+
if (diffRoot === null || diffRoot.flavor !== cwd.flavor) {
|
|
24353
|
+
throw new AgentFileChangeReportError("providerError", "The captured turn-diff root is invalid");
|
|
24354
|
+
}
|
|
24355
|
+
const roots = [cwd, ...workspace.additionalDirectories.flatMap((directory) => {
|
|
24356
|
+
const root = normalizeWorkspaceRoot(directory);
|
|
24357
|
+
return root === null || root.flavor !== cwd.flavor ? [] : [root];
|
|
24358
|
+
})];
|
|
24359
|
+
const paths = [];
|
|
24360
|
+
const seen = /* @__PURE__ */ new Set();
|
|
24361
|
+
let totalBytes = 0;
|
|
24362
|
+
let truncated = false;
|
|
24363
|
+
for (const reportedPath of report.paths) {
|
|
24364
|
+
if (reportedPath.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
24365
|
+
truncated = true;
|
|
24366
|
+
continue;
|
|
24367
|
+
}
|
|
24368
|
+
const normalized = normalizeReportedPath(reportedPath, diffRoot, roots);
|
|
24369
|
+
if (normalized === null || normalized.value.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
24370
|
+
truncated = true;
|
|
24371
|
+
continue;
|
|
24372
|
+
}
|
|
24373
|
+
const key = normalized.flavor === "windows" ? normalized.value.toLowerCase() : normalized.value;
|
|
24374
|
+
if (seen.has(key)) {
|
|
24375
|
+
continue;
|
|
24376
|
+
}
|
|
24377
|
+
const bytes = Buffer.byteLength(normalized.value, "utf8");
|
|
24378
|
+
if (paths.length >= AGENT_FILE_CHANGE_REPORT_MAX_PATHS || totalBytes + bytes > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
24379
|
+
truncated = true;
|
|
24380
|
+
continue;
|
|
24381
|
+
}
|
|
24382
|
+
seen.add(key);
|
|
24383
|
+
paths.push(normalized.value);
|
|
24384
|
+
totalBytes += bytes;
|
|
24385
|
+
}
|
|
24386
|
+
return {
|
|
24387
|
+
paths,
|
|
24388
|
+
declaredComplete: report.complete && !truncated,
|
|
24389
|
+
truncated,
|
|
24390
|
+
...report.uncertainty ? { uncertainty: report.uncertainty } : {}
|
|
24391
|
+
};
|
|
24392
|
+
}
|
|
24393
|
+
function normalizeWorkspaceRoot(value) {
|
|
24394
|
+
const root = parseWorkspaceRoot(value);
|
|
24395
|
+
return root === null ? null : canonicalizeWorkspaceRoot(root);
|
|
24396
|
+
}
|
|
24397
|
+
function parseWorkspaceRoot(value) {
|
|
24398
|
+
const trimmed = value.trim();
|
|
24399
|
+
if (!isValidPathText(trimmed)) {
|
|
24400
|
+
return null;
|
|
24401
|
+
}
|
|
24402
|
+
if (isWindowsAbsolutePath(trimmed)) {
|
|
24403
|
+
return {
|
|
24404
|
+
value: path3.win32.normalize(trimmed.replace(/\//g, "\\")),
|
|
24405
|
+
flavor: "windows"
|
|
24406
|
+
};
|
|
24407
|
+
}
|
|
24408
|
+
if (path3.posix.isAbsolute(trimmed)) {
|
|
24409
|
+
return {
|
|
24410
|
+
value: path3.posix.normalize(trimmed.replace(/\\/g, "/")),
|
|
24411
|
+
flavor: "posix"
|
|
24412
|
+
};
|
|
24413
|
+
}
|
|
24414
|
+
return null;
|
|
24415
|
+
}
|
|
24416
|
+
function normalizeReportedPath(value, relativeRoot, roots) {
|
|
24417
|
+
if (!isValidPathText(value) || /^[A-Za-z]:[^\\/]/.test(value) || /^\\\\[?.]\\/.test(value) || /^(?:\\\\|\/\/)/.test(value) && !isWindowsAbsolutePath(value) || relativeRoot.flavor === "windows" && /^\\(?!\\)/.test(value) || /^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(value)) {
|
|
24418
|
+
return null;
|
|
24419
|
+
}
|
|
24420
|
+
let candidate;
|
|
24421
|
+
if (isWindowsAbsolutePath(value)) {
|
|
24422
|
+
candidate = { value: path3.win32.normalize(value.replace(/\//g, "\\")), flavor: "windows" };
|
|
24423
|
+
} else if (path3.posix.isAbsolute(value)) {
|
|
24424
|
+
candidate = { value: path3.posix.normalize(value.replace(/\\/g, "/")), flavor: "posix" };
|
|
24425
|
+
} else if (relativeRoot.flavor === "windows") {
|
|
24426
|
+
candidate = {
|
|
24427
|
+
value: path3.win32.resolve(relativeRoot.value, value.replace(/\//g, "\\")),
|
|
24428
|
+
flavor: "windows"
|
|
24429
|
+
};
|
|
24430
|
+
} else {
|
|
24431
|
+
candidate = {
|
|
24432
|
+
value: path3.posix.resolve(relativeRoot.value, value.replace(/\\/g, "/")),
|
|
24433
|
+
flavor: "posix"
|
|
24434
|
+
};
|
|
24435
|
+
}
|
|
24436
|
+
candidate = canonicalizeReportedPath(candidate);
|
|
24437
|
+
return roots.some((root) => pathIsStrictlyInside(root, candidate)) ? candidate : null;
|
|
24438
|
+
}
|
|
24439
|
+
function findDiffDisplayRoot(cwd) {
|
|
24440
|
+
if (!isNativePathFlavor(cwd.flavor)) return cwd;
|
|
24441
|
+
const pathImplementation = cwd.flavor === "windows" ? path3.win32 : path3.posix;
|
|
24442
|
+
let current = cwd.value;
|
|
24443
|
+
while (true) {
|
|
24444
|
+
if (fs2.existsSync(pathImplementation.join(current, ".git"))) {
|
|
24445
|
+
return canonicalizeWorkspaceRoot({ value: current, flavor: cwd.flavor });
|
|
24446
|
+
}
|
|
24447
|
+
const parent = pathImplementation.dirname(current);
|
|
24448
|
+
if (parent === current) return cwd;
|
|
24449
|
+
current = parent;
|
|
24450
|
+
}
|
|
24451
|
+
}
|
|
24452
|
+
function canonicalizeWorkspaceRoot(root) {
|
|
24453
|
+
if (!isNativePathFlavor(root.flavor)) {
|
|
24454
|
+
return root;
|
|
24455
|
+
}
|
|
24456
|
+
return { ...root, value: canonicalizeFromExistingAncestor(root.value) };
|
|
24457
|
+
}
|
|
24458
|
+
function canonicalizeReportedPath(candidate) {
|
|
24459
|
+
if (!isNativePathFlavor(candidate.flavor)) {
|
|
24460
|
+
return candidate;
|
|
24461
|
+
}
|
|
24462
|
+
const parent = canonicalizeFromExistingAncestor(path3.dirname(candidate.value));
|
|
24463
|
+
return { ...candidate, value: path3.resolve(parent, path3.basename(candidate.value)) };
|
|
24464
|
+
}
|
|
24465
|
+
function canonicalizeFromExistingAncestor(value) {
|
|
24466
|
+
const original = path3.resolve(value);
|
|
24467
|
+
let current = original;
|
|
24468
|
+
const missingSegments = [];
|
|
24469
|
+
while (true) {
|
|
24470
|
+
try {
|
|
24471
|
+
const canonical = fs2.realpathSync.native(current);
|
|
24472
|
+
return path3.resolve(canonical, ...missingSegments.reverse());
|
|
24473
|
+
} catch (error51) {
|
|
24474
|
+
if (!isMissingPathError(error51)) return original;
|
|
24475
|
+
}
|
|
24476
|
+
const parent = path3.dirname(current);
|
|
24477
|
+
if (parent === current) return original;
|
|
24478
|
+
missingSegments.push(path3.basename(current));
|
|
24479
|
+
current = parent;
|
|
24480
|
+
}
|
|
24481
|
+
}
|
|
24482
|
+
function isMissingPathError(error51) {
|
|
24483
|
+
if (typeof error51 !== "object" || error51 === null || !("code" in error51)) return false;
|
|
24484
|
+
return error51.code === "ENOENT" || error51.code === "ENOTDIR";
|
|
24485
|
+
}
|
|
24486
|
+
function isNativePathFlavor(flavor) {
|
|
24487
|
+
return process.platform === "win32" ? flavor === "windows" : flavor === "posix";
|
|
24488
|
+
}
|
|
24489
|
+
function pathIsStrictlyInside(root, candidate) {
|
|
24490
|
+
if (root.flavor !== candidate.flavor) {
|
|
24491
|
+
return false;
|
|
24492
|
+
}
|
|
24493
|
+
const pathImplementation = root.flavor === "windows" ? path3.win32 : path3.posix;
|
|
24494
|
+
const relative = pathImplementation.relative(root.value, candidate.value);
|
|
24495
|
+
return relative.length > 0 && !pathImplementation.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${pathImplementation.sep}`);
|
|
24496
|
+
}
|
|
24497
|
+
function isWindowsAbsolutePath(value) {
|
|
24498
|
+
const portable = value.replace(/\\/g, "/");
|
|
24499
|
+
return /^[A-Za-z]:\//.test(portable) || /^\/\/[^/]+\/[^/]+(?:\/|$)/.test(portable);
|
|
24500
|
+
}
|
|
24501
|
+
function isValidPathText(value) {
|
|
24502
|
+
return value.length > 0 && !/[\u0000-\u001F\u007F-\u009F]/.test(value);
|
|
24503
|
+
}
|
|
24504
|
+
function asRecord2(value) {
|
|
24505
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
24506
|
+
}
|
|
24507
|
+
function hasOnlyKeys(value, allowed) {
|
|
24508
|
+
const allowedKeys = new Set(allowed);
|
|
24509
|
+
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
24510
|
+
}
|
|
24511
|
+
|
|
24512
|
+
// src/CodexEventHandler.ts
|
|
24513
|
+
var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
|
|
24514
|
+
var SESSION_FAILURE_POLICY = {
|
|
24515
|
+
transport_lost: {
|
|
24516
|
+
category: "connection",
|
|
24517
|
+
actions: ["retry", "new_session"]
|
|
24518
|
+
},
|
|
24519
|
+
auth_required: {
|
|
24520
|
+
category: "access",
|
|
24521
|
+
actions: ["login"]
|
|
24522
|
+
},
|
|
24523
|
+
rate_limited: {
|
|
24524
|
+
category: "limit",
|
|
24525
|
+
actions: ["retry"]
|
|
24526
|
+
},
|
|
24527
|
+
quota_exhausted: {
|
|
24528
|
+
category: "limit",
|
|
24529
|
+
actions: []
|
|
24530
|
+
},
|
|
24531
|
+
overloaded: {
|
|
24532
|
+
category: "service",
|
|
24533
|
+
actions: ["retry"]
|
|
24534
|
+
},
|
|
24535
|
+
context_exhausted: {
|
|
24536
|
+
category: "limit",
|
|
24537
|
+
actions: ["new_session"]
|
|
24538
|
+
},
|
|
24539
|
+
budget_exhausted: {
|
|
24540
|
+
category: "limit",
|
|
24541
|
+
actions: ["new_session"]
|
|
24542
|
+
},
|
|
24543
|
+
policy_denied: {
|
|
24544
|
+
category: "request",
|
|
24545
|
+
actions: []
|
|
24546
|
+
},
|
|
24547
|
+
bad_request: {
|
|
24548
|
+
category: "request",
|
|
24549
|
+
actions: []
|
|
24550
|
+
},
|
|
24551
|
+
provider_error: {
|
|
24552
|
+
category: "service",
|
|
24553
|
+
actions: ["retry"]
|
|
24554
|
+
},
|
|
24555
|
+
internal_error: {
|
|
24556
|
+
category: "service",
|
|
24557
|
+
actions: ["retry", "new_session"]
|
|
24558
|
+
}
|
|
24559
|
+
};
|
|
24560
|
+
var SYNTHETIC_FAILURE_TITLE = {
|
|
24561
|
+
transport_lost: "Connection to Codex was lost.",
|
|
24562
|
+
internal_error: "Codex encountered an internal error."
|
|
24563
|
+
};
|
|
24564
|
+
function nextSessionFailureRevision(previous, id) {
|
|
24565
|
+
return previous?.id === id ? previous.revision + 1 : 1;
|
|
24566
|
+
}
|
|
24567
|
+
var STRING_CODEX_ERROR_CATEGORIES = {
|
|
24568
|
+
contextWindowExceeded: "context_exhausted",
|
|
24569
|
+
sessionBudgetExceeded: "budget_exhausted",
|
|
24570
|
+
usageLimitExceeded: "quota_exhausted",
|
|
24571
|
+
rateLimitExceeded: "rate_limited",
|
|
24572
|
+
serverOverloaded: "overloaded",
|
|
24573
|
+
cyberPolicy: "policy_denied",
|
|
24574
|
+
misalignmentPolicyViolation: "policy_denied",
|
|
24575
|
+
internalServerError: "internal_error",
|
|
24576
|
+
unauthorized: "auth_required",
|
|
24577
|
+
badRequest: "bad_request",
|
|
24578
|
+
threadRollbackFailed: "provider_error",
|
|
24579
|
+
sandboxError: "provider_error",
|
|
24580
|
+
other: "provider_error"
|
|
24581
|
+
};
|
|
24582
|
+
var STRUCTURED_CODEX_ERROR_CATEGORIES = {
|
|
24583
|
+
httpConnectionFailed: "transport_lost",
|
|
24584
|
+
responseStreamConnectionFailed: "transport_lost",
|
|
24585
|
+
responseStreamDisconnected: "transport_lost",
|
|
24586
|
+
responseTooManyFailedAttempts: "transport_lost",
|
|
24587
|
+
activeTurnNotSteerable: "provider_error"
|
|
24588
|
+
};
|
|
24589
|
+
var CodexEventHandler = class _CodexEventHandler {
|
|
24590
|
+
static PLAN_UPDATE_INTERVAL_MS = 150;
|
|
24591
|
+
sessionState;
|
|
24592
|
+
supportsPlanUpdates;
|
|
24593
|
+
supportsTypedSessionFailures;
|
|
24594
|
+
sessionFailureEpoch;
|
|
24595
|
+
pendingErrors = [];
|
|
24596
|
+
failuresById = /* @__PURE__ */ new Map();
|
|
24597
|
+
activeFailureIdByScope = /* @__PURE__ */ new Map();
|
|
24598
|
+
failureTurnIdById = /* @__PURE__ */ new Map();
|
|
24599
|
+
allocatedFailureScopes = /* @__PURE__ */ new Set();
|
|
24600
|
+
lastSessionNotice;
|
|
24601
|
+
nextNoticeId = 1;
|
|
24602
|
+
failure = null;
|
|
24603
|
+
completedPlan = null;
|
|
24604
|
+
activeFuzzyFileSearchSessions = /* @__PURE__ */ new Set();
|
|
24605
|
+
activeGuardianApprovalReviews = /* @__PURE__ */ new Set();
|
|
24606
|
+
activeImageGenerationItems = /* @__PURE__ */ new Set();
|
|
24607
|
+
emittedImageViewItems = /* @__PURE__ */ new Set();
|
|
24608
|
+
planDeltaTextByItemId = /* @__PURE__ */ new Map();
|
|
24609
|
+
pendingPlanItemIds = /* @__PURE__ */ new Set();
|
|
24610
|
+
lastEmittedPlanTextByItemId = /* @__PURE__ */ new Map();
|
|
24611
|
+
session;
|
|
24612
|
+
planUpdateTimer = null;
|
|
24613
|
+
planUpdateChain = Promise.resolve();
|
|
24614
|
+
disposed = false;
|
|
24615
|
+
seenReasoningDeltaItemIds = /* @__PURE__ */ new Set();
|
|
24616
|
+
terminalCommandIds = /* @__PURE__ */ new Set();
|
|
24617
|
+
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
24618
|
+
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
24619
|
+
turnDiffs = /* @__PURE__ */ new Map();
|
|
24620
|
+
oversizedTurnDiffs = /* @__PURE__ */ new Set();
|
|
24621
|
+
collectTurnDiffs;
|
|
24622
|
+
subagents;
|
|
24623
|
+
/** Connection-level `authStatus` sink; the app-server account push feeds it. */
|
|
24624
|
+
onAccountUpdated;
|
|
24625
|
+
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID(), subagents = new CodexSubagentEventRouter(
|
|
24626
|
+
sessionState.sessionId,
|
|
24627
|
+
false,
|
|
24628
|
+
new ACPSessionConnection(connection, sessionState.sessionId)
|
|
24629
|
+
), onAccountUpdated, collectTurnDiffs = false) {
|
|
24630
|
+
this.onAccountUpdated = onAccountUpdated;
|
|
24631
|
+
this.sessionState = sessionState;
|
|
24632
|
+
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
24633
|
+
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
24634
|
+
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
24635
|
+
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
24636
|
+
this.subagents = subagents;
|
|
24637
|
+
this.collectTurnDiffs = collectTurnDiffs;
|
|
24638
|
+
if (sessionState.sessionFailure !== void 0) {
|
|
24639
|
+
this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
|
|
24640
|
+
}
|
|
24641
|
+
}
|
|
24642
|
+
getFailure() {
|
|
24643
|
+
return this.failure;
|
|
24644
|
+
}
|
|
24645
|
+
getTurnDiff(turnId) {
|
|
24646
|
+
return this.turnDiffs.get(turnId) ?? "";
|
|
24647
|
+
}
|
|
24648
|
+
isTurnDiffOversized(turnId) {
|
|
24649
|
+
return this.oversizedTurnDiffs.has(turnId);
|
|
24650
|
+
}
|
|
24651
|
+
getTerminalSessionFailureMeta(turnId, allowUnattributed = false) {
|
|
24652
|
+
const failure = this.sessionState.sessionFailure;
|
|
24653
|
+
if (!this.supportsTypedSessionFailures || failure === void 0 || (this.failureTurnIdById.get(failure.id) === void 0 ? !allowUnattributed : turnId === null || this.failureTurnIdById.get(failure.id) !== turnId)) {
|
|
24654
|
+
return null;
|
|
24655
|
+
}
|
|
24656
|
+
return this.createSessionFailureMeta(failure);
|
|
24657
|
+
}
|
|
24658
|
+
recordSyntheticTerminalFailure(kind, turnId) {
|
|
24659
|
+
this.recordSessionFailure(kind, turnId ?? void 0, "error", SYNTHETIC_FAILURE_TITLE[kind]);
|
|
24660
|
+
}
|
|
24661
|
+
/**
|
|
24662
|
+
* Handles notifications after the prompt-local handler has been disposed. The app-server subscription
|
|
24663
|
+
* remains installed until the ACP session closes, so terminal errors need a durable session-level path
|
|
24664
|
+
* instead of entering a turn buffer that will never be flushed.
|
|
24665
|
+
*/
|
|
24666
|
+
async handleSessionScopedNotification(notification) {
|
|
24667
|
+
if (notification.method !== "error") {
|
|
24668
|
+
await this.handleNotification(notification);
|
|
24260
24669
|
return;
|
|
24261
24670
|
}
|
|
24262
24671
|
if (!this.supportsTypedSessionFailures) {
|
|
@@ -24398,6 +24807,8 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
24398
24807
|
this.pendingPlanItemIds.clear();
|
|
24399
24808
|
this.planDeltaTextByItemId.clear();
|
|
24400
24809
|
this.lastEmittedPlanTextByItemId.clear();
|
|
24810
|
+
this.turnDiffs.clear();
|
|
24811
|
+
this.oversizedTurnDiffs.clear();
|
|
24401
24812
|
}
|
|
24402
24813
|
async createUpdateEvent(notification) {
|
|
24403
24814
|
switch (notification.method) {
|
|
@@ -24416,6 +24827,20 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
24416
24827
|
case "turn/plan/updated":
|
|
24417
24828
|
this.completeRetryIncidentOnTurnProgress();
|
|
24418
24829
|
return await this.updatePlan(notification.params);
|
|
24830
|
+
case "turn/diff/updated":
|
|
24831
|
+
if (notification.params.threadId === this.sessionState.sessionId) {
|
|
24832
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
24833
|
+
if (!this.disposed && this.collectTurnDiffs) {
|
|
24834
|
+
if (Buffer.byteLength(notification.params.diff, "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_DIFF_BYTES) {
|
|
24835
|
+
this.turnDiffs.delete(notification.params.turnId);
|
|
24836
|
+
this.oversizedTurnDiffs.add(notification.params.turnId);
|
|
24837
|
+
} else {
|
|
24838
|
+
this.oversizedTurnDiffs.delete(notification.params.turnId);
|
|
24839
|
+
this.turnDiffs.set(notification.params.turnId, notification.params.diff);
|
|
24840
|
+
}
|
|
24841
|
+
}
|
|
24842
|
+
}
|
|
24843
|
+
return null;
|
|
24419
24844
|
case "error":
|
|
24420
24845
|
return await this.createErrorEvent(notification.params);
|
|
24421
24846
|
case "turn/started":
|
|
@@ -24510,7 +24935,6 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
24510
24935
|
case "command/exec/outputDelta":
|
|
24511
24936
|
case "hook/started":
|
|
24512
24937
|
case "hook/completed":
|
|
24513
|
-
case "turn/diff/updated":
|
|
24514
24938
|
case "turn/moderationMetadata":
|
|
24515
24939
|
case "item/fileChange/outputDelta":
|
|
24516
24940
|
case "item/fileChange/patchUpdated":
|
|
@@ -24694,10 +25118,16 @@ ${event.details}` : event.summary;
|
|
|
24694
25118
|
async completeItemEvent(event) {
|
|
24695
25119
|
switch (event.item.type) {
|
|
24696
25120
|
case "fileChange":
|
|
25121
|
+
return {
|
|
25122
|
+
sessionUpdate: "tool_call_update",
|
|
25123
|
+
toolCallId: event.item.id,
|
|
25124
|
+
status: event.item.status === "completed" ? "completed" : "failed"
|
|
25125
|
+
};
|
|
24697
25126
|
case "dynamicToolCall":
|
|
24698
25127
|
return {
|
|
24699
25128
|
sessionUpdate: "tool_call_update",
|
|
24700
25129
|
toolCallId: event.item.id,
|
|
25130
|
+
name: functionToolName(event.item.tool, event.item.namespace),
|
|
24701
25131
|
status: event.item.status === "completed" ? "completed" : "failed"
|
|
24702
25132
|
};
|
|
24703
25133
|
case "mcpToolCall":
|
|
@@ -24909,9 +25339,11 @@ ${event.stdin}
|
|
|
24909
25339
|
return `mcp_startup.${encodeURIComponent(serverName)}`;
|
|
24910
25340
|
}
|
|
24911
25341
|
completeCommandExecutionEvent(item) {
|
|
25342
|
+
const name = commandToolName(item.source);
|
|
24912
25343
|
const update = {
|
|
24913
25344
|
sessionUpdate: "tool_call_update",
|
|
24914
25345
|
toolCallId: item.id,
|
|
25346
|
+
...name === void 0 ? {} : { name },
|
|
24915
25347
|
status: item.status === "completed" ? "completed" : "failed",
|
|
24916
25348
|
rawOutput: {
|
|
24917
25349
|
formatted_output: item.aggregatedOutput ?? "",
|
|
@@ -25527,7 +25959,8 @@ function nonBlank(value) {
|
|
|
25527
25959
|
}
|
|
25528
25960
|
|
|
25529
25961
|
// src/permissions/presentation.ts
|
|
25530
|
-
function commandToolCall(params) {
|
|
25962
|
+
function commandToolCall(params, permissionContext) {
|
|
25963
|
+
const name = permissionContext.commandName(params.threadId, params.itemId);
|
|
25531
25964
|
const network = params.networkApprovalContext;
|
|
25532
25965
|
const rawInput = {
|
|
25533
25966
|
...params.command ? { command: stripShellPrefix(params.command) } : {},
|
|
@@ -25538,6 +25971,7 @@ function commandToolCall(params) {
|
|
|
25538
25971
|
const additionalPermissionContent = params.additionalPermissions ? permissionProfileContent(params.additionalPermissions) : [];
|
|
25539
25972
|
return {
|
|
25540
25973
|
toolCallId: params.itemId,
|
|
25974
|
+
...name !== void 0 ? { name } : {},
|
|
25541
25975
|
kind: "execute",
|
|
25542
25976
|
status: "pending",
|
|
25543
25977
|
title: network ? `${network.protocol} network access to ${network.host}` : commandTitle(params.commandActions),
|
|
@@ -25563,6 +25997,7 @@ function additionalPermissionsToolCall(itemId, cwd, environmentId, permissions)
|
|
|
25563
25997
|
const content = permissionProfileContent(permissions);
|
|
25564
25998
|
return {
|
|
25565
25999
|
toolCallId: itemId,
|
|
26000
|
+
name: "request_permissions",
|
|
25566
26001
|
kind: "other",
|
|
25567
26002
|
status: "pending",
|
|
25568
26003
|
title: "Additional sandbox permissions",
|
|
@@ -25661,7 +26096,7 @@ var CodexApprovalHandler = class {
|
|
|
25661
26096
|
try {
|
|
25662
26097
|
const response = await this.requestPermission({
|
|
25663
26098
|
sessionId: params.threadId,
|
|
25664
|
-
toolCall: commandToolCall(authoritativeParams),
|
|
26099
|
+
toolCall: commandToolCall(authoritativeParams, this.permissionContext),
|
|
25665
26100
|
options: decisions.map(({ option }) => option),
|
|
25666
26101
|
_meta: requestPermissionMeta(
|
|
25667
26102
|
params.networkApprovalContext ? CODEX_NETWORK_PERMISSION_TITLE : CODEX_COMMAND_PERMISSION_TITLE,
|
|
@@ -25769,6 +26204,7 @@ var PermissionPromptContext = class {
|
|
|
25769
26204
|
this.nextStandaloneId = nextStandaloneId;
|
|
25770
26205
|
}
|
|
25771
26206
|
nextStandaloneId;
|
|
26207
|
+
commandNames = /* @__PURE__ */ new Map();
|
|
25772
26208
|
fileChanges = /* @__PURE__ */ new Map();
|
|
25773
26209
|
pendingMcpApprovals = /* @__PURE__ */ new Map();
|
|
25774
26210
|
handleNotification(notification) {
|
|
@@ -25792,6 +26228,9 @@ var PermissionPromptContext = class {
|
|
|
25792
26228
|
fileChange(threadId, itemId) {
|
|
25793
26229
|
return this.fileChanges.get(threadId)?.get(itemId);
|
|
25794
26230
|
}
|
|
26231
|
+
commandName(threadId, itemId) {
|
|
26232
|
+
return this.commandNames.get(threadId)?.get(itemId);
|
|
26233
|
+
}
|
|
25795
26234
|
popPendingMcpApproval(threadId, serverName) {
|
|
25796
26235
|
const byServer = this.pendingMcpApprovals.get(threadId);
|
|
25797
26236
|
if (!byServer) return void 0;
|
|
@@ -25806,6 +26245,15 @@ var PermissionPromptContext = class {
|
|
|
25806
26245
|
return this.nextStandaloneId(serverName);
|
|
25807
26246
|
}
|
|
25808
26247
|
handleItemStarted(threadId, item) {
|
|
26248
|
+
if (item.type === "commandExecution") {
|
|
26249
|
+
const name = commandToolName(item.source);
|
|
26250
|
+
if (name !== void 0) {
|
|
26251
|
+
const byItem = this.commandNames.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
26252
|
+
byItem.set(item.id, name);
|
|
26253
|
+
this.commandNames.set(threadId, byItem);
|
|
26254
|
+
}
|
|
26255
|
+
return;
|
|
26256
|
+
}
|
|
25809
26257
|
if (item.type === "fileChange") {
|
|
25810
26258
|
const byItem = this.fileChanges.get(threadId) ?? /* @__PURE__ */ new Map();
|
|
25811
26259
|
byItem.set(item.id, item);
|
|
@@ -25820,6 +26268,12 @@ var PermissionPromptContext = class {
|
|
|
25820
26268
|
this.pendingMcpApprovals.set(threadId, byServer);
|
|
25821
26269
|
}
|
|
25822
26270
|
handleItemCompleted(threadId, item) {
|
|
26271
|
+
if (item.type === "commandExecution") {
|
|
26272
|
+
const byItem = this.commandNames.get(threadId);
|
|
26273
|
+
byItem?.delete(item.id);
|
|
26274
|
+
if (byItem?.size === 0) this.commandNames.delete(threadId);
|
|
26275
|
+
return;
|
|
26276
|
+
}
|
|
25823
26277
|
if (item.type === "fileChange") {
|
|
25824
26278
|
const byItem = this.fileChanges.get(threadId);
|
|
25825
26279
|
byItem?.delete(item.id);
|
|
@@ -25837,6 +26291,7 @@ var PermissionPromptContext = class {
|
|
|
25837
26291
|
if (byServer.size === 0) this.pendingMcpApprovals.delete(threadId);
|
|
25838
26292
|
}
|
|
25839
26293
|
clearTransientState(threadId) {
|
|
26294
|
+
this.commandNames.delete(threadId);
|
|
25840
26295
|
this.fileChanges.delete(threadId);
|
|
25841
26296
|
this.pendingMcpApprovals.delete(threadId);
|
|
25842
26297
|
}
|
|
@@ -25969,8 +26424,9 @@ function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToo
|
|
|
25969
26424
|
toolCallId: nextStandaloneToolCallId(),
|
|
25970
26425
|
kind: context.isToolApproval ? "execute" : "other",
|
|
25971
26426
|
status: "pending",
|
|
26427
|
+
title: context.isToolApproval ? "MCP tool call approval" : "Question from MCP server",
|
|
25972
26428
|
content: [messageContent],
|
|
25973
|
-
rawInput: { serverName: params.serverName, schema: params.requestedSchema }
|
|
26429
|
+
rawInput: { serverName: params.serverName, description: params.message, schema: params.requestedSchema }
|
|
25974
26430
|
},
|
|
25975
26431
|
...context.isToolApproval ? { _meta: { is_mcp_tool_approval: true } } : {},
|
|
25976
26432
|
options
|
|
@@ -25988,8 +26444,9 @@ function buildMcpPermissionRequest(sessionId, params, context, nextStandaloneToo
|
|
|
25988
26444
|
toolCallId: `elicitation-${params.elicitationId}`,
|
|
25989
26445
|
kind: "fetch",
|
|
25990
26446
|
status: "pending",
|
|
26447
|
+
title: "MCP server requests to open a URL",
|
|
25991
26448
|
content: [messageContent],
|
|
25992
|
-
rawInput: { serverName: params.serverName, url: params.url }
|
|
26449
|
+
rawInput: { serverName: params.serverName, description: params.message, url: params.url }
|
|
25993
26450
|
},
|
|
25994
26451
|
options
|
|
25995
26452
|
},
|
|
@@ -26023,7 +26480,9 @@ function cancelledResponse() {
|
|
|
26023
26480
|
}
|
|
26024
26481
|
|
|
26025
26482
|
// src/CodexElicitationHandler.ts
|
|
26026
|
-
var
|
|
26483
|
+
var USER_INPUT_NOTE_FIELD_SUFFIX = "_note";
|
|
26484
|
+
var USER_INPUT_OTHER_OPTION = "None of the above";
|
|
26485
|
+
var USER_INPUT_NOTE_PREFIX = "user_note: ";
|
|
26027
26486
|
function normalizeElicitationSchema(value) {
|
|
26028
26487
|
const normalized = normalizeElicitationSchemaValue(value);
|
|
26029
26488
|
if (!isRecord2(normalized)) {
|
|
@@ -26080,16 +26539,14 @@ function elicitationResponseMeta(response, context, persist = void 0) {
|
|
|
26080
26539
|
}
|
|
26081
26540
|
return Object.keys(meta3).length === 0 ? null : meta3;
|
|
26082
26541
|
}
|
|
26083
|
-
function
|
|
26084
|
-
const base = `${questionId}${
|
|
26085
|
-
|
|
26086
|
-
return base;
|
|
26087
|
-
}
|
|
26542
|
+
function userInputNoteFieldId(questionId, questionIds) {
|
|
26543
|
+
const base = `${questionId}${USER_INPUT_NOTE_FIELD_SUFFIX}`;
|
|
26544
|
+
let fieldId = base;
|
|
26088
26545
|
let index = 1;
|
|
26089
|
-
while (questionIds.has(
|
|
26090
|
-
|
|
26546
|
+
while (questionIds.has(fieldId)) {
|
|
26547
|
+
fieldId = `${base}${index++}`;
|
|
26091
26548
|
}
|
|
26092
|
-
return
|
|
26549
|
+
return fieldId;
|
|
26093
26550
|
}
|
|
26094
26551
|
function userInputResponseValue(content, fieldId) {
|
|
26095
26552
|
const value = content[fieldId];
|
|
@@ -26166,11 +26623,29 @@ var CodexElicitationHandler = class {
|
|
|
26166
26623
|
context.isToolApproval,
|
|
26167
26624
|
context.persistOptions
|
|
26168
26625
|
);
|
|
26169
|
-
if (correlatedCallId !== void 0
|
|
26170
|
-
|
|
26171
|
-
|
|
26172
|
-
|
|
26173
|
-
|
|
26626
|
+
if (correlatedCallId !== void 0) {
|
|
26627
|
+
if (result.action === "accept") {
|
|
26628
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26629
|
+
sessionId: params.threadId,
|
|
26630
|
+
update: { sessionUpdate: "tool_call_update", toolCallId: correlatedCallId, status: "in_progress" }
|
|
26631
|
+
});
|
|
26632
|
+
}
|
|
26633
|
+
} else {
|
|
26634
|
+
try {
|
|
26635
|
+
await this.connection.notify(methods.client.session.update, {
|
|
26636
|
+
sessionId: params.threadId,
|
|
26637
|
+
update: {
|
|
26638
|
+
sessionUpdate: "tool_call_update",
|
|
26639
|
+
toolCallId: request.toolCall.toolCallId,
|
|
26640
|
+
status: "completed",
|
|
26641
|
+
title: request.toolCall.title,
|
|
26642
|
+
content: request.toolCall.content,
|
|
26643
|
+
rawOutput: { action: result.action }
|
|
26644
|
+
}
|
|
26645
|
+
});
|
|
26646
|
+
} catch (error51) {
|
|
26647
|
+
logger.error("Failed to finalize standalone MCP elicitation tool call", error51);
|
|
26648
|
+
}
|
|
26174
26649
|
}
|
|
26175
26650
|
return result;
|
|
26176
26651
|
} catch (error51) {
|
|
@@ -26308,8 +26783,8 @@ var CodexElicitationHandler = class {
|
|
|
26308
26783
|
const hasOptions = options.length > 0;
|
|
26309
26784
|
const hasOtherAnswer = question.isOther && hasOptions;
|
|
26310
26785
|
const base = {
|
|
26311
|
-
title: question.header || question.id,
|
|
26312
|
-
description: question.
|
|
26786
|
+
title: question.question || question.header || question.id,
|
|
26787
|
+
...question.header ? { description: question.header } : {},
|
|
26313
26788
|
_meta: {
|
|
26314
26789
|
codex: {
|
|
26315
26790
|
isOther: question.isOther,
|
|
@@ -26317,42 +26792,45 @@ var CodexElicitationHandler = class {
|
|
|
26317
26792
|
}
|
|
26318
26793
|
}
|
|
26319
26794
|
};
|
|
26320
|
-
|
|
26321
|
-
required2.push(question.id);
|
|
26322
|
-
}
|
|
26795
|
+
required2.push(question.id);
|
|
26323
26796
|
properties[question.id] = hasOptions ? {
|
|
26324
26797
|
...base,
|
|
26325
26798
|
type: "string",
|
|
26326
|
-
oneOf:
|
|
26327
|
-
|
|
26328
|
-
|
|
26329
|
-
|
|
26330
|
-
|
|
26799
|
+
oneOf: [
|
|
26800
|
+
...options.map((option) => ({
|
|
26801
|
+
const: option.label,
|
|
26802
|
+
title: option.label,
|
|
26803
|
+
...option.description ? { description: option.description } : {}
|
|
26804
|
+
})),
|
|
26805
|
+
...hasOtherAnswer && !options.some((option) => option.label === USER_INPUT_OTHER_OPTION) ? [{
|
|
26806
|
+
const: USER_INPUT_OTHER_OPTION,
|
|
26807
|
+
title: USER_INPUT_OTHER_OPTION,
|
|
26808
|
+
description: "Provide a different answer in the note field."
|
|
26809
|
+
}] : []
|
|
26810
|
+
]
|
|
26331
26811
|
} : {
|
|
26332
26812
|
...base,
|
|
26333
26813
|
type: "string"
|
|
26334
26814
|
};
|
|
26335
26815
|
if (hasOtherAnswer) {
|
|
26336
|
-
properties[
|
|
26816
|
+
properties[userInputNoteFieldId(question.id, questionIds)] = {
|
|
26337
26817
|
type: "string",
|
|
26338
|
-
title: "
|
|
26339
|
-
description: "Type your own answer instead of choosing an option above.",
|
|
26818
|
+
title: "Additional answer or note",
|
|
26340
26819
|
_meta: {
|
|
26341
26820
|
codex: {
|
|
26342
26821
|
questionId: question.id,
|
|
26343
|
-
|
|
26822
|
+
role: "user_note",
|
|
26344
26823
|
isSecret: question.isSecret
|
|
26345
26824
|
}
|
|
26346
26825
|
}
|
|
26347
26826
|
};
|
|
26348
26827
|
}
|
|
26349
26828
|
}
|
|
26350
|
-
const firstQuestion = params.questions[0];
|
|
26351
26829
|
return {
|
|
26352
26830
|
sessionId: params.threadId,
|
|
26353
26831
|
toolCallId: params.itemId,
|
|
26354
26832
|
mode: "form",
|
|
26355
|
-
message:
|
|
26833
|
+
message: "Codex needs your input to continue.",
|
|
26356
26834
|
requestedSchema: {
|
|
26357
26835
|
type: "object",
|
|
26358
26836
|
properties,
|
|
@@ -26403,12 +26881,23 @@ var CodexElicitationHandler = class {
|
|
|
26403
26881
|
const content = contentRecord(response.content);
|
|
26404
26882
|
const questionIds = new Set(params.questions.map((question) => question.id));
|
|
26405
26883
|
for (const question of params.questions) {
|
|
26406
|
-
const
|
|
26407
|
-
|
|
26884
|
+
const answerValues = [];
|
|
26885
|
+
const value = userInputResponseValue(content, question.id);
|
|
26886
|
+
if (value !== void 0) {
|
|
26887
|
+
answerValues.push(...Array.isArray(value) ? value.map(String) : [String(value)]);
|
|
26888
|
+
}
|
|
26889
|
+
if (question.isOther && question.options != null && question.options.length > 0) {
|
|
26890
|
+
const note = userInputResponseValue(content, userInputNoteFieldId(question.id, questionIds));
|
|
26891
|
+
if (note !== void 0) {
|
|
26892
|
+
const notes = Array.isArray(note) ? note : [note];
|
|
26893
|
+
answerValues.push(...notes.map((item) => `${USER_INPUT_NOTE_PREFIX}${String(item).trim()}`));
|
|
26894
|
+
}
|
|
26895
|
+
}
|
|
26896
|
+
if (answerValues.length === 0) {
|
|
26408
26897
|
continue;
|
|
26409
26898
|
}
|
|
26410
26899
|
answers[question.id] = {
|
|
26411
|
-
answers:
|
|
26900
|
+
answers: answerValues
|
|
26412
26901
|
};
|
|
26413
26902
|
}
|
|
26414
26903
|
return { answers };
|
|
@@ -26498,31 +26987,31 @@ function isCodexAuthRequest(request) {
|
|
|
26498
26987
|
|
|
26499
26988
|
// node_modules/open/index.js
|
|
26500
26989
|
import process11 from "node:process";
|
|
26501
|
-
import
|
|
26990
|
+
import path5 from "node:path";
|
|
26502
26991
|
import { fileURLToPath } from "node:url";
|
|
26503
26992
|
import childProcess4 from "node:child_process";
|
|
26504
|
-
import
|
|
26993
|
+
import fs7, { constants as fsConstants2 } from "node:fs/promises";
|
|
26505
26994
|
|
|
26506
26995
|
// node_modules/wsl-utils/index.js
|
|
26507
|
-
import
|
|
26996
|
+
import path4 from "node:path";
|
|
26508
26997
|
import { promisify as promisify2 } from "node:util";
|
|
26509
26998
|
import childProcess2 from "node:child_process";
|
|
26510
|
-
import
|
|
26999
|
+
import fs6, { constants as fsConstants } from "node:fs/promises";
|
|
26511
27000
|
|
|
26512
27001
|
// node_modules/is-wsl/index.js
|
|
26513
27002
|
import process3 from "node:process";
|
|
26514
27003
|
import os from "node:os";
|
|
26515
|
-
import
|
|
27004
|
+
import fs5 from "node:fs";
|
|
26516
27005
|
|
|
26517
27006
|
// node_modules/is-inside-container/index.js
|
|
26518
|
-
import
|
|
27007
|
+
import fs4 from "node:fs";
|
|
26519
27008
|
|
|
26520
27009
|
// node_modules/is-docker/index.js
|
|
26521
|
-
import
|
|
27010
|
+
import fs3 from "node:fs";
|
|
26522
27011
|
var isDockerCached;
|
|
26523
27012
|
function hasDockerEnv() {
|
|
26524
27013
|
try {
|
|
26525
|
-
|
|
27014
|
+
fs3.statSync("/.dockerenv");
|
|
26526
27015
|
return true;
|
|
26527
27016
|
} catch {
|
|
26528
27017
|
return false;
|
|
@@ -26530,7 +27019,7 @@ function hasDockerEnv() {
|
|
|
26530
27019
|
}
|
|
26531
27020
|
function hasDockerCGroup() {
|
|
26532
27021
|
try {
|
|
26533
|
-
return
|
|
27022
|
+
return fs3.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
26534
27023
|
} catch {
|
|
26535
27024
|
return false;
|
|
26536
27025
|
}
|
|
@@ -26546,7 +27035,7 @@ function isDocker() {
|
|
|
26546
27035
|
var cachedResult;
|
|
26547
27036
|
var hasContainerEnv = () => {
|
|
26548
27037
|
try {
|
|
26549
|
-
|
|
27038
|
+
fs4.statSync("/run/.containerenv");
|
|
26550
27039
|
return true;
|
|
26551
27040
|
} catch {
|
|
26552
27041
|
return false;
|
|
@@ -26571,12 +27060,12 @@ var isWsl = () => {
|
|
|
26571
27060
|
return true;
|
|
26572
27061
|
}
|
|
26573
27062
|
try {
|
|
26574
|
-
if (
|
|
27063
|
+
if (fs5.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
|
|
26575
27064
|
return !isInsideContainer();
|
|
26576
27065
|
}
|
|
26577
27066
|
} catch {
|
|
26578
27067
|
}
|
|
26579
|
-
if (
|
|
27068
|
+
if (fs5.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs5.existsSync("/run/WSL")) {
|
|
26580
27069
|
return !isInsideContainer();
|
|
26581
27070
|
}
|
|
26582
27071
|
return false;
|
|
@@ -26644,14 +27133,14 @@ var wslDrivesMountPoint = /* @__PURE__ */ (() => {
|
|
|
26644
27133
|
const configFilePath = "/etc/wsl.conf";
|
|
26645
27134
|
let isConfigFileExists = false;
|
|
26646
27135
|
try {
|
|
26647
|
-
await
|
|
27136
|
+
await fs6.access(configFilePath, fsConstants.F_OK);
|
|
26648
27137
|
isConfigFileExists = true;
|
|
26649
27138
|
} catch {
|
|
26650
27139
|
}
|
|
26651
27140
|
if (!isConfigFileExists) {
|
|
26652
27141
|
return defaultMountPoint;
|
|
26653
27142
|
}
|
|
26654
|
-
const configContent = await
|
|
27143
|
+
const configContent = await fs6.readFile(configFilePath, { encoding: "utf8" });
|
|
26655
27144
|
const parsedMountPoint = parseMountPointFromConfig(configContent);
|
|
26656
27145
|
if (parsedMountPoint === void 0) {
|
|
26657
27146
|
return defaultMountPoint;
|
|
@@ -26671,7 +27160,7 @@ var canAccessPowerShell = async () => {
|
|
|
26671
27160
|
canAccessPowerShellPromise ??= (async () => {
|
|
26672
27161
|
try {
|
|
26673
27162
|
const psPath = await powerShellPath2();
|
|
26674
|
-
await
|
|
27163
|
+
await fs6.access(psPath, fsConstants.X_OK);
|
|
26675
27164
|
return true;
|
|
26676
27165
|
} catch {
|
|
26677
27166
|
return false;
|
|
@@ -26684,7 +27173,7 @@ var wslDefaultBrowser = async () => {
|
|
|
26684
27173
|
const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
|
|
26685
27174
|
const { stdout } = await executePowerShell(command, {
|
|
26686
27175
|
powerShellPath: psPath,
|
|
26687
|
-
cwd:
|
|
27176
|
+
cwd: path4.dirname(psPath)
|
|
26688
27177
|
});
|
|
26689
27178
|
return stdout.trim();
|
|
26690
27179
|
};
|
|
@@ -26890,8 +27379,8 @@ var is_in_ssh_default = isInSsh;
|
|
|
26890
27379
|
|
|
26891
27380
|
// node_modules/open/index.js
|
|
26892
27381
|
var fallbackAttemptSymbol = /* @__PURE__ */ Symbol("fallbackAttempt");
|
|
26893
|
-
var __dirname = import.meta.url ?
|
|
26894
|
-
var localXdgOpenPath =
|
|
27382
|
+
var __dirname = import.meta.url ? path5.dirname(fileURLToPath(import.meta.url)) : "";
|
|
27383
|
+
var localXdgOpenPath = path5.join(__dirname, "xdg-open");
|
|
26895
27384
|
var { platform, arch } = process11;
|
|
26896
27385
|
var tryEachApp = async (apps2, opener) => {
|
|
26897
27386
|
if (apps2.length === 0) {
|
|
@@ -27033,7 +27522,7 @@ var baseOpen = async (options) => {
|
|
|
27033
27522
|
childProcessOptions.stdio = "ignore";
|
|
27034
27523
|
}
|
|
27035
27524
|
if (is_wsl_default) {
|
|
27036
|
-
childProcessOptions.cwd =
|
|
27525
|
+
childProcessOptions.cwd = path5.dirname(command);
|
|
27037
27526
|
}
|
|
27038
27527
|
} else {
|
|
27039
27528
|
if (app) {
|
|
@@ -27042,7 +27531,7 @@ var baseOpen = async (options) => {
|
|
|
27042
27531
|
const isBundled = !__dirname || __dirname === "/";
|
|
27043
27532
|
let exeLocalXdgOpen = false;
|
|
27044
27533
|
try {
|
|
27045
|
-
await
|
|
27534
|
+
await fs7.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
27046
27535
|
exeLocalXdgOpen = true;
|
|
27047
27536
|
} catch {
|
|
27048
27537
|
}
|
|
@@ -27330,7 +27819,7 @@ var package_default = {
|
|
|
27330
27819
|
publishConfig: {
|
|
27331
27820
|
access: "public"
|
|
27332
27821
|
},
|
|
27333
|
-
version: "1.
|
|
27822
|
+
version: "1.12.0-agentconnect.1",
|
|
27334
27823
|
description: "",
|
|
27335
27824
|
main: "dist/index.js",
|
|
27336
27825
|
bin: {
|
|
@@ -27355,428 +27844,132 @@ var package_default = {
|
|
|
27355
27844
|
"package:linux-x64": "cd dist/bin && zip codex-acp-x64-linux.zip codex-acp-x64-linux",
|
|
27356
27845
|
"package:linux-arm64": "cd dist/bin && zip codex-acp-arm64-linux.zip codex-acp-arm64-linux",
|
|
27357
27846
|
"package:darwin-x64": "cd dist/bin && zip codex-acp-x64-darwin.zip codex-acp-x64-darwin",
|
|
27358
|
-
"package:darwin-arm64": "cd dist/bin && zip codex-acp-arm64-darwin.zip codex-acp-arm64-darwin",
|
|
27359
|
-
"package:win-x64": "cd dist/bin && zip codex-acp-x64-windows.zip codex-acp-x64-windows.exe",
|
|
27360
|
-
"package:win-arm64": "cd dist/bin && zip codex-acp-arm64-windows.zip codex-acp-arm64-windows.exe",
|
|
27361
|
-
start: "node --import tsx src/index.ts",
|
|
27362
|
-
"example:simple-client": "node --import tsx examples/simple-client.ts",
|
|
27363
|
-
"example:steering": "node --import tsx examples/steering.ts",
|
|
27364
|
-
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
27365
|
-
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
27366
|
-
"release:preflight": "bash scripts/release-preflight.sh",
|
|
27367
|
-
test: "vitest run --no-file-parallelism --retry=2",
|
|
27368
|
-
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run --no-file-parallelism --retry=2 src/__tests__/CodexACPAgent/e2e",
|
|
27369
|
-
"test:watch": "vitest",
|
|
27370
|
-
typecheck: "tsc --noEmit && tsc --noEmit -p examples/tsconfig.json",
|
|
27371
|
-
"codex-test": "tsx .claude/skills/run-codex/scripts/run-codex-test.ts"
|
|
27372
|
-
},
|
|
27373
|
-
homepage: "https://github.com/agentconnect-md/codex-acp#readme",
|
|
27374
|
-
bugs: {
|
|
27375
|
-
url: "https://github.com/agentconnect-md/codex-acp/issues"
|
|
27376
|
-
},
|
|
27377
|
-
repository: {
|
|
27378
|
-
type: "git",
|
|
27379
|
-
url: "git+https://github.com/agentconnect-md/codex-acp.git"
|
|
27380
|
-
},
|
|
27381
|
-
keywords: [],
|
|
27382
|
-
author: "Agent Client Protocol",
|
|
27383
|
-
license: "Apache-2.0",
|
|
27384
|
-
type: "module",
|
|
27385
|
-
devDependencies: {
|
|
27386
|
-
"@types/node": "^26.1.0",
|
|
27387
|
-
esbuild: "^0.28.2",
|
|
27388
|
-
"mcp-hello-world": "^1.1.2",
|
|
27389
|
-
tsx: "^4.23.12",
|
|
27390
|
-
typescript: "^7.0.2",
|
|
27391
|
-
vitest: "^4.1.11"
|
|
27392
|
-
},
|
|
27393
|
-
dependencies: {
|
|
27394
|
-
"@agentclientprotocol/sdk": "^1.4.0",
|
|
27395
|
-
"@openai/codex": "^0.
|
|
27396
|
-
diff: "^9.0.0",
|
|
27397
|
-
open: "^11.0.1",
|
|
27398
|
-
"vscode-jsonrpc": "^9.0.1",
|
|
27399
|
-
zod: "^4.0.0"
|
|
27400
|
-
}
|
|
27401
|
-
};
|
|
27402
|
-
|
|
27403
|
-
// src/CollaborationModeConfig.ts
|
|
27404
|
-
var COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
|
|
27405
|
-
var DEFAULT_COLLABORATION_MODE = "default";
|
|
27406
|
-
var PLAN_COLLABORATION_MODE = "plan";
|
|
27407
|
-
function createCollaborationModeConfigOption(currentValue) {
|
|
27408
|
-
return {
|
|
27409
|
-
id: COLLABORATION_MODE_CONFIG_ID,
|
|
27410
|
-
name: "Collaboration mode",
|
|
27411
|
-
description: "How Codex collaborates for subsequent turns",
|
|
27412
|
-
category: "collaboration_mode",
|
|
27413
|
-
type: "select",
|
|
27414
|
-
currentValue,
|
|
27415
|
-
options: [
|
|
27416
|
-
{ value: DEFAULT_COLLABORATION_MODE, name: "Default" },
|
|
27417
|
-
{ value: PLAN_COLLABORATION_MODE, name: "Plan", description: "Plan before making changes" }
|
|
27418
|
-
]
|
|
27419
|
-
};
|
|
27420
|
-
}
|
|
27421
|
-
function parseCollaborationMode(value) {
|
|
27422
|
-
if (value === DEFAULT_COLLABORATION_MODE) return DEFAULT_COLLABORATION_MODE;
|
|
27423
|
-
if (value === PLAN_COLLABORATION_MODE) return PLAN_COLLABORATION_MODE;
|
|
27424
|
-
return null;
|
|
27425
|
-
}
|
|
27426
|
-
function createCodexCollaborationMode(mode, currentModelId) {
|
|
27427
|
-
const modelId = ModelId.fromString(currentModelId);
|
|
27428
|
-
return {
|
|
27429
|
-
mode,
|
|
27430
|
-
settings: {
|
|
27431
|
-
model: modelId.model,
|
|
27432
|
-
reasoning_effort: modelId.effort,
|
|
27433
|
-
developer_instructions: null
|
|
27434
|
-
}
|
|
27435
|
-
};
|
|
27436
|
-
}
|
|
27437
|
-
|
|
27438
|
-
// src/PathUtils.ts
|
|
27439
|
-
import path5 from "node:path";
|
|
27440
|
-
function isAbsolutePathLike(value) {
|
|
27441
|
-
const trimmed = value.trim();
|
|
27442
|
-
return path5.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
|
|
27443
|
-
}
|
|
27444
|
-
function arePathsEqual(left, right) {
|
|
27445
|
-
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
27446
|
-
}
|
|
27447
|
-
function arePathBasenamesEqual(left, right) {
|
|
27448
|
-
const leftBase = path5.posix.basename(normalizePathForComparison(left));
|
|
27449
|
-
const rightBase = path5.posix.basename(normalizePathForComparison(right));
|
|
27450
|
-
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
27451
|
-
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
27452
|
-
}
|
|
27453
|
-
return leftBase === rightBase;
|
|
27454
|
-
}
|
|
27455
|
-
function normalizePathForComparison(value) {
|
|
27456
|
-
const trimmed = value.trim();
|
|
27457
|
-
if (trimmed.length === 0) {
|
|
27458
|
-
return "";
|
|
27459
|
-
}
|
|
27460
|
-
if (isWindowsAbsolutePath(trimmed)) {
|
|
27461
|
-
const normalized2 = path5.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
27462
|
-
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
27463
|
-
}
|
|
27464
|
-
const pathForComparison = path5.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
27465
|
-
const normalized = path5.posix.normalize(pathForComparison);
|
|
27466
|
-
return trimTrailingPathSeparators(normalized);
|
|
27467
|
-
}
|
|
27468
|
-
function isWindowsAbsolutePath(value) {
|
|
27469
|
-
const portableValue = value.replace(/\\/g, "/");
|
|
27470
|
-
return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
|
|
27471
|
-
}
|
|
27472
|
-
function shouldComparePathCaseInsensitive(value) {
|
|
27473
|
-
return isWindowsAbsolutePath(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
|
|
27474
|
-
}
|
|
27475
|
-
function trimTrailingPathSeparators(value) {
|
|
27476
|
-
let trimmed = value;
|
|
27477
|
-
while (trimmed.endsWith("/") && !isRootPath(trimmed)) {
|
|
27478
|
-
trimmed = trimmed.slice(0, -1);
|
|
27479
|
-
}
|
|
27480
|
-
return trimmed;
|
|
27481
|
-
}
|
|
27482
|
-
function isRootPath(value) {
|
|
27483
|
-
return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
|
|
27484
|
-
}
|
|
27485
|
-
|
|
27486
|
-
// src/AgentFileChangeReport.ts
|
|
27487
|
-
import fs7 from "node:fs";
|
|
27488
|
-
import path6 from "node:path";
|
|
27489
|
-
var AGENT_FILE_CHANGE_REPORT_VERSION = 1;
|
|
27490
|
-
var AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS = 3e4;
|
|
27491
|
-
var AGENT_FILE_CHANGE_REPORT_MAX_PATHS = 1024;
|
|
27492
|
-
var AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH = 4096;
|
|
27493
|
-
var AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES = 256 * 1024;
|
|
27494
|
-
var AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH = 2e3;
|
|
27495
|
-
var AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA = {
|
|
27496
|
-
type: "object",
|
|
27497
|
-
additionalProperties: false,
|
|
27498
|
-
required: ["paths", "complete", "uncertainty"],
|
|
27499
|
-
properties: {
|
|
27500
|
-
paths: {
|
|
27501
|
-
type: "array",
|
|
27502
|
-
items: { type: "string" }
|
|
27503
|
-
},
|
|
27504
|
-
complete: { type: "boolean" },
|
|
27505
|
-
uncertainty: {
|
|
27506
|
-
anyOf: [{
|
|
27507
|
-
type: "string",
|
|
27508
|
-
maxLength: AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH
|
|
27509
|
-
}, {
|
|
27510
|
-
type: "null"
|
|
27511
|
-
}]
|
|
27512
|
-
}
|
|
27513
|
-
}
|
|
27514
|
-
};
|
|
27515
|
-
var AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS = `You are running an internal, read-only file-change audit for the immediately preceding turn.
|
|
27516
|
-
Do not modify files, run commands that can modify files, or ask the user questions.
|
|
27517
|
-
Report files that the preceding turn causally created, modified, deleted, or moved, including changes made by shell commands, version-control commands, generators, and child processes.
|
|
27518
|
-
Do not report files that were only read or inspected.
|
|
27519
|
-
You may use read-only inspection when needed. If the list may be incomplete, set complete to false and briefly explain why in uncertainty.`;
|
|
27520
|
-
function createAgentFileChangeReportPrompt(workspace) {
|
|
27521
|
-
return `List the paths changed by the immediately preceding turn.
|
|
27522
|
-
Return only the structured result required by the output schema.
|
|
27523
|
-
Relative paths are resolved against the working directory.
|
|
27524
|
-
Working directory: ${JSON.stringify(workspace.cwd)}
|
|
27525
|
-
Additional allowed directories: ${JSON.stringify(workspace.additionalDirectories)}`;
|
|
27526
|
-
}
|
|
27527
|
-
function parseAgentFileChangeReportRequest(meta3) {
|
|
27528
|
-
const jetbrains = asRecord(meta3?.[JETBRAINS_META_KEY]);
|
|
27529
|
-
const air = asRecord(jetbrains?.[AIR_META_KEY]);
|
|
27530
|
-
const request = asRecord(air?.[AIR_AGENT_FILE_CHANGE_REPORT_REQUEST_KEY]);
|
|
27531
|
-
if (request === null || !hasOnlyKeys(request, ["version", "requestId"]) || request["version"] !== AGENT_FILE_CHANGE_REPORT_VERSION) {
|
|
27532
|
-
return null;
|
|
27533
|
-
}
|
|
27534
|
-
const requestId = request["requestId"];
|
|
27535
|
-
if (typeof requestId !== "string" || !/^[A-Za-z0-9._:-]{1,128}$/.test(requestId)) {
|
|
27536
|
-
return null;
|
|
27537
|
-
}
|
|
27538
|
-
return { version: AGENT_FILE_CHANGE_REPORT_VERSION, requestId };
|
|
27539
|
-
}
|
|
27540
|
-
function createReportedAgentFileChangeReport(requestId, turn, workspace) {
|
|
27541
|
-
const modelReport = parseModelFileChangeReport(turn);
|
|
27542
|
-
const normalized = normalizeModelFileChangeReport(modelReport, workspace);
|
|
27543
|
-
return fitReportedAgentFileChangeReport({
|
|
27544
|
-
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
27545
|
-
requestId,
|
|
27546
|
-
status: "reported",
|
|
27547
|
-
...normalized
|
|
27548
|
-
});
|
|
27549
|
-
}
|
|
27550
|
-
function createUnavailableAgentFileChangeReport(requestId, reason) {
|
|
27551
|
-
return {
|
|
27552
|
-
version: AGENT_FILE_CHANGE_REPORT_VERSION,
|
|
27553
|
-
requestId,
|
|
27554
|
-
status: "unavailable",
|
|
27555
|
-
reason
|
|
27556
|
-
};
|
|
27557
|
-
}
|
|
27558
|
-
var AgentFileChangeReportError = class extends Error {
|
|
27559
|
-
reason;
|
|
27560
|
-
constructor(reason, message) {
|
|
27561
|
-
super(message);
|
|
27562
|
-
this.name = "AgentFileChangeReportError";
|
|
27563
|
-
this.reason = reason;
|
|
27564
|
-
}
|
|
27565
|
-
};
|
|
27566
|
-
function parseModelFileChangeReport(turn) {
|
|
27567
|
-
switch (turn.status) {
|
|
27568
|
-
case "interrupted":
|
|
27569
|
-
throw new AgentFileChangeReportError("cancelled", "The audit turn was interrupted");
|
|
27570
|
-
case "failed":
|
|
27571
|
-
throw new AgentFileChangeReportError(
|
|
27572
|
-
"providerError",
|
|
27573
|
-
`The audit turn failed${turn.error?.message ? `: ${turn.error.message}` : ""}`
|
|
27574
|
-
);
|
|
27575
|
-
case "inProgress":
|
|
27576
|
-
throw new AgentFileChangeReportError("notReported", "The audit turn did not complete");
|
|
27577
|
-
case "completed":
|
|
27578
|
-
break;
|
|
27579
|
-
}
|
|
27580
|
-
let text = null;
|
|
27581
|
-
for (let index = turn.items.length - 1; index >= 0; index -= 1) {
|
|
27582
|
-
const item = turn.items[index];
|
|
27583
|
-
if (item?.type === "agentMessage") {
|
|
27584
|
-
text = item.text;
|
|
27585
|
-
break;
|
|
27586
|
-
}
|
|
27587
|
-
}
|
|
27588
|
-
if (text === null) {
|
|
27589
|
-
throw new AgentFileChangeReportError("notReported", "The audit turn returned no agent message");
|
|
27590
|
-
}
|
|
27591
|
-
let value;
|
|
27592
|
-
try {
|
|
27593
|
-
value = JSON.parse(text);
|
|
27594
|
-
} catch {
|
|
27595
|
-
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid JSON");
|
|
27596
|
-
}
|
|
27597
|
-
const report = asRecord(value);
|
|
27598
|
-
if (report === null || !hasOnlyKeys(report, ["paths", "complete", "uncertainty"])) {
|
|
27599
|
-
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned an invalid object");
|
|
27600
|
-
}
|
|
27601
|
-
const paths = report["paths"];
|
|
27602
|
-
const complete = report["complete"];
|
|
27603
|
-
const uncertainty = report["uncertainty"];
|
|
27604
|
-
if (!Array.isArray(paths) || !paths.every((item) => typeof item === "string") || typeof complete !== "boolean" || uncertainty !== void 0 && uncertainty !== null && typeof uncertainty !== "string") {
|
|
27605
|
-
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned invalid fields");
|
|
27606
|
-
}
|
|
27607
|
-
const normalizedUncertainty = typeof uncertainty === "string" ? uncertainty.trim() : void 0;
|
|
27608
|
-
if (normalizedUncertainty !== void 0 && normalizedUncertainty.length > AGENT_FILE_CHANGE_REPORT_MAX_UNCERTAINTY_LENGTH) {
|
|
27609
|
-
throw new AgentFileChangeReportError("invalidOutput", "The audit turn returned oversized uncertainty");
|
|
27610
|
-
}
|
|
27611
|
-
return {
|
|
27612
|
-
paths,
|
|
27613
|
-
complete,
|
|
27614
|
-
...normalizedUncertainty ? { uncertainty: normalizedUncertainty } : {}
|
|
27615
|
-
};
|
|
27616
|
-
}
|
|
27617
|
-
function fitReportedAgentFileChangeReport(report) {
|
|
27618
|
-
const paths = [...report.paths];
|
|
27619
|
-
let truncated = report.truncated;
|
|
27620
|
-
let fitted = report;
|
|
27621
|
-
while (Buffer.byteLength(JSON.stringify(fitted), "utf8") > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
27622
|
-
if (paths.length === 0) {
|
|
27623
|
-
throw new AgentFileChangeReportError("invalidOutput", "The audit report exceeds the wire limit");
|
|
27624
|
-
}
|
|
27625
|
-
paths.pop();
|
|
27626
|
-
truncated = true;
|
|
27627
|
-
fitted = {
|
|
27628
|
-
...report,
|
|
27629
|
-
paths: [...paths],
|
|
27630
|
-
declaredComplete: false,
|
|
27631
|
-
truncated
|
|
27632
|
-
};
|
|
27633
|
-
}
|
|
27634
|
-
return fitted;
|
|
27635
|
-
}
|
|
27636
|
-
function normalizeModelFileChangeReport(report, workspace) {
|
|
27637
|
-
const cwd = normalizeWorkspaceRoot(workspace.cwd);
|
|
27638
|
-
if (cwd === null) {
|
|
27639
|
-
throw new AgentFileChangeReportError("providerError", "The session working directory is not absolute");
|
|
27640
|
-
}
|
|
27641
|
-
const roots = [cwd, ...workspace.additionalDirectories.flatMap((directory) => {
|
|
27642
|
-
const root = normalizeWorkspaceRoot(directory);
|
|
27643
|
-
return root === null || root.flavor !== cwd.flavor ? [] : [root];
|
|
27644
|
-
})];
|
|
27645
|
-
const paths = [];
|
|
27646
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27647
|
-
let totalBytes = 0;
|
|
27648
|
-
let truncated = false;
|
|
27649
|
-
for (const reportedPath of report.paths) {
|
|
27650
|
-
if (reportedPath.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
27651
|
-
truncated = true;
|
|
27652
|
-
continue;
|
|
27653
|
-
}
|
|
27654
|
-
const normalized = normalizeReportedPath(reportedPath, cwd, roots);
|
|
27655
|
-
if (normalized === null || normalized.value.length > AGENT_FILE_CHANGE_REPORT_MAX_PATH_LENGTH) {
|
|
27656
|
-
truncated = true;
|
|
27657
|
-
continue;
|
|
27658
|
-
}
|
|
27659
|
-
const key = normalized.flavor === "windows" ? normalized.value.toLowerCase() : normalized.value;
|
|
27660
|
-
if (seen.has(key)) {
|
|
27661
|
-
continue;
|
|
27662
|
-
}
|
|
27663
|
-
const bytes = Buffer.byteLength(normalized.value, "utf8");
|
|
27664
|
-
if (paths.length >= AGENT_FILE_CHANGE_REPORT_MAX_PATHS || totalBytes + bytes > AGENT_FILE_CHANGE_REPORT_MAX_TOTAL_BYTES) {
|
|
27665
|
-
truncated = true;
|
|
27666
|
-
continue;
|
|
27667
|
-
}
|
|
27668
|
-
seen.add(key);
|
|
27669
|
-
paths.push(normalized.value);
|
|
27670
|
-
totalBytes += bytes;
|
|
27847
|
+
"package:darwin-arm64": "cd dist/bin && zip codex-acp-arm64-darwin.zip codex-acp-arm64-darwin",
|
|
27848
|
+
"package:win-x64": "cd dist/bin && zip codex-acp-x64-windows.zip codex-acp-x64-windows.exe",
|
|
27849
|
+
"package:win-arm64": "cd dist/bin && zip codex-acp-arm64-windows.zip codex-acp-arm64-windows.exe",
|
|
27850
|
+
start: "node --import tsx src/index.ts",
|
|
27851
|
+
"example:simple-client": "node --import tsx examples/simple-client.ts",
|
|
27852
|
+
"example:steering": "node --import tsx examples/steering.ts",
|
|
27853
|
+
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
27854
|
+
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
27855
|
+
"release:preflight": "bash scripts/release-preflight.sh",
|
|
27856
|
+
test: "vitest run --no-file-parallelism --retry=2",
|
|
27857
|
+
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run --no-file-parallelism --retry=2 src/__tests__/CodexACPAgent/e2e",
|
|
27858
|
+
"test:watch": "vitest",
|
|
27859
|
+
typecheck: "tsc --noEmit && tsc --noEmit -p examples/tsconfig.json",
|
|
27860
|
+
"codex-test": "tsx .claude/skills/run-codex/scripts/run-codex-test.ts"
|
|
27861
|
+
},
|
|
27862
|
+
homepage: "https://github.com/agentconnect-md/codex-acp#readme",
|
|
27863
|
+
bugs: {
|
|
27864
|
+
url: "https://github.com/agentconnect-md/codex-acp/issues"
|
|
27865
|
+
},
|
|
27866
|
+
repository: {
|
|
27867
|
+
type: "git",
|
|
27868
|
+
url: "git+https://github.com/agentconnect-md/codex-acp.git"
|
|
27869
|
+
},
|
|
27870
|
+
keywords: [],
|
|
27871
|
+
author: "Agent Client Protocol",
|
|
27872
|
+
license: "Apache-2.0",
|
|
27873
|
+
type: "module",
|
|
27874
|
+
devDependencies: {
|
|
27875
|
+
"@types/node": "^26.1.0",
|
|
27876
|
+
esbuild: "^0.28.2",
|
|
27877
|
+
"mcp-hello-world": "^1.1.2",
|
|
27878
|
+
tsx: "^4.23.12",
|
|
27879
|
+
typescript: "^7.0.2",
|
|
27880
|
+
vitest: "^4.1.11"
|
|
27881
|
+
},
|
|
27882
|
+
dependencies: {
|
|
27883
|
+
"@agentclientprotocol/sdk": "^1.4.0",
|
|
27884
|
+
"@openai/codex": "^0.154.0",
|
|
27885
|
+
diff: "^9.0.0",
|
|
27886
|
+
open: "^11.0.1",
|
|
27887
|
+
"vscode-jsonrpc": "^9.0.1",
|
|
27888
|
+
zod: "^4.0.0"
|
|
27671
27889
|
}
|
|
27890
|
+
};
|
|
27891
|
+
|
|
27892
|
+
// src/CollaborationModeConfig.ts
|
|
27893
|
+
var COLLABORATION_MODE_CONFIG_ID = "collaboration_mode";
|
|
27894
|
+
var DEFAULT_COLLABORATION_MODE = "default";
|
|
27895
|
+
var PLAN_COLLABORATION_MODE = "plan";
|
|
27896
|
+
function createCollaborationModeConfigOption(currentValue) {
|
|
27672
27897
|
return {
|
|
27673
|
-
|
|
27674
|
-
|
|
27675
|
-
|
|
27676
|
-
|
|
27898
|
+
id: COLLABORATION_MODE_CONFIG_ID,
|
|
27899
|
+
name: "Collaboration mode",
|
|
27900
|
+
description: "How Codex collaborates for subsequent turns",
|
|
27901
|
+
category: "collaboration_mode",
|
|
27902
|
+
type: "select",
|
|
27903
|
+
currentValue,
|
|
27904
|
+
options: [
|
|
27905
|
+
{ value: DEFAULT_COLLABORATION_MODE, name: "Default" },
|
|
27906
|
+
{ value: PLAN_COLLABORATION_MODE, name: "Plan", description: "Plan before making changes" }
|
|
27907
|
+
]
|
|
27677
27908
|
};
|
|
27678
27909
|
}
|
|
27679
|
-
function
|
|
27680
|
-
|
|
27681
|
-
if (
|
|
27682
|
-
return null;
|
|
27683
|
-
}
|
|
27684
|
-
if (isWindowsAbsolutePath2(trimmed)) {
|
|
27685
|
-
return canonicalizeWorkspaceRoot({
|
|
27686
|
-
value: path6.win32.normalize(trimmed.replace(/\//g, "\\")),
|
|
27687
|
-
flavor: "windows"
|
|
27688
|
-
});
|
|
27689
|
-
}
|
|
27690
|
-
if (path6.posix.isAbsolute(trimmed)) {
|
|
27691
|
-
return canonicalizeWorkspaceRoot({
|
|
27692
|
-
value: path6.posix.normalize(trimmed.replace(/\\/g, "/")),
|
|
27693
|
-
flavor: "posix"
|
|
27694
|
-
});
|
|
27695
|
-
}
|
|
27910
|
+
function parseCollaborationMode(value) {
|
|
27911
|
+
if (value === DEFAULT_COLLABORATION_MODE) return DEFAULT_COLLABORATION_MODE;
|
|
27912
|
+
if (value === PLAN_COLLABORATION_MODE) return PLAN_COLLABORATION_MODE;
|
|
27696
27913
|
return null;
|
|
27697
27914
|
}
|
|
27698
|
-
function
|
|
27915
|
+
function createCodexCollaborationMode(mode, currentModelId) {
|
|
27916
|
+
const modelId = ModelId.fromString(currentModelId);
|
|
27917
|
+
return {
|
|
27918
|
+
mode,
|
|
27919
|
+
settings: {
|
|
27920
|
+
model: modelId.model,
|
|
27921
|
+
reasoning_effort: modelId.effort,
|
|
27922
|
+
developer_instructions: null
|
|
27923
|
+
}
|
|
27924
|
+
};
|
|
27925
|
+
}
|
|
27926
|
+
|
|
27927
|
+
// src/PathUtils.ts
|
|
27928
|
+
import path6 from "node:path";
|
|
27929
|
+
function isAbsolutePathLike(value) {
|
|
27699
27930
|
const trimmed = value.trim();
|
|
27700
|
-
|
|
27701
|
-
return null;
|
|
27702
|
-
}
|
|
27703
|
-
let candidate;
|
|
27704
|
-
if (isWindowsAbsolutePath2(trimmed)) {
|
|
27705
|
-
candidate = { value: path6.win32.normalize(trimmed.replace(/\//g, "\\")), flavor: "windows" };
|
|
27706
|
-
} else if (path6.posix.isAbsolute(trimmed)) {
|
|
27707
|
-
candidate = { value: path6.posix.normalize(trimmed.replace(/\\/g, "/")), flavor: "posix" };
|
|
27708
|
-
} else if (cwd.flavor === "windows") {
|
|
27709
|
-
candidate = {
|
|
27710
|
-
value: path6.win32.resolve(cwd.value, trimmed.replace(/\//g, "\\")),
|
|
27711
|
-
flavor: "windows"
|
|
27712
|
-
};
|
|
27713
|
-
} else {
|
|
27714
|
-
candidate = {
|
|
27715
|
-
value: path6.posix.resolve(cwd.value, trimmed.replace(/\\/g, "/")),
|
|
27716
|
-
flavor: "posix"
|
|
27717
|
-
};
|
|
27718
|
-
}
|
|
27719
|
-
candidate = canonicalizeReportedPath(candidate);
|
|
27720
|
-
return roots.some((root) => pathIsStrictlyInside(root, candidate)) ? candidate : null;
|
|
27931
|
+
return path6.isAbsolute(trimmed) || isWindowsAbsolutePath2(trimmed);
|
|
27721
27932
|
}
|
|
27722
|
-
function
|
|
27723
|
-
|
|
27724
|
-
return root;
|
|
27725
|
-
}
|
|
27726
|
-
return { ...root, value: canonicalizeFromExistingAncestor(root.value) };
|
|
27933
|
+
function arePathsEqual(left, right) {
|
|
27934
|
+
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
27727
27935
|
}
|
|
27728
|
-
function
|
|
27729
|
-
|
|
27730
|
-
|
|
27936
|
+
function arePathBasenamesEqual(left, right) {
|
|
27937
|
+
const leftBase = path6.posix.basename(normalizePathForComparison(left));
|
|
27938
|
+
const rightBase = path6.posix.basename(normalizePathForComparison(right));
|
|
27939
|
+
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
27940
|
+
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
27731
27941
|
}
|
|
27732
|
-
|
|
27733
|
-
return { ...candidate, value: path6.resolve(parent, path6.basename(candidate.value)) };
|
|
27942
|
+
return leftBase === rightBase;
|
|
27734
27943
|
}
|
|
27735
|
-
function
|
|
27736
|
-
const
|
|
27737
|
-
|
|
27738
|
-
|
|
27739
|
-
while (true) {
|
|
27740
|
-
try {
|
|
27741
|
-
const canonical = fs7.realpathSync.native(current);
|
|
27742
|
-
return path6.resolve(canonical, ...missingSegments.reverse());
|
|
27743
|
-
} catch (error51) {
|
|
27744
|
-
if (!isMissingPathError(error51)) return original;
|
|
27745
|
-
}
|
|
27746
|
-
const parent = path6.dirname(current);
|
|
27747
|
-
if (parent === current) return original;
|
|
27748
|
-
missingSegments.push(path6.basename(current));
|
|
27749
|
-
current = parent;
|
|
27944
|
+
function normalizePathForComparison(value) {
|
|
27945
|
+
const trimmed = value.trim();
|
|
27946
|
+
if (trimmed.length === 0) {
|
|
27947
|
+
return "";
|
|
27750
27948
|
}
|
|
27751
|
-
|
|
27752
|
-
|
|
27753
|
-
|
|
27754
|
-
return error51.code === "ENOENT" || error51.code === "ENOTDIR";
|
|
27755
|
-
}
|
|
27756
|
-
function isNativePathFlavor(flavor) {
|
|
27757
|
-
return process.platform === "win32" ? flavor === "windows" : flavor === "posix";
|
|
27758
|
-
}
|
|
27759
|
-
function pathIsStrictlyInside(root, candidate) {
|
|
27760
|
-
if (root.flavor !== candidate.flavor) {
|
|
27761
|
-
return false;
|
|
27949
|
+
if (isWindowsAbsolutePath2(trimmed)) {
|
|
27950
|
+
const normalized2 = path6.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
27951
|
+
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
27762
27952
|
}
|
|
27763
|
-
const
|
|
27764
|
-
const
|
|
27765
|
-
return
|
|
27953
|
+
const pathForComparison = path6.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
27954
|
+
const normalized = path6.posix.normalize(pathForComparison);
|
|
27955
|
+
return trimTrailingPathSeparators(normalized);
|
|
27766
27956
|
}
|
|
27767
27957
|
function isWindowsAbsolutePath2(value) {
|
|
27768
|
-
const
|
|
27769
|
-
return /^[A-Za-z]:\//.test(
|
|
27958
|
+
const portableValue = value.replace(/\\/g, "/");
|
|
27959
|
+
return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
|
|
27770
27960
|
}
|
|
27771
|
-
function
|
|
27772
|
-
return value
|
|
27961
|
+
function shouldComparePathCaseInsensitive(value) {
|
|
27962
|
+
return isWindowsAbsolutePath2(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
|
|
27773
27963
|
}
|
|
27774
|
-
function
|
|
27775
|
-
|
|
27964
|
+
function trimTrailingPathSeparators(value) {
|
|
27965
|
+
let trimmed = value;
|
|
27966
|
+
while (trimmed.endsWith("/") && !isRootPath(trimmed)) {
|
|
27967
|
+
trimmed = trimmed.slice(0, -1);
|
|
27968
|
+
}
|
|
27969
|
+
return trimmed;
|
|
27776
27970
|
}
|
|
27777
|
-
function
|
|
27778
|
-
|
|
27779
|
-
return Object.keys(value).every((key) => allowedKeys.has(key));
|
|
27971
|
+
function isRootPath(value) {
|
|
27972
|
+
return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
|
|
27780
27973
|
}
|
|
27781
27974
|
|
|
27782
27975
|
// src/subagents/CodexSubagentSubscriptions.ts
|
|
@@ -27900,6 +28093,7 @@ async function forkSession(request, additionalDirectories, dependencies) {
|
|
|
27900
28093
|
const lastTurnId = await resolveForkTurnId(request, dependencies.codexClient);
|
|
27901
28094
|
const prepared = await dependencies.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
27902
28095
|
const response = await dependencies.codexClient.threadFork({
|
|
28096
|
+
excludeTurns: true,
|
|
27903
28097
|
config: prepared.config,
|
|
27904
28098
|
cwd: request.cwd,
|
|
27905
28099
|
...lastTurnId !== void 0 && { lastTurnId },
|
|
@@ -27922,10 +28116,7 @@ async function forkSession(request, additionalDirectories, dependencies) {
|
|
|
27922
28116
|
async function resolveForkTurnId(request, codexClient) {
|
|
27923
28117
|
const forkPoint = readAirForkPoint(request._meta);
|
|
27924
28118
|
if (!forkPoint) return void 0;
|
|
27925
|
-
const history = await codexClient.
|
|
27926
|
-
threadId: request.sessionId,
|
|
27927
|
-
includeTurns: true
|
|
27928
|
-
});
|
|
28119
|
+
const history = await codexClient.threadReadWithHistory(request.sessionId);
|
|
27929
28120
|
const candidateIds = airForkMessageIdCandidates(forkPoint.messageId);
|
|
27930
28121
|
const itemTurnId = candidateIds.map((candidateId) => history.thread.turns.find((turn) => turn.items.some((item) => item.id === candidateId))?.id).find((turnId) => turnId !== void 0);
|
|
27931
28122
|
if (itemTurnId) return itemTurnId;
|
|
@@ -28380,6 +28571,7 @@ var CodexAcpClient = class {
|
|
|
28380
28571
|
const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
28381
28572
|
await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
|
|
28382
28573
|
const response = await this.codexClient.threadResume({
|
|
28574
|
+
excludeTurns: true,
|
|
28383
28575
|
config: prepared.config,
|
|
28384
28576
|
cwd: request.cwd,
|
|
28385
28577
|
modelProvider: await this.getResumeModelProvider(),
|
|
@@ -28419,6 +28611,7 @@ var CodexAcpClient = class {
|
|
|
28419
28611
|
const prepared = await this.createSessionConfig(request.cwd, additionalDirectories, request.mcpServers ?? []);
|
|
28420
28612
|
await this.restrictResumedHttpMcpServers(request.sessionId, prepared);
|
|
28421
28613
|
const response = await this.codexClient.threadResume({
|
|
28614
|
+
excludeTurns: true,
|
|
28422
28615
|
config: prepared.config,
|
|
28423
28616
|
cwd: request.cwd,
|
|
28424
28617
|
modelProvider: await this.getResumeModelProvider(),
|
|
@@ -28426,10 +28619,10 @@ var CodexAcpClient = class {
|
|
|
28426
28619
|
...this.permissionProfileSelection(initialAgentMode, request.cwd, additionalDirectories)
|
|
28427
28620
|
});
|
|
28428
28621
|
onSubscribed?.();
|
|
28429
|
-
const
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
});
|
|
28622
|
+
const thread = response.thread.historyMode === "paginated" ? {
|
|
28623
|
+
...response.thread,
|
|
28624
|
+
turns: response.turnsBackwardsCursor === null ? [] : await this.codexClient.threadReadHistory(response.thread.id, response.turnsBackwardsCursor)
|
|
28625
|
+
} : (await this.codexClient.threadReadWithHistory(response.thread.id)).thread;
|
|
28433
28626
|
const codexModels = await this.fetchAvailableModels();
|
|
28434
28627
|
const currentModelId = this.createModelId(codexModels, response.model, response.reasoningEffort).toString();
|
|
28435
28628
|
return {
|
|
@@ -28439,16 +28632,13 @@ var CodexAcpClient = class {
|
|
|
28439
28632
|
collaborationMode: this.getCollaborationMode(response.thread.id),
|
|
28440
28633
|
modelProvider: response.modelProvider,
|
|
28441
28634
|
currentServiceTier: response.serviceTier ?? null,
|
|
28442
|
-
thread
|
|
28635
|
+
thread,
|
|
28443
28636
|
additionalDirectories,
|
|
28444
28637
|
fullAccessHttpMcpServers: prepared.fullAccessHttpMcpServers
|
|
28445
28638
|
};
|
|
28446
28639
|
}
|
|
28447
28640
|
async readSessionThread(sessionId) {
|
|
28448
|
-
return (await this.codexClient.
|
|
28449
|
-
threadId: sessionId,
|
|
28450
|
-
includeTurns: true
|
|
28451
|
-
})).thread;
|
|
28641
|
+
return (await this.codexClient.threadReadWithHistory(sessionId)).thread;
|
|
28452
28642
|
}
|
|
28453
28643
|
async newSession(request) {
|
|
28454
28644
|
const additionalDirectories = readAdditionalDirectories(request.cwd, request.additionalDirectories, request._meta);
|
|
@@ -28583,7 +28773,7 @@ var CodexAcpClient = class {
|
|
|
28583
28773
|
baseUrl: activeProvider.baseUrl
|
|
28584
28774
|
});
|
|
28585
28775
|
const mergedConfig = {
|
|
28586
|
-
...mergeGatewayConfig(this.config, this.gatewayConfig),
|
|
28776
|
+
...forceGitRootTurnDiffPaths(mergeGatewayConfig(this.config, this.gatewayConfig)),
|
|
28587
28777
|
projects: Object.fromEntries(sessionRoots2.map((root) => [root, {
|
|
28588
28778
|
trust_level: "trusted"
|
|
28589
28779
|
}]))
|
|
@@ -28750,100 +28940,6 @@ var CodexAcpClient = class {
|
|
|
28750
28940
|
serviceTier
|
|
28751
28941
|
}, onTurnStarted);
|
|
28752
28942
|
}
|
|
28753
|
-
async runAgentFileChangeReport(params) {
|
|
28754
|
-
if (params.signal?.aborted) {
|
|
28755
|
-
return createUnavailableAgentFileChangeReport(params.requestId, "cancelled");
|
|
28756
|
-
}
|
|
28757
|
-
const budget = new AgentFileChangeReportBudget(params.signal);
|
|
28758
|
-
let forkThreadId = null;
|
|
28759
|
-
let auditTurnId = null;
|
|
28760
|
-
let auditTurnCompleted = false;
|
|
28761
|
-
let lateStopReason = null;
|
|
28762
|
-
try {
|
|
28763
|
-
const forkPromise = this.codexClient.threadFork({
|
|
28764
|
-
threadId: params.sessionId,
|
|
28765
|
-
lastTurnId: params.turnId,
|
|
28766
|
-
cwd: params.workspace.cwd,
|
|
28767
|
-
approvalPolicy: "never",
|
|
28768
|
-
sandbox: "read-only",
|
|
28769
|
-
developerInstructions: AGENT_FILE_CHANGE_REPORT_DEVELOPER_INSTRUCTIONS,
|
|
28770
|
-
ephemeral: true
|
|
28771
|
-
});
|
|
28772
|
-
void forkPromise.then((fork2) => {
|
|
28773
|
-
if (lateStopReason !== null && forkThreadId === null) {
|
|
28774
|
-
void this.unsubscribeAgentFileChangeReportThread(fork2.thread.id, budget);
|
|
28775
|
-
}
|
|
28776
|
-
}, () => {
|
|
28777
|
-
});
|
|
28778
|
-
const fork = await budget.wait(forkPromise);
|
|
28779
|
-
forkThreadId = fork.thread.id;
|
|
28780
|
-
const turnPromise = this.codexClient.runTurn({
|
|
28781
|
-
threadId: forkThreadId,
|
|
28782
|
-
input: [{
|
|
28783
|
-
type: "text",
|
|
28784
|
-
text: createAgentFileChangeReportPrompt(params.workspace),
|
|
28785
|
-
text_elements: []
|
|
28786
|
-
}],
|
|
28787
|
-
cwd: params.workspace.cwd,
|
|
28788
|
-
approvalPolicy: "never",
|
|
28789
|
-
sandboxPolicy: { type: "readOnly", networkAccess: false },
|
|
28790
|
-
summary: "none",
|
|
28791
|
-
outputSchema: AGENT_FILE_CHANGE_REPORT_OUTPUT_SCHEMA
|
|
28792
|
-
}, (turnId) => {
|
|
28793
|
-
auditTurnId = turnId;
|
|
28794
|
-
if (lateStopReason !== null && forkThreadId !== null) {
|
|
28795
|
-
void this.interruptAgentFileChangeReport(forkThreadId, turnId, lateStopReason, budget);
|
|
28796
|
-
}
|
|
28797
|
-
});
|
|
28798
|
-
const outcome = await budget.wait(turnPromise);
|
|
28799
|
-
auditTurnCompleted = true;
|
|
28800
|
-
return createReportedAgentFileChangeReport(
|
|
28801
|
-
params.requestId,
|
|
28802
|
-
outcome.turn,
|
|
28803
|
-
params.workspace
|
|
28804
|
-
);
|
|
28805
|
-
} catch (error51) {
|
|
28806
|
-
if (error51 instanceof AgentFileChangeReportBudgetError) {
|
|
28807
|
-
lateStopReason = error51.reason;
|
|
28808
|
-
if (!auditTurnCompleted && forkThreadId !== null && auditTurnId !== null) {
|
|
28809
|
-
await this.interruptAgentFileChangeReport(
|
|
28810
|
-
forkThreadId,
|
|
28811
|
-
auditTurnId,
|
|
28812
|
-
error51.reason,
|
|
28813
|
-
budget
|
|
28814
|
-
);
|
|
28815
|
-
}
|
|
28816
|
-
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
28817
|
-
}
|
|
28818
|
-
if (error51 instanceof AgentFileChangeReportError) {
|
|
28819
|
-
logger.error("Agent file-change report unavailable", error51);
|
|
28820
|
-
return createUnavailableAgentFileChangeReport(params.requestId, error51.reason);
|
|
28821
|
-
}
|
|
28822
|
-
logger.error("Agent file-change report failed", error51);
|
|
28823
|
-
return createUnavailableAgentFileChangeReport(params.requestId, "providerError");
|
|
28824
|
-
} finally {
|
|
28825
|
-
if (forkThreadId !== null) {
|
|
28826
|
-
await this.unsubscribeAgentFileChangeReportThread(forkThreadId, budget);
|
|
28827
|
-
}
|
|
28828
|
-
}
|
|
28829
|
-
}
|
|
28830
|
-
async interruptAgentFileChangeReport(threadId, turnId, reason, budget) {
|
|
28831
|
-
this.codexClient.markTurnStale(threadId, turnId);
|
|
28832
|
-
try {
|
|
28833
|
-
await budget.wait(this.codexClient.turnInterrupt({ threadId, turnId }));
|
|
28834
|
-
} catch (error51) {
|
|
28835
|
-
logger.error(`Failed to interrupt ${reason} agent file-change report`, error51);
|
|
28836
|
-
} finally {
|
|
28837
|
-
this.codexClient.resolveTurnInterrupted(threadId, turnId);
|
|
28838
|
-
}
|
|
28839
|
-
}
|
|
28840
|
-
async unsubscribeAgentFileChangeReportThread(threadId, budget) {
|
|
28841
|
-
try {
|
|
28842
|
-
await budget.wait(this.codexClient.threadUnsubscribe({ threadId }));
|
|
28843
|
-
} catch (error51) {
|
|
28844
|
-
logger.error("Failed to unsubscribe the agent file-change report thread", error51);
|
|
28845
|
-
}
|
|
28846
|
-
}
|
|
28847
28943
|
async setAgentMode(sessionId, agentMode) {
|
|
28848
28944
|
const config2 = this.permissionProfileConfig;
|
|
28849
28945
|
if (!config2) return;
|
|
@@ -29009,58 +29105,6 @@ var CodexAcpClient = class {
|
|
|
29009
29105
|
};
|
|
29010
29106
|
}
|
|
29011
29107
|
};
|
|
29012
|
-
var AgentFileChangeReportBudgetError = class extends Error {
|
|
29013
|
-
constructor(reason) {
|
|
29014
|
-
super(`Agent file-change report ${reason}`);
|
|
29015
|
-
this.reason = reason;
|
|
29016
|
-
this.name = "AgentFileChangeReportBudgetError";
|
|
29017
|
-
}
|
|
29018
|
-
reason;
|
|
29019
|
-
};
|
|
29020
|
-
var AgentFileChangeReportBudget = class {
|
|
29021
|
-
constructor(signal) {
|
|
29022
|
-
this.signal = signal;
|
|
29023
|
-
}
|
|
29024
|
-
signal;
|
|
29025
|
-
deadline = Date.now() + AGENT_FILE_CHANGE_REPORT_TIMEOUT_MS;
|
|
29026
|
-
async wait(operation) {
|
|
29027
|
-
void operation.catch(() => {
|
|
29028
|
-
});
|
|
29029
|
-
const immediateReason = this.stopReason();
|
|
29030
|
-
if (immediateReason !== null) {
|
|
29031
|
-
throw new AgentFileChangeReportBudgetError(immediateReason);
|
|
29032
|
-
}
|
|
29033
|
-
return await new Promise((resolve, reject) => {
|
|
29034
|
-
let settled = false;
|
|
29035
|
-
const finish = (action) => {
|
|
29036
|
-
if (settled) return;
|
|
29037
|
-
settled = true;
|
|
29038
|
-
clearTimeout(timeout);
|
|
29039
|
-
this.signal?.removeEventListener("abort", onAbort);
|
|
29040
|
-
action();
|
|
29041
|
-
};
|
|
29042
|
-
const onAbort = () => finish(() => reject(new AgentFileChangeReportBudgetError("cancelled")));
|
|
29043
|
-
const timeout = setTimeout(
|
|
29044
|
-
() => finish(() => reject(new AgentFileChangeReportBudgetError("timeout"))),
|
|
29045
|
-
Math.max(1, this.deadline - Date.now())
|
|
29046
|
-
);
|
|
29047
|
-
timeout.unref();
|
|
29048
|
-
this.signal?.addEventListener("abort", onAbort, { once: true });
|
|
29049
|
-
if (this.signal?.aborted) {
|
|
29050
|
-
onAbort();
|
|
29051
|
-
}
|
|
29052
|
-
void operation.then(
|
|
29053
|
-
(value) => finish(() => resolve(value)),
|
|
29054
|
-
(error51) => finish(() => reject(error51))
|
|
29055
|
-
);
|
|
29056
|
-
});
|
|
29057
|
-
}
|
|
29058
|
-
stopReason() {
|
|
29059
|
-
if (this.signal?.aborted) return "cancelled";
|
|
29060
|
-
if (Date.now() >= this.deadline) return "timeout";
|
|
29061
|
-
return null;
|
|
29062
|
-
}
|
|
29063
|
-
};
|
|
29064
29108
|
function buildPromptItems(prompt) {
|
|
29065
29109
|
return prompt.map((block) => {
|
|
29066
29110
|
switch (block.type) {
|
|
@@ -29175,6 +29219,16 @@ function mergeSandboxWorkspaceWriteRoots(config2, roots) {
|
|
|
29175
29219
|
}
|
|
29176
29220
|
};
|
|
29177
29221
|
}
|
|
29222
|
+
function forceGitRootTurnDiffPaths(config2) {
|
|
29223
|
+
const features = isJsonObject(config2["features"]) ? config2["features"] : {};
|
|
29224
|
+
return {
|
|
29225
|
+
...config2,
|
|
29226
|
+
features: {
|
|
29227
|
+
...features,
|
|
29228
|
+
cwd_relative_turn_diffs: false
|
|
29229
|
+
}
|
|
29230
|
+
};
|
|
29231
|
+
}
|
|
29178
29232
|
function addAdditionalDirectoriesToSandboxPolicy(sandboxPolicy, additionalDirectories) {
|
|
29179
29233
|
if (additionalDirectories.length === 0 || sandboxPolicy.type !== "workspaceWrite") {
|
|
29180
29234
|
return sandboxPolicy;
|
|
@@ -29607,6 +29661,41 @@ var CodexAppServerClient = class {
|
|
|
29607
29661
|
async threadRead(params) {
|
|
29608
29662
|
return await this.sendRequest({ method: "thread/read", params });
|
|
29609
29663
|
}
|
|
29664
|
+
async threadTurnsList(params) {
|
|
29665
|
+
return await this.sendRequest({ method: "thread/turns/list", params });
|
|
29666
|
+
}
|
|
29667
|
+
async threadReadWithHistory(threadId) {
|
|
29668
|
+
const response = await this.threadRead({ threadId });
|
|
29669
|
+
if (response.thread.historyMode === "legacy") {
|
|
29670
|
+
return await this.threadRead({ threadId, includeTurns: true });
|
|
29671
|
+
}
|
|
29672
|
+
const turns = await this.threadReadHistory(threadId);
|
|
29673
|
+
return { ...response, thread: { ...response.thread, turns } };
|
|
29674
|
+
}
|
|
29675
|
+
async threadReadHistory(threadId, initialCursor = null) {
|
|
29676
|
+
const turns = [];
|
|
29677
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
29678
|
+
if (initialCursor !== null) seenCursors.add(initialCursor);
|
|
29679
|
+
let cursor = initialCursor;
|
|
29680
|
+
do {
|
|
29681
|
+
const page = await this.threadTurnsList({
|
|
29682
|
+
threadId,
|
|
29683
|
+
cursor,
|
|
29684
|
+
limit: 50,
|
|
29685
|
+
sortDirection: "desc",
|
|
29686
|
+
itemsView: "full"
|
|
29687
|
+
});
|
|
29688
|
+
turns.push(...page.data);
|
|
29689
|
+
cursor = page.nextCursor;
|
|
29690
|
+
if (cursor !== null) {
|
|
29691
|
+
if (seenCursors.has(cursor)) {
|
|
29692
|
+
throw new Error("Codex returned a repeated thread history cursor");
|
|
29693
|
+
}
|
|
29694
|
+
seenCursors.add(cursor);
|
|
29695
|
+
}
|
|
29696
|
+
} while (cursor !== null);
|
|
29697
|
+
return turns.reverse();
|
|
29698
|
+
}
|
|
29610
29699
|
async threadArchive(params) {
|
|
29611
29700
|
return await this.sendRequest({ method: "thread/archive", params });
|
|
29612
29701
|
}
|
|
@@ -30045,6 +30134,10 @@ function extractTurnRouting(notification) {
|
|
|
30045
30134
|
// src/ModelConfigOption.ts
|
|
30046
30135
|
var MODEL_CONFIG_ID = "model";
|
|
30047
30136
|
var REASONING_EFFORT_CONFIG_ID = "reasoning_effort";
|
|
30137
|
+
function formatModelDisplayName(displayName) {
|
|
30138
|
+
if (!/^gpt-/i.test(displayName)) return displayName;
|
|
30139
|
+
return displayName.replace(/^gpt-/i, "").split(/[-/]+/).filter(Boolean).map(capitalize).join(" ");
|
|
30140
|
+
}
|
|
30048
30141
|
function capitalize(value) {
|
|
30049
30142
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
30050
30143
|
}
|
|
@@ -30052,19 +30145,20 @@ function findSupportedEffort(options, effort) {
|
|
|
30052
30145
|
if (!effort) return void 0;
|
|
30053
30146
|
return options.find((o) => o.reasoningEffort === effort)?.reasoningEffort;
|
|
30054
30147
|
}
|
|
30055
|
-
function createModelConfigOption(availableModels, currentBaseModelId) {
|
|
30148
|
+
function createModelConfigOption(availableModels, currentBaseModelId, recommendedModelId) {
|
|
30056
30149
|
const options = availableModels.map((model) => ({
|
|
30057
30150
|
value: model.id,
|
|
30058
|
-
name: model.displayName,
|
|
30151
|
+
name: formatModelDisplayName(model.displayName),
|
|
30059
30152
|
description: model.description
|
|
30060
30153
|
}));
|
|
30061
30154
|
if (!availableModels.some((model) => model.id === currentBaseModelId)) {
|
|
30062
30155
|
options.unshift({
|
|
30063
30156
|
value: currentBaseModelId,
|
|
30064
|
-
name: currentBaseModelId,
|
|
30157
|
+
name: formatModelDisplayName(currentBaseModelId),
|
|
30065
30158
|
description: null
|
|
30066
30159
|
});
|
|
30067
30160
|
}
|
|
30161
|
+
const recommendation = recommendedModelId && options.some((option) => option.value === recommendedModelId) ? recommendedModelId : void 0;
|
|
30068
30162
|
return {
|
|
30069
30163
|
id: MODEL_CONFIG_ID,
|
|
30070
30164
|
name: "Model",
|
|
@@ -30072,10 +30166,12 @@ function createModelConfigOption(availableModels, currentBaseModelId) {
|
|
|
30072
30166
|
category: "model",
|
|
30073
30167
|
type: "select",
|
|
30074
30168
|
currentValue: currentBaseModelId,
|
|
30075
|
-
options
|
|
30169
|
+
options,
|
|
30170
|
+
...recommendation ? { _meta: withAirMeta(void 0, AIR_RECOMMENDED_CONFIG_VALUE_KEY, recommendation) } : {}
|
|
30076
30171
|
};
|
|
30077
30172
|
}
|
|
30078
|
-
function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEffort) {
|
|
30173
|
+
function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEffort, recommendedEffort) {
|
|
30174
|
+
const recommendation = findSupportedEffort(supportedReasoningEfforts, recommendedEffort);
|
|
30079
30175
|
return {
|
|
30080
30176
|
id: REASONING_EFFORT_CONFIG_ID,
|
|
30081
30177
|
name: "Reasoning effort",
|
|
@@ -30087,7 +30183,8 @@ function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEff
|
|
|
30087
30183
|
value: option.reasoningEffort,
|
|
30088
30184
|
name: capitalize(option.reasoningEffort),
|
|
30089
30185
|
description: option.description
|
|
30090
|
-
}))
|
|
30186
|
+
})),
|
|
30187
|
+
...recommendation ? { _meta: withAirMeta(void 0, AIR_RECOMMENDED_CONFIG_VALUE_KEY, recommendation) } : {}
|
|
30091
30188
|
};
|
|
30092
30189
|
}
|
|
30093
30190
|
|
|
@@ -30787,14 +30884,14 @@ function parseJsonRecord(line) {
|
|
|
30787
30884
|
}
|
|
30788
30885
|
try {
|
|
30789
30886
|
const value = JSON.parse(line);
|
|
30790
|
-
return
|
|
30887
|
+
return asRecord3(value);
|
|
30791
30888
|
} catch {
|
|
30792
30889
|
return null;
|
|
30793
30890
|
}
|
|
30794
30891
|
}
|
|
30795
30892
|
function extractResponseItem(record2) {
|
|
30796
30893
|
if (record2["type"] === "response_item") {
|
|
30797
|
-
return
|
|
30894
|
+
return asRecord3(record2["payload"]);
|
|
30798
30895
|
}
|
|
30799
30896
|
const itemType = record2["type"];
|
|
30800
30897
|
if (typeof itemType === "string" && isLegacyResponseItemType(itemType)) {
|
|
@@ -30828,7 +30925,7 @@ function createEventMsgUpdates(record2) {
|
|
|
30828
30925
|
if (record2["type"] !== "event_msg") {
|
|
30829
30926
|
return null;
|
|
30830
30927
|
}
|
|
30831
|
-
const payload =
|
|
30928
|
+
const payload = asRecord3(record2["payload"]);
|
|
30832
30929
|
if (!payload) {
|
|
30833
30930
|
return [];
|
|
30834
30931
|
}
|
|
@@ -30872,7 +30969,7 @@ function imageBlocks(images) {
|
|
|
30872
30969
|
if (typeof image === "string") {
|
|
30873
30970
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
30874
30971
|
}
|
|
30875
|
-
const record2 =
|
|
30972
|
+
const record2 = asRecord3(image);
|
|
30876
30973
|
const path9 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
30877
30974
|
return path9 ? [{ type: "text", text: `[@image](${path9})` }] : [];
|
|
30878
30975
|
});
|
|
@@ -30882,7 +30979,7 @@ function contentBlocksFromResponseContent(content) {
|
|
|
30882
30979
|
return [];
|
|
30883
30980
|
}
|
|
30884
30981
|
return content.flatMap((entry) => {
|
|
30885
|
-
const record2 =
|
|
30982
|
+
const record2 = asRecord3(entry);
|
|
30886
30983
|
if (!record2) {
|
|
30887
30984
|
return [];
|
|
30888
30985
|
}
|
|
@@ -30915,7 +31012,7 @@ function textParts(value) {
|
|
|
30915
31012
|
if (typeof entry === "string") {
|
|
30916
31013
|
return entry.length > 0 ? [entry] : [];
|
|
30917
31014
|
}
|
|
30918
|
-
const record2 =
|
|
31015
|
+
const record2 = asRecord3(entry);
|
|
30919
31016
|
if (!record2) {
|
|
30920
31017
|
return [];
|
|
30921
31018
|
}
|
|
@@ -30929,6 +31026,7 @@ function createFunctionCallUpdate(item) {
|
|
|
30929
31026
|
if (!toolCallId || !name) {
|
|
30930
31027
|
return null;
|
|
30931
31028
|
}
|
|
31029
|
+
const toolName = functionToolName(name, stringValue(item["namespace"]));
|
|
30932
31030
|
const isExecCommand = name === "exec_command";
|
|
30933
31031
|
const args = parseFunctionArguments(item["arguments"]);
|
|
30934
31032
|
const command = isExecCommand ? commandFromFunctionArguments(args) : null;
|
|
@@ -30936,7 +31034,10 @@ function createFunctionCallUpdate(item) {
|
|
|
30936
31034
|
const commandAction = command ? inferCommandAction(command, cwd) : null;
|
|
30937
31035
|
if (commandAction) {
|
|
30938
31036
|
return {
|
|
30939
|
-
update:
|
|
31037
|
+
update: {
|
|
31038
|
+
...createCommandActionEvent(toolCallId, "inProgress", cwd, commandAction),
|
|
31039
|
+
name: toolName
|
|
31040
|
+
},
|
|
30940
31041
|
usesTerminal: false,
|
|
30941
31042
|
isExecCommand
|
|
30942
31043
|
};
|
|
@@ -30944,6 +31045,7 @@ function createFunctionCallUpdate(item) {
|
|
|
30944
31045
|
const update = {
|
|
30945
31046
|
sessionUpdate: "tool_call",
|
|
30946
31047
|
toolCallId,
|
|
31048
|
+
name: toolName,
|
|
30947
31049
|
kind: toolKindForFunctionCall(name),
|
|
30948
31050
|
title: titleForFunctionCall(name, args),
|
|
30949
31051
|
status: "in_progress",
|
|
@@ -31007,7 +31109,7 @@ function parseFunctionArguments(value) {
|
|
|
31007
31109
|
}
|
|
31008
31110
|
function rawInputForFunctionCall(name, args) {
|
|
31009
31111
|
if (name === "exec_command") {
|
|
31010
|
-
const record2 =
|
|
31112
|
+
const record2 = asRecord3(args);
|
|
31011
31113
|
if (record2) {
|
|
31012
31114
|
return {
|
|
31013
31115
|
command: stringValue(record2["cmd"]) ?? stringValue(record2["command"]),
|
|
@@ -31054,14 +31156,14 @@ function functionCallUsesTerminal(item) {
|
|
|
31054
31156
|
return item["name"] === "exec_command";
|
|
31055
31157
|
}
|
|
31056
31158
|
function commandFromFunctionArguments(args) {
|
|
31057
|
-
const record2 =
|
|
31159
|
+
const record2 = asRecord3(args);
|
|
31058
31160
|
if (!record2) {
|
|
31059
31161
|
return null;
|
|
31060
31162
|
}
|
|
31061
31163
|
return stringValue(record2["cmd"]) ?? stringValue(record2["command"]);
|
|
31062
31164
|
}
|
|
31063
31165
|
function cwdFromFunctionArguments(args) {
|
|
31064
|
-
const record2 =
|
|
31166
|
+
const record2 = asRecord3(args);
|
|
31065
31167
|
if (!record2) {
|
|
31066
31168
|
return "";
|
|
31067
31169
|
}
|
|
@@ -31533,7 +31635,7 @@ function outputText(output) {
|
|
|
31533
31635
|
return "";
|
|
31534
31636
|
}
|
|
31535
31637
|
return output.flatMap((entry) => {
|
|
31536
|
-
const record2 =
|
|
31638
|
+
const record2 = asRecord3(entry);
|
|
31537
31639
|
if (!record2) {
|
|
31538
31640
|
return [];
|
|
31539
31641
|
}
|
|
@@ -31549,7 +31651,7 @@ function outputText(output) {
|
|
|
31549
31651
|
}).join("\n");
|
|
31550
31652
|
}
|
|
31551
31653
|
function parseExitCode(rawOutput, output) {
|
|
31552
|
-
const record2 =
|
|
31654
|
+
const record2 = asRecord3(rawOutput);
|
|
31553
31655
|
if (record2) {
|
|
31554
31656
|
const exitCode2 = numberValue(record2["exit_code"]) ?? numberValue(record2["exitCode"]);
|
|
31555
31657
|
if (exitCode2 !== null) {
|
|
@@ -31580,7 +31682,7 @@ function looksLikeCommandFailure(output) {
|
|
|
31580
31682
|
}
|
|
31581
31683
|
return /(^|\n)(Error|Failed|Command failed|Sandbox error|No such file or directory|Permission denied|Operation not permitted|ENOENT|EACCES)(:|\b)/i.test(trimmed);
|
|
31582
31684
|
}
|
|
31583
|
-
function
|
|
31685
|
+
function asRecord3(value) {
|
|
31584
31686
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
31585
31687
|
return null;
|
|
31586
31688
|
}
|
|
@@ -32230,12 +32332,7 @@ function clientSupportsTypedSessionFailures(capabilities) {
|
|
|
32230
32332
|
function clientSupportsAgentFileChangeReports(capabilities) {
|
|
32231
32333
|
return clientSupportsAirCapability(capabilities, AIR_AGENT_FILE_CHANGE_REPORT_KEY);
|
|
32232
32334
|
}
|
|
32233
|
-
var CodexAcpServer = class
|
|
32234
|
-
static MODEL_NAME_TOKEN_OVERRIDES = {
|
|
32235
|
-
gpt: "GPT",
|
|
32236
|
-
mini: "Mini",
|
|
32237
|
-
codex: "Codex"
|
|
32238
|
-
};
|
|
32335
|
+
var CodexAcpServer = class {
|
|
32239
32336
|
codexAcpClient;
|
|
32240
32337
|
connection;
|
|
32241
32338
|
defaultAuthRequest;
|
|
@@ -32362,7 +32459,8 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
32362
32459
|
AIR_SESSION_FAILURE_KEY,
|
|
32363
32460
|
AIR_AGENT_FILE_CHANGE_REPORT_KEY,
|
|
32364
32461
|
AIR_NATIVE_SUBAGENT_SESSIONS_KEY,
|
|
32365
|
-
AIR_ASYNC_TASKS_KEY
|
|
32462
|
+
AIR_ASYNC_TASKS_KEY,
|
|
32463
|
+
AIR_RECOMMENDED_CONFIG_VALUE_KEY
|
|
32366
32464
|
]
|
|
32367
32465
|
}
|
|
32368
32466
|
}
|
|
@@ -33535,14 +33633,24 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33535
33633
|
}
|
|
33536
33634
|
createSessionConfigOptions(sessionState) {
|
|
33537
33635
|
const currentModelId = ModelId.fromString(sessionState.currentModelId);
|
|
33636
|
+
const useRecommendedValue = clientSupportsAirCapability(
|
|
33637
|
+
this.clientCapabilities,
|
|
33638
|
+
AIR_RECOMMENDED_CONFIG_VALUE_KEY
|
|
33639
|
+
);
|
|
33640
|
+
const currentModel = this.findCurrentModel(sessionState.availableModels, sessionState.currentModelId);
|
|
33641
|
+
const recommendedModelId = useRecommendedValue ? sessionState.availableModels.find((model) => model.isDefault)?.id : void 0;
|
|
33538
33642
|
const configOptions = [
|
|
33539
33643
|
sessionState.agentMode.toConfigOption(),
|
|
33540
33644
|
createCollaborationModeConfigOption(sessionState.collaborationMode),
|
|
33541
|
-
createModelConfigOption(sessionState.availableModels, currentModelId.model)
|
|
33645
|
+
createModelConfigOption(sessionState.availableModels, currentModelId.model, recommendedModelId)
|
|
33542
33646
|
];
|
|
33543
33647
|
if (sessionState.supportedReasoningEfforts.length > 0) {
|
|
33544
33648
|
configOptions.push(
|
|
33545
|
-
createReasoningEffortConfigOption(
|
|
33649
|
+
createReasoningEffortConfigOption(
|
|
33650
|
+
sessionState.supportedReasoningEfforts,
|
|
33651
|
+
currentModelId.effort,
|
|
33652
|
+
useRecommendedValue ? currentModel?.defaultReasoningEffort : void 0
|
|
33653
|
+
)
|
|
33546
33654
|
);
|
|
33547
33655
|
}
|
|
33548
33656
|
if (sessionState.currentModelSupportsFast) {
|
|
@@ -33619,14 +33727,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33619
33727
|
const modelId = ModelId.fromString(currentModelId);
|
|
33620
33728
|
return models.find((m) => m.id === modelId.model);
|
|
33621
33729
|
}
|
|
33622
|
-
normalizeModelDisplayName(displayName) {
|
|
33623
|
-
return displayName.split("-").map((token) => _CodexAcpServer.MODEL_NAME_TOKEN_OVERRIDES[token.toLowerCase()] ?? token).join("-");
|
|
33624
|
-
}
|
|
33625
33730
|
createModelState(availableModels, selectedModelId) {
|
|
33626
33731
|
const allowedModels = availableModels.flatMap(
|
|
33627
33732
|
(model) => model.supportedReasoningEfforts.map((effort) => ({
|
|
33628
33733
|
modelId: ModelId.fromComponents(model, effort.reasoningEffort).toString(),
|
|
33629
|
-
name: `${
|
|
33734
|
+
name: `${formatModelDisplayName(model.displayName)} (${effort.reasoningEffort})`,
|
|
33630
33735
|
description: `${model.description} ${effort.description}`
|
|
33631
33736
|
}))
|
|
33632
33737
|
);
|
|
@@ -33894,24 +33999,19 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
33894
33999
|
title
|
|
33895
34000
|
});
|
|
33896
34001
|
}
|
|
33897
|
-
async publishAgentFileChangeReport(sessionState, turnId, request, unavailableReason,
|
|
34002
|
+
async publishAgentFileChangeReport(sessionState, turnId, request, unavailableReason, turnDiff, workspace) {
|
|
33898
34003
|
let report;
|
|
33899
34004
|
try {
|
|
33900
|
-
report = turnId === null ? createUnavailableAgentFileChangeReport(request.requestId, unavailableReason) :
|
|
33901
|
-
sessionId: sessionState.sessionId,
|
|
33902
|
-
turnId,
|
|
33903
|
-
// The client owns request-id correlation and duplicate suppression. The wrapper
|
|
33904
|
-
// stays stateless so a retried ACP prompt still receives a terminal report.
|
|
33905
|
-
requestId: request.requestId,
|
|
33906
|
-
workspace: {
|
|
33907
|
-
cwd: sessionState.cwd,
|
|
33908
|
-
additionalDirectories: sessionState.additionalDirectories
|
|
33909
|
-
},
|
|
33910
|
-
signal
|
|
33911
|
-
});
|
|
34005
|
+
report = turnId === null ? createUnavailableAgentFileChangeReport(request.requestId, unavailableReason) : createReportedAgentFileChangeReport(request.requestId, turnDiff, workspace);
|
|
33912
34006
|
} catch (error51) {
|
|
33913
|
-
logger.error(
|
|
33914
|
-
|
|
34007
|
+
logger.error(
|
|
34008
|
+
error51 instanceof AgentFileChangeReportError ? "Agent file-change report unavailable" : "Agent file-change report failed unexpectedly",
|
|
34009
|
+
error51
|
|
34010
|
+
);
|
|
34011
|
+
report = createUnavailableAgentFileChangeReport(
|
|
34012
|
+
request.requestId,
|
|
34013
|
+
error51 instanceof AgentFileChangeReportError ? error51.reason : "providerError"
|
|
34014
|
+
);
|
|
33915
34015
|
}
|
|
33916
34016
|
try {
|
|
33917
34017
|
const session = new ACPSessionConnection(this.connection, sessionState.sessionId);
|
|
@@ -34381,6 +34481,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34381
34481
|
});
|
|
34382
34482
|
const sessionState = this.getSessionState(params.sessionId);
|
|
34383
34483
|
const agentFileChangeReportRequest = clientSupportsAgentFileChangeReports(this.clientCapabilities) ? parseAgentFileChangeReportRequest(params._meta) : null;
|
|
34484
|
+
const agentFileChangeWorkspace = agentFileChangeReportRequest === null ? null : captureAgentFileChangeWorkspace(sessionState.cwd, sessionState.additionalDirectories);
|
|
34384
34485
|
let agentFileChangeReportTurnId = null;
|
|
34385
34486
|
let agentFileChangeReportUnavailableReason = "providerError";
|
|
34386
34487
|
let promptWasCancelled = false;
|
|
@@ -34420,7 +34521,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34420
34521
|
clientSupportsTypedSessionFailures(this.clientCapabilities),
|
|
34421
34522
|
this.sessionFailureEpoch,
|
|
34422
34523
|
sessionState.subagents,
|
|
34423
|
-
(accountUpdated) => this.handleAccountUpdated(accountUpdated)
|
|
34524
|
+
(accountUpdated) => this.handleAccountUpdated(accountUpdated),
|
|
34525
|
+
agentFileChangeReportRequest !== null
|
|
34424
34526
|
);
|
|
34425
34527
|
eventHandler = promptEventHandler;
|
|
34426
34528
|
const permissionLifecycle = this.permissionLifecycleContext(sessionState);
|
|
@@ -34791,13 +34893,21 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
34791
34893
|
} catch (error51) {
|
|
34792
34894
|
logger.error("Failed to publish terminal subagent state during prompt cleanup", error51);
|
|
34793
34895
|
}
|
|
34794
|
-
if (agentFileChangeReportRequest !== null) {
|
|
34896
|
+
if (agentFileChangeReportRequest !== null && agentFileChangeWorkspace !== null) {
|
|
34897
|
+
if (promptWasCancelled || activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId)) {
|
|
34898
|
+
agentFileChangeReportTurnId = null;
|
|
34899
|
+
agentFileChangeReportUnavailableReason = "cancelled";
|
|
34900
|
+
} else if (agentFileChangeReportTurnId !== null && eventHandler?.isTurnDiffOversized(agentFileChangeReportTurnId)) {
|
|
34901
|
+
agentFileChangeReportTurnId = null;
|
|
34902
|
+
agentFileChangeReportUnavailableReason = "invalidOutput";
|
|
34903
|
+
}
|
|
34795
34904
|
await this.publishAgentFileChangeReport(
|
|
34796
34905
|
sessionState,
|
|
34797
34906
|
agentFileChangeReportTurnId,
|
|
34798
34907
|
agentFileChangeReportRequest,
|
|
34799
34908
|
agentFileChangeReportUnavailableReason,
|
|
34800
|
-
|
|
34909
|
+
agentFileChangeReportTurnId === null || eventHandler === null ? "" : eventHandler.getTurnDiff(agentFileChangeReportTurnId),
|
|
34910
|
+
agentFileChangeWorkspace
|
|
34801
34911
|
);
|
|
34802
34912
|
}
|
|
34803
34913
|
logger.log("Prompt completed", { sessionId: params.sessionId });
|