@averyyy/pi-coding-agent 0.82.1-piclient.5 → 0.82.1-piclient.7

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +0 -12
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +1 -2
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  6. package/dist/core/agent-session-runtime.js +0 -5
  7. package/dist/core/agent-session-runtime.js.map +1 -1
  8. package/dist/core/agent-session.d.ts +1 -12
  9. package/dist/core/agent-session.d.ts.map +1 -1
  10. package/dist/core/agent-session.js +89 -314
  11. package/dist/core/agent-session.js.map +1 -1
  12. package/dist/core/pi-server-client.d.ts +2 -53
  13. package/dist/core/pi-server-client.d.ts.map +1 -1
  14. package/dist/core/pi-server-client.js +271 -2063
  15. package/dist/core/pi-server-client.js.map +1 -1
  16. package/dist/core/pi-server-protocol.d.ts +0 -2
  17. package/dist/core/pi-server-protocol.d.ts.map +1 -1
  18. package/dist/core/pi-server-protocol.js +1 -24
  19. package/dist/core/pi-server-protocol.js.map +1 -1
  20. package/dist/core/pi-server-request.d.ts +0 -28
  21. package/dist/core/pi-server-request.d.ts.map +1 -1
  22. package/dist/core/pi-server-request.js +75 -492
  23. package/dist/core/pi-server-request.js.map +1 -1
  24. package/dist/core/sdk.d.ts.map +1 -1
  25. package/dist/core/sdk.js +53 -69
  26. package/dist/core/sdk.js.map +1 -1
  27. package/dist/core/session-manager.d.ts +2 -86
  28. package/dist/core/session-manager.d.ts.map +1 -1
  29. package/dist/core/session-manager.js +144 -737
  30. package/dist/core/session-manager.js.map +1 -1
  31. package/dist/core/tools/output-accumulator.d.ts +1 -3
  32. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  33. package/dist/core/tools/output-accumulator.js +26 -46
  34. package/dist/core/tools/output-accumulator.js.map +1 -1
  35. package/dist/main.d.ts.map +1 -1
  36. package/dist/main.js +0 -13
  37. package/dist/main.js.map +1 -1
  38. package/dist/modes/interactive/components/session-selector.d.ts +0 -15
  39. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  40. package/dist/modes/interactive/components/session-selector.js +29 -98
  41. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  42. package/package.json +4 -4
  43. package/dist/cli/tool-effects.d.ts +0 -6
  44. package/dist/cli/tool-effects.d.ts.map +0 -1
  45. package/dist/cli/tool-effects.js +0 -164
  46. package/dist/cli/tool-effects.js.map +0 -1
  47. package/dist/core/pi-server-compact-state.d.ts +0 -81
  48. package/dist/core/pi-server-compact-state.d.ts.map +0 -1
  49. package/dist/core/pi-server-compact-state.js +0 -438
  50. package/dist/core/pi-server-compact-state.js.map +0 -1
  51. package/dist/core/pi-server-run-state.d.ts +0 -41
  52. package/dist/core/pi-server-run-state.d.ts.map +0 -1
  53. package/dist/core/pi-server-run-state.js +0 -318
  54. package/dist/core/pi-server-run-state.js.map +0 -1
  55. package/dist/core/tool-effect-journal.d.ts +0 -103
  56. package/dist/core/tool-effect-journal.d.ts.map +0 -1
  57. package/dist/core/tool-effect-journal.js +0 -1442
  58. package/dist/core/tool-effect-journal.js.map +0 -1
@@ -12,7 +12,6 @@
12
12
  *
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
- import { randomUUID } from "node:crypto";
16
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
16
  import { basename, dirname } from "node:path";
18
17
  import { contentText } from "@earendil-works/pi-ai";
@@ -30,14 +29,11 @@ import { createToolHtmlRenderer } from "./export-html/tool-renderer.js";
30
29
  import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
31
30
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
32
31
  import { ModelRegistry } from "./model-registry.js";
33
- import { acknowledgePiServerCompaction, acknowledgePiServerRunMessage, acquirePiServerSessionLease, compactPiServer, getPiServerRunDiagnostic, recordPiServerCompactionApplied, recoverPendingPiServerCompaction, releasePiServerRunLease, releasePiServerSessionLease, syncPiServerTree, } from "./pi-server-client.js";
34
- import { getPiServerCompactStatePath, readPiServerPendingCompact } from "./pi-server-compact-state.js";
35
- import { getPiServerRunStatePath, readPiServerPendingRun } from "./pi-server-run-state.js";
32
+ import { compactPiServer, syncPiServerTree, } from "./pi-server-client.js";
36
33
  import { expandPromptTemplate } from "./prompt-templates.js";
