@averyyy/pi-coding-agent 0.84.3-piclient.1 → 0.84.4-piclient.1

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 (92) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/README.md +5 -4
  3. package/dist/bundle/chunks/{chunk-GPPBJGBU.js → chunk-2KVJKXS2.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-QI42RBZ4.js → chunk-AP7VCR6I.js} +73 -72
  5. package/dist/bundle/chunks/{google-generative-ai-XDKMGBCJ.js → google-generative-ai-YMUPJBKR.js} +1 -1
  6. package/dist/bundle/chunks/{google-vertex-D5FGEO3Y.js → google-vertex-MPWMV4OF.js} +1 -1
  7. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +13 -0
  8. package/dist/bundle/chunks/{mistral-conversations-YK73UAOZ.js → mistral-conversations-Q3AWZJAZ.js} +1 -1
  9. package/dist/bundle/chunks/{openai-completions-JD4WAC3R.js → openai-completions-ERMU2SS7.js} +1 -1
  10. package/dist/bundle/cli.js +1 -1
  11. package/dist/bundle/index.js +1 -1
  12. package/dist/bundle/rpc-entry.js +1 -1
  13. package/dist/cli/startup-ui.d.ts.map +1 -1
  14. package/dist/cli/startup-ui.js +2 -1
  15. package/dist/cli/startup-ui.js.map +1 -1
  16. package/dist/core/agent-session.d.ts +12 -1
  17. package/dist/core/agent-session.d.ts.map +1 -1
  18. package/dist/core/agent-session.js +102 -19
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  21. package/dist/core/compaction/branch-summarization.js +8 -1
  22. package/dist/core/compaction/branch-summarization.js.map +1 -1
  23. package/dist/core/compaction/compaction.d.ts +9 -4
  24. package/dist/core/compaction/compaction.d.ts.map +1 -1
  25. package/dist/core/compaction/compaction.js +42 -22
  26. package/dist/core/compaction/compaction.js.map +1 -1
  27. package/dist/core/extensions/index.d.ts +1 -1
  28. package/dist/core/extensions/index.d.ts.map +1 -1
  29. package/dist/core/extensions/index.js.map +1 -1
  30. package/dist/core/extensions/runner.d.ts +5 -0
  31. package/dist/core/extensions/runner.d.ts.map +1 -1
  32. package/dist/core/extensions/runner.js +45 -1
  33. package/dist/core/extensions/runner.js.map +1 -1
  34. package/dist/core/extensions/types.d.ts +18 -1
  35. package/dist/core/extensions/types.d.ts.map +1 -1
  36. package/dist/core/extensions/types.js.map +1 -1
  37. package/dist/core/session-manager.d.ts.map +1 -1
  38. package/dist/core/session-manager.js +4 -2
  39. package/dist/core/session-manager.js.map +1 -1
  40. package/dist/core/settings-manager.d.ts +8 -1
  41. package/dist/core/settings-manager.d.ts.map +1 -1
  42. package/dist/core/settings-manager.js +17 -0
  43. package/dist/core/settings-manager.js.map +1 -1
  44. package/dist/index.d.ts +2 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/main.d.ts.map +1 -1
  49. package/dist/main.js +2 -0
  50. package/dist/main.js.map +1 -1
  51. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  52. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  53. package/dist/modes/interactive/components/settings-selector.js +10 -0
  54. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  55. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  56. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  57. package/dist/modes/interactive/interactive-mode.js +48 -24
  58. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  59. package/dist/modes/rpc/rpc-client.d.ts +7 -0
  60. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  61. package/dist/modes/rpc/rpc-client.js +7 -0
  62. package/dist/modes/rpc/rpc-client.js.map +1 -1
  63. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  64. package/dist/modes/rpc/rpc-mode.js +3 -0
  65. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  66. package/dist/modes/rpc/rpc-types.d.ts +12 -0
  67. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  68. package/dist/modes/rpc/rpc-types.js.map +1 -1
  69. package/dist/utils/shell.d.ts.map +1 -1
  70. package/dist/utils/shell.js +6 -4
  71. package/dist/utils/shell.js.map +1 -1
  72. package/docs/compaction.md +2 -0
  73. package/docs/custom-provider.md +7 -7
  74. package/docs/environment-variables.md +3 -0
  75. package/docs/extensions.md +18 -0
  76. package/docs/keybindings.md +1 -1
  77. package/docs/quickstart.md +1 -1
  78. package/docs/rpc.md +23 -0
  79. package/docs/settings.md +12 -4
  80. package/docs/terminal-setup.md +12 -0
  81. package/docs/usage.md +4 -3
  82. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  83. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  84. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  85. package/examples/extensions/gondolin/package-lock.json +2 -2
  86. package/examples/extensions/gondolin/package.json +1 -1
  87. package/examples/extensions/sandbox/package-lock.json +2 -2
  88. package/examples/extensions/sandbox/package.json +1 -1
  89. package/examples/extensions/with-deps/package-lock.json +2 -2
  90. package/examples/extensions/with-deps/package.json +1 -1
  91. package/package.json +6 -6
  92. package/dist/bundle/chunks/dist-RDWOYWHR.js +0 -13
