@averyyy/pi-coding-agent 0.85.1-piclient.2 → 0.85.1-piclient.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/bundle/chunks/{chunk-YGXEFPSS.js → chunk-LQDML2ZO.js} +60 -51
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +21 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +26 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +210 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/pi-server-client.d.ts +4 -0
- package/dist/core/pi-server-client.d.ts.map +1 -1
- package/dist/core/pi-server-client.js +162 -46
- package/dist/core/pi-server-client.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +17 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +236 -44
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/package.json +4 -4
|
@@ -30,7 +30,7 @@ import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
|
|
|
30
30
|
import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
|
|
31
31
|
import { emitSessionShutdownEvent } from "./extensions/runner.js";
|
|
32
32
|
import { ModelRegistry } from "./model-registry.js";
|
|
33
|
-
import { compactPiServer } from "./pi-server-client.js";
|
|
33
|
+
import { cancelPiServerOperations, compactPiServer, } from "./pi-server-client.js";
|
|
34
34
|
import { expandPromptTemplate } from "./prompt-templates.js";
|
|
35
35
|
import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
|
|
36
36
|
import { createSyntheticSourceInfo } from "./source-info.js";
|
|
@@ -152,6 +152,10 @@ export class AgentSession {
|
|
|
152
152
|
_isAgentRunActive = false;
|
|
153
153
|
_idleWaitPromise;
|
|
154
154
|
_resolveIdleWait;
|
|
155
|
+
_abortPromise;
|
|
156
|
+
_isAborting = false;
|
|
157
|
+
_abortError;
|
|
158
|
+
_continueAfterAbortRequested = false;
|
|
155
159
|
/** Tracks pending steering messages for UI display. Removed when delivered. */
|
|
156
160
|
_steeringMessages = [];
|
|
157
161
|
/** Tracks pending follow-up messages for UI display. Removed when delivered. */
|
|
@@ -163,15 +167,22 @@ export class AgentSession {
|
|
|
163
167
|
// Compaction state
|
|
164
168
|
_compactionAbortController = undefined;
|
|
165
169
|
_autoCompactionAbortController = undefined;
|
|
170
|
+
_compactionCompletionPromise = undefined;
|
|
171
|
+
_prePromptAbortController = undefined;
|
|
172
|
+
_prePromptCompletionPromise = undefined;
|
|
166
173
|
_overflowRecoveryAttempted = false;
|
|
167
174
|
_lastServerCompactionTimestamp = undefined;
|
|
168
175
|
// Branch summarization state
|
|
169
176
|
_branchSummaryAbortController = undefined;
|
|
177
|
+
_branchSummaryCompletionPromise = undefined;
|
|
170
178
|
// Retry state
|
|
171
179
|
_retryAbortController = undefined;
|
|
172
180
|
_retryAttempt = 0;
|
|
181
|
+
// Post-turn session naming is a provider request too, so cancellation must reach it.
|
|
182
|
+
_sessionNameAbortController = undefined;
|
|
173
183
|
// Bash execution state
|
|
174
184
|
_bashAbortControllers = new Set();
|
|
185
|
+
_bashCompletionPromises = new Set();
|
|
175
186
|
_pendingBashMessages = [];
|
|
176
187
|
// Extension system
|
|
177
188
|
_extensionRunner;
|
|
@@ -743,6 +754,14 @@ export class AgentSession {
|
|
|
743
754
|
get isStreaming() {
|
|
744
755
|
return this._isAgentRunActive;
|
|
745
756
|
}
|
|
757
|
+
/** Whether the current run is being cancelled. New queued intent is drained after cancellation. */
|
|
758
|
+
get isAborting() {
|
|
759
|
+
return this._isAborting;
|
|
760
|
+
}
|
|
761
|
+
/** Error from the most recent cancellation attempt, if it failed. */
|
|
762
|
+
get abortError() {
|
|
763
|
+
return this._abortError;
|
|
764
|
+
}
|
|
746
765
|
/** Whether the session has no active agent run, compaction, branch summary, retry, or queued continuation. */
|
|
747
766
|
get isIdle() {
|
|
748
767
|
return !this._isAgentRunActive && !this.isCompacting;
|
|
@@ -896,11 +915,16 @@ export class AgentSession {
|
|
|
896
915
|
// =========================================================================
|
|
897
916
|
// Prompting
|
|
898
917
|
// =========================================================================
|
|
899
|
-
async
|
|
918
|
+
async _runAgentOperation(start) {
|
|
900
919
|
this._isAgentRunActive = true;
|
|
901
920
|
try {
|
|
902
|
-
await
|
|
921
|
+
await start();
|
|
903
922
|
while (await this._handlePostAgentRun()) {
|
|
923
|
+
// Esc cancels the current agent run. Keep messages queued during that
|
|
924
|
+
// cancellation for the single deferred continuation in abort().
|
|
925
|
+
if (this._isAborting) {
|
|
926
|
+
break;
|
|
927
|
+
}
|
|
904
928
|
try {
|
|
905
929
|
await this.agent.continue();
|
|
906
930
|
}
|
|
@@ -918,7 +942,9 @@ export class AgentSession {
|
|
|
918
942
|
throw error;
|
|
919
943
|
}
|
|
920
944
|
}
|
|
921
|
-
|
|
945
|
+
if (!this._isAborting) {
|
|
946
|
+
await this._maybeGenerateSessionName();
|
|
947
|
+
}
|
|
922
948
|
}
|
|
923
949
|
finally {
|
|
924
950
|
this._systemPromptOverride = undefined;
|
|
@@ -927,6 +953,9 @@ export class AgentSession {
|
|
|
927
953
|
await this._emitAgentSettled();
|
|
928
954
|
}
|
|
929
955
|
}
|
|
956
|
+
async _runAgentPrompt(messages) {
|
|
957
|
+
await this._runAgentOperation(() => this.agent.prompt(messages));
|
|
958
|
+
}
|
|
930
959
|
_sessionHasInfoEntry() {
|
|
931
960
|
return this.sessionManager.getEntries().some((entry) => entry.type === "session_info");
|
|
932
961
|
}
|
|
@@ -960,6 +989,7 @@ export class AgentSession {
|
|
|
960
989
|
const transcript = this._buildSessionNameTranscript();
|
|
961
990
|
if (!model || !transcript)
|
|
962
991
|
return;
|
|
992
|
+
this._sessionNameAbortController = new AbortController();
|
|
963
993
|
try {
|
|
964
994
|
const stream = await this.agent.streamFunction(model, {
|
|
965
995
|
systemPrompt: this.systemPrompt,
|
|
@@ -978,6 +1008,7 @@ export class AgentSession {
|
|
|
978
1008
|
transport: this.agent.transport,
|
|
979
1009
|
thinkingBudgets: this.agent.thinkingBudgets,
|
|
980
1010
|
maxRetryDelayMs: this.agent.maxRetryDelayMs,
|
|
1011
|
+
signal: this._sessionNameAbortController.signal,
|
|
981
1012
|
});
|
|
982
1013
|
for await (const _event of stream) {
|
|
983
1014
|
// Drain the title stream without surfacing it as a chat message.
|
|
@@ -992,6 +1023,9 @@ export class AgentSession {
|
|
|
992
1023
|
catch {
|
|
993
1024
|
// Session naming is a post-turn convenience; the completed assistant turn stays authoritative.
|
|
994
1025
|
}
|
|
1026
|
+
finally {
|
|
1027
|
+
this._sessionNameAbortController = undefined;
|
|
1028
|
+
}
|
|
995
1029
|
}
|
|
996
1030
|
async _handlePostAgentRun() {
|
|
997
1031
|
const msg = this._lastAssistantMessage;
|
|
@@ -999,9 +1033,18 @@ export class AgentSession {
|
|
|
999
1033
|
if (!msg) {
|
|
1000
1034
|
return false;
|
|
1001
1035
|
}
|
|
1036
|
+
if (this._isAborting) {
|
|
1037
|
+
if (isPiServerMode() && this._isTerminalAssistantFailure(msg)) {
|
|
1038
|
+
this._detachPiServerTerminalAssistantFailure();
|
|
1039
|
+
}
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1002
1042
|
if (this._isRetryableError(msg) && (await this._prepareRetry(msg))) {
|
|
1003
1043
|
return true;
|
|
1004
1044
|
}
|
|
1045
|
+
if (this._isAborting) {
|
|
1046
|
+
return false;
|
|
1047
|
+
}
|
|
1005
1048
|
if (msg.stopReason === "error" && this._retryAttempt > 0) {
|
|
1006
1049
|
this._emit({
|
|
1007
1050
|
type: "auto_retry_end",
|
|
@@ -1045,7 +1088,7 @@ export class AgentSession {
|
|
|
1045
1088
|
return;
|
|
1046
1089
|
}
|
|
1047
1090
|
}
|
|
1048
|
-
if (this._compactionAbortController !== undefined) {
|
|
1091
|
+
if (this._compactionAbortController !== undefined && !this._isAborting) {
|
|
1049
1092
|
throw new Error("Cannot submit a prompt while compaction is in progress. Wait for compaction to finish and retry.");
|
|
1050
1093
|
}
|
|
1051
1094
|
// Emit input event for extension interception (before skill/template expansion)
|
|
@@ -1069,7 +1112,7 @@ export class AgentSession {
|
|
|
1069
1112
|
expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
|
|
1070
1113
|
}
|
|
1071
1114
|
// If streaming, queue via steer() or followUp() based on option
|
|
1072
|
-
if (this.isStreaming) {
|
|
1115
|
+
if (this.isStreaming || this._isAborting) {
|
|
1073
1116
|
if (!options?.streamingBehavior) {
|
|
1074
1117
|
throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
|
|
1075
1118
|
}
|
|
@@ -1102,9 +1145,35 @@ export class AgentSession {
|
|
|
1102
1145
|
}
|
|
1103
1146
|
// Check if we need to compact before sending (catches aborted responses).
|
|
1104
1147
|
// The user's new prompt is sent below, so do not call agent.continue() here.
|
|
1148
|
+
if (this._isAborting) {
|
|
1149
|
+
preflightResult?.(false);
|
|
1150
|
+
return;
|
|
1151
|
+
}
|
|
1105
1152
|
const lastAssistant = this._findLastAssistantMessage();
|
|
1106
1153
|
if (lastAssistant) {
|
|
1107
|
-
|
|
1154
|
+
const prePromptAbortController = new AbortController();
|
|
1155
|
+
let resolvePrePromptCompletion;
|
|
1156
|
+
const prePromptCompletion = new Promise((resolve) => {
|
|
1157
|
+
resolvePrePromptCompletion = resolve;
|
|
1158
|
+
});
|
|
1159
|
+
this._prePromptAbortController = prePromptAbortController;
|
|
1160
|
+
this._prePromptCompletionPromise = prePromptCompletion;
|
|
1161
|
+
try {
|
|
1162
|
+
await this._checkCompaction(lastAssistant, false, prePromptAbortController.signal);
|
|
1163
|
+
}
|
|
1164
|
+
finally {
|
|
1165
|
+
if (this._prePromptAbortController === prePromptAbortController) {
|
|
1166
|
+
this._prePromptAbortController = undefined;
|
|
1167
|
+
}
|
|
1168
|
+
if (this._prePromptCompletionPromise === prePromptCompletion) {
|
|
1169
|
+
this._prePromptCompletionPromise = undefined;
|
|
1170
|
+
}
|
|
1171
|
+
resolvePrePromptCompletion?.();
|
|
1172
|
+
}
|
|
1173
|
+
if (prePromptAbortController.signal.aborted || this._isAborting) {
|
|
1174
|
+
preflightResult?.(false);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1108
1177
|
}
|
|
1109
1178
|
if (isPiServerMode()) {
|
|
1110
1179
|
this._detachPiServerTerminalAssistantFailure();
|
|
@@ -1270,6 +1339,9 @@ export class AgentSession {
|
|
|
1270
1339
|
content,
|
|
1271
1340
|
timestamp: Date.now(),
|
|
1272
1341
|
});
|
|
1342
|
+
if (this._isAborting) {
|
|
1343
|
+
this._continueAfterAbortRequested = true;
|
|
1344
|
+
}
|
|
1273
1345
|
}
|
|
1274
1346
|
/**
|
|
1275
1347
|
* Internal: Queue a follow-up message (already expanded, no extension command check).
|
|
@@ -1286,6 +1358,9 @@ export class AgentSession {
|
|
|
1286
1358
|
content,
|
|
1287
1359
|
timestamp: Date.now(),
|
|
1288
1360
|
});
|
|
1361
|
+
if (this._isAborting) {
|
|
1362
|
+
this._continueAfterAbortRequested = true;
|
|
1363
|
+
}
|
|
1289
1364
|
}
|
|
1290
1365
|
/**
|
|
1291
1366
|
* Throw an error if the text is an extension command.
|
|
@@ -1324,12 +1399,18 @@ export class AgentSession {
|
|
|
1324
1399
|
if (options?.deliverAs === "nextTurn") {
|
|
1325
1400
|
this._pendingNextTurnMessages.push(appMessage);
|
|
1326
1401
|
}
|
|
1327
|
-
else if (this.isStreaming && options?.triggerTurn !== false) {
|
|
1402
|
+
else if ((this.isStreaming || this._isAborting) && options?.triggerTurn !== false) {
|
|
1328
1403
|
if (options?.deliverAs === "followUp") {
|
|
1329
1404
|
this.agent.followUp(appMessage);
|
|
1405
|
+
if (this._isAborting) {
|
|
1406
|
+
this._continueAfterAbortRequested = true;
|
|
1407
|
+
}
|
|
1330
1408
|
}
|
|
1331
1409
|
else {
|
|
1332
1410
|
this.agent.steer(appMessage);
|
|
1411
|
+
if (this._isAborting) {
|
|
1412
|
+
this._continueAfterAbortRequested = true;
|
|
1413
|
+
}
|
|
1333
1414
|
}
|
|
1334
1415
|
}
|
|
1335
1416
|
else if (options?.triggerTurn) {
|
|
@@ -1431,15 +1512,79 @@ export class AgentSession {
|
|
|
1431
1512
|
get resourceLoader() {
|
|
1432
1513
|
return this._resourceLoader;
|
|
1433
1514
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1515
|
+
_startQueuedAgentRunAfterAbort() {
|
|
1516
|
+
if (this._isAgentRunActive || this._isAborting || !this.agent.hasQueuedMessages()) {
|
|
1517
|
+
return;
|
|
1518
|
+
}
|
|
1519
|
+
void this._runAgentOperation(() => this.agent.continue()).catch((error) => {
|
|
1520
|
+
this._extensionRunner.emitError({
|
|
1521
|
+
extensionPath: "<runtime>",
|
|
1522
|
+
event: "abort_continuation",
|
|
1523
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1524
|
+
});
|
|
1525
|
+
});
|
|
1526
|
+
}
|
|
1527
|
+
async _performAbort() {
|
|
1438
1528
|
this.abortRetry();
|
|
1439
1529
|
this.abortCompaction();
|
|
1440
1530
|
this.abortBranchSummary();
|
|
1531
|
+
this.abortBash();
|
|
1532
|
+
this._prePromptAbortController?.abort();
|
|
1533
|
+
this._sessionNameAbortController?.abort();
|
|
1441
1534
|
this.agent.abort();
|
|
1442
|
-
|
|
1535
|
+
// _runAgentOperation owns the settled event and the idle waiter. Do not
|
|
1536
|
+
// start a queued continuation until that cleanup has completed.
|
|
1537
|
+
try {
|
|
1538
|
+
const cleanupPromises = [
|
|
1539
|
+
this.waitForIdle(),
|
|
1540
|
+
...(this._compactionCompletionPromise ? [this._compactionCompletionPromise] : []),
|
|
1541
|
+
...(this._prePromptCompletionPromise ? [this._prePromptCompletionPromise] : []),
|
|
1542
|
+
...(this._branchSummaryCompletionPromise ? [this._branchSummaryCompletionPromise] : []),
|
|
1543
|
+
...this._bashCompletionPromises,
|
|
1544
|
+
];
|
|
1545
|
+
if (isPiServerMode()) {
|
|
1546
|
+
cleanupPromises.push(cancelPiServerOperations(this.sessionId));
|
|
1547
|
+
}
|
|
1548
|
+
const cleanupResults = await Promise.allSettled(cleanupPromises);
|
|
1549
|
+
const cleanupFailure = cleanupResults.find((result) => result.status === "rejected");
|
|
1550
|
+
if (cleanupFailure?.status === "rejected") {
|
|
1551
|
+
throw cleanupFailure.reason;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
catch (error) {
|
|
1555
|
+
this._abortError = error instanceof Error ? error.message : String(error);
|
|
1556
|
+
this._abortPromise = undefined;
|
|
1557
|
+
this._emit({ type: "abort_error", errorMessage: this._abortError });
|
|
1558
|
+
throw error;
|
|
1559
|
+
}
|
|
1560
|
+
this._isAborting = false;
|
|
1561
|
+
const continueAfterAbort = this._continueAfterAbortRequested && this.agent.hasQueuedMessages();
|
|
1562
|
+
this._continueAfterAbortRequested = false;
|
|
1563
|
+
this._abortError = undefined;
|
|
1564
|
+
this._abortPromise = undefined;
|
|
1565
|
+
this._emit({ type: "abort_end" });
|
|
1566
|
+
if (continueAfterAbort) {
|
|
1567
|
+
this._startQueuedAgentRunAfterAbort();
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Abort the current operation and wait for cancellation cleanup to finish.
|
|
1572
|
+
* Messages queued while cancellation is in progress are sent in one deferred continuation.
|
|
1573
|
+
*/
|
|
1574
|
+
abort() {
|
|
1575
|
+
if (this._abortPromise) {
|
|
1576
|
+
return this._abortPromise;
|
|
1577
|
+
}
|
|
1578
|
+
if (this._isAborting) {
|
|
1579
|
+
this._abortError = undefined;
|
|
1580
|
+
}
|
|
1581
|
+
else {
|
|
1582
|
+
this._isAborting = true;
|
|
1583
|
+
}
|
|
1584
|
+
const abortPromise = this._performAbort();
|
|
1585
|
+
this._abortPromise = abortPromise;
|
|
1586
|
+
this._emit({ type: "abort_start" });
|
|
1587
|
+
return abortPromise;
|
|
1443
1588
|
}
|
|
1444
1589
|
async waitForIdle() {
|
|
1445
1590
|
if (this.isIdle) {
|
|
@@ -1706,8 +1851,13 @@ export class AgentSession {
|
|
|
1706
1851
|
async compact(customInstructions) {
|
|
1707
1852
|
await this.abort();
|
|
1708
1853
|
this._compactionAbortController = new AbortController();
|
|
1709
|
-
|
|
1854
|
+
let resolveCompactionCompletion;
|
|
1855
|
+
const compactionCompletion = new Promise((resolve) => {
|
|
1856
|
+
resolveCompactionCompletion = resolve;
|
|
1857
|
+
});
|
|
1858
|
+
this._compactionCompletionPromise = compactionCompletion;
|
|
1710
1859
|
try {
|
|
1860
|
+
this._emit({ type: "compaction_start", reason: "manual" });
|
|
1711
1861
|
if (!this.model) {
|
|
1712
1862
|
throw new Error(formatNoModelSelectedMessage());
|
|
1713
1863
|
}
|
|
@@ -1849,6 +1999,11 @@ export class AgentSession {
|
|
|
1849
1999
|
}
|
|
1850
2000
|
finally {
|
|
1851
2001
|
this._clearManualCompactionState();
|
|
2002
|
+
this._compactionAbortController = undefined;
|
|
2003
|
+
if (this._compactionCompletionPromise === compactionCompletion) {
|
|
2004
|
+
this._compactionCompletionPromise = undefined;
|
|
2005
|
+
}
|
|
2006
|
+
resolveCompactionCompletion?.();
|
|
1852
2007
|
}
|
|
1853
2008
|
}
|
|
1854
2009
|
/**
|
|
@@ -1876,7 +2031,9 @@ export class AgentSession {
|
|
|
1876
2031
|
* @param assistantMessage The assistant message to check
|
|
1877
2032
|
* @param skipAbortedCheck If false, include aborted messages (for pre-prompt check). Default: true
|
|
1878
2033
|
*/
|
|
1879
|
-
async _checkCompaction(assistantMessage, skipAbortedCheck = true) {
|
|
2034
|
+
async _checkCompaction(assistantMessage, skipAbortedCheck = true, externalSignal) {
|
|
2035
|
+
if (externalSignal?.aborted)
|
|
2036
|
+
return false;
|
|
1880
2037
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1881
2038
|
if (!settings.enabled)
|
|
1882
2039
|
return false;
|
|
@@ -1909,7 +2066,7 @@ export class AgentSession {
|
|
|
1909
2066
|
if (contextOverflow || recoverableLength) {
|
|
1910
2067
|
const willRetry = assistantMessage.stopReason !== "stop";
|
|
1911
2068
|
if (!willRetry) {
|
|
1912
|
-
return await this._runAutoCompaction("overflow", false);
|
|
2069
|
+
return await this._runAutoCompaction("overflow", false, undefined, undefined, externalSignal);
|
|
1913
2070
|
}
|
|
1914
2071
|
if (this._overflowRecoveryAttempted) {
|
|
1915
2072
|
const errorMessage = contextOverflow
|
|
@@ -1940,7 +2097,7 @@ export class AgentSession {
|
|
|
1940
2097
|
this.agent.state.messages = messages.slice(0, -1);
|
|
1941
2098
|
}
|
|
1942
2099
|
}
|
|
1943
|
-
return await this._runAutoCompaction("overflow", willRetry, terminalFailurePreparation);
|
|
2100
|
+
return await this._runAutoCompaction("overflow", willRetry, terminalFailurePreparation, undefined, externalSignal);
|
|
1944
2101
|
}
|
|
1945
2102
|
// Case 2: Threshold - context is getting large
|
|
1946
2103
|
// For error messages or all-zero usage messages, estimate from the last valid response.
|
|
@@ -1968,25 +2125,33 @@ export class AgentSession {
|
|
|
1968
2125
|
contextTokens = directContextTokens;
|
|
1969
2126
|
}
|
|
1970
2127
|
if (shouldCompact(contextTokens, contextWindow, settings)) {
|
|
1971
|
-
return await this._runAutoCompaction("threshold", false);
|
|
2128
|
+
return await this._runAutoCompaction("threshold", false, undefined, undefined, externalSignal);
|
|
1972
2129
|
}
|
|
1973
2130
|
return false;
|
|
1974
2131
|
}
|
|
1975
2132
|
/**
|
|
1976
2133
|
* Internal: Run auto-compaction with events.
|
|
1977
2134
|
*/
|
|
1978
|
-
async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
|
|
2135
|
+
async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions, externalSignal) {
|
|
1979
2136
|
const settings = this.settingsManager.getCompactionSettings();
|
|
1980
2137
|
let started = false;
|
|
1981
2138
|
let fromExtension = false;
|
|
2139
|
+
if (externalSignal?.aborted)
|
|
2140
|
+
return false;
|
|
2141
|
+
const abortExternal = () => this._autoCompactionAbortController?.abort();
|
|
2142
|
+
externalSignal?.addEventListener("abort", abortExternal, { once: true });
|
|
1982
2143
|
try {
|
|
1983
2144
|
if (!this.model) {
|
|
1984
2145
|
return false;
|
|
1985
2146
|
}
|
|
1986
2147
|
const { model: requestModel, apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);
|
|
2148
|
+
if (externalSignal?.aborted)
|
|
2149
|
+
return false;
|
|
1987
2150
|
if (isPiServerMode()) {
|
|
1988
2151
|
this._emit({ type: "compaction_start", reason });
|
|
1989
2152
|
this._autoCompactionAbortController = new AbortController();
|
|
2153
|
+
if (externalSignal?.aborted)
|
|
2154
|
+
this._autoCompactionAbortController.abort();
|
|
1990
2155
|
started = true;
|
|
1991
2156
|
const signal = this._autoCompactionAbortController.signal;
|
|
1992
2157
|
const piServerResult = await compactPiServer(requestModel, {
|
|
@@ -2004,18 +2169,26 @@ export class AgentSession {
|
|
|
2004
2169
|
reasoning: toProviderReasoning(this.thinkingLevel),
|
|
2005
2170
|
onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
|
|
2006
2171
|
});
|
|
2172
|
+
if (externalSignal?.aborted || signal.aborted) {
|
|
2173
|
+
this._emit({ type: "compaction_end", reason, result: undefined, aborted: true, willRetry: false });
|
|
2174
|
+
return false;
|
|
2175
|
+
}
|
|
2007
2176
|
const result = await this._applyPiServerCompactionResult(piServerResult, reason, willRetry);
|
|
2008
2177
|
this._lastServerCompactionTimestamp = Date.now();
|
|
2009
2178
|
this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
|
|
2010
2179
|
return willRetry ? true : this.agent.hasQueuedMessages();
|
|
2011
2180
|
}
|
|
2012
2181
|
const pathEntries = this.sessionManager.getBranch();
|
|
2182
|
+
if (externalSignal?.aborted)
|
|
2183
|
+
return false;
|
|
2013
2184
|
const preparation = preparationOverride ?? prepareCompaction(pathEntries, settings);
|
|
2014
2185
|
if (!preparation) {
|
|
2015
2186
|
return false;
|
|
2016
2187
|
}
|
|
2017
2188
|
this._emit({ type: "compaction_start", reason });
|
|
2018
2189
|
this._autoCompactionAbortController = new AbortController();
|
|
2190
|
+
if (externalSignal?.aborted)
|
|
2191
|
+
this._autoCompactionAbortController.abort();
|
|
2019
2192
|
started = true;
|
|
2020
2193
|
let extensionCompaction;
|
|
2021
2194
|
if (this._extensionRunner.hasHandlers("session_before_compact")) {
|
|
@@ -2071,7 +2244,7 @@ export class AgentSession {
|
|
|
2071
2244
|
usage = compactResult.usage;
|
|
2072
2245
|
details = compactResult.details;
|
|
2073
2246
|
}
|
|
2074
|
-
if (this._autoCompactionAbortController.signal.aborted) {
|
|
2247
|
+
if (externalSignal?.aborted || this._autoCompactionAbortController.signal.aborted) {
|
|
2075
2248
|
this._emit({
|
|
2076
2249
|
type: "compaction_end",
|
|
2077
2250
|
reason,
|
|
@@ -2154,6 +2327,7 @@ export class AgentSession {
|
|
|
2154
2327
|
return false;
|
|
2155
2328
|
}
|
|
2156
2329
|
finally {
|
|
2330
|
+
externalSignal?.removeEventListener("abort", abortExternal);
|
|
2157
2331
|
this._autoCompactionAbortController = undefined;
|
|
2158
2332
|
this._resolveIdleWaitIfIdle();
|
|
2159
2333
|
}
|
|
@@ -2714,6 +2888,11 @@ export class AgentSession {
|
|
|
2714
2888
|
async executeBash(command, onChunk, options) {
|
|
2715
2889
|
const abortController = new AbortController();
|
|
2716
2890
|
this._bashAbortControllers.add(abortController);
|
|
2891
|
+
let resolveBashCompletion;
|
|
2892
|
+
const bashCompletion = new Promise((resolve) => {
|
|
2893
|
+
resolveBashCompletion = resolve;
|
|
2894
|
+
});
|
|
2895
|
+
this._bashCompletionPromises.add(bashCompletion);
|
|
2717
2896
|
// Apply command prefix if configured (e.g., "shopt -s expand_aliases" for alias support)
|
|
2718
2897
|
const prefix = this.settingsManager.getShellCommandPrefix();
|
|
2719
2898
|
const shellPath = this.settingsManager.getShellPath();
|
|
@@ -2731,6 +2910,8 @@ export class AgentSession {
|
|
|
2731
2910
|
}
|
|
2732
2911
|
finally {
|
|
2733
2912
|
this._bashAbortControllers.delete(abortController);
|
|
2913
|
+
this._bashCompletionPromises.delete(bashCompletion);
|
|
2914
|
+
resolveBashCompletion?.();
|
|
2734
2915
|
}
|
|
2735
2916
|
}
|
|
2736
2917
|
/**
|
|
@@ -2853,6 +3034,11 @@ export class AgentSession {
|
|
|
2853
3034
|
};
|
|
2854
3035
|
// Set up abort controller for summarization
|
|
2855
3036
|
this._branchSummaryAbortController = new AbortController();
|
|
3037
|
+
let resolveBranchSummaryCompletion;
|
|
3038
|
+
const branchSummaryCompletion = new Promise((resolve) => {
|
|
3039
|
+
resolveBranchSummaryCompletion = resolve;
|
|
3040
|
+
});
|
|
3041
|
+
this._branchSummaryCompletionPromise = branchSummaryCompletion;
|
|
2856
3042
|
try {
|
|
2857
3043
|
let extensionSummary;
|
|
2858
3044
|
let fromExtension = false;
|
|
@@ -2977,6 +3163,10 @@ export class AgentSession {
|
|
|
2977
3163
|
}
|
|
2978
3164
|
finally {
|
|
2979
3165
|
this._branchSummaryAbortController = undefined;
|
|
3166
|
+
if (this._branchSummaryCompletionPromise === branchSummaryCompletion) {
|
|
3167
|
+
this._branchSummaryCompletionPromise = undefined;
|
|
3168
|
+
}
|
|
3169
|
+
resolveBranchSummaryCompletion?.();
|
|
2980
3170
|
this._resolveIdleWaitIfIdle();
|
|
2981
3171
|
}
|
|
2982
3172
|
}
|