@averyyy/pi-coding-agent 0.82.1-piclient.6 → 0.82.1-piclient.8

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 -317
  11. package/dist/core/agent-session.js.map +1 -1
  12. package/dist/core/pi-server-client.d.ts +2 -54
  13. package/dist/core/pi-server-client.d.ts.map +1 -1
  14. package/dist/core/pi-server-client.js +272 -2320
  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 -439
  50. package/dist/core/pi-server-compact-state.js.map +0 -1
  51. package/dist/core/pi-server-run-state.d.ts +0 -42
  52. package/dist/core/pi-server-run-state.d.ts.map +0 -1
  53. package/dist/core/pi-server-run-state.js +0 -320
  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,105 +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, {
380
- signal,
381
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
382
- });
383
- if (!result)
384
- return undefined;
385
- return this._applyPiServerCompactionResult(result, reason, willRetry);
386
- }
387
263
  async _getRequiredRequestAuth(model) {
388
264
  let result;
389
265
  try {
@@ -412,7 +288,7 @@ export class AgentSession {
412
288
  throw new Error(formatNoApiKeyFoundMessage(model.provider));
413
289
  }
414
290
  async _getSummarizationRequestAuth(model) {
415
- if (this._getAuxiliaryStreamFunction() === streamSimple) {
291
+ if (this.agent.streamFunction === streamSimple) {
416
292
  return this._getRequiredRequestAuth(model);
417
293
  }
418
294
  try {
@@ -604,33 +480,18 @@ export class AgentSession {
604
480
  }
605
481
  async _emitAgentSettled() {
606
482
  this._isAgentRunActive = false;
607
- await this._extensionRunner.emit({ type: "agent_settled" });
608
- 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
+ }
609
490
  }
610
491
  // Track last assistant message for auto-compaction check
611
492
  _lastAssistantMessage = undefined;
612
493
  /** Internal handler for agent events - shared by subscribe and reconnect */
613
494
  _handleAgentEvent = async (event, signal) => {
614
- if (event.type === "tool_execution_start") {
615
- beginSessionToolEffect(this.sessionManager, event);
616
- }
617
- else if (event.type === "tool_execution_end") {
618
- writeSessionToolEffectResult(this.sessionManager, event.toolResult, { finalizationPending: true });
619
- this._toolResultsInFinalization.add(event.toolResult);
620
- }
621
- else if (event.type === "message_start" &&
622
- event.message.role === "toolResult" &&
623
- !this._toolResultsInFinalization.has(event.message)) {
624
- beginSessionToolEffectFinalization(this.sessionManager, event.message);
625
- this._toolResultsInFinalization.add(event.message);
626
- }
627
- else if (event.type === "message_end" &&
628
- event.message.role === "toolResult" &&
629
- !this._toolResultsInFinalization.has(event.message)) {
630
- beginSessionToolEffectFinalization(this.sessionManager, event.message);
631
- this._toolResultsInFinalization.add(event.message);
632
- }
633
- const finalizingToolResult = event.type === "message_end" && this._toolResultsInFinalization.has(event.message);
634
495
  // When a user message starts, check if it's from either queue and remove it BEFORE emitting
635
496
  // This ensures the UI sees the updated queue state
636
497
  if (event.type === "message_start" && event.message.role === "user") {
@@ -657,13 +518,6 @@ export class AgentSession {
657
518
  await this._emitExtensionEvent(event);
658
519
  // Notify all listeners
659
520
  this._emit(event.type === "agent_end" ? { ...event, willRetry: this._willRetryAfterAgentEnd(event) } : event);
660
- if (finalizingToolResult) {
661
- if (event.message.role !== "toolResult") {
662
- throw new Error("A toolResult message_end replacement must remain a toolResult");
663
- }
664
- writeSessionToolEffectFinalResult(this.sessionManager, event.message);
665
- this._toolResultsInFinalization.delete(event.message);
666
- }
667
521
  // Handle session persistence
668
522
  if (event.type === "message_end") {
669
523
  // Check if this is a custom message from extensions
@@ -675,11 +529,7 @@ export class AgentSession {
675
529
  event.message.role === "assistant" ||
676
530
  event.message.role === "toolResult") {
677
531
  // Regular LLM message - persist as SessionMessageEntry
678
- const sessionEntryId = this.sessionManager.appendMessage(event.message);
679
- if (event.message.role === "toolResult") {
680
- this.sessionManager.flushSessionFile();
681
- commitSessionToolEffect(this.sessionManager, event.message, sessionEntryId);
682
- }
532
+ this.sessionManager.appendMessage(event.message);
683
533
  }
684
534
  // Other message types (bashExecution, compactionSummary, branchSummary) are persisted elsewhere
685
535
  // Track assistant message for auto-compaction (checked on agent_end)
@@ -699,10 +549,12 @@ export class AgentSession {
699
549
  });
700
550
  this._retryAttempt = 0;
701
551
  }
702
- if (isPiServerMode() &&
703
- !this._isPostAssistantPiServerSyncFailure(assistantMsg) &&
704
- !isPiServerControlPlaneFailure(assistantMsg)) {
705
- 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) });
706
558
  }
707
559
  }
708
560
  }
@@ -968,7 +820,7 @@ export class AgentSession {
968
820
  }
969
821
  /** Whether the session has no active agent run, retry, auto-compaction, or queued continuation. */
970
822
  get isIdle() {
971
- return !this._isAgentRunActive && !this._piServerSessionLeaseOwner;
823
+ return !this._isAgentRunActive;
972
824
  }
973
825
  /** Current effective system prompt (includes any per-turn extension modifications) */
974
826
  get systemPrompt() {
@@ -1120,11 +972,9 @@ export class AgentSession {
1120
972
  // Prompting
1121
973
  // =========================================================================
1122
974
  async _runAgentPrompt(messages) {
1123
- const piServerLease = this._acquirePiServerOperationLease();
1124
975
  this._resetValidationHintState();
1125
976
  this._isAgentRunActive = true;
1126
977
  try {
1127
- await this._recoverPendingPiServerCompaction("threshold", false);
1128
978
  await this.agent.prompt(messages);
1129
979
  while (await this._handlePostAgentRun()) {
1130
980
  try {
@@ -1147,15 +997,9 @@ export class AgentSession {
1147
997
  await this._maybeGenerateSessionName();
1148
998
  }
1149
999
  finally {
1150
- try {
1151
- this._systemPromptOverride = undefined;
1152
- this._flushPendingBashMessages();
1153
- await this._emitAgentSettled();
1154
- }
1155
- finally {
1156
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
1157
- this._resolveIdleWaitIfIdle();
1158
- }
1000
+ this._systemPromptOverride = undefined;
1001
+ this._flushPendingBashMessages();
1002
+ await this._emitAgentSettled();
1159
1003
  }
1160
1004
  }
1161
1005
  _sessionHasInfoEntry() {
@@ -1192,7 +1036,7 @@ export class AgentSession {
1192
1036
  if (!model || !transcript)
1193
1037
  return;
1194
1038
  try {
1195
- const stream = await this._getAuxiliaryStreamFunction()(model, {
1039
+ const stream = await this.agent.streamFunction(model, {
1196
1040
  systemPrompt: this.systemPrompt,
1197
1041
  messages: [
1198
1042
  {
@@ -1205,7 +1049,7 @@ export class AgentSession {
1205
1049
  }, {
1206
1050
  maxTokens: 32,
1207
1051
  reasoning: undefined,
1208
- sessionId: randomUUID(),
1052
+ sessionId: this.sessionId,
1209
1053
  transport: this.agent.transport,
1210
1054
  thinkingBudgets: this.agent.thinkingBudgets,
1211
1055
  maxRetryDelayMs: this.agent.maxRetryDelayMs,
@@ -1838,26 +1682,9 @@ export class AgentSession {
1838
1682
  // Compaction
1839
1683
  // =========================================================================
1840
1684
  async _applyPiServerCompactionResult(result, reason, willRetry) {
1841
- const compactionEntry = result.compactionEntry;
1842
- const operation = compactionEntry.piServerCompactOperation;
1843
- if (!operation ||
1844
- !Number.isSafeInteger(operation.baseEntryCount) ||
1845
- operation.baseEntryCount < 0 ||
1846
- (operation.baseLeafId !== null &&
1847
- (typeof operation.baseLeafId !== "string" || operation.baseLeafId.length === 0)) ||
1848
- typeof operation.baseTreeHash !== "string" ||
1849
- !/^[a-f0-9]{64}$/u.test(operation.baseTreeHash)) {
1850
- throw new Error("Pi-server compaction result is missing a valid durable base identity");
1851
- }
1852
- this.sessionManager.appendCompactionEntry(compactionEntry, {
1853
- baseEntryCount: operation.baseEntryCount,
1854
- baseLeafId: operation.baseLeafId,
1855
- baseTreeHash: operation.baseTreeHash,
1856
- });
1857
- recordPiServerCompactionApplied(result);
1685
+ this.sessionManager.replaceTree(result.entries, result.leafId);
1858
1686
  const sessionContext = this.sessionManager.buildSessionContext();
1859
1687
  this.agent.state.messages = sessionContext.messages;
1860
- await acknowledgePiServerCompaction(result);
1861
1688
  const firstKeptEntryId = result.compaction.firstKeptEntryId;
1862
1689
  if (!firstKeptEntryId) {
1863
1690
  throw new Error("Pi-server compaction result is missing firstKeptEntryId");
@@ -1876,7 +1703,7 @@ export class AgentSession {
1876
1703
  await this._extensionRunner.emit({
1877
1704
  type: "session_compact",
1878
1705
  compactionEntry: savedCompactionEntry,
1879
- fromExtension: savedCompactionEntry.fromHook === true,
1706
+ fromExtension: false,
1880
1707
  reason,
1881
1708
  willRetry,
1882
1709
  });
@@ -1893,31 +1720,38 @@ export class AgentSession {
1893
1720
  await this.abort();
1894
1721
  this._compactionAbortController = new AbortController();
1895
1722
  this._emit({ type: "compaction_start", reason: "manual" });
1896
- let piServerLease = {
1897
- path: undefined,
1898
- acquired: false,
1899
- owner: undefined,
1900
- };
1901
1723
  try {
1902
- piServerLease = this._acquirePiServerOperationLease();
1903
- await this._recoverPendingPiServerRunBeforeControlOperation(this._compactionAbortController.signal);
1904
- const recoveredCompaction = await this._recoverPendingPiServerCompaction("manual", false, this._compactionAbortController.signal);
1905
- if (recoveredCompaction) {
1906
- this._emit({
1907
- type: "compaction_end",
1908
- reason: "manual",
1909
- result: recoveredCompaction,
1910
- aborted: false,
1911
- willRetry: false,
1912
- });
1913
- return recoveredCompaction;
1914
- }
1915
1724
  if (!this.model) {
1916
1725
  throw new Error(formatNoModelSelectedMessage());
1917
1726
  }
1918
1727
  const { apiKey, headers, env } = await this._getSummarizationRequestAuth(this.model);
1919
1728
  if (isPiServerMode()) {
1920
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;
1921
1755
  }
1922
1756
  const pathEntries = this.sessionManager.getBranch();
1923
1757
  const settings = this.settingsManager.getCompactionSettings();
@@ -1950,42 +1784,6 @@ export class AgentSession {
1950
1784
  fromExtension = true;
1951
1785
  }
1952
1786
  }
1953
- if (isPiServerMode()) {
1954
- const sessionFile = this.sessionManager.getSessionFile();
1955
- if (!sessionFile) {
1956
- throw new Error("Durable pi-server compaction requires a persisted session file");
1957
- }
1958
- const piServerResult = await compactPiServer(this.model, {
1959
- systemPrompt: this.systemPrompt,
1960
- messages: this.agent.state.messages,
1961
- tools: this.agent.state.tools,
1962
- }, {
1963
- sessionId: this.sessionId,
1964
- apiKey,
1965
- headers,
1966
- env,
1967
- customInstructions,
1968
- settings,
1969
- preparation: { firstKeptEntryId: preparation.firstKeptEntryId },
1970
- extensionCompaction,
1971
- retry: this.settingsManager.getRetrySettings(),
1972
- sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
1973
- piServerCompactStatePath: getPiServerCompactStatePath(sessionFile),
1974
- signal: this._compactionAbortController.signal,
1975
- reasoning: toProviderReasoning(this.thinkingLevel),
1976
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
1977
- });
1978
- const result = await this._applyPiServerCompactionResult(piServerResult, "manual", false);
1979
- this._lastServerCompactionTimestamp = Date.now();
1980
- this._emit({
1981
- type: "compaction_end",
1982
- reason: "manual",
1983
- result,
1984
- aborted: false,
1985
- willRetry: false,
1986
- });
1987
- return result;
1988
- }
1989
1787
  let summary;
1990
1788
  let firstKeptEntryId;
1991
1789
  let tokensBefore;
@@ -2001,7 +1799,7 @@ export class AgentSession {
2001
1799
  }
2002
1800
  else {
2003
1801
  // Generate compaction result
2004
- 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" }));
2005
1803
  summary = result.summary;
2006
1804
  firstKeptEntryId = result.firstKeptEntryId;
2007
1805
  tokensBefore = result.tokensBefore;
@@ -2058,7 +1856,6 @@ export class AgentSession {
2058
1856
  throw error;
2059
1857
  }
2060
1858
  finally {
2061
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
2062
1859
  this._compactionAbortController = undefined;
2063
1860
  this._reconnectToAgent();
2064
1861
  }
@@ -2182,33 +1979,45 @@ export class AgentSession {
2182
1979
  */
2183
1980
  async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
2184
1981
  const settings = this.settingsManager.getCompactionSettings();
2185
- const model = this.model;
2186
1982
  let started = false;
2187
- let piServerLease = {
2188
- path: undefined,
2189
- acquired: false,
2190
- owner: undefined,
2191
- };
2192
1983
  try {
2193
- piServerLease = this._acquirePiServerOperationLease(this._isAgentRunActive ? this._piServerSessionLeaseOwner : undefined);
2194
- if (!this._isAgentRunActive) {
2195
- await this._recoverPendingPiServerRunBeforeControlOperation();
1984
+ if (!this.model) {
1985
+ return false;
2196
1986
  }
2197
- const recoveredCompaction = await this._recoverPendingPiServerCompaction(reason, willRetry);
2198
- 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()) {
2199
1997
  this._emit({ type: "compaction_start", reason });
1998
+ this._autoCompactionAbortController = new AbortController();
2200
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);
2201
2017
  this._lastServerCompactionTimestamp = Date.now();
2202
- this._emit({ type: "compaction_end", reason, result: recoveredCompaction, aborted: false, willRetry });
2018
+ this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
2203
2019
  return willRetry ? true : this.agent.hasQueuedMessages();
2204
2020
  }
2205
- if (!model) {
2206
- return false;
2207
- }
2208
- let apiKey;
2209
- let headers;
2210
- let env;
2211
- ({ apiKey, headers, env } = await this._getSummarizationRequestAuth(model));
2212
2021
  const pathEntries = this.sessionManager.getBranch();
2213
2022
  const preparation = preparationOverride ?? prepareCompaction(pathEntries, settings);
2214
2023
  if (!preparation) {
@@ -2217,7 +2026,6 @@ export class AgentSession {
2217
2026
  this._emit({ type: "compaction_start", reason });
2218
2027
  this._autoCompactionAbortController = new AbortController();
2219
2028
  started = true;
2220
- const signal = this._autoCompactionAbortController.signal;
2221
2029
  let extensionCompaction;
2222
2030
  let fromExtension = false;
2223
2031
  if (this._extensionRunner.hasHandlers("session_before_compact")) {
@@ -2228,7 +2036,7 @@ export class AgentSession {
2228
2036
  customInstructions: undefined,
2229
2037
  reason,
2230
2038
  willRetry,
2231
- signal,
2039
+ signal: this._autoCompactionAbortController.signal,
2232
2040
  }));
2233
2041
  if (extensionResult?.cancel) {
2234
2042
  this._emit({
@@ -2245,35 +2053,6 @@ export class AgentSession {
2245
2053
  fromExtension = true;
2246
2054
  }
2247
2055
  }
2248
- if (isPiServerMode()) {
2249
- const sessionFile = this.sessionManager.getSessionFile();
2250
- if (!sessionFile) {
2251
- throw new Error("Durable pi-server compaction requires a persisted session file");
2252
- }
2253
- const piServerResult = await compactPiServer(model, {
2254
- systemPrompt: this.systemPrompt,
2255
- messages: this.agent.state.messages,
2256
- tools: this.agent.state.tools,
2257
- }, {
2258
- sessionId: this.sessionId,
2259
- apiKey,
2260
- headers,
2261
- env,
2262
- settings,
2263
- retry: this.settingsManager.getRetrySettings(),
2264
- preparation: preparationOptions ?? { firstKeptEntryId: preparation.firstKeptEntryId },
2265
- extensionCompaction,
2266
- sessionTree: { entries: this.sessionManager.getEntries(), leafId: this.sessionManager.getLeafId() },
2267
- piServerCompactStatePath: getPiServerCompactStatePath(sessionFile),
2268
- signal,
2269
- reasoning: toProviderReasoning(this.thinkingLevel),
2270
- onHistoryReconciled: (snapshot) => this.reconcilePiServerHistory(snapshot),
2271
- });
2272
- const result = await this._applyPiServerCompactionResult(piServerResult, reason, willRetry);
2273
- this._lastServerCompactionTimestamp = Date.now();
2274
- this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry });
2275
- return willRetry ? true : this.agent.hasQueuedMessages();
2276
- }
2277
2056
  let summary;
2278
2057
  let firstKeptEntryId;
2279
2058
  let tokensBefore;
@@ -2289,7 +2068,7 @@ export class AgentSession {
2289
2068
  }
2290
2069
  else {
2291
2070
  // Generate compaction result
2292
- 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 }));
2293
2072
  summary = compactResult.summary;
2294
2073
  firstKeptEntryId = compactResult.firstKeptEntryId;
2295
2074
  tokensBefore = compactResult.tokensBefore;
@@ -2360,7 +2139,6 @@ export class AgentSession {
2360
2139
  return false;
2361
2140
  }
2362
2141
  finally {
2363
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
2364
2142
  this._autoCompactionAbortController = undefined;
2365
2143
  }
2366
2144
  }
@@ -2776,12 +2554,8 @@ export class AgentSession {
2776
2554
  return false;
2777
2555
  if (this._isPostAssistantPiServerSyncFailure(message))
2778
2556
  return false;
2779
- if (isPiServerRestartUncertainty(message))
2780
- return false;
2781
- const piServerFailure = getPiServerFailureMetadata(message);
2782
- if (piServerFailure?.phase && piServerFailure.phase !== "provider_stream")
2783
- return false;
2784
- if (piServerFailure?.retryable === false)
2557
+ const piServerPhase = getPiServerFailurePhase(message);
2558
+ if (piServerPhase && piServerPhase !== "provider_stream")
2785
2559
  return false;
2786
2560
  if (message.errorMessage && this._isNonRetryableProviderLimitError(message.errorMessage))
2787
2561
  return false;
@@ -3048,7 +2822,6 @@ export class AgentSession {
3048
2822
  replaceInstructions,
3049
2823
  label,
3050
2824
  };
3051
- const piServerLease = this._acquirePiServerOperationLease();
3052
2825
  // Set up abort controller for summarization
3053
2826
  this._branchSummaryAbortController = new AbortController();
3054
2827
  try {
@@ -3096,7 +2869,7 @@ export class AgentSession {
3096
2869
  customInstructions,
3097
2870
  replaceInstructions,
3098
2871
  reserveTokens: branchSummarySettings.reserveTokens,
3099
- streamFn: this._getAuxiliaryStreamFunction(),
2872
+ streamFn: this.agent.streamFunction,
3100
2873
  retry: this.settingsManager.getRetrySettings(),
3101
2874
  callbacks: this._summarizationRetryCallbacks({ source: "branchSummary" }),
3102
2875
  });
@@ -3181,7 +2954,6 @@ export class AgentSession {
3181
2954
  return { editorText, cancelled: false, summaryEntry };
3182
2955
  }
3183
2956
  finally {
3184
- this._releasePiServerOperationLease(piServerLease.path, piServerLease.acquired, piServerLease.owner);
3185
2957
  this._branchSummaryAbortController = undefined;
3186
2958
  }
3187
2959
  }