@agentclientprotocol/codex-acp 1.1.14 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +640 -95
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -3453,7 +3453,7 @@ var require_main = __commonJS({
|
|
|
3453
3453
|
exports.createMessageConnection = createMessageConnection2;
|
|
3454
3454
|
var ril_1 = __importDefault(require_ril());
|
|
3455
3455
|
ril_1.default.install();
|
|
3456
|
-
var
|
|
3456
|
+
var path7 = __importStar(__require("path"));
|
|
3457
3457
|
var os2 = __importStar(__require("os"));
|
|
3458
3458
|
var fs7 = __importStar(__require("fs"));
|
|
3459
3459
|
var crypto_1 = __require("crypto");
|
|
@@ -3605,7 +3605,7 @@ var require_main = __commonJS({
|
|
|
3605
3605
|
throw new Error(`Unable to generate a random pipe name with ${randomLength} characters.`);
|
|
3606
3606
|
}
|
|
3607
3607
|
const randomSuffix = (0, crypto_1.randomBytes)(Math.floor(randomLength / 2)).toString("hex");
|
|
3608
|
-
return
|
|
3608
|
+
return path7.join(tmpDir, `lsp-${randomSuffix}.sock`);
|
|
3609
3609
|
}
|
|
3610
3610
|
function createClientPipeTransport(pipeName, encoding = "utf-8") {
|
|
3611
3611
|
let connectResolve;
|
|
@@ -4509,10 +4509,10 @@ function mergeDefs(...defs) {
|
|
|
4509
4509
|
function cloneDef(schema) {
|
|
4510
4510
|
return mergeDefs(schema._zod.def);
|
|
4511
4511
|
}
|
|
4512
|
-
function getElementAtPath(obj,
|
|
4513
|
-
if (!
|
|
4512
|
+
function getElementAtPath(obj, path7) {
|
|
4513
|
+
if (!path7)
|
|
4514
4514
|
return obj;
|
|
4515
|
-
return
|
|
4515
|
+
return path7.reduce((acc, key) => acc?.[key], obj);
|
|
4516
4516
|
}
|
|
4517
4517
|
function promiseAllObject(promisesObj) {
|
|
4518
4518
|
const keys = Object.keys(promisesObj);
|
|
@@ -4921,11 +4921,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
4921
4921
|
}
|
|
4922
4922
|
return false;
|
|
4923
4923
|
}
|
|
4924
|
-
function prefixIssues(
|
|
4924
|
+
function prefixIssues(path7, issues) {
|
|
4925
4925
|
return issues.map((iss) => {
|
|
4926
4926
|
var _a3;
|
|
4927
4927
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
4928
|
-
iss.path.unshift(
|
|
4928
|
+
iss.path.unshift(path7);
|
|
4929
4929
|
return iss;
|
|
4930
4930
|
});
|
|
4931
4931
|
}
|
|
@@ -5072,16 +5072,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5072
5072
|
}
|
|
5073
5073
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
5074
5074
|
const fieldErrors = { _errors: [] };
|
|
5075
|
-
const processError = (error52,
|
|
5075
|
+
const processError = (error52, path7 = []) => {
|
|
5076
5076
|
for (const issue2 of error52.issues) {
|
|
5077
5077
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5078
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5078
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
5079
5079
|
} else if (issue2.code === "invalid_key") {
|
|
5080
|
-
processError({ issues: issue2.issues }, [...
|
|
5080
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
5081
5081
|
} else if (issue2.code === "invalid_element") {
|
|
5082
|
-
processError({ issues: issue2.issues }, [...
|
|
5082
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
5083
5083
|
} else {
|
|
5084
|
-
const fullpath = [...
|
|
5084
|
+
const fullpath = [...path7, ...issue2.path];
|
|
5085
5085
|
if (fullpath.length === 0) {
|
|
5086
5086
|
fieldErrors._errors.push(mapper(issue2));
|
|
5087
5087
|
} else {
|
|
@@ -5108,17 +5108,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5108
5108
|
}
|
|
5109
5109
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
5110
5110
|
const result = { errors: [] };
|
|
5111
|
-
const processError = (error52,
|
|
5111
|
+
const processError = (error52, path7 = []) => {
|
|
5112
5112
|
var _a3, _b;
|
|
5113
5113
|
for (const issue2 of error52.issues) {
|
|
5114
5114
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5115
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5115
|
+
issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
|
|
5116
5116
|
} else if (issue2.code === "invalid_key") {
|
|
5117
|
-
processError({ issues: issue2.issues }, [...
|
|
5117
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
5118
5118
|
} else if (issue2.code === "invalid_element") {
|
|
5119
|
-
processError({ issues: issue2.issues }, [...
|
|
5119
|
+
processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
|
|
5120
5120
|
} else {
|
|
5121
|
-
const fullpath = [...
|
|
5121
|
+
const fullpath = [...path7, ...issue2.path];
|
|
5122
5122
|
if (fullpath.length === 0) {
|
|
5123
5123
|
result.errors.push(mapper(issue2));
|
|
5124
5124
|
continue;
|
|
@@ -5150,8 +5150,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
5150
5150
|
}
|
|
5151
5151
|
function toDotPath(_path) {
|
|
5152
5152
|
const segs = [];
|
|
5153
|
-
const
|
|
5154
|
-
for (const seg of
|
|
5153
|
+
const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5154
|
+
for (const seg of path7) {
|
|
5155
5155
|
if (typeof seg === "number")
|
|
5156
5156
|
segs.push(`[${seg}]`);
|
|
5157
5157
|
else if (typeof seg === "symbol")
|
|
@@ -17843,13 +17843,13 @@ function resolveRef(ref, ctx) {
|
|
|
17843
17843
|
if (!ref.startsWith("#")) {
|
|
17844
17844
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
17845
17845
|
}
|
|
17846
|
-
const
|
|
17847
|
-
if (
|
|
17846
|
+
const path7 = ref.slice(1).split("/").filter(Boolean);
|
|
17847
|
+
if (path7.length === 0) {
|
|
17848
17848
|
return ctx.rootSchema;
|
|
17849
17849
|
}
|
|
17850
17850
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
17851
|
-
if (
|
|
17852
|
-
const key =
|
|
17851
|
+
if (path7[0] === defsKey) {
|
|
17852
|
+
const key = path7[1];
|
|
17853
17853
|
if (!key || !ctx.defs[key]) {
|
|
17854
17854
|
throw new Error(`Reference not found: ${ref}`);
|
|
17855
17855
|
}
|
|
@@ -22777,8 +22777,20 @@ function createTerminalOutputMeta(mode, terminalId, data) {
|
|
|
22777
22777
|
}
|
|
22778
22778
|
}
|
|
22779
22779
|
|
|
22780
|
+
// src/ContextCompactionMeta.ts
|
|
22781
|
+
var CONTEXT_COMPACTION_META_KEY = "contextCompaction";
|
|
22782
|
+
var CONTEXT_COMPACTION_META_VERSION = 1;
|
|
22783
|
+
function createContextCompactionMeta(metadata = {}) {
|
|
22784
|
+
return {
|
|
22785
|
+
[CONTEXT_COMPACTION_META_KEY]: {
|
|
22786
|
+
version: CONTEXT_COMPACTION_META_VERSION,
|
|
22787
|
+
...metadata
|
|
22788
|
+
}
|
|
22789
|
+
};
|
|
22790
|
+
}
|
|
22791
|
+
|
|
22780
22792
|
// src/CodexToolCallMapper.ts
|
|
22781
|
-
var CONTEXT_COMPACTION_META =
|
|
22793
|
+
var CONTEXT_COMPACTION_META = createContextCompactionMeta();
|
|
22782
22794
|
function toAcpStatus(status) {
|
|
22783
22795
|
switch (status) {
|
|
22784
22796
|
case "inProgress":
|
|
@@ -22925,8 +22937,8 @@ function createContextCompactionStartUpdate(item) {
|
|
|
22925
22937
|
return {
|
|
22926
22938
|
sessionUpdate: "tool_call",
|
|
22927
22939
|
toolCallId: item.id,
|
|
22928
|
-
kind: "
|
|
22929
|
-
title: "
|
|
22940
|
+
kind: "think",
|
|
22941
|
+
title: "Compact conversation",
|
|
22930
22942
|
status: "in_progress",
|
|
22931
22943
|
_meta: CONTEXT_COMPACTION_META
|
|
22932
22944
|
};
|
|
@@ -22935,7 +22947,7 @@ function createContextCompactionCompleteUpdate(item) {
|
|
|
22935
22947
|
return {
|
|
22936
22948
|
sessionUpdate: "tool_call_update",
|
|
22937
22949
|
toolCallId: item.id,
|
|
22938
|
-
title: "
|
|
22950
|
+
title: "Compact conversation",
|
|
22939
22951
|
status: "completed",
|
|
22940
22952
|
_meta: CONTEXT_COMPACTION_META
|
|
22941
22953
|
};
|
|
@@ -22944,8 +22956,8 @@ function createCompletedContextCompactionUpdate(item) {
|
|
|
22944
22956
|
return {
|
|
22945
22957
|
sessionUpdate: "tool_call",
|
|
22946
22958
|
toolCallId: item.id,
|
|
22947
|
-
kind: "
|
|
22948
|
-
title: "
|
|
22959
|
+
kind: "think",
|
|
22960
|
+
title: "Compact conversation",
|
|
22949
22961
|
status: "completed",
|
|
22950
22962
|
_meta: CONTEXT_COMPACTION_META
|
|
22951
22963
|
};
|
|
@@ -23235,13 +23247,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
23235
23247
|
}
|
|
23236
23248
|
};
|
|
23237
23249
|
}
|
|
23238
|
-
function createSearchTitle(query,
|
|
23239
|
-
if (query &&
|
|
23240
|
-
return `Search for '${query}' in ${
|
|
23250
|
+
function createSearchTitle(query, path7) {
|
|
23251
|
+
if (query && path7) {
|
|
23252
|
+
return `Search for '${query}' in ${path7}`;
|
|
23241
23253
|
} else if (query) {
|
|
23242
23254
|
return `Search for '${query}'`;
|
|
23243
|
-
} else if (
|
|
23244
|
-
return `Search in '${
|
|
23255
|
+
} else if (path7) {
|
|
23256
|
+
return `Search in '${path7}'`;
|
|
23245
23257
|
}
|
|
23246
23258
|
return "Search";
|
|
23247
23259
|
}
|
|
@@ -23467,12 +23479,12 @@ function revertPatch(unifiedDiff) {
|
|
|
23467
23479
|
if (!patch) return null;
|
|
23468
23480
|
return reversePatch(patch);
|
|
23469
23481
|
}
|
|
23470
|
-
function createUpdateDiffContent(
|
|
23482
|
+
function createUpdateDiffContent(path7, oldText, newText) {
|
|
23471
23483
|
return {
|
|
23472
23484
|
type: "diff",
|
|
23473
23485
|
oldText,
|
|
23474
23486
|
newText,
|
|
23475
|
-
path:
|
|
23487
|
+
path: path7,
|
|
23476
23488
|
_meta: {
|
|
23477
23489
|
kind: "update"
|
|
23478
23490
|
}
|
|
@@ -23597,10 +23609,104 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23597
23609
|
}
|
|
23598
23610
|
|
|
23599
23611
|
// src/CodexEventHandler.ts
|
|
23612
|
+
import { randomUUID } from "node:crypto";
|
|
23613
|
+
|
|
23614
|
+
// src/AirExtension.ts
|
|
23615
|
+
var JETBRAINS_META_KEY = "jetbrains";
|
|
23616
|
+
var AIR_META_KEY = "air";
|
|
23617
|
+
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
23618
|
+
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
23619
|
+
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
23620
|
+
var AIR_EXTENSION_VERSION = 1;
|
|
23621
|
+
|
|
23622
|
+
// src/CodexEventHandler.ts
|
|
23623
|
+
var MAX_SESSION_FAILURE_TITLE_LENGTH = 240;
|
|
23624
|
+
var SESSION_FAILURE_POLICY = {
|
|
23625
|
+
transport_lost: {
|
|
23626
|
+
category: "connection",
|
|
23627
|
+
actions: ["retry", "new_session"]
|
|
23628
|
+
},
|
|
23629
|
+
auth_required: {
|
|
23630
|
+
category: "access",
|
|
23631
|
+
actions: ["login"]
|
|
23632
|
+
},
|
|
23633
|
+
rate_limited: {
|
|
23634
|
+
category: "limit",
|
|
23635
|
+
actions: ["retry"]
|
|
23636
|
+
},
|
|
23637
|
+
quota_exhausted: {
|
|
23638
|
+
category: "limit",
|
|
23639
|
+
actions: []
|
|
23640
|
+
},
|
|
23641
|
+
overloaded: {
|
|
23642
|
+
category: "service",
|
|
23643
|
+
actions: ["retry"]
|
|
23644
|
+
},
|
|
23645
|
+
context_exhausted: {
|
|
23646
|
+
category: "limit",
|
|
23647
|
+
actions: ["new_session"]
|
|
23648
|
+
},
|
|
23649
|
+
budget_exhausted: {
|
|
23650
|
+
category: "limit",
|
|
23651
|
+
actions: ["new_session"]
|
|
23652
|
+
},
|
|
23653
|
+
policy_denied: {
|
|
23654
|
+
category: "request",
|
|
23655
|
+
actions: []
|
|
23656
|
+
},
|
|
23657
|
+
bad_request: {
|
|
23658
|
+
category: "request",
|
|
23659
|
+
actions: []
|
|
23660
|
+
},
|
|
23661
|
+
provider_error: {
|
|
23662
|
+
category: "service",
|
|
23663
|
+
actions: ["retry"]
|
|
23664
|
+
},
|
|
23665
|
+
internal_error: {
|
|
23666
|
+
category: "service",
|
|
23667
|
+
actions: ["retry", "new_session"]
|
|
23668
|
+
}
|
|
23669
|
+
};
|
|
23670
|
+
var SYNTHETIC_FAILURE_TITLE = {
|
|
23671
|
+
transport_lost: "Connection to Codex was lost.",
|
|
23672
|
+
internal_error: "Codex encountered an internal error."
|
|
23673
|
+
};
|
|
23674
|
+
function nextSessionFailureRevision(previous, id) {
|
|
23675
|
+
return previous?.id === id ? previous.revision + 1 : 1;
|
|
23676
|
+
}
|
|
23677
|
+
var STRING_CODEX_ERROR_CATEGORIES = {
|
|
23678
|
+
contextWindowExceeded: "context_exhausted",
|
|
23679
|
+
sessionBudgetExceeded: "budget_exhausted",
|
|
23680
|
+
usageLimitExceeded: "quota_exhausted",
|
|
23681
|
+
serverOverloaded: "overloaded",
|
|
23682
|
+
cyberPolicy: "policy_denied",
|
|
23683
|
+
internalServerError: "internal_error",
|
|
23684
|
+
unauthorized: "auth_required",
|
|
23685
|
+
badRequest: "bad_request",
|
|
23686
|
+
threadRollbackFailed: "provider_error",
|
|
23687
|
+
sandboxError: "provider_error",
|
|
23688
|
+
other: "provider_error"
|
|
23689
|
+
};
|
|
23690
|
+
var STRUCTURED_CODEX_ERROR_CATEGORIES = {
|
|
23691
|
+
httpConnectionFailed: "transport_lost",
|
|
23692
|
+
responseStreamConnectionFailed: "transport_lost",
|
|
23693
|
+
responseStreamDisconnected: "transport_lost",
|
|
23694
|
+
responseTooManyFailedAttempts: "transport_lost",
|
|
23695
|
+
activeTurnNotSteerable: "provider_error"
|
|
23696
|
+
};
|
|
23600
23697
|
var CodexEventHandler = class _CodexEventHandler {
|
|
23601
23698
|
static PLAN_UPDATE_INTERVAL_MS = 150;
|
|
23602
23699
|
sessionState;
|
|
23603
23700
|
supportsPlanUpdates;
|
|
23701
|
+
supportsTypedSessionFailures;
|
|
23702
|
+
sessionFailureEpoch;
|
|
23703
|
+
pendingErrors = [];
|
|
23704
|
+
failuresById = /* @__PURE__ */ new Map();
|
|
23705
|
+
activeFailureIdByScope = /* @__PURE__ */ new Map();
|
|
23706
|
+
failureTurnIdById = /* @__PURE__ */ new Map();
|
|
23707
|
+
allocatedFailureScopes = /* @__PURE__ */ new Set();
|
|
23708
|
+
lastSessionNotice;
|
|
23709
|
+
nextNoticeId = 1;
|
|
23604
23710
|
failure = null;
|
|
23605
23711
|
completedPlan = null;
|
|
23606
23712
|
activeFuzzyFileSearchSessions = /* @__PURE__ */ new Set();
|
|
@@ -23619,20 +23725,113 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23619
23725
|
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
23620
23726
|
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
23621
23727
|
activeSubAgentActivities = /* @__PURE__ */ new Set();
|
|
23622
|
-
constructor(connection, sessionState, supportsPlanUpdates = false) {
|
|
23728
|
+
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID()) {
|
|
23623
23729
|
this.sessionState = sessionState;
|
|
23624
23730
|
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
23731
|
+
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
23732
|
+
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
23625
23733
|
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
23734
|
+
if (sessionState.sessionFailure !== void 0) {
|
|
23735
|
+
this.failuresById.set(sessionState.sessionFailure.id, sessionState.sessionFailure);
|
|
23736
|
+
}
|
|
23626
23737
|
}
|
|
23627
23738
|
getFailure() {
|
|
23628
23739
|
return this.failure;
|
|
23629
23740
|
}
|
|
23741
|
+
getTerminalSessionFailureMeta(turnId, allowUnattributed = false) {
|
|
23742
|
+
const failure = this.sessionState.sessionFailure;
|
|
23743
|
+
if (!this.supportsTypedSessionFailures || failure === void 0 || (this.failureTurnIdById.get(failure.id) === void 0 ? !allowUnattributed : turnId === null || this.failureTurnIdById.get(failure.id) !== turnId)) {
|
|
23744
|
+
return null;
|
|
23745
|
+
}
|
|
23746
|
+
return this.createSessionFailureMeta(failure);
|
|
23747
|
+
}
|
|
23748
|
+
recordSyntheticTerminalFailure(kind, turnId) {
|
|
23749
|
+
this.recordSessionFailure(kind, turnId ?? void 0, "error", SYNTHETIC_FAILURE_TITLE[kind]);
|
|
23750
|
+
}
|
|
23751
|
+
/**
|
|
23752
|
+
* Handles notifications after the prompt-local handler has been disposed. The app-server subscription
|
|
23753
|
+
* remains installed until the ACP session closes, so terminal errors need a durable session-level path
|
|
23754
|
+
* instead of entering a turn buffer that will never be flushed.
|
|
23755
|
+
*/
|
|
23756
|
+
async handleSessionScopedNotification(notification) {
|
|
23757
|
+
if (notification.method !== "error") {
|
|
23758
|
+
await this.handleNotification(notification);
|
|
23759
|
+
return;
|
|
23760
|
+
}
|
|
23761
|
+
if (!this.supportsTypedSessionFailures) {
|
|
23762
|
+
await this.handleNotification(notification);
|
|
23763
|
+
return;
|
|
23764
|
+
}
|
|
23765
|
+
if (notification.params.willRetry) {
|
|
23766
|
+
await this.session.update(this.createSessionFailureUpdate(this.recordRetryWarning(notification.params, false)));
|
|
23767
|
+
return;
|
|
23768
|
+
}
|
|
23769
|
+
const failure = this.recordSessionFailure(
|
|
23770
|
+
this.sessionFailureKind(notification.params.error.codexErrorInfo),
|
|
23771
|
+
notification.params.turnId,
|
|
23772
|
+
"error",
|
|
23773
|
+
notification.params.error.message,
|
|
23774
|
+
void 0,
|
|
23775
|
+
false
|
|
23776
|
+
);
|
|
23777
|
+
await this.session.update(this.createSessionFailureUpdate(failure));
|
|
23778
|
+
}
|
|
23779
|
+
async flushPendingErrors() {
|
|
23780
|
+
if (this.sessionState.currentTurnId === null || this.pendingErrors.length === 0) {
|
|
23781
|
+
return;
|
|
23782
|
+
}
|
|
23783
|
+
const errors = this.pendingErrors.splice(0);
|
|
23784
|
+
for (const error51 of errors) {
|
|
23785
|
+
const update = await this.createErrorEvent(error51);
|
|
23786
|
+
if (update) {
|
|
23787
|
+
await this.session.update(update);
|
|
23788
|
+
}
|
|
23789
|
+
}
|
|
23790
|
+
}
|
|
23791
|
+
async flushPendingErrorsAsSessionScoped() {
|
|
23792
|
+
if (!this.supportsTypedSessionFailures || this.pendingErrors.length === 0) {
|
|
23793
|
+
return;
|
|
23794
|
+
}
|
|
23795
|
+
const errors = this.pendingErrors.splice(0);
|
|
23796
|
+
for (const error51 of errors) {
|
|
23797
|
+
await this.handleSessionScopedNotification({ method: "error", params: error51 });
|
|
23798
|
+
}
|
|
23799
|
+
}
|
|
23800
|
+
async clearSessionFailure() {
|
|
23801
|
+
delete this.sessionState.sessionFailure;
|
|
23802
|
+
}
|
|
23803
|
+
async completeSuccessfulTurn(turnId) {
|
|
23804
|
+
this.lastSessionNotice = void 0;
|
|
23805
|
+
if (!this.supportsTypedSessionFailures || turnId === null) return;
|
|
23806
|
+
const active = this.sessionState.sessionFailure;
|
|
23807
|
+
if (active?.id !== this.activeFailureIdByScope.get(turnId) || active?.severity !== "warning") return;
|
|
23808
|
+
this.activeFailureIdByScope.delete(turnId);
|
|
23809
|
+
delete this.sessionState.sessionFailure;
|
|
23810
|
+
}
|
|
23811
|
+
async handleFailedTurn(turn) {
|
|
23812
|
+
const activeFailure = this.sessionState.sessionFailure;
|
|
23813
|
+
if (!this.supportsTypedSessionFailures || turn.status !== "failed" || this.failure !== null || this.failureTurnIdById.get(activeFailure?.id ?? "") === turn.id && activeFailure?.severity === "error") {
|
|
23814
|
+
return;
|
|
23815
|
+
}
|
|
23816
|
+
const error51 = turn.error ?? {
|
|
23817
|
+
message: "Turn failed",
|
|
23818
|
+
codexErrorInfo: null,
|
|
23819
|
+
additionalDetails: null
|
|
23820
|
+
};
|
|
23821
|
+
this.recordTypedSessionFailure({
|
|
23822
|
+
threadId: this.sessionState.sessionId,
|
|
23823
|
+
turnId: turn.id,
|
|
23824
|
+
willRetry: false,
|
|
23825
|
+
error: error51
|
|
23826
|
+
});
|
|
23827
|
+
}
|
|
23630
23828
|
takeCompletedPlan() {
|
|
23631
23829
|
const plan = this.completedPlan;
|
|
23632
23830
|
this.completedPlan = null;
|
|
23633
23831
|
return plan;
|
|
23634
23832
|
}
|
|
23635
23833
|
async handleNotification(notification) {
|
|
23834
|
+
await this.flushPendingErrors();
|
|
23636
23835
|
const updateEvent = await this.createUpdateEvent(notification);
|
|
23637
23836
|
if (updateEvent) {
|
|
23638
23837
|
await this.session.update(updateEvent);
|
|
@@ -23653,6 +23852,14 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23653
23852
|
async dispose() {
|
|
23654
23853
|
if (this.disposed) return;
|
|
23655
23854
|
await this.flushPendingPlanUpdates();
|
|
23855
|
+
if (this.pendingErrors.length > 0) {
|
|
23856
|
+
logger.log("Discarding app-server errors that arrived before a turn started", {
|
|
23857
|
+
sessionId: this.sessionState.sessionId,
|
|
23858
|
+
count: this.pendingErrors.length,
|
|
23859
|
+
turnIds: this.pendingErrors.map((error51) => error51.turnId)
|
|
23860
|
+
});
|
|
23861
|
+
this.pendingErrors.splice(0);
|
|
23862
|
+
}
|
|
23656
23863
|
this.disposed = true;
|
|
23657
23864
|
this.cancelPlanUpdateTimer();
|
|
23658
23865
|
this.pendingPlanItemIds.clear();
|
|
@@ -23662,19 +23869,25 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23662
23869
|
async createUpdateEvent(notification) {
|
|
23663
23870
|
switch (notification.method) {
|
|
23664
23871
|
case "item/agentMessage/delta":
|
|
23872
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23665
23873
|
return await this.createTextEvent(notification.params);
|
|
23666
23874
|
case "item/plan/delta":
|
|
23875
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23667
23876
|
return this.createPlanDeltaEvent(notification.params);
|
|
23668
23877
|
case "item/started":
|
|
23878
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23669
23879
|
return await this.createItemEvent(notification.params);
|
|
23670
23880
|
case "item/completed":
|
|
23881
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23671
23882
|
return await this.completeItemEvent(notification.params);
|
|
23672
23883
|
case "turn/plan/updated":
|
|
23884
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23673
23885
|
return await this.updatePlan(notification.params);
|
|
23674
23886
|
case "error":
|
|
23675
23887
|
return await this.createErrorEvent(notification.params);
|
|
23676
23888
|
case "turn/started":
|
|
23677
23889
|
this.sessionState.currentTurnId = notification.params.turn.id;
|
|
23890
|
+
await this.flushPendingErrors();
|
|
23678
23891
|
return null;
|
|
23679
23892
|
case "turn/completed":
|
|
23680
23893
|
await this.flushPendingPlanUpdates();
|
|
@@ -23707,8 +23920,10 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23707
23920
|
closed: true
|
|
23708
23921
|
});
|
|
23709
23922
|
case "item/commandExecution/outputDelta":
|
|
23923
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23710
23924
|
return this.createCommandOutputDeltaEvent(notification.params);
|
|
23711
23925
|
case "item/mcpToolCall/progress":
|
|
23926
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23712
23927
|
return this.createMcpToolProgressEvent(notification.params);
|
|
23713
23928
|
case "account/rateLimits/updated":
|
|
23714
23929
|
this.handleRateLimitsUpdated(notification.params);
|
|
@@ -23719,6 +23934,8 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23719
23934
|
return this.createWarningEvent(notification.params);
|
|
23720
23935
|
case "guardianWarning":
|
|
23721
23936
|
return null;
|
|
23937
|
+
case "deprecationNotice":
|
|
23938
|
+
return this.createDeprecationNoticeEvent(notification.params);
|
|
23722
23939
|
case "item/autoApprovalReview/started":
|
|
23723
23940
|
return this.handleGuardianApprovalReviewStarted(notification.params);
|
|
23724
23941
|
case "item/autoApprovalReview/completed":
|
|
@@ -23726,10 +23943,13 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23726
23943
|
case "thread/compacted":
|
|
23727
23944
|
return this.createContextCompactedEvent();
|
|
23728
23945
|
case "item/reasoning/summaryTextDelta":
|
|
23946
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23729
23947
|
return this.createReasoningDeltaEvent(notification.params);
|
|
23730
23948
|
case "item/reasoning/textDelta":
|
|
23949
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23731
23950
|
return this.createReasoningDeltaEvent(notification.params);
|
|
23732
23951
|
case "item/reasoning/summaryPartAdded":
|
|
23952
|
+
this.completeRetryIncidentOnTurnProgress();
|
|
23733
23953
|
return this.createReasoningSectionBreakEvent(notification.params);
|
|
23734
23954
|
case "model/rerouted":
|
|
23735
23955
|
return this.createModelReroutedEvent(notification.params);
|
|
@@ -23772,7 +23992,6 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23772
23992
|
case "windowsSandbox/setupCompleted":
|
|
23773
23993
|
case "account/login/completed":
|
|
23774
23994
|
case "skills/changed":
|
|
23775
|
-
case "deprecationNotice":
|
|
23776
23995
|
case "mcpServer/oauthLogin/completed":
|
|
23777
23996
|
case "externalAgentConfig/import/completed":
|
|
23778
23997
|
case "rawResponseItem/completed":
|
|
@@ -23800,14 +24019,31 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23800
24019
|
return createAgentTextMessageChunk(event.delta, event.itemId, createCodexMessagePhaseMeta(phase));
|
|
23801
24020
|
}
|
|
23802
24021
|
async createConfigWarningEvent(event) {
|
|
23803
|
-
|
|
24022
|
+
if (this.supportsTypedSessionFailures) {
|
|
24023
|
+
return this.createSessionFailureUpdate(this.recordSessionNotice(...this.sessionNoticeContent(event.summary, event.details)));
|
|
24024
|
+
}
|
|
24025
|
+
const text = event.details ? `${event.summary}
|
|
23804
24026
|
|
|
23805
|
-
${event.details}` :
|
|
23806
|
-
return createAgentTextMessageChunk(`Config warning: ${
|
|
24027
|
+
${event.details}` : event.summary;
|
|
24028
|
+
return createAgentTextMessageChunk(`Config warning: ${text}
|
|
23807
24029
|
|
|
23808
24030
|
`);
|
|
23809
24031
|
}
|
|
24032
|
+
/**
|
|
24033
|
+
* Unlike `warning` and `configWarning`, this notification was dropped outright, so there is no
|
|
24034
|
+
* legacy rendering to preserve. It is surfaced only to clients that negotiated typed records;
|
|
24035
|
+
* every other client keeps seeing exactly what it sees today, which is nothing.
|
|
24036
|
+
*/
|
|
24037
|
+
createDeprecationNoticeEvent(event) {
|
|
24038
|
+
if (!this.supportsTypedSessionFailures) return null;
|
|
24039
|
+
return this.createSessionFailureUpdate(
|
|
24040
|
+
this.recordSessionNotice(...this.sessionNoticeContent(event.summary, event.details))
|
|
24041
|
+
);
|
|
24042
|
+
}
|
|
23810
24043
|
createWarningEvent(event) {
|
|
24044
|
+
if (this.supportsTypedSessionFailures) {
|
|
24045
|
+
return this.createSessionFailureUpdate(this.recordSessionNotice(event.message));
|
|
24046
|
+
}
|
|
23811
24047
|
return createAgentTextMessageChunk(`Warning: ${event.message}
|
|
23812
24048
|
|
|
23813
24049
|
`);
|
|
@@ -24174,7 +24410,33 @@ ${event.stdin}
|
|
|
24174
24410
|
}
|
|
24175
24411
|
async createErrorEvent(params) {
|
|
24176
24412
|
const error51 = params.error.codexErrorInfo;
|
|
24413
|
+
if (this.sessionState.currentTurnId === null) {
|
|
24414
|
+
this.pendingErrors.push(params);
|
|
24415
|
+
logger.log("Buffered app-server error until the active turn is known", {
|
|
24416
|
+
sessionId: this.sessionState.sessionId,
|
|
24417
|
+
turnId: params.turnId,
|
|
24418
|
+
willRetry: params.willRetry
|
|
24419
|
+
});
|
|
24420
|
+
return null;
|
|
24421
|
+
}
|
|
24422
|
+
if (params.turnId !== this.sessionState.currentTurnId) {
|
|
24423
|
+
if (this.supportsTypedSessionFailures) {
|
|
24424
|
+
const failure = params.willRetry ? this.recordRetryWarning(params) : this.recordSessionFailure(
|
|
24425
|
+
this.sessionFailureKind(params.error.codexErrorInfo),
|
|
24426
|
+
params.turnId,
|
|
24427
|
+
"error",
|
|
24428
|
+
params.error.message
|
|
24429
|
+
);
|
|
24430
|
+
return this.createSessionFailureUpdate(failure);
|
|
24431
|
+
}
|
|
24432
|
+
return this.createCodexSessionInfoUpdate({
|
|
24433
|
+
error: { ...params.error, turnId: params.turnId, willRetry: params.willRetry }
|
|
24434
|
+
});
|
|
24435
|
+
}
|
|
24177
24436
|
if (params.willRetry) {
|
|
24437
|
+
if (this.supportsTypedSessionFailures) {
|
|
24438
|
+
return this.createSessionFailureUpdate(this.recordRetryWarning(params));
|
|
24439
|
+
}
|
|
24178
24440
|
return this.createCodexSessionInfoUpdate({
|
|
24179
24441
|
error: {
|
|
24180
24442
|
...params.error,
|
|
@@ -24182,7 +24444,12 @@ ${event.stdin}
|
|
|
24182
24444
|
willRetry: true
|
|
24183
24445
|
}
|
|
24184
24446
|
});
|
|
24185
|
-
}
|
|
24447
|
+
}
|
|
24448
|
+
if (this.supportsTypedSessionFailures) {
|
|
24449
|
+
this.recordTypedSessionFailure(params);
|
|
24450
|
+
return null;
|
|
24451
|
+
}
|
|
24452
|
+
if (error51 === "usageLimitExceeded") {
|
|
24186
24453
|
this.failure = RequestError.internalError(
|
|
24187
24454
|
this.createTurnErrorData(params.error)
|
|
24188
24455
|
);
|
|
@@ -24193,22 +24460,125 @@ ${event.stdin}
|
|
|
24193
24460
|
|
|
24194
24461
|
`);
|
|
24195
24462
|
}
|
|
24463
|
+
recordTypedSessionFailure(params) {
|
|
24464
|
+
const kind = this.sessionFailureKind(params.error.codexErrorInfo);
|
|
24465
|
+
this.recordSessionFailure(kind, params.turnId, "error", params.error.message);
|
|
24466
|
+
}
|
|
24467
|
+
recordSessionFailure(kind, turnId, severity, title, actionsOverride, attributeToTurn = true) {
|
|
24468
|
+
const policy = SESSION_FAILURE_POLICY[kind];
|
|
24469
|
+
const scope = turnId ?? this.sessionState.sessionId;
|
|
24470
|
+
const id = this.activeFailureIdByScope.get(scope) ?? this.allocateFailureId(scope, turnId);
|
|
24471
|
+
const previous = this.failuresById.get(id);
|
|
24472
|
+
const failure = {
|
|
24473
|
+
id,
|
|
24474
|
+
revision: nextSessionFailureRevision(previous, id),
|
|
24475
|
+
category: policy.category,
|
|
24476
|
+
severity,
|
|
24477
|
+
title,
|
|
24478
|
+
actions: actionsOverride ?? policy.actions
|
|
24479
|
+
};
|
|
24480
|
+
this.failuresById.set(id, failure);
|
|
24481
|
+
this.failureTurnIdById.set(id, attributeToTurn ? turnId : void 0);
|
|
24482
|
+
this.activeFailureIdByScope.set(scope, id);
|
|
24483
|
+
this.sessionState.sessionFailure = failure;
|
|
24484
|
+
this.lastSessionNotice = void 0;
|
|
24485
|
+
return failure;
|
|
24486
|
+
}
|
|
24487
|
+
allocateFailureId(scope, turnId) {
|
|
24488
|
+
if (turnId !== void 0 && !this.allocatedFailureScopes.has(scope)) {
|
|
24489
|
+
this.allocatedFailureScopes.add(scope);
|
|
24490
|
+
return `${turnId}:error`;
|
|
24491
|
+
}
|
|
24492
|
+
this.allocatedFailureScopes.add(scope);
|
|
24493
|
+
return `${scope}:error:${this.sessionFailureEpoch}:${this.nextNoticeId++}`;
|
|
24494
|
+
}
|
|
24495
|
+
/**
|
|
24496
|
+
* A retry warning remains the active incident until Codex produces turn content again. That content is
|
|
24497
|
+
* the only positive signal available from app-server that the turn recovered; a later error then starts
|
|
24498
|
+
* a new incident instead of overwriting the historical reconnect entry. Terminal errors remain active so
|
|
24499
|
+
* duplicate late notifications cannot append duplicate transcript rows.
|
|
24500
|
+
*/
|
|
24501
|
+
completeRetryIncidentOnTurnProgress() {
|
|
24502
|
+
const turnId = this.sessionState.currentTurnId;
|
|
24503
|
+
if (turnId === null) return;
|
|
24504
|
+
const activeId = this.activeFailureIdByScope.get(turnId);
|
|
24505
|
+
if (activeId === void 0 || this.failuresById.get(activeId)?.severity !== "warning") return;
|
|
24506
|
+
this.activeFailureIdByScope.delete(turnId);
|
|
24507
|
+
if (this.sessionState.sessionFailure?.id === activeId) {
|
|
24508
|
+
delete this.sessionState.sessionFailure;
|
|
24509
|
+
}
|
|
24510
|
+
}
|
|
24511
|
+
recordRetryWarning(params, attributeToTurn = true) {
|
|
24512
|
+
const kind = this.sessionFailureKind(params.error.codexErrorInfo);
|
|
24513
|
+
return this.recordSessionFailure(
|
|
24514
|
+
kind,
|
|
24515
|
+
params.turnId,
|
|
24516
|
+
"warning",
|
|
24517
|
+
params.error.message,
|
|
24518
|
+
[],
|
|
24519
|
+
attributeToTurn
|
|
24520
|
+
);
|
|
24521
|
+
}
|
|
24522
|
+
recordSessionNotice(title, details) {
|
|
24523
|
+
const key = `${title}\0${details ?? ""}`;
|
|
24524
|
+
const previous = this.lastSessionNotice?.key === key ? this.lastSessionNotice.failure : void 0;
|
|
24525
|
+
const id = previous?.id ?? `${this.sessionState.sessionId}:notice:${this.sessionFailureEpoch}:${this.nextNoticeId++}`;
|
|
24526
|
+
const notice = {
|
|
24527
|
+
id,
|
|
24528
|
+
revision: nextSessionFailureRevision(previous, id),
|
|
24529
|
+
category: "unknown",
|
|
24530
|
+
severity: "warning",
|
|
24531
|
+
title,
|
|
24532
|
+
...details === void 0 ? {} : { details },
|
|
24533
|
+
actions: []
|
|
24534
|
+
};
|
|
24535
|
+
this.lastSessionNotice = { key, failure: notice };
|
|
24536
|
+
return notice;
|
|
24537
|
+
}
|
|
24538
|
+
sessionNoticeContent(summary, details) {
|
|
24539
|
+
if (details === null) return [summary];
|
|
24540
|
+
const combinedTitle = `${summary} \u2014 ${details}`;
|
|
24541
|
+
return combinedTitle.length <= MAX_SESSION_FAILURE_TITLE_LENGTH ? [combinedTitle] : [summary, details];
|
|
24542
|
+
}
|
|
24543
|
+
createSessionFailureMeta(failure) {
|
|
24544
|
+
return {
|
|
24545
|
+
[JETBRAINS_META_KEY]: {
|
|
24546
|
+
[AIR_META_KEY]: {
|
|
24547
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
24548
|
+
[AIR_SESSION_FAILURE_KEY]: failure
|
|
24549
|
+
}
|
|
24550
|
+
}
|
|
24551
|
+
};
|
|
24552
|
+
}
|
|
24553
|
+
createSessionFailureUpdate(failure) {
|
|
24554
|
+
return {
|
|
24555
|
+
sessionUpdate: "session_info_update",
|
|
24556
|
+
_meta: this.createSessionFailureMeta(failure)
|
|
24557
|
+
};
|
|
24558
|
+
}
|
|
24559
|
+
sessionFailureKind(error51) {
|
|
24560
|
+
if (this.isAuthenticationRequiredError(error51)) return "auth_required";
|
|
24561
|
+
if (this.getHttpStatusCode(error51) === 429) return "rate_limited";
|
|
24562
|
+
if (typeof error51 === "string") {
|
|
24563
|
+
return STRING_CODEX_ERROR_CATEGORIES[error51] ?? "provider_error";
|
|
24564
|
+
}
|
|
24565
|
+
if (error51 !== null) {
|
|
24566
|
+
for (const kind of Object.keys(STRUCTURED_CODEX_ERROR_CATEGORIES)) {
|
|
24567
|
+
if (kind in error51) {
|
|
24568
|
+
return STRUCTURED_CODEX_ERROR_CATEGORIES[kind] ?? "provider_error";
|
|
24569
|
+
}
|
|
24570
|
+
}
|
|
24571
|
+
}
|
|
24572
|
+
return "provider_error";
|
|
24573
|
+
}
|
|
24196
24574
|
isAuthenticationRequiredError(error51) {
|
|
24197
24575
|
return error51 === "unauthorized" || this.getHttpStatusCode(error51) === 401;
|
|
24198
24576
|
}
|
|
24199
24577
|
getHttpStatusCode(error51) {
|
|
24200
|
-
if (error51
|
|
24201
|
-
|
|
24202
|
-
|
|
24203
|
-
|
|
24204
|
-
return error51.responseStreamConnectionFailed.httpStatusCode;
|
|
24205
|
-
} else if ("responseStreamDisconnected" in error51) {
|
|
24206
|
-
return error51.responseStreamDisconnected.httpStatusCode;
|
|
24207
|
-
} else if ("responseTooManyFailedAttempts" in error51) {
|
|
24208
|
-
return error51.responseTooManyFailedAttempts.httpStatusCode;
|
|
24209
|
-
}
|
|
24210
|
-
}
|
|
24211
|
-
return null;
|
|
24578
|
+
if (error51 === null || typeof error51 !== "object") return null;
|
|
24579
|
+
const details = Object.values(error51)[0];
|
|
24580
|
+
if (details === null || typeof details !== "object" || !("httpStatusCode" in details)) return null;
|
|
24581
|
+
return typeof details.httpStatusCode === "number" ? details.httpStatusCode : null;
|
|
24212
24582
|
}
|
|
24213
24583
|
createTurnErrorData(error51) {
|
|
24214
24584
|
const data = {
|
|
@@ -24637,11 +25007,11 @@ var CodexApprovalHandler = class {
|
|
|
24637
25007
|
});
|
|
24638
25008
|
}
|
|
24639
25009
|
const fileSystem = permissions.fileSystem;
|
|
24640
|
-
for (const
|
|
24641
|
-
changes.push(this.fileSystemGrantChange(
|
|
25010
|
+
for (const path7 of fileSystem?.read ?? []) {
|
|
25011
|
+
changes.push(this.fileSystemGrantChange(path7, "read", lifetime, suffix));
|
|
24642
25012
|
}
|
|
24643
|
-
for (const
|
|
24644
|
-
changes.push(this.fileSystemGrantChange(
|
|
25013
|
+
for (const path7 of fileSystem?.write ?? []) {
|
|
25014
|
+
changes.push(this.fileSystemGrantChange(path7, "write", lifetime, suffix));
|
|
24645
25015
|
}
|
|
24646
25016
|
for (const entry of fileSystem?.entries ?? []) {
|
|
24647
25017
|
const matcher = (() => {
|
|
@@ -24670,16 +25040,16 @@ var CodexApprovalHandler = class {
|
|
|
24670
25040
|
}
|
|
24671
25041
|
return changes.length > 0 ? { version: 1, changes } : void 0;
|
|
24672
25042
|
}
|
|
24673
|
-
fileSystemGrantChange(
|
|
25043
|
+
fileSystemGrantChange(path7, access, lifetime, suffix) {
|
|
24674
25044
|
return {
|
|
24675
25045
|
type: "grant",
|
|
24676
25046
|
operation: "grant",
|
|
24677
|
-
description: `Allow ${access} access to ${
|
|
25047
|
+
description: `Allow ${access} access to ${path7}${suffix}`,
|
|
24678
25048
|
lifetime,
|
|
24679
25049
|
targets: [{
|
|
24680
25050
|
type: "filesystem",
|
|
24681
25051
|
access: [access],
|
|
24682
|
-
matcher: { type: "exact_path", path:
|
|
25052
|
+
matcher: { type: "exact_path", path: path7 }
|
|
24683
25053
|
}]
|
|
24684
25054
|
};
|
|
24685
25055
|
}
|
|
@@ -25589,15 +25959,15 @@ var wslDefaultBrowser = async () => {
|
|
|
25589
25959
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
25590
25960
|
return stdout.trim();
|
|
25591
25961
|
};
|
|
25592
|
-
var convertWslPathToWindows = async (
|
|
25593
|
-
if (/^[a-z]+:\/\//i.test(
|
|
25594
|
-
return
|
|
25962
|
+
var convertWslPathToWindows = async (path7) => {
|
|
25963
|
+
if (/^[a-z]+:\/\//i.test(path7)) {
|
|
25964
|
+
return path7;
|
|
25595
25965
|
}
|
|
25596
25966
|
try {
|
|
25597
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
25967
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path7], { encoding: "utf8" });
|
|
25598
25968
|
return stdout.trim();
|
|
25599
25969
|
} catch {
|
|
25600
|
-
return
|
|
25970
|
+
return path7;
|
|
25601
25971
|
}
|
|
25602
25972
|
};
|
|
25603
25973
|
|
|
@@ -26147,7 +26517,7 @@ var AgentMode = class _AgentMode {
|
|
|
26147
26517
|
};
|
|
26148
26518
|
|
|
26149
26519
|
// src/CodexAcpClient.ts
|
|
26150
|
-
import
|
|
26520
|
+
import path5 from "node:path";
|
|
26151
26521
|
|
|
26152
26522
|
// src/McpServerName.ts
|
|
26153
26523
|
var MCP_SERVER_NAME_WHITESPACE = /\p{White_Space}/gu;
|
|
@@ -26161,7 +26531,7 @@ var package_default = {
|
|
|
26161
26531
|
publishConfig: {
|
|
26162
26532
|
access: "public"
|
|
26163
26533
|
},
|
|
26164
|
-
version: "1.
|
|
26534
|
+
version: "1.3.0",
|
|
26165
26535
|
description: "",
|
|
26166
26536
|
main: "dist/index.js",
|
|
26167
26537
|
bin: {
|
|
@@ -26194,6 +26564,7 @@ var package_default = {
|
|
|
26194
26564
|
"example:steering": "node --import tsx examples/steering.ts",
|
|
26195
26565
|
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
26196
26566
|
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
26567
|
+
"release:preflight": "bash scripts/release-preflight.sh",
|
|
26197
26568
|
test: "vitest run",
|
|
26198
26569
|
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run src/__tests__/CodexACPAgent/e2e",
|
|
26199
26570
|
"test:watch": "vitest",
|
|
@@ -26265,8 +26636,58 @@ function createCodexCollaborationMode(mode, currentModelId) {
|
|
|
26265
26636
|
};
|
|
26266
26637
|
}
|
|
26267
26638
|
|
|
26639
|
+
// src/PathUtils.ts
|
|
26640
|
+
import path4 from "node:path";
|
|
26641
|
+
function isAbsolutePathLike(value) {
|
|
26642
|
+
const trimmed = value.trim();
|
|
26643
|
+
return path4.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
|
|
26644
|
+
}
|
|
26645
|
+
function arePathsEqual(left, right) {
|
|
26646
|
+
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
26647
|
+
}
|
|
26648
|
+
function arePathBasenamesEqual(left, right) {
|
|
26649
|
+
const leftBase = path4.posix.basename(normalizePathForComparison(left));
|
|
26650
|
+
const rightBase = path4.posix.basename(normalizePathForComparison(right));
|
|
26651
|
+
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
26652
|
+
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
26653
|
+
}
|
|
26654
|
+
return leftBase === rightBase;
|
|
26655
|
+
}
|
|
26656
|
+
function normalizePathForComparison(value) {
|
|
26657
|
+
const trimmed = value.trim();
|
|
26658
|
+
if (trimmed.length === 0) {
|
|
26659
|
+
return "";
|
|
26660
|
+
}
|
|
26661
|
+
if (isWindowsAbsolutePath(trimmed)) {
|
|
26662
|
+
const normalized2 = path4.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
26663
|
+
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
26664
|
+
}
|
|
26665
|
+
const pathForComparison = path4.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
26666
|
+
const normalized = path4.posix.normalize(pathForComparison);
|
|
26667
|
+
return trimTrailingPathSeparators(normalized);
|
|
26668
|
+
}
|
|
26669
|
+
function isWindowsAbsolutePath(value) {
|
|
26670
|
+
const portableValue = value.replace(/\\/g, "/");
|
|
26671
|
+
return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
|
|
26672
|
+
}
|
|
26673
|
+
function shouldComparePathCaseInsensitive(value) {
|
|
26674
|
+
return isWindowsAbsolutePath(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
|
|
26675
|
+
}
|
|
26676
|
+
function trimTrailingPathSeparators(value) {
|
|
26677
|
+
let trimmed = value;
|
|
26678
|
+
while (trimmed.endsWith("/") && !isRootPath(trimmed)) {
|
|
26679
|
+
trimmed = trimmed.slice(0, -1);
|
|
26680
|
+
}
|
|
26681
|
+
return trimmed;
|
|
26682
|
+
}
|
|
26683
|
+
function isRootPath(value) {
|
|
26684
|
+
return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
|
|
26685
|
+
}
|
|
26686
|
+
|
|
26268
26687
|
// src/CodexAcpClient.ts
|
|
26269
26688
|
var CUSTOM_GATEWAY_PROVIDER_ID = "custom-gateway";
|
|
26689
|
+
var OPENAI_PROVIDER_ID = "openai";
|
|
26690
|
+
var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
26270
26691
|
var SUPPORTED_GATEWAY_PROTOCOLS = {
|
|
26271
26692
|
openai: "responses"
|
|
26272
26693
|
};
|
|
@@ -26480,34 +26901,47 @@ var CodexAcpClient = class {
|
|
|
26480
26901
|
};
|
|
26481
26902
|
}
|
|
26482
26903
|
/**
|
|
26483
|
-
* `providers/list`: returns
|
|
26484
|
-
*
|
|
26485
|
-
* `null` when the provider is not configured/disabled.
|
|
26904
|
+
* `providers/list`: returns Codex's OpenAI slot. With no ACP override, the
|
|
26905
|
+
* slot reports native OpenAI routing; headers are never exposed.
|
|
26486
26906
|
*/
|
|
26487
26907
|
listProviders() {
|
|
26488
26908
|
const gatewayConfig = this.gatewayConfig;
|
|
26489
26909
|
const current = gatewayConfig ? {
|
|
26490
26910
|
apiType: gatewayApiTypeFromConfig(gatewayConfig),
|
|
26491
26911
|
baseUrl: gatewayConfig.config.base_url
|
|
26492
|
-
} :
|
|
26912
|
+
} : this.getNativeProviderConfig();
|
|
26493
26913
|
return [
|
|
26494
26914
|
{
|
|
26495
|
-
providerId:
|
|
26915
|
+
providerId: OPENAI_PROVIDER_ID,
|
|
26496
26916
|
supported: Object.keys(SUPPORTED_GATEWAY_PROTOCOLS),
|
|
26497
26917
|
required: false,
|
|
26498
26918
|
current
|
|
26499
26919
|
}
|
|
26500
26920
|
];
|
|
26501
26921
|
}
|
|
26922
|
+
getNativeProviderConfig() {
|
|
26923
|
+
const configuredProviderId = this.modelProvider ?? (typeof this.config["model_provider"] === "string" ? this.config["model_provider"] : null);
|
|
26924
|
+
const configuredProviders = this.config["model_providers"];
|
|
26925
|
+
if (configuredProviderId && configuredProviders && typeof configuredProviders === "object" && !Array.isArray(configuredProviders)) {
|
|
26926
|
+
const configuredProvider = configuredProviders[configuredProviderId];
|
|
26927
|
+
if (configuredProvider && typeof configuredProvider === "object" && !Array.isArray(configuredProvider)) {
|
|
26928
|
+
const baseUrl = configuredProvider["base_url"];
|
|
26929
|
+
if (typeof baseUrl === "string" && baseUrl.length > 0) {
|
|
26930
|
+
return { apiType: "openai", baseUrl };
|
|
26931
|
+
}
|
|
26932
|
+
}
|
|
26933
|
+
}
|
|
26934
|
+
return { apiType: "openai", baseUrl: DEFAULT_OPENAI_BASE_URL };
|
|
26935
|
+
}
|
|
26502
26936
|
/**
|
|
26503
26937
|
* `providers/set`: replaces the full configuration for the custom gateway
|
|
26504
26938
|
* provider. Rejects unknown provider ids with `invalid_params`.
|
|
26505
26939
|
*/
|
|
26506
26940
|
setProvider(request) {
|
|
26507
|
-
if (request.providerId !==
|
|
26941
|
+
if (request.providerId !== OPENAI_PROVIDER_ID) {
|
|
26508
26942
|
throw RequestError.invalidParams(
|
|
26509
26943
|
{ providerId: request.providerId },
|
|
26510
|
-
`Unknown providerId "${request.providerId}"; only "${
|
|
26944
|
+
`Unknown providerId "${request.providerId}"; only "${OPENAI_PROVIDER_ID}" is configurable`
|
|
26511
26945
|
);
|
|
26512
26946
|
}
|
|
26513
26947
|
this.applyGatewayConfig({
|
|
@@ -26521,7 +26955,7 @@ var CodexAcpClient = class {
|
|
|
26521
26955
|
* unknown provider id is idempotent success (RFD behavior §7).
|
|
26522
26956
|
*/
|
|
26523
26957
|
disableProvider(request) {
|
|
26524
|
-
if (request.providerId ===
|
|
26958
|
+
if (request.providerId === OPENAI_PROVIDER_ID) {
|
|
26525
26959
|
this.gatewayConfig = null;
|
|
26526
26960
|
}
|
|
26527
26961
|
}
|
|
@@ -26719,7 +27153,7 @@ var CodexAcpClient = class {
|
|
|
26719
27153
|
if (!cwd) {
|
|
26720
27154
|
return;
|
|
26721
27155
|
}
|
|
26722
|
-
const skillExtraRoots = additionalRoots.map((root) =>
|
|
27156
|
+
const skillExtraRoots = additionalRoots.map((root) => path5.join(root, ".agents", "skills"));
|
|
26723
27157
|
if (!arraysEqual(this.skillExtraRoots, skillExtraRoots)) {
|
|
26724
27158
|
await this.codexClient.skillsExtraRootsSet({ extraRoots: skillExtraRoots });
|
|
26725
27159
|
this.skillExtraRoots = skillExtraRoots;
|
|
@@ -26910,11 +27344,10 @@ var CodexAcpClient = class {
|
|
|
26910
27344
|
const requestedCwd = request.cwd?.trim() ?? null;
|
|
26911
27345
|
const filterByCwd = (thread) => {
|
|
26912
27346
|
if (!requestedCwd) return true;
|
|
26913
|
-
if (
|
|
26914
|
-
return thread.cwd
|
|
27347
|
+
if (isAbsolutePathLike(requestedCwd)) {
|
|
27348
|
+
return arePathsEqual(thread.cwd, requestedCwd);
|
|
26915
27349
|
}
|
|
26916
|
-
|
|
26917
|
-
return path4.basename(thread.cwd) === requestedBase;
|
|
27350
|
+
return arePathBasenamesEqual(thread.cwd, requestedCwd);
|
|
26918
27351
|
};
|
|
26919
27352
|
const preferredProvider = this.getModelProvider();
|
|
26920
27353
|
const modelProviders = preferredProvider ? [preferredProvider] : [];
|
|
@@ -26936,7 +27369,7 @@ var CodexAcpClient = class {
|
|
|
26936
27369
|
let sessions = listResponse.data.map(mapThreadToSession);
|
|
26937
27370
|
if (requestedCwd) {
|
|
26938
27371
|
const filtered = listResponse.data.filter(filterByCwd).map(mapThreadToSession);
|
|
26939
|
-
if (filtered.length > 0 ||
|
|
27372
|
+
if (filtered.length > 0 || isAbsolutePathLike(requestedCwd)) {
|
|
26940
27373
|
sessions = filtered;
|
|
26941
27374
|
} else {
|
|
26942
27375
|
logger.log("Ignoring non-absolute cwd filter for session/list", { cwd: requestedCwd });
|
|
@@ -27051,8 +27484,8 @@ function formatUriAsLink(name, uri) {
|
|
|
27051
27484
|
return `[@${name}](${uri})`;
|
|
27052
27485
|
}
|
|
27053
27486
|
if (uri.startsWith("file://")) {
|
|
27054
|
-
const
|
|
27055
|
-
const fileName =
|
|
27487
|
+
const path7 = uri.replace("file://", "");
|
|
27488
|
+
const fileName = path7.split("/").pop() ?? path7;
|
|
27056
27489
|
return `[@${fileName}](${uri})`;
|
|
27057
27490
|
}
|
|
27058
27491
|
return uri;
|
|
@@ -27082,7 +27515,7 @@ function readAdditionalDirectories(cwd, additionalDirectories, meta3) {
|
|
|
27082
27515
|
if (directory.length === 0) {
|
|
27083
27516
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must not be empty");
|
|
27084
27517
|
}
|
|
27085
|
-
if (!
|
|
27518
|
+
if (!path5.isAbsolute(directory)) {
|
|
27086
27519
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must be absolute paths");
|
|
27087
27520
|
}
|
|
27088
27521
|
if (!seen.has(directory)) {
|
|
@@ -27685,7 +28118,7 @@ var SteeringQueue = class {
|
|
|
27685
28118
|
|
|
27686
28119
|
// src/ResponseItemHistoryFallback.ts
|
|
27687
28120
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
27688
|
-
import
|
|
28121
|
+
import path6 from "node:path";
|
|
27689
28122
|
function historyFallbackUpdateKey(update) {
|
|
27690
28123
|
switch (update.sessionUpdate) {
|
|
27691
28124
|
case "user_message_chunk":
|
|
@@ -27925,8 +28358,8 @@ function imageBlocks(images) {
|
|
|
27925
28358
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
27926
28359
|
}
|
|
27927
28360
|
const record2 = asRecord(image);
|
|
27928
|
-
const
|
|
27929
|
-
return
|
|
28361
|
+
const path7 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
28362
|
+
return path7 ? [{ type: "text", text: `[@image](${path7})` }] : [];
|
|
27930
28363
|
});
|
|
27931
28364
|
}
|
|
27932
28365
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -28558,10 +28991,10 @@ function baseCommandName(commandName) {
|
|
|
28558
28991
|
return commandName.split(/[\\/]/).pop() ?? commandName;
|
|
28559
28992
|
}
|
|
28560
28993
|
function absolutizePath(cwd, targetPath) {
|
|
28561
|
-
if (
|
|
28994
|
+
if (path6.isAbsolute(targetPath) || cwd.length === 0) {
|
|
28562
28995
|
return targetPath;
|
|
28563
28996
|
}
|
|
28564
|
-
return
|
|
28997
|
+
return path6.join(cwd, targetPath);
|
|
28565
28998
|
}
|
|
28566
28999
|
function withTerminalContent(event, terminalId, cwd) {
|
|
28567
29000
|
const { rawInput, ...eventWithoutRawInput } = event;
|
|
@@ -28717,8 +29150,17 @@ function clientSupportsPlanUpdates(clientCapabilities) {
|
|
|
28717
29150
|
}
|
|
28718
29151
|
|
|
28719
29152
|
// src/CodexAcpServer.ts
|
|
29153
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
28720
29154
|
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
28721
29155
|
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
29156
|
+
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
29157
|
+
function clientSupportsTypedSessionFailures(capabilities) {
|
|
29158
|
+
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
29159
|
+
const air = jetbrains?.[AIR_META_KEY];
|
|
29160
|
+
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
29161
|
+
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
29162
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(AIR_SESSION_FAILURE_KEY);
|
|
29163
|
+
}
|
|
28722
29164
|
var CodexAcpServer = class _CodexAcpServer {
|
|
28723
29165
|
static MODEL_NAME_TOKEN_OVERRIDES = {
|
|
28724
29166
|
gpt: "GPT",
|
|
@@ -28730,6 +29172,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28730
29172
|
defaultAuthRequest;
|
|
28731
29173
|
getExitCode;
|
|
28732
29174
|
getRecentStderr;
|
|
29175
|
+
sessionFailureEpoch;
|
|
28733
29176
|
availableCommands;
|
|
28734
29177
|
clientInfo;
|
|
28735
29178
|
clientCapabilities;
|
|
@@ -28759,6 +29202,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28759
29202
|
this.defaultAuthRequest = defaultAuthRequest ?? null;
|
|
28760
29203
|
this.getExitCode = getExitCode ?? (() => null);
|
|
28761
29204
|
this.getRecentStderr = getRecentStderr ?? (() => "");
|
|
29205
|
+
this.sessionFailureEpoch = randomUUID2();
|
|
28762
29206
|
this.clientInfo = null;
|
|
28763
29207
|
this.clientCapabilities = null;
|
|
28764
29208
|
this.terminalOutputMode = "terminal_output_delta";
|
|
@@ -28816,6 +29260,12 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28816
29260
|
version: GOAL_EXTENSION_VERSION,
|
|
28817
29261
|
controlMethod: GOAL_CONTROL_METHOD,
|
|
28818
29262
|
actions: [...GOAL_CONTROL_ACTIONS]
|
|
29263
|
+
},
|
|
29264
|
+
[JETBRAINS_META_KEY]: {
|
|
29265
|
+
[AIR_META_KEY]: {
|
|
29266
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
29267
|
+
[AIR_EXTENSION_CAPABILITIES_KEY]: [AIR_SESSION_FAILURE_KEY]
|
|
29268
|
+
}
|
|
28819
29269
|
}
|
|
28820
29270
|
}
|
|
28821
29271
|
};
|
|
@@ -29999,8 +30449,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
29999
30449
|
return `[@${name}](${uri})`;
|
|
30000
30450
|
}
|
|
30001
30451
|
if (uri.startsWith("file://")) {
|
|
30002
|
-
const
|
|
30003
|
-
const fileName =
|
|
30452
|
+
const path7 = uri.replace("file://", "");
|
|
30453
|
+
const fileName = path7.split("/").pop() ?? path7;
|
|
30004
30454
|
return `[@${fileName}](${uri})`;
|
|
30005
30455
|
}
|
|
30006
30456
|
return uri;
|
|
@@ -30253,6 +30703,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30253
30703
|
prompt: params.prompt
|
|
30254
30704
|
});
|
|
30255
30705
|
const sessionState = this.getSessionState(params.sessionId);
|
|
30706
|
+
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
30256
30707
|
sessionState.currentTurnId = null;
|
|
30257
30708
|
sessionState.lastTokenUsage = null;
|
|
30258
30709
|
const activePrompt = this.trackActivePrompt(params.sessionId);
|
|
@@ -30266,11 +30717,21 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30266
30717
|
};
|
|
30267
30718
|
const disposePromptRequestCancellation = this.observePromptRequestCancellation(signal, sessionState, activePrompt);
|
|
30268
30719
|
let eventHandler = null;
|
|
30720
|
+
let promptNotificationsActive = true;
|
|
30721
|
+
const clearRecoveredSessionFailure = async (handler) => {
|
|
30722
|
+
await handler.completeSuccessfulTurn(sessionState.currentTurnId);
|
|
30723
|
+
const current = sessionState.sessionFailure;
|
|
30724
|
+
if (recoverableSessionFailure !== void 0 && current !== void 0 && current.id === recoverableSessionFailure.id && current.revision === recoverableSessionFailure.revision) {
|
|
30725
|
+
await handler.clearSessionFailure();
|
|
30726
|
+
}
|
|
30727
|
+
};
|
|
30269
30728
|
try {
|
|
30270
30729
|
const promptEventHandler = new CodexEventHandler(
|
|
30271
30730
|
this.connection,
|
|
30272
30731
|
sessionState,
|
|
30273
|
-
clientSupportsPlanUpdates(this.clientCapabilities)
|
|
30732
|
+
clientSupportsPlanUpdates(this.clientCapabilities),
|
|
30733
|
+
clientSupportsTypedSessionFailures(this.clientCapabilities),
|
|
30734
|
+
this.sessionFailureEpoch
|
|
30274
30735
|
);
|
|
30275
30736
|
eventHandler = promptEventHandler;
|
|
30276
30737
|
const approvalHandler = new CodexApprovalHandler(this.connection, sessionState, activePrompt.signal);
|
|
@@ -30283,8 +30744,16 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30283
30744
|
await this.codexAcpClient.subscribeToSessionEvents(
|
|
30284
30745
|
params.sessionId,
|
|
30285
30746
|
async (event) => {
|
|
30747
|
+
if (!promptNotificationsActive) {
|
|
30748
|
+
await promptEventHandler.handleSessionScopedNotification(event);
|
|
30749
|
+
return;
|
|
30750
|
+
}
|
|
30751
|
+
const completesActiveTurn = event.method === "turn/completed" && event.params.turn.id === sessionState.currentTurnId;
|
|
30286
30752
|
await elicitationHandler.handleNotification(event);
|
|
30287
|
-
|
|
30753
|
+
await promptEventHandler.handleNotification(event);
|
|
30754
|
+
if (completesActiveTurn) {
|
|
30755
|
+
promptNotificationsActive = false;
|
|
30756
|
+
}
|
|
30288
30757
|
},
|
|
30289
30758
|
approvalHandler,
|
|
30290
30759
|
elicitationHandler
|
|
@@ -30334,8 +30803,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30334
30803
|
return this.cancelledPromptResponse(sessionState);
|
|
30335
30804
|
}
|
|
30336
30805
|
if (commandResult.handled) {
|
|
30806
|
+
promptNotificationsActive = false;
|
|
30337
30807
|
logger.log("Prompt handled by a command");
|
|
30338
30808
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30809
|
+
await eventHandler.flushPendingErrors();
|
|
30810
|
+
await eventHandler.flushPendingErrorsAsSessionScoped();
|
|
30811
|
+
if (commandResult.turnCompleted) {
|
|
30812
|
+
await eventHandler.handleFailedTurn(commandResult.turnCompleted.turn);
|
|
30813
|
+
}
|
|
30339
30814
|
if (commandResult.turnCompleted?.turn.status === "interrupted") {
|
|
30340
30815
|
return this.cancelledPromptResponse(sessionState);
|
|
30341
30816
|
}
|
|
@@ -30343,6 +30818,15 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30343
30818
|
if (error52) {
|
|
30344
30819
|
throw error52;
|
|
30345
30820
|
}
|
|
30821
|
+
const terminalFailure2 = this.terminalFailurePromptResponse(
|
|
30822
|
+
sessionState,
|
|
30823
|
+
eventHandler,
|
|
30824
|
+
commandResult.turnCompleted?.turn.id ?? sessionState.currentTurnId
|
|
30825
|
+
);
|
|
30826
|
+
if (terminalFailure2) {
|
|
30827
|
+
return terminalFailure2;
|
|
30828
|
+
}
|
|
30829
|
+
await clearRecoveredSessionFailure(eventHandler);
|
|
30346
30830
|
return {
|
|
30347
30831
|
stopReason: "end_turn",
|
|
30348
30832
|
usage: this.buildPromptUsage(sessionState.lastTokenUsage),
|
|
@@ -30408,6 +30892,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30408
30892
|
return this.cancelledPromptResponse(sessionState);
|
|
30409
30893
|
}
|
|
30410
30894
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30895
|
+
await eventHandler.flushPendingErrors();
|
|
30896
|
+
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
30897
|
+
promptNotificationsActive = false;
|
|
30411
30898
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30412
30899
|
await eventHandler.flushPendingPlanUpdates();
|
|
30413
30900
|
return this.cancelledPromptResponse(sessionState);
|
|
@@ -30416,6 +30903,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30416
30903
|
if (error51) {
|
|
30417
30904
|
throw error51;
|
|
30418
30905
|
}
|
|
30906
|
+
const terminalFailure = this.terminalFailurePromptResponse(
|
|
30907
|
+
sessionState,
|
|
30908
|
+
eventHandler,
|
|
30909
|
+
turnCompleted.turn.id
|
|
30910
|
+
);
|
|
30911
|
+
if (terminalFailure) {
|
|
30912
|
+
return terminalFailure;
|
|
30913
|
+
}
|
|
30419
30914
|
await eventHandler.flushPendingPlanUpdates();
|
|
30420
30915
|
const completedPlan = eventHandler.takeCompletedPlan();
|
|
30421
30916
|
if (completedPlan !== null && sessionState.collaborationMode === PLAN_COLLABORATION_MODE && !this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
@@ -30439,6 +30934,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30439
30934
|
prompt: [{ type: "text", text: "Implement the approved plan." }]
|
|
30440
30935
|
};
|
|
30441
30936
|
activePrompt.currentTurn = null;
|
|
30937
|
+
sessionState.currentTurnId = null;
|
|
30442
30938
|
const implementationPromise = this.runWithProcessCheck(
|
|
30443
30939
|
() => this.codexAcpClient.sendPrompt(
|
|
30444
30940
|
implementationRequest,
|
|
@@ -30456,6 +30952,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30456
30952
|
return;
|
|
30457
30953
|
}
|
|
30458
30954
|
sessionState.currentTurnId = turnId;
|
|
30955
|
+
recoverableSessionFailure = sessionState.sessionFailure;
|
|
30956
|
+
promptNotificationsActive = true;
|
|
30459
30957
|
},
|
|
30460
30958
|
() => this.promptShouldStop(params.sessionId, activePrompt)
|
|
30461
30959
|
)
|
|
@@ -30474,6 +30972,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30474
30972
|
return this.cancelledPromptResponse(sessionState);
|
|
30475
30973
|
}
|
|
30476
30974
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30975
|
+
await eventHandler.flushPendingErrors();
|
|
30976
|
+
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
30977
|
+
promptNotificationsActive = false;
|
|
30477
30978
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30478
30979
|
await eventHandler.flushPendingPlanUpdates();
|
|
30479
30980
|
return this.cancelledPromptResponse(sessionState);
|
|
@@ -30482,8 +30983,17 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30482
30983
|
if (implementationError) {
|
|
30483
30984
|
throw implementationError;
|
|
30484
30985
|
}
|
|
30986
|
+
const implementationFailure = this.terminalFailurePromptResponse(
|
|
30987
|
+
sessionState,
|
|
30988
|
+
eventHandler,
|
|
30989
|
+
turnCompleted.turn.id
|
|
30990
|
+
);
|
|
30991
|
+
if (implementationFailure) {
|
|
30992
|
+
return implementationFailure;
|
|
30993
|
+
}
|
|
30485
30994
|
}
|
|
30486
30995
|
}
|
|
30996
|
+
await clearRecoveredSessionFailure(eventHandler);
|
|
30487
30997
|
await this.publishFallbackSessionTitle(
|
|
30488
30998
|
sessionState,
|
|
30489
30999
|
this.createPromptFallbackTitle(params.prompt)
|
|
@@ -30495,8 +31005,29 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30495
31005
|
};
|
|
30496
31006
|
} catch (err) {
|
|
30497
31007
|
logger.error(`Prompt for session ${params.sessionId} failed`, err);
|
|
31008
|
+
if (activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId)) {
|
|
31009
|
+
return this.cancelledPromptResponse(sessionState);
|
|
31010
|
+
}
|
|
31011
|
+
const isProcessExit = err instanceof RequestError && err.code === CODEX_PROCESS_EXITED_ERROR_CODE;
|
|
31012
|
+
const isUnexpectedFailure = !(err instanceof RequestError);
|
|
31013
|
+
if (eventHandler !== null && clientSupportsTypedSessionFailures(this.clientCapabilities) && (isProcessExit || isUnexpectedFailure)) {
|
|
31014
|
+
eventHandler.recordSyntheticTerminalFailure(
|
|
31015
|
+
isProcessExit ? "transport_lost" : "internal_error",
|
|
31016
|
+
sessionState.currentTurnId
|
|
31017
|
+
);
|
|
31018
|
+
const failureResponse = this.terminalFailurePromptResponse(
|
|
31019
|
+
sessionState,
|
|
31020
|
+
eventHandler,
|
|
31021
|
+
sessionState.currentTurnId,
|
|
31022
|
+
true
|
|
31023
|
+
);
|
|
31024
|
+
if (failureResponse !== null) {
|
|
31025
|
+
return failureResponse;
|
|
31026
|
+
}
|
|
31027
|
+
}
|
|
30498
31028
|
throw err;
|
|
30499
31029
|
} finally {
|
|
31030
|
+
promptNotificationsActive = false;
|
|
30500
31031
|
logger.log("Prompt completed", { sessionId: params.sessionId });
|
|
30501
31032
|
await eventHandler?.dispose();
|
|
30502
31033
|
disposePromptRequestCancellation();
|
|
@@ -30567,6 +31098,20 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30567
31098
|
_meta: this.buildQuotaMeta(sessionState)
|
|
30568
31099
|
};
|
|
30569
31100
|
}
|
|
31101
|
+
terminalFailurePromptResponse(sessionState, eventHandler, turnId, allowUnattributed = false) {
|
|
31102
|
+
const failureMeta = eventHandler.getTerminalSessionFailureMeta(turnId, allowUnattributed);
|
|
31103
|
+
if (failureMeta === null) {
|
|
31104
|
+
return null;
|
|
31105
|
+
}
|
|
31106
|
+
return {
|
|
31107
|
+
stopReason: "end_turn",
|
|
31108
|
+
usage: this.buildPromptUsage(sessionState.lastTokenUsage),
|
|
31109
|
+
_meta: {
|
|
31110
|
+
...this.buildQuotaMeta(sessionState),
|
|
31111
|
+
...failureMeta
|
|
31112
|
+
}
|
|
31113
|
+
};
|
|
31114
|
+
}
|
|
30570
31115
|
buildQuotaMeta(sessionState) {
|
|
30571
31116
|
const lastTokenUsage = sessionState.lastTokenUsage;
|
|
30572
31117
|
const modelName = sessionState.currentModelId.replace(/\[.*?]$/, "");
|
|
@@ -30589,7 +31134,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30589
31134
|
return await operation();
|
|
30590
31135
|
} catch (err) {
|
|
30591
31136
|
const exitCode = this.getExitCode();
|
|
30592
|
-
const requestErrorCode =
|
|
31137
|
+
const requestErrorCode = CODEX_PROCESS_EXITED_ERROR_CODE;
|
|
30593
31138
|
if (exitCode == 3221225781) {
|
|
30594
31139
|
throw new RequestError(requestErrorCode, `VC++ redistributable should be installed`);
|
|
30595
31140
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.3.0",
|
|
7
7
|
"description": "",
|
|
8
8
|
"main": "dist/index.js",
|
|
9
9
|
"bin": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"example:steering": "node --import tsx examples/steering.ts",
|
|
37
37
|
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
38
38
|
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
39
|
+
"release:preflight": "bash scripts/release-preflight.sh",
|
|
39
40
|
"test": "vitest run",
|
|
40
41
|
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run src/__tests__/CodexACPAgent/e2e",
|
|
41
42
|
"test:watch": "vitest",
|