@agentclientprotocol/codex-acp 1.1.13 → 1.2.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 +567 -99
- package/package.json +3 -2
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
|
}
|
|
@@ -23235,13 +23235,13 @@ function createTerminalCommandEvent(event, terminalId, cwd) {
|
|
|
23235
23235
|
}
|
|
23236
23236
|
};
|
|
23237
23237
|
}
|
|
23238
|
-
function createSearchTitle(query,
|
|
23239
|
-
if (query &&
|
|
23240
|
-
return `Search for '${query}' in ${
|
|
23238
|
+
function createSearchTitle(query, path7) {
|
|
23239
|
+
if (query && path7) {
|
|
23240
|
+
return `Search for '${query}' in ${path7}`;
|
|
23241
23241
|
} else if (query) {
|
|
23242
23242
|
return `Search for '${query}'`;
|
|
23243
|
-
} else if (
|
|
23244
|
-
return `Search in '${
|
|
23243
|
+
} else if (path7) {
|
|
23244
|
+
return `Search in '${path7}'`;
|
|
23245
23245
|
}
|
|
23246
23246
|
return "Search";
|
|
23247
23247
|
}
|
|
@@ -23467,12 +23467,12 @@ function revertPatch(unifiedDiff) {
|
|
|
23467
23467
|
if (!patch) return null;
|
|
23468
23468
|
return reversePatch(patch);
|
|
23469
23469
|
}
|
|
23470
|
-
function createUpdateDiffContent(
|
|
23470
|
+
function createUpdateDiffContent(path7, oldText, newText) {
|
|
23471
23471
|
return {
|
|
23472
23472
|
type: "diff",
|
|
23473
23473
|
oldText,
|
|
23474
23474
|
newText,
|
|
23475
|
-
path:
|
|
23475
|
+
path: path7,
|
|
23476
23476
|
_meta: {
|
|
23477
23477
|
kind: "update"
|
|
23478
23478
|
}
|
|
@@ -23560,7 +23560,7 @@ function createAgentTextThoughtChunk(text, messageId, meta3) {
|
|
|
23560
23560
|
var GOAL_EXTENSION_VERSION = 1;
|
|
23561
23561
|
var GOAL_CONTROL_METHOD = "_session/goal";
|
|
23562
23562
|
var LEGACY_GOAL_CONTROL_METHOD = "_codex/session/goal_control";
|
|
23563
|
-
var GOAL_CONTROL_ACTIONS = ["pause", "resume", "clear"];
|
|
23563
|
+
var GOAL_CONTROL_ACTIONS = ["set", "pause", "resume", "clear"];
|
|
23564
23564
|
|
|
23565
23565
|
// src/ThreadGoalSnapshot.ts
|
|
23566
23566
|
function toGoalStatus(status) {
|
|
@@ -23597,10 +23597,57 @@ function sameThreadGoalSnapshot(left, right) {
|
|
|
23597
23597
|
}
|
|
23598
23598
|
|
|
23599
23599
|
// src/CodexEventHandler.ts
|
|
23600
|
+
import { randomUUID } from "node:crypto";
|
|
23601
|
+
|
|
23602
|
+
// src/AirExtension.ts
|
|
23603
|
+
var JETBRAINS_META_KEY = "jetbrains";
|
|
23604
|
+
var AIR_META_KEY = "air";
|
|
23605
|
+
var AIR_EXTENSION_VERSION_KEY = "version";
|
|
23606
|
+
var AIR_EXTENSION_CAPABILITIES_KEY = "capabilities";
|
|
23607
|
+
var AIR_SESSION_FAILURE_KEY = "sessionFailure";
|
|
23608
|
+
var AIR_EXTENSION_VERSION = 1;
|
|
23609
|
+
|
|
23610
|
+
// src/CodexEventHandler.ts
|
|
23611
|
+
var SESSION_FAILURE_PRESENTATION = {
|
|
23612
|
+
transport_lost: { message: "Connection to Codex was lost.", retryable: true, actions: ["reconnect", "retry"] },
|
|
23613
|
+
auth_required: { message: "Sign in to continue using Codex.", retryable: false, actions: ["login"] },
|
|
23614
|
+
rate_limited: { message: "The Codex rate limit was reached.", retryable: true, actions: ["retry"] },
|
|
23615
|
+
quota_exhausted: { message: "The Codex usage quota is exhausted.", retryable: false, actions: ["new_session"] },
|
|
23616
|
+
overloaded: { message: "Codex is temporarily overloaded.", retryable: true, actions: ["retry"] },
|
|
23617
|
+
context_exhausted: { message: "This conversation has reached its context limit.", retryable: false, actions: ["new_turn"] },
|
|
23618
|
+
budget_exhausted: { message: "This session has reached its usage budget.", retryable: false, actions: ["new_session"] },
|
|
23619
|
+
policy_denied: { message: "The request was blocked by provider policy.", retryable: false, actions: [] },
|
|
23620
|
+
bad_request: { message: "Codex could not process this request.", retryable: false, actions: ["new_turn"] },
|
|
23621
|
+
provider_error: { message: "The model provider reported an error.", retryable: true, actions: ["retry"] },
|
|
23622
|
+
internal_error: { message: "Codex encountered an internal error.", retryable: true, actions: ["retry"] }
|
|
23623
|
+
};
|
|
23624
|
+
var STRING_CODEX_ERROR_CATEGORIES = {
|
|
23625
|
+
contextWindowExceeded: "context_exhausted",
|
|
23626
|
+
sessionBudgetExceeded: "budget_exhausted",
|
|
23627
|
+
usageLimitExceeded: "quota_exhausted",
|
|
23628
|
+
serverOverloaded: "overloaded",
|
|
23629
|
+
cyberPolicy: "policy_denied",
|
|
23630
|
+
internalServerError: "internal_error",
|
|
23631
|
+
unauthorized: "auth_required",
|
|
23632
|
+
badRequest: "bad_request",
|
|
23633
|
+
threadRollbackFailed: "provider_error",
|
|
23634
|
+
sandboxError: "provider_error",
|
|
23635
|
+
other: "provider_error"
|
|
23636
|
+
};
|
|
23637
|
+
var STRUCTURED_CODEX_ERROR_CATEGORIES = {
|
|
23638
|
+
httpConnectionFailed: "transport_lost",
|
|
23639
|
+
responseStreamConnectionFailed: "transport_lost",
|
|
23640
|
+
responseStreamDisconnected: "transport_lost",
|
|
23641
|
+
responseTooManyFailedAttempts: "transport_lost",
|
|
23642
|
+
activeTurnNotSteerable: "provider_error"
|
|
23643
|
+
};
|
|
23600
23644
|
var CodexEventHandler = class _CodexEventHandler {
|
|
23601
23645
|
static PLAN_UPDATE_INTERVAL_MS = 150;
|
|
23602
23646
|
sessionState;
|
|
23603
23647
|
supportsPlanUpdates;
|
|
23648
|
+
supportsTypedSessionFailures;
|
|
23649
|
+
sessionFailureEpoch;
|
|
23650
|
+
pendingErrors = [];
|
|
23604
23651
|
failure = null;
|
|
23605
23652
|
completedPlan = null;
|
|
23606
23653
|
activeFuzzyFileSearchSessions = /* @__PURE__ */ new Set();
|
|
@@ -23619,20 +23666,108 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23619
23666
|
terminalCommandOutputIds = /* @__PURE__ */ new Set();
|
|
23620
23667
|
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
23621
23668
|
activeSubAgentActivities = /* @__PURE__ */ new Set();
|
|
23622
|
-
constructor(connection, sessionState, supportsPlanUpdates = false) {
|
|
23669
|
+
constructor(connection, sessionState, supportsPlanUpdates = false, supportsTypedSessionFailures = false, sessionFailureEpoch = randomUUID()) {
|
|
23623
23670
|
this.sessionState = sessionState;
|
|
23624
23671
|
this.supportsPlanUpdates = supportsPlanUpdates;
|
|
23672
|
+
this.supportsTypedSessionFailures = supportsTypedSessionFailures;
|
|
23673
|
+
this.sessionFailureEpoch = sessionFailureEpoch;
|
|
23625
23674
|
this.session = new ACPSessionConnection(connection, sessionState.sessionId);
|
|
23626
23675
|
}
|
|
23627
23676
|
getFailure() {
|
|
23628
23677
|
return this.failure;
|
|
23629
23678
|
}
|
|
23679
|
+
getTerminalSessionFailureMeta(turnId, allowUnattributed = false) {
|
|
23680
|
+
const failure = this.sessionState.sessionFailure;
|
|
23681
|
+
if (!this.supportsTypedSessionFailures || failure?.phase !== "active" || (failure.turnId === void 0 ? !allowUnattributed : turnId === null || failure.turnId !== turnId)) {
|
|
23682
|
+
return null;
|
|
23683
|
+
}
|
|
23684
|
+
return this.createSessionFailureMeta(failure);
|
|
23685
|
+
}
|
|
23686
|
+
recordSyntheticTerminalFailure(category, turnId) {
|
|
23687
|
+
this.recordSessionFailure(category, turnId ?? void 0);
|
|
23688
|
+
}
|
|
23689
|
+
/**
|
|
23690
|
+
* Handles notifications after the prompt-local handler has been disposed. The app-server subscription
|
|
23691
|
+
* remains installed until the ACP session closes, so terminal errors need a durable session-level path
|
|
23692
|
+
* instead of entering a turn buffer that will never be flushed.
|
|
23693
|
+
*/
|
|
23694
|
+
async handleSessionScopedNotification(notification) {
|
|
23695
|
+
if (notification.method !== "error") {
|
|
23696
|
+
await this.handleNotification(notification);
|
|
23697
|
+
return;
|
|
23698
|
+
}
|
|
23699
|
+
if (!this.supportsTypedSessionFailures) {
|
|
23700
|
+
await this.handleNotification(notification);
|
|
23701
|
+
return;
|
|
23702
|
+
}
|
|
23703
|
+
if (notification.params.willRetry) {
|
|
23704
|
+
await this.session.update(this.createSafeErrorDiagnostic(notification.params));
|
|
23705
|
+
return;
|
|
23706
|
+
}
|
|
23707
|
+
const failure = this.recordSessionFailure(
|
|
23708
|
+
this.sessionFailureCategory(notification.params.error.codexErrorInfo),
|
|
23709
|
+
void 0
|
|
23710
|
+
);
|
|
23711
|
+
await this.session.update(this.createSessionFailureUpdate(failure));
|
|
23712
|
+
}
|
|
23713
|
+
async flushPendingErrors() {
|
|
23714
|
+
if (this.sessionState.currentTurnId === null || this.pendingErrors.length === 0) {
|
|
23715
|
+
return;
|
|
23716
|
+
}
|
|
23717
|
+
const errors = this.pendingErrors.splice(0);
|
|
23718
|
+
for (const error51 of errors) {
|
|
23719
|
+
const update = await this.createErrorEvent(error51);
|
|
23720
|
+
if (update) {
|
|
23721
|
+
await this.session.update(update);
|
|
23722
|
+
}
|
|
23723
|
+
}
|
|
23724
|
+
}
|
|
23725
|
+
async flushPendingErrorsAsSessionScoped() {
|
|
23726
|
+
if (!this.supportsTypedSessionFailures || this.pendingErrors.length === 0) {
|
|
23727
|
+
return;
|
|
23728
|
+
}
|
|
23729
|
+
const errors = this.pendingErrors.splice(0);
|
|
23730
|
+
for (const error51 of errors) {
|
|
23731
|
+
await this.handleSessionScopedNotification({ method: "error", params: error51 });
|
|
23732
|
+
}
|
|
23733
|
+
}
|
|
23734
|
+
async clearSessionFailure() {
|
|
23735
|
+
const active = this.sessionState.sessionFailure;
|
|
23736
|
+
if (!this.supportsTypedSessionFailures || active?.phase !== "active") {
|
|
23737
|
+
return;
|
|
23738
|
+
}
|
|
23739
|
+
const cleared = {
|
|
23740
|
+
...active,
|
|
23741
|
+
revision: active.revision + 1,
|
|
23742
|
+
phase: "cleared"
|
|
23743
|
+
};
|
|
23744
|
+
await this.session.update(this.createSessionFailureUpdate(cleared));
|
|
23745
|
+
this.sessionState.sessionFailure = cleared;
|
|
23746
|
+
}
|
|
23747
|
+
async handleFailedTurn(turn) {
|
|
23748
|
+
const activeFailure = this.sessionState.sessionFailure;
|
|
23749
|
+
if (!this.supportsTypedSessionFailures || turn.status !== "failed" || this.failure !== null || activeFailure?.phase === "active" && activeFailure.turnId === turn.id) {
|
|
23750
|
+
return;
|
|
23751
|
+
}
|
|
23752
|
+
const error51 = turn.error ?? {
|
|
23753
|
+
message: "Turn failed",
|
|
23754
|
+
codexErrorInfo: null,
|
|
23755
|
+
additionalDetails: null
|
|
23756
|
+
};
|
|
23757
|
+
this.recordTypedSessionFailure({
|
|
23758
|
+
threadId: this.sessionState.sessionId,
|
|
23759
|
+
turnId: turn.id,
|
|
23760
|
+
willRetry: false,
|
|
23761
|
+
error: error51
|
|
23762
|
+
});
|
|
23763
|
+
}
|
|
23630
23764
|
takeCompletedPlan() {
|
|
23631
23765
|
const plan = this.completedPlan;
|
|
23632
23766
|
this.completedPlan = null;
|
|
23633
23767
|
return plan;
|
|
23634
23768
|
}
|
|
23635
23769
|
async handleNotification(notification) {
|
|
23770
|
+
await this.flushPendingErrors();
|
|
23636
23771
|
const updateEvent = await this.createUpdateEvent(notification);
|
|
23637
23772
|
if (updateEvent) {
|
|
23638
23773
|
await this.session.update(updateEvent);
|
|
@@ -23653,6 +23788,14 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23653
23788
|
async dispose() {
|
|
23654
23789
|
if (this.disposed) return;
|
|
23655
23790
|
await this.flushPendingPlanUpdates();
|
|
23791
|
+
if (this.pendingErrors.length > 0) {
|
|
23792
|
+
logger.log("Discarding app-server errors that arrived before a turn started", {
|
|
23793
|
+
sessionId: this.sessionState.sessionId,
|
|
23794
|
+
count: this.pendingErrors.length,
|
|
23795
|
+
turnIds: this.pendingErrors.map((error51) => error51.turnId)
|
|
23796
|
+
});
|
|
23797
|
+
this.pendingErrors.splice(0);
|
|
23798
|
+
}
|
|
23656
23799
|
this.disposed = true;
|
|
23657
23800
|
this.cancelPlanUpdateTimer();
|
|
23658
23801
|
this.pendingPlanItemIds.clear();
|
|
@@ -23675,6 +23818,7 @@ var CodexEventHandler = class _CodexEventHandler {
|
|
|
23675
23818
|
return await this.createErrorEvent(notification.params);
|
|
23676
23819
|
case "turn/started":
|
|
23677
23820
|
this.sessionState.currentTurnId = notification.params.turn.id;
|
|
23821
|
+
await this.flushPendingErrors();
|
|
23678
23822
|
return null;
|
|
23679
23823
|
case "turn/completed":
|
|
23680
23824
|
await this.flushPendingPlanUpdates();
|
|
@@ -24174,7 +24318,27 @@ ${event.stdin}
|
|
|
24174
24318
|
}
|
|
24175
24319
|
async createErrorEvent(params) {
|
|
24176
24320
|
const error51 = params.error.codexErrorInfo;
|
|
24321
|
+
if (this.sessionState.currentTurnId === null) {
|
|
24322
|
+
this.pendingErrors.push(params);
|
|
24323
|
+
logger.log("Buffered app-server error until the active turn is known", {
|
|
24324
|
+
sessionId: this.sessionState.sessionId,
|
|
24325
|
+
turnId: params.turnId,
|
|
24326
|
+
willRetry: params.willRetry
|
|
24327
|
+
});
|
|
24328
|
+
return null;
|
|
24329
|
+
}
|
|
24330
|
+
if (params.turnId !== this.sessionState.currentTurnId) {
|
|
24331
|
+
if (this.supportsTypedSessionFailures) {
|
|
24332
|
+
return this.createSafeErrorDiagnostic(params);
|
|
24333
|
+
}
|
|
24334
|
+
return this.createCodexSessionInfoUpdate({
|
|
24335
|
+
error: { ...params.error, turnId: params.turnId, willRetry: params.willRetry }
|
|
24336
|
+
});
|
|
24337
|
+
}
|
|
24177
24338
|
if (params.willRetry) {
|
|
24339
|
+
if (this.supportsTypedSessionFailures) {
|
|
24340
|
+
return this.createSafeErrorDiagnostic(params);
|
|
24341
|
+
}
|
|
24178
24342
|
return this.createCodexSessionInfoUpdate({
|
|
24179
24343
|
error: {
|
|
24180
24344
|
...params.error,
|
|
@@ -24182,7 +24346,12 @@ ${event.stdin}
|
|
|
24182
24346
|
willRetry: true
|
|
24183
24347
|
}
|
|
24184
24348
|
});
|
|
24185
|
-
}
|
|
24349
|
+
}
|
|
24350
|
+
if (this.supportsTypedSessionFailures) {
|
|
24351
|
+
this.recordTypedSessionFailure(params);
|
|
24352
|
+
return null;
|
|
24353
|
+
}
|
|
24354
|
+
if (error51 === "usageLimitExceeded") {
|
|
24186
24355
|
this.failure = RequestError.internalError(
|
|
24187
24356
|
this.createTurnErrorData(params.error)
|
|
24188
24357
|
);
|
|
@@ -24193,22 +24362,78 @@ ${event.stdin}
|
|
|
24193
24362
|
|
|
24194
24363
|
`);
|
|
24195
24364
|
}
|
|
24365
|
+
createSafeErrorDiagnostic(params) {
|
|
24366
|
+
const category = this.sessionFailureCategory(params.error.codexErrorInfo);
|
|
24367
|
+
return this.createCodexSessionInfoUpdate({
|
|
24368
|
+
error: {
|
|
24369
|
+
category,
|
|
24370
|
+
message: SESSION_FAILURE_PRESENTATION[category].message,
|
|
24371
|
+
turnId: params.turnId,
|
|
24372
|
+
willRetry: params.willRetry
|
|
24373
|
+
}
|
|
24374
|
+
});
|
|
24375
|
+
}
|
|
24376
|
+
recordTypedSessionFailure(params) {
|
|
24377
|
+
const category = this.sessionFailureCategory(params.error.codexErrorInfo);
|
|
24378
|
+
this.recordSessionFailure(category, params.turnId);
|
|
24379
|
+
}
|
|
24380
|
+
recordSessionFailure(category, turnId) {
|
|
24381
|
+
const presentation = SESSION_FAILURE_PRESENTATION[category];
|
|
24382
|
+
const previous = this.sessionState.sessionFailure;
|
|
24383
|
+
const id = previous?.phase === "active" ? previous.id : turnId === void 0 ? `${this.sessionState.sessionId}:error:${this.sessionFailureEpoch}` : `${turnId}:error`;
|
|
24384
|
+
const failure = {
|
|
24385
|
+
id,
|
|
24386
|
+
revision: previous?.id === id ? previous.revision + 1 : 1,
|
|
24387
|
+
phase: "active",
|
|
24388
|
+
category,
|
|
24389
|
+
source: "codex",
|
|
24390
|
+
safeMessage: presentation.message,
|
|
24391
|
+
retryable: presentation.retryable,
|
|
24392
|
+
actions: presentation.actions,
|
|
24393
|
+
...turnId === void 0 ? {} : { turnId }
|
|
24394
|
+
};
|
|
24395
|
+
this.sessionState.sessionFailure = failure;
|
|
24396
|
+
return failure;
|
|
24397
|
+
}
|
|
24398
|
+
createSessionFailureMeta(failure) {
|
|
24399
|
+
return {
|
|
24400
|
+
[JETBRAINS_META_KEY]: {
|
|
24401
|
+
[AIR_META_KEY]: {
|
|
24402
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
24403
|
+
[AIR_SESSION_FAILURE_KEY]: failure
|
|
24404
|
+
}
|
|
24405
|
+
}
|
|
24406
|
+
};
|
|
24407
|
+
}
|
|
24408
|
+
createSessionFailureUpdate(failure) {
|
|
24409
|
+
return {
|
|
24410
|
+
sessionUpdate: "session_info_update",
|
|
24411
|
+
_meta: this.createSessionFailureMeta(failure)
|
|
24412
|
+
};
|
|
24413
|
+
}
|
|
24414
|
+
sessionFailureCategory(error51) {
|
|
24415
|
+
if (this.isAuthenticationRequiredError(error51)) return "auth_required";
|
|
24416
|
+
if (this.getHttpStatusCode(error51) === 429) return "rate_limited";
|
|
24417
|
+
if (typeof error51 === "string") {
|
|
24418
|
+
return STRING_CODEX_ERROR_CATEGORIES[error51] ?? "provider_error";
|
|
24419
|
+
}
|
|
24420
|
+
if (error51 !== null) {
|
|
24421
|
+
for (const kind of Object.keys(STRUCTURED_CODEX_ERROR_CATEGORIES)) {
|
|
24422
|
+
if (kind in error51) {
|
|
24423
|
+
return STRUCTURED_CODEX_ERROR_CATEGORIES[kind] ?? "provider_error";
|
|
24424
|
+
}
|
|
24425
|
+
}
|
|
24426
|
+
}
|
|
24427
|
+
return "provider_error";
|
|
24428
|
+
}
|
|
24196
24429
|
isAuthenticationRequiredError(error51) {
|
|
24197
24430
|
return error51 === "unauthorized" || this.getHttpStatusCode(error51) === 401;
|
|
24198
24431
|
}
|
|
24199
24432
|
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;
|
|
24433
|
+
if (error51 === null || typeof error51 !== "object") return null;
|
|
24434
|
+
const details = Object.values(error51)[0];
|
|
24435
|
+
if (details === null || typeof details !== "object" || !("httpStatusCode" in details)) return null;
|
|
24436
|
+
return typeof details.httpStatusCode === "number" ? details.httpStatusCode : null;
|
|
24212
24437
|
}
|
|
24213
24438
|
createTurnErrorData(error51) {
|
|
24214
24439
|
const data = {
|
|
@@ -24637,11 +24862,11 @@ var CodexApprovalHandler = class {
|
|
|
24637
24862
|
});
|
|
24638
24863
|
}
|
|
24639
24864
|
const fileSystem = permissions.fileSystem;
|
|
24640
|
-
for (const
|
|
24641
|
-
changes.push(this.fileSystemGrantChange(
|
|
24865
|
+
for (const path7 of fileSystem?.read ?? []) {
|
|
24866
|
+
changes.push(this.fileSystemGrantChange(path7, "read", lifetime, suffix));
|
|
24642
24867
|
}
|
|
24643
|
-
for (const
|
|
24644
|
-
changes.push(this.fileSystemGrantChange(
|
|
24868
|
+
for (const path7 of fileSystem?.write ?? []) {
|
|
24869
|
+
changes.push(this.fileSystemGrantChange(path7, "write", lifetime, suffix));
|
|
24645
24870
|
}
|
|
24646
24871
|
for (const entry of fileSystem?.entries ?? []) {
|
|
24647
24872
|
const matcher = (() => {
|
|
@@ -24670,16 +24895,16 @@ var CodexApprovalHandler = class {
|
|
|
24670
24895
|
}
|
|
24671
24896
|
return changes.length > 0 ? { version: 1, changes } : void 0;
|
|
24672
24897
|
}
|
|
24673
|
-
fileSystemGrantChange(
|
|
24898
|
+
fileSystemGrantChange(path7, access, lifetime, suffix) {
|
|
24674
24899
|
return {
|
|
24675
24900
|
type: "grant",
|
|
24676
24901
|
operation: "grant",
|
|
24677
|
-
description: `Allow ${access} access to ${
|
|
24902
|
+
description: `Allow ${access} access to ${path7}${suffix}`,
|
|
24678
24903
|
lifetime,
|
|
24679
24904
|
targets: [{
|
|
24680
24905
|
type: "filesystem",
|
|
24681
24906
|
access: [access],
|
|
24682
|
-
matcher: { type: "exact_path", path:
|
|
24907
|
+
matcher: { type: "exact_path", path: path7 }
|
|
24683
24908
|
}]
|
|
24684
24909
|
};
|
|
24685
24910
|
}
|
|
@@ -25589,15 +25814,15 @@ var wslDefaultBrowser = async () => {
|
|
|
25589
25814
|
const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
|
|
25590
25815
|
return stdout.trim();
|
|
25591
25816
|
};
|
|
25592
|
-
var convertWslPathToWindows = async (
|
|
25593
|
-
if (/^[a-z]+:\/\//i.test(
|
|
25594
|
-
return
|
|
25817
|
+
var convertWslPathToWindows = async (path7) => {
|
|
25818
|
+
if (/^[a-z]+:\/\//i.test(path7)) {
|
|
25819
|
+
return path7;
|
|
25595
25820
|
}
|
|
25596
25821
|
try {
|
|
25597
|
-
const { stdout } = await execFile2("wslpath", ["-aw",
|
|
25822
|
+
const { stdout } = await execFile2("wslpath", ["-aw", path7], { encoding: "utf8" });
|
|
25598
25823
|
return stdout.trim();
|
|
25599
25824
|
} catch {
|
|
25600
|
-
return
|
|
25825
|
+
return path7;
|
|
25601
25826
|
}
|
|
25602
25827
|
};
|
|
25603
25828
|
|
|
@@ -26147,7 +26372,7 @@ var AgentMode = class _AgentMode {
|
|
|
26147
26372
|
};
|
|
26148
26373
|
|
|
26149
26374
|
// src/CodexAcpClient.ts
|
|
26150
|
-
import
|
|
26375
|
+
import path5 from "node:path";
|
|
26151
26376
|
|
|
26152
26377
|
// src/McpServerName.ts
|
|
26153
26378
|
var MCP_SERVER_NAME_WHITESPACE = /\p{White_Space}/gu;
|
|
@@ -26161,7 +26386,7 @@ var package_default = {
|
|
|
26161
26386
|
publishConfig: {
|
|
26162
26387
|
access: "public"
|
|
26163
26388
|
},
|
|
26164
|
-
version: "1.
|
|
26389
|
+
version: "1.2.0",
|
|
26165
26390
|
description: "",
|
|
26166
26391
|
main: "dist/index.js",
|
|
26167
26392
|
bin: {
|
|
@@ -26194,6 +26419,7 @@ var package_default = {
|
|
|
26194
26419
|
"example:steering": "node --import tsx examples/steering.ts",
|
|
26195
26420
|
"example:steering:multistep": "node --import tsx examples/steering.ts",
|
|
26196
26421
|
"generate-types": "./node_modules/.bin/codex app-server generate-ts --out src/app-server",
|
|
26422
|
+
"release:preflight": "bash scripts/release-preflight.sh",
|
|
26197
26423
|
test: "vitest run",
|
|
26198
26424
|
"test:e2e": "npm run build && RUN_E2E_TESTS=true vitest run src/__tests__/CodexACPAgent/e2e",
|
|
26199
26425
|
"test:watch": "vitest",
|
|
@@ -26222,7 +26448,7 @@ var package_default = {
|
|
|
26222
26448
|
},
|
|
26223
26449
|
dependencies: {
|
|
26224
26450
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
26225
|
-
"@openai/codex": "^0.
|
|
26451
|
+
"@openai/codex": "^0.147.0",
|
|
26226
26452
|
diff: "^9.0.0",
|
|
26227
26453
|
open: "^11.0.0",
|
|
26228
26454
|
"vscode-jsonrpc": "^9.0.1",
|
|
@@ -26265,6 +26491,54 @@ function createCodexCollaborationMode(mode, currentModelId) {
|
|
|
26265
26491
|
};
|
|
26266
26492
|
}
|
|
26267
26493
|
|
|
26494
|
+
// src/PathUtils.ts
|
|
26495
|
+
import path4 from "node:path";
|
|
26496
|
+
function isAbsolutePathLike(value) {
|
|
26497
|
+
const trimmed = value.trim();
|
|
26498
|
+
return path4.isAbsolute(trimmed) || isWindowsAbsolutePath(trimmed);
|
|
26499
|
+
}
|
|
26500
|
+
function arePathsEqual(left, right) {
|
|
26501
|
+
return normalizePathForComparison(left) === normalizePathForComparison(right);
|
|
26502
|
+
}
|
|
26503
|
+
function arePathBasenamesEqual(left, right) {
|
|
26504
|
+
const leftBase = path4.posix.basename(normalizePathForComparison(left));
|
|
26505
|
+
const rightBase = path4.posix.basename(normalizePathForComparison(right));
|
|
26506
|
+
if (shouldComparePathCaseInsensitive(left) || shouldComparePathCaseInsensitive(right)) {
|
|
26507
|
+
return leftBase.toLowerCase() === rightBase.toLowerCase();
|
|
26508
|
+
}
|
|
26509
|
+
return leftBase === rightBase;
|
|
26510
|
+
}
|
|
26511
|
+
function normalizePathForComparison(value) {
|
|
26512
|
+
const trimmed = value.trim();
|
|
26513
|
+
if (trimmed.length === 0) {
|
|
26514
|
+
return "";
|
|
26515
|
+
}
|
|
26516
|
+
if (isWindowsAbsolutePath(trimmed)) {
|
|
26517
|
+
const normalized2 = path4.win32.normalize(trimmed).replace(/\\/g, "/");
|
|
26518
|
+
return trimTrailingPathSeparators(normalized2).toLowerCase();
|
|
26519
|
+
}
|
|
26520
|
+
const pathForComparison = path4.isAbsolute(trimmed) ? trimmed : trimmed.replace(/\\/g, "/");
|
|
26521
|
+
const normalized = path4.posix.normalize(pathForComparison);
|
|
26522
|
+
return trimTrailingPathSeparators(normalized);
|
|
26523
|
+
}
|
|
26524
|
+
function isWindowsAbsolutePath(value) {
|
|
26525
|
+
const portableValue = value.replace(/\\/g, "/");
|
|
26526
|
+
return /^[A-Za-z]:\//.test(portableValue) || /^\/\/[^/]+\/[^/]+/.test(portableValue);
|
|
26527
|
+
}
|
|
26528
|
+
function shouldComparePathCaseInsensitive(value) {
|
|
26529
|
+
return isWindowsAbsolutePath(value) || /^[A-Za-z]:/.test(value) || value.includes("\\");
|
|
26530
|
+
}
|
|
26531
|
+
function trimTrailingPathSeparators(value) {
|
|
26532
|
+
let trimmed = value;
|
|
26533
|
+
while (trimmed.endsWith("/") && !isRootPath(trimmed)) {
|
|
26534
|
+
trimmed = trimmed.slice(0, -1);
|
|
26535
|
+
}
|
|
26536
|
+
return trimmed;
|
|
26537
|
+
}
|
|
26538
|
+
function isRootPath(value) {
|
|
26539
|
+
return value === "/" || /^[A-Za-z]:\/$/.test(value) || /^\/\/[^/]+\/[^/]+\/$/.test(value);
|
|
26540
|
+
}
|
|
26541
|
+
|
|
26268
26542
|
// src/CodexAcpClient.ts
|
|
26269
26543
|
var CUSTOM_GATEWAY_PROVIDER_ID = "custom-gateway";
|
|
26270
26544
|
var SUPPORTED_GATEWAY_PROTOCOLS = {
|
|
@@ -26624,12 +26898,16 @@ var CodexAcpClient = class {
|
|
|
26624
26898
|
const response = await this.codexClient.threadGoalGet({ threadId: sessionId });
|
|
26625
26899
|
return response?.goal ?? null;
|
|
26626
26900
|
}
|
|
26627
|
-
async setGoal(sessionId, objective, onTurnStarted) {
|
|
26628
|
-
|
|
26901
|
+
async setGoal(sessionId, objective, onTurnStarted, onGoalSet) {
|
|
26902
|
+
const params = {
|
|
26629
26903
|
threadId: sessionId,
|
|
26630
26904
|
objective,
|
|
26631
26905
|
status: "active"
|
|
26632
|
-
}
|
|
26906
|
+
};
|
|
26907
|
+
if (onGoalSet === void 0) {
|
|
26908
|
+
return await this.codexClient.runGoalSet(params, onTurnStarted);
|
|
26909
|
+
}
|
|
26910
|
+
return await this.codexClient.runGoalSet(params, onTurnStarted, void 0, onGoalSet);
|
|
26633
26911
|
}
|
|
26634
26912
|
async setGoalStatus(sessionId, status) {
|
|
26635
26913
|
let updatedGoal = null;
|
|
@@ -26644,11 +26922,15 @@ var CodexAcpClient = class {
|
|
|
26644
26922
|
}
|
|
26645
26923
|
return updatedGoal;
|
|
26646
26924
|
}
|
|
26647
|
-
async resumeGoal(sessionId, onTurnStarted) {
|
|
26648
|
-
|
|
26925
|
+
async resumeGoal(sessionId, onTurnStarted, onGoalSet) {
|
|
26926
|
+
const params = {
|
|
26649
26927
|
threadId: sessionId,
|
|
26650
26928
|
status: "active"
|
|
26651
|
-
}
|
|
26929
|
+
};
|
|
26930
|
+
if (onGoalSet === void 0) {
|
|
26931
|
+
return await this.codexClient.runGoalSet(params, onTurnStarted);
|
|
26932
|
+
}
|
|
26933
|
+
return await this.codexClient.runGoalSet(params, onTurnStarted, void 0, onGoalSet);
|
|
26652
26934
|
}
|
|
26653
26935
|
async clearGoal(sessionId) {
|
|
26654
26936
|
await this.codexClient.runGoalClear({ threadId: sessionId });
|
|
@@ -26711,7 +26993,7 @@ var CodexAcpClient = class {
|
|
|
26711
26993
|
if (!cwd) {
|
|
26712
26994
|
return;
|
|
26713
26995
|
}
|
|
26714
|
-
const skillExtraRoots = additionalRoots.map((root) =>
|
|
26996
|
+
const skillExtraRoots = additionalRoots.map((root) => path5.join(root, ".agents", "skills"));
|
|
26715
26997
|
if (!arraysEqual(this.skillExtraRoots, skillExtraRoots)) {
|
|
26716
26998
|
await this.codexClient.skillsExtraRootsSet({ extraRoots: skillExtraRoots });
|
|
26717
26999
|
this.skillExtraRoots = skillExtraRoots;
|
|
@@ -26902,11 +27184,10 @@ var CodexAcpClient = class {
|
|
|
26902
27184
|
const requestedCwd = request.cwd?.trim() ?? null;
|
|
26903
27185
|
const filterByCwd = (thread) => {
|
|
26904
27186
|
if (!requestedCwd) return true;
|
|
26905
|
-
if (
|
|
26906
|
-
return thread.cwd
|
|
27187
|
+
if (isAbsolutePathLike(requestedCwd)) {
|
|
27188
|
+
return arePathsEqual(thread.cwd, requestedCwd);
|
|
26907
27189
|
}
|
|
26908
|
-
|
|
26909
|
-
return path4.basename(thread.cwd) === requestedBase;
|
|
27190
|
+
return arePathBasenamesEqual(thread.cwd, requestedCwd);
|
|
26910
27191
|
};
|
|
26911
27192
|
const preferredProvider = this.getModelProvider();
|
|
26912
27193
|
const modelProviders = preferredProvider ? [preferredProvider] : [];
|
|
@@ -26928,7 +27209,7 @@ var CodexAcpClient = class {
|
|
|
26928
27209
|
let sessions = listResponse.data.map(mapThreadToSession);
|
|
26929
27210
|
if (requestedCwd) {
|
|
26930
27211
|
const filtered = listResponse.data.filter(filterByCwd).map(mapThreadToSession);
|
|
26931
|
-
if (filtered.length > 0 ||
|
|
27212
|
+
if (filtered.length > 0 || isAbsolutePathLike(requestedCwd)) {
|
|
26932
27213
|
sessions = filtered;
|
|
26933
27214
|
} else {
|
|
26934
27215
|
logger.log("Ignoring non-absolute cwd filter for session/list", { cwd: requestedCwd });
|
|
@@ -27043,8 +27324,8 @@ function formatUriAsLink(name, uri) {
|
|
|
27043
27324
|
return `[@${name}](${uri})`;
|
|
27044
27325
|
}
|
|
27045
27326
|
if (uri.startsWith("file://")) {
|
|
27046
|
-
const
|
|
27047
|
-
const fileName =
|
|
27327
|
+
const path7 = uri.replace("file://", "");
|
|
27328
|
+
const fileName = path7.split("/").pop() ?? path7;
|
|
27048
27329
|
return `[@${fileName}](${uri})`;
|
|
27049
27330
|
}
|
|
27050
27331
|
return uri;
|
|
@@ -27074,7 +27355,7 @@ function readAdditionalDirectories(cwd, additionalDirectories, meta3) {
|
|
|
27074
27355
|
if (directory.length === 0) {
|
|
27075
27356
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must not be empty");
|
|
27076
27357
|
}
|
|
27077
|
-
if (!
|
|
27358
|
+
if (!path5.isAbsolute(directory)) {
|
|
27078
27359
|
throw RequestError.invalidParams(void 0, "additionalDirectories entries must be absolute paths");
|
|
27079
27360
|
}
|
|
27080
27361
|
if (!seen.has(directory)) {
|
|
@@ -27189,6 +27470,10 @@ function createReasoningEffortConfigOption(supportedReasoningEfforts, currentEff
|
|
|
27189
27470
|
}
|
|
27190
27471
|
|
|
27191
27472
|
// src/CodexCommands.ts
|
|
27473
|
+
var GOAL_CONTINUATION_PROMPT = [{
|
|
27474
|
+
type: "text",
|
|
27475
|
+
text: "Continue working toward the active goal."
|
|
27476
|
+
}];
|
|
27192
27477
|
var CodexCommands = class {
|
|
27193
27478
|
connection;
|
|
27194
27479
|
codexAcpClient;
|
|
@@ -27477,7 +27762,7 @@ var CodexCommands = class {
|
|
|
27477
27762
|
}
|
|
27478
27763
|
createGoalCommandResult(turnCompleted) {
|
|
27479
27764
|
if (turnCompleted === null) {
|
|
27480
|
-
return { handled:
|
|
27765
|
+
return { handled: false, prompt: GOAL_CONTINUATION_PROMPT };
|
|
27481
27766
|
}
|
|
27482
27767
|
return {
|
|
27483
27768
|
handled: true,
|
|
@@ -27673,7 +27958,7 @@ var SteeringQueue = class {
|
|
|
27673
27958
|
|
|
27674
27959
|
// src/ResponseItemHistoryFallback.ts
|
|
27675
27960
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
27676
|
-
import
|
|
27961
|
+
import path6 from "node:path";
|
|
27677
27962
|
function historyFallbackUpdateKey(update) {
|
|
27678
27963
|
switch (update.sessionUpdate) {
|
|
27679
27964
|
case "user_message_chunk":
|
|
@@ -27913,8 +28198,8 @@ function imageBlocks(images) {
|
|
|
27913
28198
|
return [{ type: "text", text: `[@image](${image})` }];
|
|
27914
28199
|
}
|
|
27915
28200
|
const record2 = asRecord(image);
|
|
27916
|
-
const
|
|
27917
|
-
return
|
|
28201
|
+
const path7 = record2 ? stringValue(record2["path"]) ?? stringValue(record2["url"]) : null;
|
|
28202
|
+
return path7 ? [{ type: "text", text: `[@image](${path7})` }] : [];
|
|
27918
28203
|
});
|
|
27919
28204
|
}
|
|
27920
28205
|
function contentBlocksFromResponseContent(content) {
|
|
@@ -28546,10 +28831,10 @@ function baseCommandName(commandName) {
|
|
|
28546
28831
|
return commandName.split(/[\\/]/).pop() ?? commandName;
|
|
28547
28832
|
}
|
|
28548
28833
|
function absolutizePath(cwd, targetPath) {
|
|
28549
|
-
if (
|
|
28834
|
+
if (path6.isAbsolute(targetPath) || cwd.length === 0) {
|
|
28550
28835
|
return targetPath;
|
|
28551
28836
|
}
|
|
28552
|
-
return
|
|
28837
|
+
return path6.join(cwd, targetPath);
|
|
28553
28838
|
}
|
|
28554
28839
|
function withTerminalContent(event, terminalId, cwd) {
|
|
28555
28840
|
const { rawInput, ...eventWithoutRawInput } = event;
|
|
@@ -28705,8 +28990,17 @@ function clientSupportsPlanUpdates(clientCapabilities) {
|
|
|
28705
28990
|
}
|
|
28706
28991
|
|
|
28707
28992
|
// src/CodexAcpServer.ts
|
|
28993
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
28708
28994
|
var IMPLEMENT_PLAN_OPTION_ID = "implement_plan";
|
|
28709
28995
|
var REVISE_PLAN_OPTION_ID = "revise_plan";
|
|
28996
|
+
var CODEX_PROCESS_EXITED_ERROR_CODE = 1001;
|
|
28997
|
+
function clientSupportsTypedSessionFailures(capabilities) {
|
|
28998
|
+
const jetbrains = capabilities?._meta?.[JETBRAINS_META_KEY];
|
|
28999
|
+
const air = jetbrains?.[AIR_META_KEY];
|
|
29000
|
+
const version2 = air?.[AIR_EXTENSION_VERSION_KEY];
|
|
29001
|
+
const supported = air?.[AIR_EXTENSION_CAPABILITIES_KEY];
|
|
29002
|
+
return typeof version2 === "number" && Number.isInteger(version2) && version2 >= AIR_EXTENSION_VERSION && Array.isArray(supported) && supported.includes(AIR_SESSION_FAILURE_KEY);
|
|
29003
|
+
}
|
|
28710
29004
|
var CodexAcpServer = class _CodexAcpServer {
|
|
28711
29005
|
static MODEL_NAME_TOKEN_OVERRIDES = {
|
|
28712
29006
|
gpt: "GPT",
|
|
@@ -28718,6 +29012,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28718
29012
|
defaultAuthRequest;
|
|
28719
29013
|
getExitCode;
|
|
28720
29014
|
getRecentStderr;
|
|
29015
|
+
sessionFailureEpoch;
|
|
28721
29016
|
availableCommands;
|
|
28722
29017
|
clientInfo;
|
|
28723
29018
|
clientCapabilities;
|
|
@@ -28731,6 +29026,7 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28731
29026
|
closingSessions;
|
|
28732
29027
|
sessionGenerations;
|
|
28733
29028
|
sessionOpenGenerations;
|
|
29029
|
+
goalControlGenerations;
|
|
28734
29030
|
constructor(connection, codexAcpClient, defaultAuthRequest, getExitCode, getRecentStderr) {
|
|
28735
29031
|
this.sessions = /* @__PURE__ */ new Map();
|
|
28736
29032
|
this.pendingMcpStartupSessions = /* @__PURE__ */ new Map();
|
|
@@ -28740,11 +29036,13 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28740
29036
|
this.closingSessions = /* @__PURE__ */ new Map();
|
|
28741
29037
|
this.sessionGenerations = /* @__PURE__ */ new Map();
|
|
28742
29038
|
this.sessionOpenGenerations = /* @__PURE__ */ new Map();
|
|
29039
|
+
this.goalControlGenerations = /* @__PURE__ */ new Map();
|
|
28743
29040
|
this.connection = connection;
|
|
28744
29041
|
this.codexAcpClient = codexAcpClient;
|
|
28745
29042
|
this.defaultAuthRequest = defaultAuthRequest ?? null;
|
|
28746
29043
|
this.getExitCode = getExitCode ?? (() => null);
|
|
28747
29044
|
this.getRecentStderr = getRecentStderr ?? (() => "");
|
|
29045
|
+
this.sessionFailureEpoch = randomUUID2();
|
|
28748
29046
|
this.clientInfo = null;
|
|
28749
29047
|
this.clientCapabilities = null;
|
|
28750
29048
|
this.terminalOutputMode = "terminal_output_delta";
|
|
@@ -28802,6 +29100,12 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28802
29100
|
version: GOAL_EXTENSION_VERSION,
|
|
28803
29101
|
controlMethod: GOAL_CONTROL_METHOD,
|
|
28804
29102
|
actions: [...GOAL_CONTROL_ACTIONS]
|
|
29103
|
+
},
|
|
29104
|
+
[JETBRAINS_META_KEY]: {
|
|
29105
|
+
[AIR_META_KEY]: {
|
|
29106
|
+
[AIR_EXTENSION_VERSION_KEY]: AIR_EXTENSION_VERSION,
|
|
29107
|
+
[AIR_EXTENSION_CAPABILITIES_KEY]: [AIR_SESSION_FAILURE_KEY]
|
|
29108
|
+
}
|
|
28805
29109
|
}
|
|
28806
29110
|
}
|
|
28807
29111
|
};
|
|
@@ -28829,12 +29133,51 @@ var CodexAcpServer = class _CodexAcpServer {
|
|
|
28829
29133
|
throw RequestError.invalidParams(void 0, `Unknown session: ${methodRequest.params.sessionId}`);
|
|
28830
29134
|
}
|
|
28831
29135
|
const sessionGeneration = this.getSessionGeneration(sessionState.sessionId);
|
|
28832
|
-
|
|
28833
|
-
|
|
28834
|
-
const
|
|
29136
|
+
const goalControlGeneration = this.bumpGoalControlGeneration(sessionState.sessionId);
|
|
29137
|
+
if (methodRequest.params.action === "set") {
|
|
29138
|
+
const objective = methodRequest.params.objective;
|
|
29139
|
+
let updatedGoal = null;
|
|
29140
|
+
const turnCompleted = await this.runWithProcessCheck(() => this.codexAcpClient.setGoal(
|
|
29141
|
+
sessionState.sessionId,
|
|
29142
|
+
objective,
|
|
29143
|
+
void 0,
|
|
29144
|
+
(goal) => {
|
|
29145
|
+
updatedGoal = goal;
|
|
29146
|
+
}
|
|
29147
|
+
));
|
|
29148
|
+
if (turnCompleted === null && updatedGoal !== null) {
|
|
29149
|
+
await this.startGoalContinuationIfCurrent(
|
|
29150
|
+
sessionState,
|
|
29151
|
+
sessionGeneration,
|
|
29152
|
+
goalControlGeneration,
|
|
29153
|
+
updatedGoal
|
|
29154
|
+
);
|
|
29155
|
+
}
|
|
29156
|
+
} else if (methodRequest.params.action === "pause") {
|
|
29157
|
+
const goal = await this.runWithProcessCheck(() => this.codexAcpClient.setGoalStatus(sessionState.sessionId, "paused"));
|
|
28835
29158
|
if (this.goalPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
28836
29159
|
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(goal), false);
|
|
28837
29160
|
}
|
|
29161
|
+
} else if (methodRequest.params.action === "resume") {
|
|
29162
|
+
let updatedGoal = null;
|
|
29163
|
+
const turnCompleted = await this.runWithProcessCheck(() => this.codexAcpClient.resumeGoal(
|
|
29164
|
+
sessionState.sessionId,
|
|
29165
|
+
void 0,
|
|
29166
|
+
(goal) => {
|
|
29167
|
+
updatedGoal = goal;
|
|
29168
|
+
}
|
|
29169
|
+
));
|
|
29170
|
+
if (updatedGoal !== null && this.goalPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
29171
|
+
await this.publishGoalSnapshot(sessionState, toThreadGoalSnapshot(updatedGoal), false);
|
|
29172
|
+
}
|
|
29173
|
+
if (turnCompleted === null && updatedGoal !== null) {
|
|
29174
|
+
await this.startGoalContinuationIfCurrent(
|
|
29175
|
+
sessionState,
|
|
29176
|
+
sessionGeneration,
|
|
29177
|
+
goalControlGeneration,
|
|
29178
|
+
updatedGoal
|
|
29179
|
+
);
|
|
29180
|
+
}
|
|
28838
29181
|
} else if (methodRequest.params.action === "clear") {
|
|
28839
29182
|
await this.runWithProcessCheck(() => this.codexAcpClient.clearGoal(sessionState.sessionId));
|
|
28840
29183
|
if (this.goalPublishIsCurrent(sessionState, sessionGeneration)) {
|
|
@@ -28934,6 +29277,11 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
28934
29277
|
getSessionGeneration(sessionId) {
|
|
28935
29278
|
return this.sessionGenerations.get(sessionId) ?? 0;
|
|
28936
29279
|
}
|
|
29280
|
+
bumpGoalControlGeneration(sessionId) {
|
|
29281
|
+
const generation = (this.goalControlGenerations.get(sessionId) ?? 0) + 1;
|
|
29282
|
+
this.goalControlGenerations.set(sessionId, generation);
|
|
29283
|
+
return generation;
|
|
29284
|
+
}
|
|
28937
29285
|
bumpSessionGeneration(sessionId) {
|
|
28938
29286
|
const generation = this.getSessionGeneration(sessionId) + 1;
|
|
28939
29287
|
this.sessionGenerations.set(sessionId, generation);
|
|
@@ -29131,6 +29479,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
29131
29479
|
this.pendingTurnStarts.delete(params.sessionId);
|
|
29132
29480
|
this.activePrompts.delete(params.sessionId);
|
|
29133
29481
|
this.steeringQueues.delete(params.sessionId);
|
|
29482
|
+
this.goalControlGenerations.delete(params.sessionId);
|
|
29134
29483
|
}
|
|
29135
29484
|
this.endSessionCloseFence(params.sessionId);
|
|
29136
29485
|
}
|
|
@@ -29488,29 +29837,48 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
29488
29837
|
* fails or is cancelled before the turn starts.
|
|
29489
29838
|
*/
|
|
29490
29839
|
async startNewTurnFromSteering(params) {
|
|
29840
|
+
await this.startNewTurnFromExternalPrompt(params, "Steering");
|
|
29841
|
+
return { outcome: "startedNewTurn" };
|
|
29842
|
+
}
|
|
29843
|
+
async startGoalContinuationIfCurrent(sessionState, sessionGeneration, goalControlGeneration, expectedGoal) {
|
|
29844
|
+
await this.startNewTurnFromExternalPrompt({
|
|
29845
|
+
sessionId: sessionState.sessionId,
|
|
29846
|
+
prompt: GOAL_CONTINUATION_PROMPT
|
|
29847
|
+
}, "Goal continuation", async () => {
|
|
29848
|
+
if (!this.goalPublishIsCurrent(sessionState, sessionGeneration) || this.goalControlGenerations.get(sessionState.sessionId) !== goalControlGeneration) {
|
|
29849
|
+
return false;
|
|
29850
|
+
}
|
|
29851
|
+
const currentGoal = await this.runWithProcessCheck(() => this.codexAcpClient.getGoal(sessionState.sessionId));
|
|
29852
|
+
return currentGoal?.status === "active" && currentGoal.objective === expectedGoal.objective && currentGoal.createdAt === expectedGoal.createdAt && this.goalControlGenerations.get(sessionState.sessionId) === goalControlGeneration;
|
|
29853
|
+
});
|
|
29854
|
+
}
|
|
29855
|
+
async startNewTurnFromExternalPrompt(params, source, canStart = async () => true) {
|
|
29491
29856
|
const previousPrompt = this.activePrompts.get(params.sessionId);
|
|
29492
29857
|
await previousPrompt?.completion;
|
|
29493
29858
|
if (this.sessionIsClosing(params.sessionId)) {
|
|
29494
29859
|
throw RequestError.invalidRequest(`Session ${params.sessionId} is closing`);
|
|
29495
29860
|
}
|
|
29861
|
+
if (!await canStart()) {
|
|
29862
|
+
return false;
|
|
29863
|
+
}
|
|
29496
29864
|
return await new Promise((resolve, reject) => {
|
|
29497
29865
|
let turnStarted = false;
|
|
29498
29866
|
const promptDone = this.prompt(params, void 0, () => {
|
|
29499
29867
|
turnStarted = true;
|
|
29500
|
-
logger.log(
|
|
29501
|
-
resolve(
|
|
29868
|
+
logger.log(`${source} started a new turn`, { sessionId: params.sessionId });
|
|
29869
|
+
resolve(true);
|
|
29502
29870
|
});
|
|
29503
29871
|
promptDone.then(
|
|
29504
29872
|
(response) => {
|
|
29505
29873
|
if (!turnStarted && response.stopReason === "cancelled") {
|
|
29506
29874
|
reject(RequestError.invalidRequest(`Session ${params.sessionId} was cancelled before the steering turn started`));
|
|
29507
29875
|
} else {
|
|
29508
|
-
resolve(
|
|
29876
|
+
resolve(turnStarted);
|
|
29509
29877
|
}
|
|
29510
29878
|
},
|
|
29511
29879
|
(error51) => {
|
|
29512
29880
|
if (turnStarted) {
|
|
29513
|
-
logger.error(
|
|
29881
|
+
logger.error(`${source} prompt for session ${params.sessionId} failed`, error51);
|
|
29514
29882
|
} else {
|
|
29515
29883
|
reject(error51);
|
|
29516
29884
|
}
|
|
@@ -29921,8 +30289,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
29921
30289
|
return `[@${name}](${uri})`;
|
|
29922
30290
|
}
|
|
29923
30291
|
if (uri.startsWith("file://")) {
|
|
29924
|
-
const
|
|
29925
|
-
const fileName =
|
|
30292
|
+
const path7 = uri.replace("file://", "");
|
|
30293
|
+
const fileName = path7.split("/").pop() ?? path7;
|
|
29926
30294
|
return `[@${fileName}](${uri})`;
|
|
29927
30295
|
}
|
|
29928
30296
|
return uri;
|
|
@@ -30175,6 +30543,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30175
30543
|
prompt: params.prompt
|
|
30176
30544
|
});
|
|
30177
30545
|
const sessionState = this.getSessionState(params.sessionId);
|
|
30546
|
+
let recoverableSessionFailure = sessionState.sessionFailure;
|
|
30178
30547
|
sessionState.currentTurnId = null;
|
|
30179
30548
|
sessionState.lastTokenUsage = null;
|
|
30180
30549
|
const activePrompt = this.trackActivePrompt(params.sessionId);
|
|
@@ -30188,11 +30557,20 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30188
30557
|
};
|
|
30189
30558
|
const disposePromptRequestCancellation = this.observePromptRequestCancellation(signal, sessionState, activePrompt);
|
|
30190
30559
|
let eventHandler = null;
|
|
30560
|
+
let promptNotificationsActive = true;
|
|
30561
|
+
const clearRecoveredSessionFailure = async (handler) => {
|
|
30562
|
+
const current = sessionState.sessionFailure;
|
|
30563
|
+
if (recoverableSessionFailure?.phase === "active" && current?.phase === "active" && current.id === recoverableSessionFailure.id && current.revision === recoverableSessionFailure.revision) {
|
|
30564
|
+
await handler.clearSessionFailure();
|
|
30565
|
+
}
|
|
30566
|
+
};
|
|
30191
30567
|
try {
|
|
30192
30568
|
const promptEventHandler = new CodexEventHandler(
|
|
30193
30569
|
this.connection,
|
|
30194
30570
|
sessionState,
|
|
30195
|
-
clientSupportsPlanUpdates(this.clientCapabilities)
|
|
30571
|
+
clientSupportsPlanUpdates(this.clientCapabilities),
|
|
30572
|
+
clientSupportsTypedSessionFailures(this.clientCapabilities),
|
|
30573
|
+
this.sessionFailureEpoch
|
|
30196
30574
|
);
|
|
30197
30575
|
eventHandler = promptEventHandler;
|
|
30198
30576
|
const approvalHandler = new CodexApprovalHandler(this.connection, sessionState, activePrompt.signal);
|
|
@@ -30205,8 +30583,16 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30205
30583
|
await this.codexAcpClient.subscribeToSessionEvents(
|
|
30206
30584
|
params.sessionId,
|
|
30207
30585
|
async (event) => {
|
|
30586
|
+
if (!promptNotificationsActive) {
|
|
30587
|
+
await promptEventHandler.handleSessionScopedNotification(event);
|
|
30588
|
+
return;
|
|
30589
|
+
}
|
|
30590
|
+
const completesActiveTurn = event.method === "turn/completed" && event.params.turn.id === sessionState.currentTurnId;
|
|
30208
30591
|
await elicitationHandler.handleNotification(event);
|
|
30209
|
-
|
|
30592
|
+
await promptEventHandler.handleNotification(event);
|
|
30593
|
+
if (completesActiveTurn) {
|
|
30594
|
+
promptNotificationsActive = false;
|
|
30595
|
+
}
|
|
30210
30596
|
},
|
|
30211
30597
|
approvalHandler,
|
|
30212
30598
|
elicitationHandler
|
|
@@ -30256,8 +30642,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30256
30642
|
return this.cancelledPromptResponse(sessionState);
|
|
30257
30643
|
}
|
|
30258
30644
|
if (commandResult.handled) {
|
|
30645
|
+
promptNotificationsActive = false;
|
|
30259
30646
|
logger.log("Prompt handled by a command");
|
|
30260
30647
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30648
|
+
await eventHandler.flushPendingErrors();
|
|
30649
|
+
await eventHandler.flushPendingErrorsAsSessionScoped();
|
|
30650
|
+
if (commandResult.turnCompleted) {
|
|
30651
|
+
await eventHandler.handleFailedTurn(commandResult.turnCompleted.turn);
|
|
30652
|
+
}
|
|
30261
30653
|
if (commandResult.turnCompleted?.turn.status === "interrupted") {
|
|
30262
30654
|
return this.cancelledPromptResponse(sessionState);
|
|
30263
30655
|
}
|
|
@@ -30265,12 +30657,22 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30265
30657
|
if (error52) {
|
|
30266
30658
|
throw error52;
|
|
30267
30659
|
}
|
|
30660
|
+
const terminalFailure2 = this.terminalFailurePromptResponse(
|
|
30661
|
+
sessionState,
|
|
30662
|
+
eventHandler,
|
|
30663
|
+
commandResult.turnCompleted?.turn.id ?? sessionState.currentTurnId
|
|
30664
|
+
);
|
|
30665
|
+
if (terminalFailure2) {
|
|
30666
|
+
return terminalFailure2;
|
|
30667
|
+
}
|
|
30668
|
+
await clearRecoveredSessionFailure(eventHandler);
|
|
30268
30669
|
return {
|
|
30269
30670
|
stopReason: "end_turn",
|
|
30270
30671
|
usage: this.buildPromptUsage(sessionState.lastTokenUsage),
|
|
30271
30672
|
_meta: this.buildQuotaMeta(sessionState)
|
|
30272
30673
|
};
|
|
30273
30674
|
}
|
|
30675
|
+
const effectiveParams = commandResult.prompt === void 0 ? params : { ...params, prompt: commandResult.prompt };
|
|
30274
30676
|
if (this.sessionIsClosing(params.sessionId)) {
|
|
30275
30677
|
return this.cancelledPromptResponse(sessionState);
|
|
30276
30678
|
}
|
|
@@ -30283,7 +30685,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30283
30685
|
reason: sessionState.account?.type === "apiKey" ? "API key" : "model lacks reasoning"
|
|
30284
30686
|
});
|
|
30285
30687
|
}
|
|
30286
|
-
if (!sessionState.supportedInputModalities.includes("image") &&
|
|
30688
|
+
if (!sessionState.supportedInputModalities.includes("image") && effectiveParams.prompt.some((b) => b.type === "image")) {
|
|
30287
30689
|
throw RequestError.invalidRequest("The current model does not support image input");
|
|
30288
30690
|
}
|
|
30289
30691
|
const agentMode = sessionState.agentMode;
|
|
@@ -30294,7 +30696,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30294
30696
|
ensurePendingTurnStart();
|
|
30295
30697
|
const sendPromptPromise = this.runWithProcessCheck(
|
|
30296
30698
|
() => this.codexAcpClient.sendPrompt(
|
|
30297
|
-
|
|
30699
|
+
effectiveParams,
|
|
30298
30700
|
agentMode,
|
|
30299
30701
|
modelId,
|
|
30300
30702
|
serviceTier,
|
|
@@ -30329,6 +30731,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30329
30731
|
return this.cancelledPromptResponse(sessionState);
|
|
30330
30732
|
}
|
|
30331
30733
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30734
|
+
await eventHandler.flushPendingErrors();
|
|
30735
|
+
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
30736
|
+
promptNotificationsActive = false;
|
|
30332
30737
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30333
30738
|
await eventHandler.flushPendingPlanUpdates();
|
|
30334
30739
|
return this.cancelledPromptResponse(sessionState);
|
|
@@ -30337,6 +30742,14 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30337
30742
|
if (error51) {
|
|
30338
30743
|
throw error51;
|
|
30339
30744
|
}
|
|
30745
|
+
const terminalFailure = this.terminalFailurePromptResponse(
|
|
30746
|
+
sessionState,
|
|
30747
|
+
eventHandler,
|
|
30748
|
+
turnCompleted.turn.id
|
|
30749
|
+
);
|
|
30750
|
+
if (terminalFailure) {
|
|
30751
|
+
return terminalFailure;
|
|
30752
|
+
}
|
|
30340
30753
|
await eventHandler.flushPendingPlanUpdates();
|
|
30341
30754
|
const completedPlan = eventHandler.takeCompletedPlan();
|
|
30342
30755
|
if (completedPlan !== null && sessionState.collaborationMode === PLAN_COLLABORATION_MODE && !this.promptShouldStop(params.sessionId, activePrompt)) {
|
|
@@ -30360,6 +30773,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30360
30773
|
prompt: [{ type: "text", text: "Implement the approved plan." }]
|
|
30361
30774
|
};
|
|
30362
30775
|
activePrompt.currentTurn = null;
|
|
30776
|
+
sessionState.currentTurnId = null;
|
|
30363
30777
|
const implementationPromise = this.runWithProcessCheck(
|
|
30364
30778
|
() => this.codexAcpClient.sendPrompt(
|
|
30365
30779
|
implementationRequest,
|
|
@@ -30377,6 +30791,8 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30377
30791
|
return;
|
|
30378
30792
|
}
|
|
30379
30793
|
sessionState.currentTurnId = turnId;
|
|
30794
|
+
recoverableSessionFailure = sessionState.sessionFailure;
|
|
30795
|
+
promptNotificationsActive = true;
|
|
30380
30796
|
},
|
|
30381
30797
|
() => this.promptShouldStop(params.sessionId, activePrompt)
|
|
30382
30798
|
)
|
|
@@ -30395,6 +30811,9 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30395
30811
|
return this.cancelledPromptResponse(sessionState);
|
|
30396
30812
|
}
|
|
30397
30813
|
await this.codexAcpClient.waitForSessionNotifications(params.sessionId);
|
|
30814
|
+
await eventHandler.flushPendingErrors();
|
|
30815
|
+
await eventHandler.handleFailedTurn(turnCompleted.turn);
|
|
30816
|
+
promptNotificationsActive = false;
|
|
30398
30817
|
if (turnCompleted.turn.status === "interrupted") {
|
|
30399
30818
|
await eventHandler.flushPendingPlanUpdates();
|
|
30400
30819
|
return this.cancelledPromptResponse(sessionState);
|
|
@@ -30403,8 +30822,17 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30403
30822
|
if (implementationError) {
|
|
30404
30823
|
throw implementationError;
|
|
30405
30824
|
}
|
|
30825
|
+
const implementationFailure = this.terminalFailurePromptResponse(
|
|
30826
|
+
sessionState,
|
|
30827
|
+
eventHandler,
|
|
30828
|
+
turnCompleted.turn.id
|
|
30829
|
+
);
|
|
30830
|
+
if (implementationFailure) {
|
|
30831
|
+
return implementationFailure;
|
|
30832
|
+
}
|
|
30406
30833
|
}
|
|
30407
30834
|
}
|
|
30835
|
+
await clearRecoveredSessionFailure(eventHandler);
|
|
30408
30836
|
await this.publishFallbackSessionTitle(
|
|
30409
30837
|
sessionState,
|
|
30410
30838
|
this.createPromptFallbackTitle(params.prompt)
|
|
@@ -30416,8 +30844,27 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30416
30844
|
};
|
|
30417
30845
|
} catch (err) {
|
|
30418
30846
|
logger.error(`Prompt for session ${params.sessionId} failed`, err);
|
|
30847
|
+
if (activePrompt.signal.aborted || this.sessionIsClosing(params.sessionId)) {
|
|
30848
|
+
return this.cancelledPromptResponse(sessionState);
|
|
30849
|
+
}
|
|
30850
|
+
const isProcessExit = err instanceof RequestError && err.code === CODEX_PROCESS_EXITED_ERROR_CODE;
|
|
30851
|
+
const isUnexpectedFailure = !(err instanceof RequestError);
|
|
30852
|
+
if (eventHandler !== null && clientSupportsTypedSessionFailures(this.clientCapabilities) && (isProcessExit || isUnexpectedFailure)) {
|
|
30853
|
+
const category = isProcessExit ? "transport_lost" : "internal_error";
|
|
30854
|
+
eventHandler.recordSyntheticTerminalFailure(category, sessionState.currentTurnId);
|
|
30855
|
+
const failureResponse = this.terminalFailurePromptResponse(
|
|
30856
|
+
sessionState,
|
|
30857
|
+
eventHandler,
|
|
30858
|
+
sessionState.currentTurnId,
|
|
30859
|
+
true
|
|
30860
|
+
);
|
|
30861
|
+
if (failureResponse !== null) {
|
|
30862
|
+
return failureResponse;
|
|
30863
|
+
}
|
|
30864
|
+
}
|
|
30419
30865
|
throw err;
|
|
30420
30866
|
} finally {
|
|
30867
|
+
promptNotificationsActive = false;
|
|
30421
30868
|
logger.log("Prompt completed", { sessionId: params.sessionId });
|
|
30422
30869
|
await eventHandler?.dispose();
|
|
30423
30870
|
disposePromptRequestCancellation();
|
|
@@ -30488,6 +30935,20 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30488
30935
|
_meta: this.buildQuotaMeta(sessionState)
|
|
30489
30936
|
};
|
|
30490
30937
|
}
|
|
30938
|
+
terminalFailurePromptResponse(sessionState, eventHandler, turnId, allowUnattributed = false) {
|
|
30939
|
+
const failureMeta = eventHandler.getTerminalSessionFailureMeta(turnId, allowUnattributed);
|
|
30940
|
+
if (failureMeta === null) {
|
|
30941
|
+
return null;
|
|
30942
|
+
}
|
|
30943
|
+
return {
|
|
30944
|
+
stopReason: "end_turn",
|
|
30945
|
+
usage: this.buildPromptUsage(sessionState.lastTokenUsage),
|
|
30946
|
+
_meta: {
|
|
30947
|
+
...this.buildQuotaMeta(sessionState),
|
|
30948
|
+
...failureMeta
|
|
30949
|
+
}
|
|
30950
|
+
};
|
|
30951
|
+
}
|
|
30491
30952
|
buildQuotaMeta(sessionState) {
|
|
30492
30953
|
const lastTokenUsage = sessionState.lastTokenUsage;
|
|
30493
30954
|
const modelName = sessionState.currentModelId.replace(/\[.*?]$/, "");
|
|
@@ -30510,7 +30971,7 @@ Check ${configPath} and project .codex directories, especially their config.toml
|
|
|
30510
30971
|
return await operation();
|
|
30511
30972
|
} catch (err) {
|
|
30512
30973
|
const exitCode = this.getExitCode();
|
|
30513
|
-
const requestErrorCode =
|
|
30974
|
+
const requestErrorCode = CODEX_PROCESS_EXITED_ERROR_CODE;
|
|
30514
30975
|
if (exitCode == 3221225781) {
|
|
30515
30976
|
throw new RequestError(requestErrorCode, `VC++ redistributable should be installed`);
|
|
30516
30977
|
}
|
|
@@ -31532,10 +31993,17 @@ var sessionSteerParamsParser = external_exports.object({
|
|
|
31532
31993
|
sessionId: external_exports.string(),
|
|
31533
31994
|
prompt: external_exports.array(external_exports.any())
|
|
31534
31995
|
}).passthrough();
|
|
31535
|
-
var goalControlParamsParser = external_exports.
|
|
31536
|
-
|
|
31537
|
-
|
|
31538
|
-
|
|
31996
|
+
var goalControlParamsParser = external_exports.discriminatedUnion("action", [
|
|
31997
|
+
external_exports.object({
|
|
31998
|
+
sessionId: external_exports.string(),
|
|
31999
|
+
action: external_exports.literal("set"),
|
|
32000
|
+
objective: external_exports.string().trim().min(1)
|
|
32001
|
+
}).passthrough(),
|
|
32002
|
+
external_exports.object({
|
|
32003
|
+
sessionId: external_exports.string(),
|
|
32004
|
+
action: external_exports.enum(["pause", "resume", "clear"])
|
|
32005
|
+
}).passthrough()
|
|
32006
|
+
]);
|
|
31539
32007
|
if (process.argv.includes("--version")) {
|
|
31540
32008
|
console.log(`${package_default.name} ${package_default.version}`);
|
|
31541
32009
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.2.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",
|
|
@@ -64,7 +65,7 @@
|
|
|
64
65
|
},
|
|
65
66
|
"dependencies": {
|
|
66
67
|
"@agentclientprotocol/sdk": "^1.3.0",
|
|
67
|
-
"@openai/codex": "^0.
|
|
68
|
+
"@openai/codex": "^0.147.0",
|
|
68
69
|
"diff": "^9.0.0",
|
|
69
70
|
"open": "^11.0.0",
|
|
70
71
|
"vscode-jsonrpc": "^9.0.1",
|