37
34
  import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
38
35
  import { createSyntheticSourceInfo } from "./source-info.js";
39
36
  import { buildSystemPrompt } from "./system-prompt.js";
40
- import { beginSessionToolEffect, beginSessionToolEffectFinalization, commitSessionToolEffect, recoverToolEffects, writeSessionToolEffectFinalResult, writeSessionToolEffectResult, } from "./tool-effect-journal.js";
41
37
  import { createLocalBashOperations } from "./tools/bash.js";
42
38
  import { createAllToolDefinitions } from "./tools/index.js";
43
39
  import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
@@ -97,26 +93,16 @@ function getStringField(input, key) {
97
93
  const value = input[key];
98
94
  return typeof value === "string" && value.trim().length > 0 ? value : undefined;
99
95
  }
100
- function getPiServerFailureMetadata(message) {
96
+ function getPiServerFailurePhase(message) {
101
97
  for (const diagnostic of message.diagnostics ?? []) {
102
98
  if (diagnostic.type !== "pi_server_failure")
103
99
  continue;
104
100
  const phase = diagnostic.details?.phase;
105
- const retryable = diagnostic.details?.retryable;
106
- return {
107
- phase: typeof phase === "string" ? phase : undefined,
108
- retryable: typeof retryable === "boolean" ? retryable : undefined,
109
- };
101
+ if (typeof phase === "string")
102
+ return phase;
110
103
  }
111
104
  return undefined;
112
105
  }
113
- function isPiServerControlPlaneFailure(message) {
114
- const hasFailure = message.diagnostics?.some((diagnostic) => diagnostic.type === "pi_server_failure") === true;
115
- return hasFailure && getPiServerRunDiagnostic(message) === undefined;
116
- }
117
- function isPiServerRestartUncertainty(message) {
118
- return getPiServerRunDiagnostic(message)?.restartUnknown === true;
119
- }
120
106
  function toolTextContent(content) {
121
107
  return content
122
108
  .filter((part) => part.type === "text")
@@ -179,7 +165,6 @@ export class AgentSession {
179
165
  _isAgentRunActive = false;
180
166
  _idleWaitPromise;
181
167
  _resolveIdleWait;
182
- _toolResultsInFinalization = new WeakSet();
183
168
  /** Tracks pending steering messages for UI display. Removed when delivered. */
184
169
  _steeringMessages = [];
185
170
  /** Tracks pending follow-up messages for UI display. Removed when delivered. */
@@ -191,7 +176,6 @@ export class AgentSession {
191
176
  _autoCompactionAbortController = undefined;
192
177
  _overflowRecoveryAttempted = false;
193
178
  _lastServerCompactionTimestamp = undefined;
194
- _piServerSessionLeaseOwner;
195
179
  // Branch summarization state
196
180
  _branchSummaryAbortController = undefined;
197
181
  // Retry state
@@ -224,7 +208,6 @@ export class AgentSession {
224
208
  _extensionErrorUnsubscriber;
225
209
  _autoSessionNameEnabled;
226
210
  _autoSessionNameAttempted = false;
227
- _auxiliaryStreamFunction;
228
211
  _modelRuntime;
229
212
  // Tool registry for extension getTools/setTools
230
213
  _toolRegistry = new Map();
@@ -244,7 +227,6 @@ export class AgentSession {
244
227
  this._customTools = config.customTools ?? [];
245
228
  this._cwd = config.cwd;
246
229
  this._modelRuntime = config.modelRuntime;
247
- this._auxiliaryStreamFunction = config.auxiliaryStreamFunction;
248
230
  this._extensionRunnerRef = config.extensionRunnerRef;
249
231
  this._initialActiveToolNames = config.initialActiveToolNames;
250
232
  this._allowedToolNames = config.allowedToolNames ? new Set(config.allowedToolNames) : undefined;
@@ -252,10 +234,6 @@ export class AgentSession {
252
234
  this._baseToolsOverride = config.baseToolsOverride;
253
235
  this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
254
236
  this._autoSessionNameEnabled = config.autoSessionName ?? true;
255
- const toolEffectRecovery = recoverToolEffects(this.sessionManager);
256
- if (toolEffectRecovery.recoveredToolCallIds.length > 0) {
257
- this.agent.state.messages = this.sessionManager.buildSessionContext().messages;
258
- }
259
237
  if (isPiServerMode()) {
260
238
  this._detachPiServerTerminalAssistantFailure();
261
239
  }
@@ -272,9 +250,6 @@ export class AgentSession {
272
250
  get modelRuntime() {
273
251
  return this._modelRuntime;
274
252
  }
275
- _getAuxiliaryStreamFunction() {
276
- return this._auxiliaryStreamFunction ?? this.agent.streamFunction;
277
- }
278
253
  reconcilePiServerHistory(snapshot) {
279
254
  this.sessionManager.replaceTree(snapshot.entries, snapshot.leafId);
280
255
  const sessionContext = this.sessionManager.buildSessionContext();
@@ -285,102 +260,6 @@ export class AgentSession {
285
260
  messageCount: snapshot.messages.length,
286
261
  });
287
262
  }
288
- async _syncAndAcknowledgePiServerAssistantMessage(message, signal) {
289
- const persistenceSignal = signal.aborted ? undefined : signal;
290
- const sessionFile = this.sessionManager.getSessionFile();
291
- const runStatePath = sessionFile ? getPiServerRunStatePath(sessionFile) : undefined;
292
- try {
293
- await syncPiServerTree(this.sessionId, {
294
- systemPrompt: this.systemPrompt,
295
- messages: this.agent.state.messages,
296
- tools: this.agent.state.tools,
297
- }, { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() }, {
298
- signal: persistenceSignal,
299
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
300
- });
301
- this.sessionManager.flushSessionFile();
302
- await acknowledgePiServerRunMessage(this.sessionId, message, runStatePath, persistenceSignal);
303
- }
304
- catch (error) {
305
- releasePiServerRunLease(this.sessionId, runStatePath);
306
- throw error;
307
- }
308
- }
309
- _acquirePiServerOperationLease(reentrantOwner) {
310
- if (!isPiServerMode())
311
- return { path: undefined, acquired: false, owner: undefined };
312
- const sessionFile = this.sessionManager.getSessionFile();
313
- const path = sessionFile ? getPiServerRunStatePath(sessionFile) : undefined;
314
- if (this._piServerSessionLeaseOwner) {
315
- if (reentrantOwner !== this._piServerSessionLeaseOwner) {
316
- throw new Error(`Cannot start a concurrent durable pi-server operation for session ${this.sessionId}`);
317
- }
318
- return { path, acquired: false, owner: this._piServerSessionLeaseOwner };
319
- }
320
- const owner = Symbol("pi-server-session-lease");
321
- if (path)
322
- acquirePiServerSessionLease(this.sessionId, path);
323
- this._piServerSessionLeaseOwner = owner;
324
- return { path, acquired: true, owner };
325
- }
326
- _releasePiServerOperationLease(path, acquired, owner) {
327
- if (!acquired)
328
- return;
329
- if (!owner || this._piServerSessionLeaseOwner !== owner) {
330
- throw new Error(`Cannot release a durable pi-server operation lease owned by another operation`);
331
- }
332
- if (path)
333
- releasePiServerSessionLease(this.sessionId, path);
334
- this._piServerSessionLeaseOwner = undefined;
335
- }
336
- async _recoverPendingPiServerRunBeforeControlOperation(signal) {
337
- if (!isPiServerMode())
338
- return;
339
- const sessionFile = this.sessionManager.getSessionFile();
340
- if (!sessionFile) {
341
- throw new Error("Durable pi-server operations require a persisted session file");
342
- }
343
- const runStatePath = getPiServerRunStatePath(sessionFile);
344
- const pending = readPiServerPendingRun(runStatePath);
345
- if (!pending)
346
- return;
347
- let terminal;
348
- const entries = this.sessionManager.getEntries();
349
- for (let index = entries.length - 1; index >= 0; index--) {
350
- const entry = entries[index];
351
- if (entry.type !== "message" || entry.message.role !== "assistant")
352
- continue;
353
- const message = entry.message;
354
- const diagnostic = getPiServerRunDiagnostic(message);
355
- if (!diagnostic || diagnostic.runId !== pending.runId)
356
- continue;
357
- if (diagnostic.sessionId !== pending.sessionId ||
358
- diagnostic.requestMac !== pending.requestHash ||
359
- pending.sessionId !== this.sessionId) {
360
- throw new Error("Pending pi-server run terminal does not match its durable client marker");
361
- }
362
- terminal = message;
363
- break;
364
- }
365
- if (!terminal) {
366
- throw new Error(`Cannot start compaction while pi-server run ${pending.runId} is pending without a durable terminal assistant`);
367
- }
368
- await this._syncAndAcknowledgePiServerAssistantMessage(terminal, signal ?? new AbortController().signal);
369
- }
370
- async _recoverPendingPiServerCompaction(reason, willRetry, signal) {
371
- if (!isPiServerMode())
372
- return undefined;
373
- const sessionFile = this.sessionManager.getSessionFile();
374
- if (!sessionFile)
375
- return undefined;
376
- const compactStatePath = getPiServerCompactStatePath(sessionFile);
377
- if (!readPiServerPendingCompact(compactStatePath))
378
- return undefined;
379
- const result = await recoverPendingPiServerCompaction(this.sessionId, { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() }, compactStatePath, { signal });
380
- if (!result)
381
- return undefined;
382
- return this._applyPiServerCompactionResult(result, reason, willRetry);
383
- }
384
263
  async _getRequiredRequestAuth(model) {
385
264
  let result;
386
265
  try {
@@ -409,7 +288,7 @@ export class AgentSession {
409
288
  throw new Error(formatNoApiKeyFoundMessage(model.provider));
410
289
  }
411
290
  async _getSummarizationRequestAuth(model) {
412
- if (this._getAuxiliaryStreamFunction() === streamSimple) {
291
+ if (this.agent.streamFunction === streamSimple) {
413
292
  return this._getRequiredRequestAuth(model);
414
293
  }
415
294
  try {
@@ -601,33 +480,18 @@ export class AgentSession {
601
480
  }
602
481
  async _emitAgentSettled() {
603
482
  this._isAgentRunActive = false;
604
- await this._extensionRunner.emit({ type: "agent_settled" });
605
- this._emit({ type: "agent_settled" });
483
+ try {
484
+ await this._extensionRunner.emit({ type: "agent_settled" });
485
+ this._emit({ type: "agent_settled" });
486
+ }
487
+ finally {
488
+ this._resolveIdleWaitIfIdle();
489
+ }
606
490
  }
607
491
  // Track last assistant message for auto-compaction check
608
492
  _lastAssistantMessage = undefined;
609
493
  /** Internal handler for agent events - shared by subscribe and reconnect */
610
494
  _handleAgentEvent = async (event, signal) => {
611
- if (event.type === "tool_execution_start") {
612
- beginSessionToolEffect(this.sessionManager, event);
613
- }
614
- else if (event.type === "tool_execution_end") {
615
- writeSessionToolEffectResult(this.sessionManager, event.toolResult, { finalizationPending: true });
616
- this._toolResultsInFinalization.add(event.toolResult);
617
- }
618
- else if (event.type === "message_start" &&
619
- event.message.role === "toolResult" &&
620
- !this._toolResultsInFinalization.has(event.message)) {
621
- beginSessionToolEffectFinalization(this.sessionManager, event.message);
622
- this._toolResultsInFinalization.add(event.message);
623
- }
624
- else if (event.type === "message_end" &&
625
- event.message.role === "toolResult" &&
626
- !this._toolResultsInFinalization.has(event.message)) {
627
- beginSessionToolEffectFinalization(this.sessionManager, event.message);
628
- this._toolResultsInFinalization.add(event.message);
629
- }
630
- const finalizingToolResult = event.type === "message_end" && this._toolResultsInFinalization.has(event.message);
631
495
  // When a user message starts, check if it's from either queue and remove it BEFORE emitting
632
496
  // This ensures the UI sees the updated queue state
633
497
  if (event.type === "message_start" && event.message.role === "user") {
@@ -654,13 +518,6 @@ export class AgentSession {
654
518
  await this._emitExtensionEvent(event);
655
519
  // Notify all listeners
656
520
  this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
657
- if (finalizingToolResult) {
658
- if (event.message.role !== "toolResult") {
659
- throw new Error("A toolResult message_end replacement must remain a toolResult");
660
- }
661
- writeSessionToolEffectFinalResult(this.sessionManager, event.message);
662
- this._toolResultsInFinalization.delete(event.message);
663
- }
664
521
  // Handle session persistence
665
522
  if (event.type === "message_end") {
666
523
  // Check if this is a custom message from extensions
@@ -672,11 +529,7 @@ export class AgentSession {
672
529
  event.message.role === "assistant" ||
673
530
  event.message.role === "toolResult") {
674
531
  // Regular LLM message - persist as SessionMessageEntry
675
- const sessionEntryId = this.sessionManager.appendMessage(event.message);
676
- if (event.message.role === "toolResult") {
677
- this.sessionManager.flushSessionFile();
678
- commitSessionToolEffect(this.sessionManager, event.message, sessionEntryId);
679
- }
532
+ this.sessionManager.appendMessage(event.message);
680
533
  }
681
534
  // Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
682
535
  // Track assistant message for auto-compaction (checked on agent_end)
@@ -696,10 +549,12 @@ export class AgentSession {
696
549
  });
697
550
  this._retryAttempt = 0;
698
551
  }
699
- if (isPiServerMode() &&
700
- !this._isPostAssistantPiServerSyncFailure(assistantMsg) &&
701
- !isPiServerControlPlaneFailure(assistantMsg)) {
702
- await this._syncAndAcknowledgePiServerAssistantMessage(assistantMsg, signal);
552
+ if (isPiServerMode() && !this._isTerminalAssistantFailure(assistantMsg)) {
553
+ await syncPiServerTree(this.sessionId, {
554
+ systemPrompt: this.systemPrompt,
555
+ messages: this.agent.state.messages,
556
+ tools: this.agent.state.tools,
557
+ }, { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() }, { signal, onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot) });
703
558
  }
704
559
  }
705
560
  }
@@ -965,7 +820,7 @@ export class AgentSession {
965
820
  }
966
821
  /** Whether the session has no active agent run, retry, auto-compaction, or queued continuation. */
967
822
  get isIdle() {
968
- return !this._isAgentRunActive && !this._piServerSessionLeaseOwner;
823
+ return !this._isAgentRunActive;
969
824
  }
970
825
  /** Current effective system prompt (includes any per-turn extension modifications) */
971
826
  get systemPrompt() {
@@ -1117,11 +972,9 @@ export class AgentSession {
1117
972
  // Prompting
1118
973
  // =========================================================================
1119
974
  async _runAgentPrompt(messages) {
1120
- const piServerLease = this._acquirePiServerOperationLease();
1121
975
  this._resetValidationHintState();
1122
976
  this._isAgentRunActive = true;
1123
977
  try {
1124
- await this._recoverPendingPiServerCompaction("threshold", false);
1125
978
  await this.agent.prompt(messages);
1126
979
  while (await this._handlePostAgentRun()) {
1127
980
  try {
@@ -1144,15 +997,9 @@ export class AgentSession {
1144
997
  await this._maybeGenerateSessionName();
1145
998
  }
1146
999
  finally {
1147
- try {
1148
- this._systemPromptOverride = undefined;
1149
- this._flushPendingBashMessages();
1150
- await this._emitAgentSettled();
1151
- }
1152
- finally {
1153
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
1154
- this._resolveIdleWaitIfIdle();
1155
- }
1000
+ this._systemPromptOverride = undefined;
1001
+ this._flushPendingBashMessages();
1002
+ await this._emitAgentSettled();
1156
1003
  }
1157
1004
  }
1158
1005
  _sessionHasInfoEntry() {
@@ -1189,7 +1036,7 @@ export class AgentSession {
1189
1036
  if (!model || !transcript)
1190
1037
  return;
1191
1038
  try {
1192
- const stream = await this._getAuxiliaryStreamFunction()(model, {
1039
+ const stream = await this.agent.streamFunction(model, {
1193
1040
  systemPrompt: this.systemPrompt,
1194
1041
  messages: [
1195
1042
  {
@@ -1202,7 +1049,7 @@ export class AgentSession {
1202
1049
  }, {
1203
1050
  maxTokens: 32,
1204
1051
  reasoning: undefined,
1205
- sessionId: randomUUID(),
1052
+ sessionId: this.sessionId,
1206
1053
  transport: this.agent.transport,
1207
1054
  thinkingBudgets: this.agent.thinkingBudgets,
1208
1055
  maxRetryDelayMs: this.agent.maxRetryDelayMs,
@@ -1835,26 +1682,9 @@ export class AgentSession {
1835
1682
  // Compaction
1836
1683
  // =========================================================================
1837
1684
  async _applyPiServerCompactionResult(result, reason, willRetry) {
1838
- const compactionEntry = result.compactionEntry;
1839
- const operation = compactionEntry.piServerCompactOperation;
1840
- if (!operation ||
1841
- !Number.isSafeInteger(operation.baseEntryCount) ||
1842
- operation.baseEntryCount < 0 ||
1843
- (operation.baseLeafId !== null &&
1844
- (typeof operation.baseLeafId !== "string" || operation.baseLeafId.length === 0)) ||
1845
- typeof operation.baseTreeHash !== "string" ||
1846
- !/^[a-f0-9]{64}$/u.test(operation.baseTreeHash)) {
1847
- throw new Error("Pi-server compaction result is missing a valid durable base identity");
1848
- }
1849
- this.sessionManager.appendCompactionEntry(compactionEntry, {
1850
- baseEntryCount: operation.baseEntryCount,
1851
- baseLeafId: operation.baseLeafId,
1852
- baseTreeHash: operation.baseTreeHash,
1853
- });
1854
- recordPiServerCompactionApplied(result);
1685
+ this.sessionManager.replaceTree(result.entries, result.leafId);
1855
1686
  const sessionContext = this.sessionManager.buildSessionContext();
1856
1687
  this.agent.state.messages = sessionContext.messages;
1857
- await acknowledgePiServerCompaction(result);
1858
1688
  const firstKeptEntryId = result.compaction.firstKeptEntryId;
1859
1689
  if (!firstKeptEntryId) {
1860
1690
  throw new Error("Pi-server compaction result is missing firstKeptEntryId");
@@ -1873,7 +1703,7 @@ export class AgentSession {
1873
1703
  await this._extensionRunner.emit({
1874
1704
  type: "session_compact",
1875
1705
  compactionEntry: savedCompactionEntry,
1876
- fromExtension: savedCompactionEntry.fromHook === true,
1706
+ fromExtension: false,
1877
1707
  reason,
1878
1708
  willRetry,
1879
1709
  });
@@ -1890,31 +1720,38 @@ export class AgentSession {
1890
1720
  await this.abort();
1891
1721
  this._compactionAbortController = new AbortController();
1892
1722
  this._emit({ type: "compaction_start", reason: "manual" });
1893
- let piServerLease = {
1894
- path: undefined,
1895
- acquired: false,
1896
- owner: undefined,
1897
- };
1898
1723
  try {
1899
- piServerLease = this._acquirePiServerOperationLease();
1900
- await this._recoverPendingPiServerRunBeforeControlOperation(this._compactionAbortController.signal);
1901
- const recoveredCompaction = await this._recoverPendingPiServerCompaction("manual", false, this._compactionAbortController.signal);
1902
- if (recoveredCompaction) {
1903
- this._emit({
1904
- type: "compaction_end",
1905
- reason: "manual",
1906
- result: recoveredCompaction,
1907
- aborted: false,
1908
- willRetry: false,
1909
- });
1910
- return recoveredCompaction;
1911
- }
1912
1724
  if (!this.model) {
1913
1725
  throw new Error(formatNoModelSelectedMessage());
1914
1726
  }
1915
1727
  const { apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);
1916
1728
  if (isPiServerMode()) {
1917
1729
  this._detachPiServerTerminalAssistantFailure();
1730
+ const piServerResult = await compactPiServer(this.model, {
1731
+ systemPrompt: this.systemPrompt,
1732
+ messages: this.agent.state.messages,
1733
+ tools: this.agent.state.tools,
1734
+ }, {
1735
+ sessionId: this.sessionId,
1736
+ apiKey,
1737
+ headers,
1738
+ customInstructions,
1739
+ settings: this.settingsManager.getCompactionSettings(),
1740
+ sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
1741
+ signal: this._compactionAbortController.signal,
1742
+ reasoning: toProviderReasoning(this.thinkingLevel),
1743
+ onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
1744
+ });
1745
+ const result = await this._applyPiServerCompactionResult(piServerResult, "manual", false);
1746
+ this._lastServerCompactionTimestamp = Date.now();
1747
+ this._emit({
1748
+ type: "compaction_end",
1749
+ reason: "manual",
1750
+ result,
1751
+ aborted: false,
1752
+ willRetry: false,
1753
+ });
1754
+ return result;
1918
1755
  }
1919
1756
  const pathEntries = this.sessionManager.getBranch();
1920
1757
  const settings = this.settingsManager.getCompactionSettings();
@@ -1947,42 +1784,6 @@ export class AgentSession {
1947
1784
  fromExtension = true;
1948
1785
  }
1949
1786
  }
1950
- if (isPiServerMode()) {
1951
- const sessionFile = this.sessionManager.getSessionFile();
1952
- if (!sessionFile) {
1953
- throw new Error("Durable pi-server compaction requires a persisted session file");
1954
- }
1955
- const piServerResult = await compactPiServer(this.model, {
1956
- systemPrompt: this.systemPrompt,
1957
- messages: this.agent.state.messages,
1958
- tools: this.agent.state.tools,
1959
- }, {
1960
- sessionId: this.sessionId,
1961
- apiKey,
1962
- headers,
1963
- env,
1964
- customInstructions,
1965
- settings,
1966
- preparation: { firstKeptEntryId: preparation.firstKeptEntryId },
1967
- extensionCompaction,
1968
- retry: this.settingsManager.getRetrySettings(),
1969
- sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
1970
- piServerCompactStatePath: getPiServerCompactStatePath(sessionFile),
1971
- signal: this._compactionAbortController.signal,
1972
- reasoning: toProviderReasoning(this.thinkingLevel),
1973
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
1974
- });
1975
- const result = await this._applyPiServerCompactionResult(piServerResult, "manual", false);
1976
- this._lastServerCompactionTimestamp = Date.now();
1977
- this._emit({
1978
- type: "compaction_end",
1979
- reason: "manual",
1980
- result,
1981
- aborted: false,
1982
- willRetry: false,
1983
- });
1984
- return result;
1985
- }
1986
1787
  let summary;
1987
1788
  let firstKeptEntryId;
1988
1789
  let tokensBefore;
@@ -1998,7 +1799,7 @@ export class AgentSession {
1998
1799
  }
1999
1800
  else {
2000
1801
  // Generate compaction result
2001
- const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this._getAuxiliaryStreamFunction(), env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }));
1802
+ const result = await compact(preparation, this.model, apiKey, headers, customInstructions, this._compactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }));
2002
1803
  summary = result.summary;
2003
1804
  firstKeptEntryId = result.firstKeptEntryId;
2004
1805
  tokensBefore = result.tokensBefore;
@@ -2055,7 +1856,6 @@ export class AgentSession {
2055
1856
  throw error;
2056
1857
  }
2057
1858
  finally {
2058
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
2059
1859
  this._compactionAbortController = undefined;
2060
1860
  this._reconnectToAgent();
2061
1861
  }
@@ -2179,33 +1979,45 @@ export class AgentSession {
2179
1979
  */
2180
1980
  async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
2181
1981
  const settings = this.settingsManager.getCompactionSettings();
2182
- const model = this.model;
2183
1982
  let started = false;
2184
- let piServerLease = {
2185
- path: undefined,
2186
- acquired: false,
2187
- owner: undefined,
2188
- };
2189
1983
  try {
2190
- piServerLease = this._acquirePiServerOperationLease(this._isAgentRunActive ? this._piServerSessionLeaseOwner : undefined);
2191
- if (!this._isAgentRunActive) {
2192
- await this._recoverPendingPiServerRunBeforeControlOperation();
1984
+ if (!this.model) {
1985
+ return false;
2193
1986
  }
2194
- const recoveredCompaction = await this._recoverPendingPiServerCompaction(reason, willRetry);
2195
- if (recoveredCompaction) {
1987
+ let apiKey;
1988
+ let headers;
1989
+ let env;
1990
+ if (this.agent.streamFunction === streamSimple) {
1991
+ ({ apiKey, headers, env } = await this._getRequiredRequestAuth(this.model));
1992
+ }
1993
+ else {
1994
+ ({ apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model));
1995
+ }
1996
+ if (isPiServerMode()) {
2196
1997
  this._emit({ type: "compaction_start", reason });
1998
+ this._autoCompactionAbortController = new AbortController();
2197
1999
  started = true;
2000
+ const signal = this._autoCompactionAbortController.signal;
2001
+ const piServerResult = await compactPiServer(this.model, {
2002
+ systemPrompt: this.systemPrompt,
2003
+ messages: this.agent.state.messages,
2004
+ tools: this.agent.state.tools,
2005
+ }, {
2006
+ sessionId: this.sessionId,
2007
+ apiKey,
2008
+ headers,
2009
+ settings,
2010
+ preparation: preparationOptions,
2011
+ sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
2012
+ signal,
2013
+ reasoning: toProviderReasoning(this.thinkingLevel),
2014
+ onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
2015
+ });
2016
+ const result = await this._applyPiServerCompactionResult(piServerResult, reason, willRetry);
2198
2017
  this._lastServerCompactionTimestamp = Date.now();
2199
- this._emit({ type: "compaction_end", reason, result: recoveredCompaction, aborted: false, willRetry });
2018
+ this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
2200
2019
  return willRetry ? true : this.agent.hasQueuedMessages();
2201
2020
  }
2202
- if (!model) {
2203
- return false;
2204
- }
2205
- let apiKey;
2206
- let headers;
2207
- let env;
2208
- ({ apiKey, headers, env } = await this._getSummarizationRequestAuth(model));
2209
2021
  const pathEntries = this.sessionManager.getBranch();
2210
2022
  const preparation = preparationOverride ?? prepareCompaction(pathEntries, settings);
2211
2023
  if (!preparation) {
@@ -2214,7 +2026,6 @@ export class AgentSession {
2214
2026
  this._emit({ type: "compaction_start", reason });
2215
2027
  this._autoCompactionAbortController = new AbortController();
2216
2028
  started = true;
2217
- const signal = this._autoCompactionAbortController.signal;
2218
2029
  let extensionCompaction;
2219
2030
  let fromExtension = false;
2220
2031
  if (this._extensionRunner.hasHandlers("session_before_compact")) {
@@ -2225,7 +2036,7 @@ export class AgentSession {
2225
2036
  customInstructions: undefined,
2226
2037
  reason,
2227
2038
  willRetry,
2228
- signal,
2039
+ signal: this._autoCompactionAbortController.signal,
2229
2040
  }));
2230
2041
  if (extensionResult?.cancel) {
2231
2042
  this._emit({
@@ -2242,35 +2053,6 @@ export class AgentSession {
2242
2053
  fromExtension = true;
2243
2054
  }
2244
2055
  }
2245
- if (isPiServerMode()) {
2246
- const sessionFile = this.sessionManager.getSessionFile();
2247
- if (!sessionFile) {
2248
- throw new Error("Durable pi-server compaction requires a persisted session file");
2249
- }
2250
- const piServerResult = await compactPiServer(model, {
2251
- systemPrompt: this.systemPrompt,
2252
- messages: this.agent.state.messages,
2253
- tools: this.agent.state.tools,
2254
- }, {
2255
- sessionId: this.sessionId,
2256
- apiKey,
2257
- headers,
2258
- env,
2259
- settings,
2260
- retry: this.settingsManager.getRetrySettings(),
2261
- preparation: preparationOptions ?? { firstKeptEntryId: preparation.firstKeptEntryId },
2262
- extensionCompaction,
2263
- sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
2264
- piServerCompactStatePath: getPiServerCompactStatePath(sessionFile),
2265
- signal,
2266
- reasoning: toProviderReasoning(this.thinkingLevel),
2267
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
2268
- });
2269
- const result = await this._applyPiServerCompactionResult(piServerResult, reason, willRetry);
2270
- this._lastServerCompactionTimestamp = Date.now();
2271
- this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
2272
- return willRetry ? true : this.agent.hasQueuedMessages();
2273
- }
2274
2056
  let summary;
2275
2057
  let firstKeptEntryId;
2276
2058
  let tokensBefore;
@@ -2286,7 +2068,7 @@ export class AgentSession {
2286
2068
  }
2287
2069
  else {
2288
2070
  // Generate compaction result
2289
- const compactResult = await compact(preparation, model, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this._getAuxiliaryStreamFunction(), env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }));
2071
+ const compactResult = await compact(preparation, this.model, apiKey, headers, undefined, this._autoCompactionAbortController.signal, this.thinkingLevel, this.agent.streamFunction, env, this.settingsManager.getRetrySettings(), this._summarizationRetryCallbacks({ source: "compaction", reason }));
2290
2072
  summary = compactResult.summary;
2291
2073
  firstKeptEntryId = compactResult.firstKeptEntryId;
2292
2074
  tokensBefore = compactResult.tokensBefore;
@@ -2357,7 +2139,6 @@ export class AgentSession {
2357
2139
  return false;
2358
2140
  }
2359
2141
  finally {
2360
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
2361
2142
  this._autoCompactionAbortController = undefined;
2362
2143
  }
2363
2144
  }
@@ -2773,12 +2554,8 @@ export class AgentSession {
2773
2554
  return false;
2774
2555
  if (this._isPostAssistantPiServerSyncFailure(message))
2775
2556
  return false;
2776
- if (isPiServerRestartUncertainty(message))
2777
- return false;
2778
- const piServerFailure = getPiServerFailureMetadata(message);
2779
- if (piServerFailure?.phase && piServerFailure.phase !== "provider_stream")
2780
- return false;
2781
- if (piServerFailure?.retryable === false)
2557
+ const piServerPhase = getPiServerFailurePhase(message);
2558
+ if (piServerPhase && piServerPhase !== "provider_stream")
2782
2559
  return false;
2783
2560
  if (message.errorMessage && this._isNonRetryableProviderLimitError(message.errorMessage))
2784
2561
  return false;
@@ -3045,7 +2822,6 @@ export class AgentSession {
3045
2822
  replaceInstructions,
3046
2823
  label,
3047
2824
  };
3048
- const piServerLease = this._acquirePiServerOperationLease();
3049
2825
  // Set up abort controller for summarization
3050
2826
  this._branchSummaryAbortController = new AbortController();
3051
2827
  try {
@@ -3093,7 +2869,7 @@ export class AgentSession {
3093
2869
  customInstructions,
3094
2870
  replaceInstructions,
3095
2871
  reserveTokens: branchSummarySettings.reserveTokens,
3096
- streamFn: this._getAuxiliaryStreamFunction(),
2872
+ streamFn: this.agent.streamFunction,
3097
2873
  retry: this.settingsManager.getRetrySettings(),
3098
2874
  callbacks: this._summarizationRetryCallbacks({ source: "branchSummary" }),
3099
2875
  });
@@ -3178,7 +2954,6 @@ export class AgentSession {
3178
2954
  return { editorText, cancelled: false, summaryEntry };
3179
2955
  }
3180
2956
  finally {
3181
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
3182
2957
  this._branchSummaryAbortController = undefined;
3183
2958
  }
3184
2959
  }