@averyyy/pi-coding-agent 0.84.1-piclient.2 → 0.84.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.
@@ -72,6 +72,7 @@ import { editInExternalEditor } from "./external-editor.js";
72
72
  import { getModelSearchText } from "./model-search.js";
73
73
  import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
74
74
  import { InteractiveThemeController } from "./theme/theme-controller.js";
75
+ const TRANSCRIPT_LAZY_LOAD_BATCH_SIZE = 20;
75
76
  function isExpandable(obj) {
76
77
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
77
78
  }
@@ -216,6 +217,11 @@ export class InteractiveMode {
216
217
  chatContainer;
217
218
  documentContainer;
218
219
  transcriptScrollView;
220
+ transcriptLazyEntries = [];
221
+ loadedTranscriptEntryIds = new Set();
222
+ transcriptWindowInitialized = false;
223
+ transcriptLatestCompactionId;
224
+ loadingEarlierTranscript = false;
219
225
  fullscreenLayoutRoot;
220
226
  pendingMessagesContainer;
221
227
  statusContainer;
@@ -625,6 +631,7 @@ export class InteractiveMode {
625
631
  follow: "end",
626
632
  primary: true,
627
633
  overscroll: "chain",
634
+ onScroll: (scrollTop) => this.handleTranscriptScroll(scrollTop),
628
635
  scrollbar: this.settingsManager.getFullscreenScrollbar(),
629
636
  scrollbarStyle: (text) => theme.bg("scrollbarThumb", text),
630
637
  });
@@ -2249,6 +2256,7 @@ export class InteractiveMode {
2249
2256
  this.defaultEditor.onAction("app.session.tree", () => this.showTreeSelector());
2250
2257
  this.defaultEditor.onAction("app.session.fork", () => this.showUserMessageSelector());
2251
2258
  this.defaultEditor.onAction("app.session.resume", () => this.showSessionSelector());
2259
+ this.defaultEditor.onAction("app.session.loadEarlier", () => this.loadEarlierTranscript());
2252
2260
  this.defaultEditor.onChange = (text) => {
2253
2261
  const wasBashMode = this.isBashMode;
2254
2262
  this.isBashMode = text.trimStart().startsWith("!");
@@ -3019,9 +3027,66 @@ export class InteractiveMode {
3019
3027
  this.chatContainer.addChild(new Spacer(1));
3020
3028
  this.chatContainer.addChild(new Text(text, 1, 0));
3021
3029
  }
3030
+ getTranscriptEntriesForRender(reset = false) {
3031
+ const branch = this.sessionManager.getBranch();
3032
+ const contextEntries = this.sessionManager.buildContextEntries();
3033
+ let latestCompactionId;
3034
+ for (let index = branch.length - 1; index >= 0; index--) {
3035
+ const entry = branch[index];
3036
+ if (entry?.type === "compaction") {
3037
+ latestCompactionId = entry.id;
3038
+ break;
3039
+ }
3040
+ }
3041
+ if (reset || (this.transcriptWindowInitialized && this.transcriptLatestCompactionId !== latestCompactionId)) {
3042
+ this.loadedTranscriptEntryIds.clear();
3043
+ }
3044
+ this.transcriptWindowInitialized = true;
3045
+ this.transcriptLatestCompactionId = latestCompactionId;
3046
+ const contextEntryIds = new Set(contextEntries.map((entry) => entry.id));
3047
+ const earlierEntries = branch.filter((entry) => !contextEntryIds.has(entry.id));
3048
+ const loadedEntries = earlierEntries.filter((entry) => this.loadedTranscriptEntryIds.has(entry.id));
3049
+ this.transcriptLazyEntries = earlierEntries.filter((entry) => !this.loadedTranscriptEntryIds.has(entry.id));
3050
+ return [...loadedEntries, ...contextEntries];
3051
+ }
3052
+ renderTranscriptEntries(entries, options = {}) {
3053
+ if (this.transcriptLazyEntries.length > 0) {
3054
+ const count = this.transcriptLazyEntries.length.toLocaleString();
3055
+ this.chatContainer.addChild(new Text(theme.fg("dim", `${count} earlier transcript entries hidden (${keyText("app.session.loadEarlier")} to load)`), 1, 0));
3056
+ this.chatContainer.addChild(new Spacer(1));
3057
+ }
3058
+ this.renderSessionEntries(entries, options);
3059
+ }
3060
+ handleTranscriptScroll(scrollTop) {
3061
+ if (scrollTop === 0) {
3062
+ this.loadEarlierTranscript();
3063
+ }
3064
+ }
3065
+ loadEarlierTranscript() {
3066
+ if (this.loadingEarlierTranscript || this.session.isStreaming || this.transcriptLazyEntries.length === 0) {
3067
+ return;
3068
+ }
3069
+ this.loadingEarlierTranscript = true;
3070
+ try {
3071
+ const firstLoadedIndex = Math.max(0, this.transcriptLazyEntries.length - TRANSCRIPT_LAZY_LOAD_BATCH_SIZE);
3072
+ const entriesToLoad = this.transcriptLazyEntries.slice(firstLoadedIndex);
3073
+ for (const entry of entriesToLoad) {
3074
+ this.loadedTranscriptEntryIds.add(entry.id);
3075
+ }
3076
+ this.rebuildChatFromMessages();
3077
+ const remaining = this.transcriptLazyEntries.length;
3078
+ this.showStatus(remaining > 0
3079
+ ? `Loaded ${entriesToLoad.length} earlier transcript entries (${remaining} remaining)`
3080
+ : "Loaded the beginning of the transcript");
3081
+ this.ui.requestRender();
3082
+ }
3083
+ finally {
3084
+ this.loadingEarlierTranscript = false;
3085
+ }
3086
+ }
3022
3087
  renderInitialMessages() {
3023
- const entries = this.sessionManager.getBranch();
3024
- this.renderSessionEntries(entries, {
3088
+ const entries = this.getTranscriptEntriesForRender(true);
3089
+ this.renderTranscriptEntries(entries, {
3025
3090
  updateFooter: true,
3026
3091
  populateHistory: true,
3027
3092
  });
@@ -3057,7 +3122,7 @@ export class InteractiveMode {
3057
3122
  }
3058
3123
  rebuildChatFromMessages() {
3059
3124
  this.chatContainer.clear();
3060
- this.renderSessionEntries(this.sessionManager.getBranch());
3125
+ this.renderTranscriptEntries(this.getTranscriptEntriesForRender());
3061
3126
  }
3062
3127
  // =========================================================================
3063
3128
  // Key handlers