@@ -170,6 +170,8 @@ export class AgentSession {
170
170
  _followUpMessages = [];
171
171
  /** Messages queued to be included with the next user prompt as context ("asides"). */
172
172
  _pendingNextTurnMessages = [];
173
+ /** Context-only custom messages queued during a run, flushed once the current turn's tool results are in. */
174
+ _pendingCustomMessages = [];
173
175
  // Compaction state
174
176
  _compactionAbortController = undefined;
175
177
  _autoCompactionAbortController = undefined;
@@ -472,6 +474,11 @@ export class AgentSession {
472
474
  followUp: [...this._followUpMessages],
473
475
  });
474
476
  }
477
+ async _emitSessionCompactFailed(event) {
478
+ if (this._extensionRunner.hasHandlers("session_compact_failed")) {
479
+ await this._extensionRunner.emit({ type: "session_compact_failed", ...event });
480
+ }
481
+ }
475
482
  _getIdleWaitPromise() {
476
483
  if (!this._idleWaitPromise) {
477
484
  this._idleWaitPromise = new Promise((resolve) => {
@@ -562,6 +569,14 @@ export class AgentSession {
562
569
  }
563
570
  }
564
571
  }
572
+ // A turn ends after its assistant message and every tool result has been appended,
573
+ // so this is the first point in the run where a context-only custom message can be
574
+ // inserted without landing between a tool call and its result. Flushing after the
575
+ // extension and listener dispatch above also picks up messages that turn_end
576
+ // handlers queued.
577
+ if (event.type === "turn_end") {
578
+ this._flushPendingCustomMessages();
579
+ }
565
580
  };
566
581
  _willRetryAfterAgentEnd(event) {
567
582
  const settings = this.settingsManager.getRetrySettings();
@@ -990,6 +1005,7 @@ export class AgentSession {
990
1005
  finally {
991
1006
  this._systemPromptOverride = undefined;
992
1007
  this._flushPendingBashMessages();
1008
+ this._flushPendingCustomMessages();
993
1009
  await this._emitAgentSettled();
994
1010
  }
995
1011
  }
@@ -1148,8 +1164,9 @@ export class AgentSession {
1148
1164
  preflightResult?.(true);
1149
1165
  return;
1150
1166
  }
1151
- // Flush any pending bash messages before the new prompt
1167
+ // Flush any pending bash and custom messages before the new prompt
1152
1168
  this._flushPendingBashMessages();
1169
+ this._flushPendingCustomMessages();
1153
1170
  // Validate model
1154
1171
  if (!this.model) {
1155
1172
  throw new Error(formatNoModelSelectedMessage());
@@ -1366,8 +1383,9 @@ export class AgentSession {
1366
1383
  /**
1367
1384
  * Send a custom message to the session. Creates a CustomMessageEntry.
1368
1385
  *
1369
- * Handles three cases:
1386
+ * Handles four cases:
1370
1387
  * - Streaming: queues message, processed when loop pulls from queue
1388
+ * - Streaming + triggerTurn false: appended to state/session once the current turn ends
1371
1389
  * - Not streaming + triggerTurn: appends to state/session, starts new turn
1372
1390
  * - Not streaming + no trigger: appends to state/session, no turn
1373
1391
  *
@@ -1399,11 +1417,34 @@ export class AgentSession {
1399
1417
  else if (options?.triggerTurn) {
1400
1418
  await this._runAgentPrompt(appMessage);
1401
1419
  }
1420
+ else if (this.isStreaming) {
1421
+ // Appending now would put the message between an assistant tool call and its
1422
+ // result, which providers that validate message order reject on replay. Defer
1423
+ // to the end of the turn. Nothing is emitted yet: message events must not
1424
+ // describe messages the session tree does not contain.
1425
+ this._pendingCustomMessages.push(appMessage);
1426
+ }
1402
1427
  else {
1403
- this.agent.state.messages.push(appMessage);
1404
- this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
1405
- this._emit({ type: "message_start", message: appMessage });
1406
- this._emit({ type: "message_end", message: appMessage });
1428
+ this._appendCustomMessage(appMessage);
1429
+ }
1430
+ }
1431
+ _appendCustomMessage(appMessage) {
1432
+ this.agent.state.messages.push(appMessage);
1433
+ this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
1434
+ this._emit({ type: "message_start", message: appMessage });
1435
+ this._emit({ type: "message_end", message: appMessage });
1436
+ }
1437
+ /**
1438
+ * Append custom messages queued while the agent was running.
1439
+ * Called once the current turn's tool results are in agent state and session history.
1440
+ */
1441
+ _flushPendingCustomMessages() {
1442
+ if (this._pendingCustomMessages.length === 0)
1443
+ return;
1444
+ const pending = this._pendingCustomMessages;
1445
+ this._pendingCustomMessages = [];
1446
+ for (const appMessage of pending) {
1447
+ this._appendCustomMessage(appMessage);
1407
1448
  }
1408
1449
  }
1409
1450
  /**
@@ -1518,6 +1559,7 @@ export class AgentSession {
1518
1559
  this.sessionManager.appendModelChange(model.provider, model.id);
1519
1560
  if (options.persist) {
1520
1561
  this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
1562
+ this._addPersistedDefaultToNonEmptyScope(model);
1521
1563
  }
1522
1564
  // Apply thinking level for the new model.
1523
1565
  // Per-model thinking level overrides take priority over the global default.
@@ -1525,6 +1567,20 @@ export class AgentSession {
1525
1567
  this.setThinkingLevel(thinkingLevel);
1526
1568
  await this._emitModelSelect(model, previousModel, "set");
1527
1569
  }
1570
+ _addPersistedDefaultToNonEmptyScope(model) {
1571
+ if (this._scopedModels.length === 0)
1572
+ return;
1573
+ if (this._scopedModels.some((scoped) => modelsAreEqual(scoped.model, model)))
1574
+ return;
1575
+ this._scopedModels = [...this._scopedModels, { model }];
1576
+ const enabledModels = this.settingsManager.getEnabledModels();
1577
+ if (!enabledModels?.length)
1578
+ return;
1579
+ const modelReference = `${model.provider}/${model.id}`;
1580
+ if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
1581
+ return;
1582
+ this.settingsManager.setEnabledModels([...enabledModels, modelReference]);
1583
+ }
1528
1584
  /**
1529
1585
  * Cycle to next/previous model.
1530
1586
  * Uses scoped models (from --models flag) if available, otherwise all available models.
@@ -1555,6 +1611,7 @@ export class AgentSession {
1555
1611
  this.sessionManager.appendModelChange(next.model.provider, next.model.id);
1556
1612
  if (options.persist) {
1557
1613
  this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
1614
+ this._addPersistedDefaultToNonEmptyScope(next.model);
1558
1615
  }
1559
1616
  // Apply thinking level for the new model.
1560
1617
  // - Explicit scoped model thinking level overrides defaults
@@ -1581,6 +1638,7 @@ export class AgentSession {
1581
1638
  this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
1582
1639
  if (options.persist) {
1583
1640
  this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
1641
+ this._addPersistedDefaultToNonEmptyScope(nextModel);
1584
1642
  }
1585
1643
  // Apply thinking level for the new model.
1586
1644
  // Model persistence does not implicitly rewrite the global thinking default.
@@ -1920,20 +1978,24 @@ export class AgentSession {
1920
1978
  // independent of the configured context size or any context-clamped provider request limit.
1921
1979
  // A successful response over the configured window should compact but must not retry: the
1922
1980
  // assistant answer already completed and agent.continue() cannot continue from an assistant.
1981
+ const contextOverflow = sameModel && isContextOverflow(assistantMessage, contextWindow);
1923
1982
  const recoverableLength = sameModel && isRecoverableLength(assistantMessage, this.model?.maxTokens ?? 0);
1924
- if (sameModel && (isContextOverflow(assistantMessage, contextWindow) || recoverableLength)) {
1983
+ if (contextOverflow || recoverableLength) {
1925
1984
  const willRetry = assistantMessage.stopReason !== "stop";
1926
1985
  if (!willRetry) {
1927
1986
  return await this._runAutoCompaction("overflow", false);
1928
1987
  }
1929
1988
  if (this._overflowRecoveryAttempted) {
1989
+ const errorMessage = contextOverflow
1990
+ ? "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model."
1991
+ : "Truncated response recovery failed after one compact-and-retry attempt.";
1930
1992
  this._emit({
1931
1993
  type: "compaction_end",
1932
1994
  reason: "overflow",
1933
1995
  result: undefined,
1934
1996
  aborted: false,
1935
1997
  willRetry: false,
1936
- errorMessage: "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.",
1998
+ errorMessage,
1937
1999
  });
1938
2000
  return false;
1939
2001
  }
@@ -1963,16 +2025,16 @@ export class AgentSession {
1963
2025
  if (assistantMessage.stopReason === "error" || directContextTokens === 0) {
1964
2026
  const messages = this.agent.state.messages;
1965
2027
  const estimate = estimateContextTokens(messages);
1966
- if (estimate.lastUsageIndex === null)
1967
- return false; // No usage data at all
1968
- // Verify the usage source is post-compaction. Kept pre-compaction messages
1969
- // have stale usage reflecting the old (larger) context and would falsely
1970
- // trigger compaction right after one just finished.
1971
- const usageMsg = messages[estimate.lastUsageIndex];
1972
- if (compactionTimestamp > 0 &&
1973
- usageMsg.role === "assistant" &&
1974
- usageMsg.timestamp <= compactionTimestamp) {
1975
- return false;
2028
+ // When a valid usage entry exists, verify it is post-compaction. Kept
2029
+ // pre-compaction messages have stale usage reflecting the old (larger)
2030
+ // context and would falsely trigger compaction right after one finished.
2031
+ if (estimate.lastUsageIndex !== null) {
2032
+ const usageMsg = messages[estimate.lastUsageIndex];
2033
+ if (compactionTimestamp > 0 &&
2034
+ usageMsg.role === "assistant" &&
2035
+ usageMsg.timestamp <= compactionTimestamp) {
2036
+ return false;
2037
+ }
1976
2038
  }
1977
2039
  contextTokens = estimate.tokens;
1978
2040
  }
@@ -1990,6 +2052,7 @@ export class AgentSession {
1990
2052
  async _runAutoCompaction(reason, willRetry, preparationOverride, preparationOptions) {
1991
2053
  const settings = this.settingsManager.getCompactionSettings();
1992
2054
  let started = false;
2055
+ let fromExtension = false;
1993
2056
  try {
1994
2057
  if (!this.model) {
1995
2058
  return false;
@@ -2029,7 +2092,6 @@ export class AgentSession {
2029
2092
  this._autoCompactionAbortController = new AbortController();
2030
2093
  started = true;
2031
2094
  let extensionCompaction;
2032
- let fromExtension = false;
2033
2095
  if (this._extensionRunner.hasHandlers("session_before_compact")) {
2034
2096
  const extensionResult = (await this._extensionRunner.emit({
2035
2097
  type: "session_before_compact",
@@ -2048,6 +2110,12 @@ export class AgentSession {
2048
2110
  aborted: true,
2049
2111
  willRetry: false,
2050
2112
  });
2113
+ await this._emitSessionCompactFailed({
2114
+ reason,
2115
+ aborted: true,
2116
+ willRetry: false,
2117
+ fromExtension: false,
2118
+ });
2051
2119
  return false;
2052
2120
  }
2053
2121
  if (extensionResult?.compaction) {
@@ -2085,6 +2153,12 @@ export class AgentSession {
2085
2153
  aborted: true,
2086
2154
  willRetry: false,
2087
2155
  });
2156
+ await this._emitSessionCompactFailed({
2157
+ reason,
2158
+ aborted: true,
2159
+ willRetry: false,
2160
+ fromExtension,
2161
+ });
2088
2162
  return false;
2089
2163
  }
2090
2164
  this.sessionManager.appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromExtension, usage);
@@ -2141,6 +2215,15 @@ export class AgentSession {
2141
2215
  ? `Context overflow recovery failed: ${errorMessage}`
2142
2216
  : `Auto-compaction failed: ${errorMessage}`,
2143
2217
  });
2218
+ await this._emitSessionCompactFailed({
2219
+ reason,
2220
+ errorMessage: reason === "overflow"
2221
+ ? `Context overflow recovery failed: ${errorMessage}`
2222
+ : `Auto-compaction failed: ${errorMessage}`,
2223
+ aborted: false,
2224
+ willRetry: false,
2225
+ fromExtension,
2226
+ });
2144
2227
  }
2145
2228
  return false;
2146
2229
  }