@caupulican/pi-adaptative 0.93.18 → 0.94.0

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 (164) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +3 -2
  3. package/dist/core/agent-session.d.ts +1 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +22 -12
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction-controller.d.ts +21 -0
  8. package/dist/core/compaction-controller.d.ts.map +1 -1
  9. package/dist/core/compaction-controller.js +149 -26
  10. package/dist/core/compaction-controller.js.map +1 -1
  11. package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
  12. package/dist/core/delegation/worker-agent-control-coordinator.js +1 -0
  13. package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
  14. package/dist/core/delegation/worker-agent-control.d.ts +2 -0
  15. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -1
  16. package/dist/core/delegation/worker-agent-control.js.map +1 -1
  17. package/dist/core/extensions/loader.d.ts +0 -1
  18. package/dist/core/extensions/loader.d.ts.map +1 -1
  19. package/dist/core/extensions/loader.js +0 -1
  20. package/dist/core/extensions/loader.js.map +1 -1
  21. package/dist/core/extensions/types.d.ts +0 -4
  22. package/dist/core/extensions/types.d.ts.map +1 -1
  23. package/dist/core/extensions/types.js.map +1 -1
  24. package/dist/core/foreground-lifecycle-adapter.d.ts +27 -0
  25. package/dist/core/foreground-lifecycle-adapter.d.ts.map +1 -0
  26. package/dist/core/foreground-lifecycle-adapter.js +61 -0
  27. package/dist/core/foreground-lifecycle-adapter.js.map +1 -0
  28. package/dist/core/foreground-lifecycle-controller.d.ts +48 -0
  29. package/dist/core/foreground-lifecycle-controller.d.ts.map +1 -0
  30. package/dist/core/foreground-lifecycle-controller.js +404 -0
  31. package/dist/core/foreground-lifecycle-controller.js.map +1 -0
  32. package/dist/core/foreground-recovery-controller.d.ts +3 -0
  33. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  34. package/dist/core/foreground-recovery-controller.js +15 -1
  35. package/dist/core/foreground-recovery-controller.js.map +1 -1
  36. package/dist/core/goals/goal-state.d.ts.map +1 -1
  37. package/dist/core/goals/goal-state.js +9 -2
  38. package/dist/core/goals/goal-state.js.map +1 -1
  39. package/dist/core/keybindings.d.ts +2 -2
  40. package/dist/core/keybindings.d.ts.map +1 -1
  41. package/dist/core/keybindings.js +2 -2
  42. package/dist/core/keybindings.js.map +1 -1
  43. package/dist/core/memory/memory-manager.d.ts +22 -0
  44. package/dist/core/memory/memory-manager.d.ts.map +1 -1
  45. package/dist/core/memory/memory-manager.js +108 -49
  46. package/dist/core/memory/memory-manager.js.map +1 -1
  47. package/dist/core/model-router/session-buffer.d.ts +10 -2
  48. package/dist/core/model-router/session-buffer.d.ts.map +1 -1
  49. package/dist/core/model-router/session-buffer.js +35 -9
  50. package/dist/core/model-router/session-buffer.js.map +1 -1
  51. package/dist/core/model-router-controller.d.ts +20 -2
  52. package/dist/core/model-router-controller.d.ts.map +1 -1
  53. package/dist/core/model-router-controller.js +70 -17
  54. package/dist/core/model-router-controller.js.map +1 -1
  55. package/dist/core/provider-request-runtime-controller.d.ts +12 -1
  56. package/dist/core/provider-request-runtime-controller.d.ts.map +1 -1
  57. package/dist/core/provider-request-runtime-controller.js +45 -2
  58. package/dist/core/provider-request-runtime-controller.js.map +1 -1
  59. package/dist/core/tools/artifact-retrieve.d.ts.map +1 -1
  60. package/dist/core/tools/artifact-retrieve.js +0 -1
  61. package/dist/core/tools/artifact-retrieve.js.map +1 -1
  62. package/dist/core/tools/delegate.d.ts.map +1 -1
  63. package/dist/core/tools/delegate.js +4 -2
  64. package/dist/core/tools/delegate.js.map +1 -1
  65. package/dist/core/tools/edit.d.ts.map +1 -1
  66. package/dist/core/tools/edit.js +0 -7
  67. package/dist/core/tools/edit.js.map +1 -1
  68. package/dist/core/tools/find.d.ts.map +1 -1
  69. package/dist/core/tools/find.js +0 -1
  70. package/dist/core/tools/find.js.map +1 -1
  71. package/dist/core/tools/grep.d.ts.map +1 -1
  72. package/dist/core/tools/grep.js +0 -1
  73. package/dist/core/tools/grep.js.map +1 -1
  74. package/dist/core/tools/ls.d.ts.map +1 -1
  75. package/dist/core/tools/ls.js +0 -1
  76. package/dist/core/tools/ls.js.map +1 -1
  77. package/dist/core/tools/skill-audit.d.ts.map +1 -1
  78. package/dist/core/tools/skill-audit.js +0 -1
  79. package/dist/core/tools/skill-audit.js.map +1 -1
  80. package/dist/core/tools/skill.d.ts.map +1 -1
  81. package/dist/core/tools/skill.js +0 -1
  82. package/dist/core/tools/skill.js.map +1 -1
  83. package/dist/core/tools/skillify.d.ts.map +1 -1
  84. package/dist/core/tools/skillify.js +0 -1
  85. package/dist/core/tools/skillify.js.map +1 -1
  86. package/dist/core/tools/write.d.ts.map +1 -1
  87. package/dist/core/tools/write.js +1 -2
  88. package/dist/core/tools/write.js.map +1 -1
  89. package/dist/modes/interactive/components/action-transcript.d.ts +24 -0
  90. package/dist/modes/interactive/components/action-transcript.d.ts.map +1 -0
  91. package/dist/modes/interactive/components/action-transcript.js +72 -0
  92. package/dist/modes/interactive/components/action-transcript.js.map +1 -0
  93. package/dist/modes/interactive/components/active-tool-call-registry.d.ts +12 -0
  94. package/dist/modes/interactive/components/active-tool-call-registry.d.ts.map +1 -0
  95. package/dist/modes/interactive/components/active-tool-call-registry.js +25 -0
  96. package/dist/modes/interactive/components/active-tool-call-registry.js.map +1 -0
  97. package/dist/modes/interactive/components/activity-lane.d.ts +1 -1
  98. package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
  99. package/dist/modes/interactive/components/activity-lane.js.map +1 -1
  100. package/dist/modes/interactive/components/assistant-message.d.ts +3 -3
  101. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  102. package/dist/modes/interactive/components/assistant-message.js +16 -20
  103. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  104. package/dist/modes/interactive/components/index.d.ts +0 -2
  105. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  106. package/dist/modes/interactive/components/index.js +0 -2
  107. package/dist/modes/interactive/components/index.js.map +1 -1
  108. package/dist/modes/interactive/components/tool-execution.d.ts +0 -7
  109. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  110. package/dist/modes/interactive/components/tool-execution.js +2 -76
  111. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  112. package/dist/modes/interactive/components/transcript-overlay.d.ts +15 -0
  113. package/dist/modes/interactive/components/transcript-overlay.d.ts.map +1 -0
  114. package/dist/modes/interactive/components/transcript-overlay.js +38 -0
  115. package/dist/modes/interactive/components/transcript-overlay.js.map +1 -0
  116. package/dist/modes/interactive/components/tree-selector.d.ts +1 -1
  117. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  118. package/dist/modes/interactive/components/tree-selector.js +7 -4
  119. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  120. package/dist/modes/interactive/interactive-event-controller.d.ts +3 -4
  121. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
  122. package/dist/modes/interactive/interactive-event-controller.js +11 -10
  123. package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
  124. package/dist/modes/interactive/interactive-mode.d.ts +15 -13
  125. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  126. package/dist/modes/interactive/interactive-mode.js +105 -184
  127. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  128. package/dist/modes/interactive/runtime-status-controller.d.ts +40 -0
  129. package/dist/modes/interactive/runtime-status-controller.d.ts.map +1 -0
  130. package/dist/modes/interactive/runtime-status-controller.js +147 -0
  131. package/dist/modes/interactive/runtime-status-controller.js.map +1 -0
  132. package/dist/modes/interactive/runtime-status.d.ts +15 -0
  133. package/dist/modes/interactive/runtime-status.d.ts.map +1 -0
  134. package/dist/modes/interactive/runtime-status.js +18 -0
  135. package/dist/modes/interactive/runtime-status.js.map +1 -0
  136. package/dist/modes/interactive/settings-selector-flow.d.ts.map +1 -1
  137. package/dist/modes/interactive/settings-selector-flow.js +3 -4
  138. package/dist/modes/interactive/settings-selector-flow.js.map +1 -1
  139. package/docs/UI_POLISH_ORCHESTRATION.md +4 -4
  140. package/docs/extensions.md +4 -12
  141. package/docs/json.md +1 -1
  142. package/docs/keybindings.md +3 -2
  143. package/docs/session-format.md +59 -4
  144. package/docs/settings.md +1 -1
  145. package/docs/task-steps.md +3 -3
  146. package/docs/tool-repair.md +1 -1
  147. package/docs/usage.md +1 -1
  148. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  149. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  150. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  151. package/examples/extensions/sandbox/package-lock.json +2 -2
  152. package/examples/extensions/sandbox/package.json +1 -1
  153. package/examples/extensions/with-deps/package-lock.json +2 -2
  154. package/examples/extensions/with-deps/package.json +1 -1
  155. package/npm-shrinkwrap.json +12 -12
  156. package/package.json +4 -4
  157. package/dist/modes/interactive/components/tool-group.d.ts +0 -25
  158. package/dist/modes/interactive/components/tool-group.d.ts.map +0 -1
  159. package/dist/modes/interactive/components/tool-group.js +0 -175
  160. package/dist/modes/interactive/components/tool-group.js.map +0 -1
  161. package/dist/modes/interactive/components/tool-panel-registry.d.ts +0 -30
  162. package/dist/modes/interactive/components/tool-panel-registry.d.ts.map +0 -1
  163. package/dist/modes/interactive/components/tool-panel-registry.js +0 -145
  164. package/dist/modes/interactive/components/tool-panel-registry.js.map +0 -1
@@ -5,7 +5,7 @@
5
5
  import * as fs from "node:fs";
6
6
  import * as path from "node:path";
7
7
  import { getToolCallRepairInfo } from "@caupulican/pi-agent-core/agent-loop";
8
- import { Container, Loader, ProcessTerminal, Spacer, setKeybindings, Text, TUI, } from "@caupulican/pi-tui";
8
+ import { Container, ProcessTerminal, Spacer, setKeybindings, Text, TUI, } from "@caupulican/pi-tui";
9
9
  import { APP_NAME, APP_TITLE, getAgentDir, VERSION } from "../../config.js";
10
10
  import { parseSkillBlock } from "../../core/agent-session.js";
11
11
  import { FooterDataProvider } from "../../core/footer-data-provider.js";
@@ -25,6 +25,8 @@ import * as autocompleteProvider from "./autocomplete-provider.js";
25
25
  import * as autonomyCommands from "./autonomy-commands.js";
26
26
  import * as clipboardInput from "./clipboard-input.js";
27
27
  import * as compactionQueue from "./compaction-queue.js";
28
+ import { ActionTranscriptComponent } from "./components/action-transcript.js";
29
+ import { ActiveToolCallRegistry } from "./components/active-tool-call-registry.js";
28
30
  import { ActivityLaneComponent } from "./components/activity-lane.js";
29
31
  import { AgentsOverlay } from "./components/agents-overlay.js";
30
32
  import { AssistantMessageComponent } from "./components/assistant-message.js";
@@ -39,9 +41,7 @@ import { FooterComponent } from "./components/footer.js";
39
41
  import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./components/keybinding-hints.js";
40
42
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
41
43
  import { ToolExecutionComponent } from "./components/tool-execution.js";
42
- import { ToolGroupComponent } from "./components/tool-group.js";
43
- import { getToolPanelActionKey, shouldReuseToolPanelInPlace, ToolPanelRegistry, } from "./components/tool-panel-registry.js";
44
- import { TranscriptPager } from "./components/transcript-pager.js";
44
+ import { openTranscriptOverlay } from "./components/transcript-overlay.js";
45
45
  import { UserMessageComponent } from "./components/user-message.js";
46
46
  import * as configBackup from "./config-backup.js";
47
47
  import { EditorOverlayHost } from "./editor-overlay-host.js";
@@ -56,6 +56,7 @@ import * as localModelCommands from "./local-model-commands.js";
56
56
  import { ProfileMenuController } from "./profile-menu-controller.js";
57
57
  import * as reportCommands from "./report-commands.js";
58
58
  import * as resourceShellCommands from "./resource-shell-commands.js";
59
+ import { RuntimeStatusController } from "./runtime-status-controller.js";
59
60
  import { SecretMenuController } from "./secret-menu-controller.js";
60
61
  import * as sessionFlows from "./session-flow-commands.js";
61
62
  import * as sessionIoCommands from "./session-io-commands.js";
@@ -108,6 +109,24 @@ export class InteractiveMode {
108
109
  get settingsManager() {
109
110
  return this.session.settingsManager;
110
111
  }
112
+ get loadingAnimation() {
113
+ return this.runtimeStatus.loadingAnimation;
114
+ }
115
+ set loadingAnimation(value) {
116
+ this.runtimeStatus.loadingAnimation = value;
117
+ }
118
+ get workingVisible() {
119
+ return this.runtimeStatus.isWorkingVisible;
120
+ }
121
+ set workingVisible(value) {
122
+ this.runtimeStatus.isWorkingVisible = value;
123
+ }
124
+ get workingIndicatorOptions() {
125
+ return this.runtimeStatus.indicatorOptions;
126
+ }
127
+ set workingIndicatorOptions(value) {
128
+ this.runtimeStatus.indicatorOptions = value;
129
+ }
111
130
  constructor(runtimeHost, options = {}) {
112
131
  this.autocompleteProviderWrappers = [];
113
132
  this.isInitialized = false;
@@ -116,13 +135,6 @@ export class InteractiveMode {
116
135
  pendingClipboardImages: [],
117
136
  clipboardImageCounter: 0,
118
137
  };
119
- this.loadingAnimation = undefined;
120
- this.workingMessage = undefined;
121
- this.workingVisible = true;
122
- this.workingIndicatorOptions = undefined;
123
- this.defaultWorkingMessage = "Working...";
124
- this.defaultHiddenThinkingLabel = "Thinking...";
125
- this.hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
126
138
  this.lastSigintTime = 0;
127
139
  this.lastEscapeTime = 0;
128
140
  this.changelogMarkdown = undefined;
@@ -141,10 +153,11 @@ export class InteractiveMode {
141
153
  this.streamingMessage = undefined;
142
154
  this.streamingUiUpdateTimer = undefined;
143
155
  this.lastStreamingUiUpdateAt = 0;
144
- // Tool execution tracking and session-scoped reusable panels
145
- this.toolPanels = new ToolPanelRegistry();
156
+ // Active execution identity. Completed actions are owned by the transcript.
157
+ this.activeToolCalls = new ActiveToolCallRegistry();
146
158
  // Tool output expansion state
147
159
  this.toolOutputExpanded = false;
160
+ this.transcriptActionsExpanded = false;
148
161
  // Thinking block visibility state
149
162
  this.hideThinkingBlock = true;
150
163
  // Skill commands: command name -> skill file path
@@ -180,7 +193,6 @@ export class InteractiveMode {
180
193
  this.runtimeHost = runtimeHost;
181
194
  this.options = options;
182
195
  this.hasHumanAudience = options.hasHumanAudience ?? true;
183
- this.workingVisible = this.hasHumanAudience;
184
196
  this.runtimeHost.setBeforeSessionInvalidate(() => {
185
197
  this.extensionUiHost.resetExtensionUI();
186
198
  });
@@ -199,6 +211,14 @@ export class InteractiveMode {
199
211
  this.activityLane = this.hasHumanAudience
200
212
  ? new ActivityLaneComponent(theme, () => this.ui.requestRender())
201
213
  : undefined;
214
+ this.runtimeStatus = new RuntimeStatusController({
215
+ ui: this.ui,
216
+ statusContainer: this.statusContainer,
217
+ activityLane: this.activityLane,
218
+ hasHumanAudience: this.hasHumanAudience,
219
+ isStreaming: () => this.session.isStreaming,
220
+ isThinkingHidden: () => this.hideThinkingBlock,
221
+ });
202
222
  this.keybindings = KeybindingsManager.create();
203
223
  setKeybindings(this.keybindings);
204
224
  const editorPaddingX = this.settingsManager.getEditorPaddingX();
@@ -414,6 +434,7 @@ export class InteractiveMode {
414
434
  hint("app.tools.expand", "to expand tools"),
415
435
  hint("app.history.load", "to load session history"),
416
436
  hint("app.agents.open", "to show live agents"),
437
+ hint("app.transcript.open", "to view transcript"),
417
438
  hint("app.thinking.toggle", "to expand thinking"),
418
439
  hint("app.editor.external", "for external editor"),
419
440
  rawKeyHint("/", "for commands"),
@@ -864,7 +885,7 @@ export class InteractiveMode {
864
885
  this.compactionQueuedMessages = [];
865
886
  this.streamingComponent = undefined;
866
887
  this.streamingMessage = undefined;
867
- this.clearRenderedToolPanelState();
888
+ this.clearActiveToolCallState();
868
889
  void this.renderInitialMessages();
869
890
  }
870
891
  /**
@@ -873,193 +894,81 @@ export class InteractiveMode {
873
894
  getRegisteredToolDefinition(toolName) {
874
895
  return this.session.getToolDefinition(toolName);
875
896
  }
876
- getToolPanelScope() {
877
- return {
878
- sessionId: this.sessionManager.getSessionId?.(),
879
- sessionFile: this.sessionManager.getSessionFile?.(),
880
- cwd: this.sessionManager.getCwd(),
881
- };
882
- }
883
- appendToolExecutionComponent(component, allowGrouping) {
884
- const toolGroup = allowGrouping ? component.toolGroup?.trim() : undefined;
885
- if (!toolGroup) {
886
- this.chatContainer.addChild(component);
887
- this.trimLiveTuiHistory();
888
- return;
889
- }
897
+ appendTranscriptAction(component) {
890
898
  const children = this.chatContainer.children;
891
- const lastChild = children[children.length - 1];
892
- if (lastChild instanceof ToolGroupComponent && lastChild.toolGroup === toolGroup) {
893
- lastChild.addTool(component);
894
- this.trimLiveTuiHistory();
895
- return;
896
- }
897
- if (lastChild instanceof ToolExecutionComponent && lastChild.toolGroup?.trim() === toolGroup) {
898
- const group = new ToolGroupComponent(toolGroup, [lastChild, component]);
899
- group.setExpanded(this.toolOutputExpanded);
900
- children[children.length - 1] = group;
901
- this.trimLiveTuiHistory();
902
- return;
903
- }
904
- this.chatContainer.addChild(component);
905
- this.trimLiveTuiHistory();
906
- }
907
- detachToolExecutionComponent(component) {
908
- const children = this.chatContainer.children;
909
- const directIndex = children.indexOf(component);
910
- if (directIndex !== -1) {
911
- children.splice(directIndex, 1);
912
- return;
913
- }
914
- for (let i = 0; i < children.length; i++) {
915
- const child = children[i];
916
- if (!(child instanceof ToolGroupComponent) || !child.removeTool(component))
917
- continue;
918
- const remaining = child.getToolCount();
919
- if (remaining === 0) {
920
- children.splice(i, 1);
921
- }
922
- else if (remaining === 1) {
923
- const onlyTool = child.getOnlyTool();
924
- if (onlyTool)
925
- children[i] = onlyTool;
899
+ for (let index = children.length - 1; index >= 0; index--) {
900
+ const candidate = children[index];
901
+ if (candidate instanceof ActionTranscriptComponent) {
902
+ if (candidate.canAccept()) {
903
+ candidate.addAction(component);
904
+ this.trimLiveTuiHistory();
905
+ return;
906
+ }
907
+ break;
926
908
  }
927
- return;
909
+ if (candidate instanceof AssistantMessageComponent && !candidate.hasVisibleOutput())
910
+ continue;
911
+ break;
928
912
  }
913
+ const transcript = new ActionTranscriptComponent([component]);
914
+ transcript.setTranscriptExpanded(this.transcriptActionsExpanded);
915
+ this.chatContainer.addChild(transcript);
916
+ this.trimLiveTuiHistory();
929
917
  }
930
918
  attachToolExecutionComponent(toolName, toolCallId, args, repair, deferResultUntilExpanded = false) {
931
- const actionKey = getToolPanelActionKey(this.getToolPanelScope(), toolName, args);
932
919
  const toolDefinition = this.getRegisteredToolDefinition(toolName);
933
- const reuseInPlace = shouldReuseToolPanelInPlace(toolName, args);
934
- const existing = this.toolPanels.getReusable(actionKey, { allowActive: reuseInPlace });
935
- if (existing) {
936
- if (reuseInPlace && actionKey) {
937
- existing.resetInvocation(toolName, toolCallId, args, toolDefinition, repair, deferResultUntilExpanded);
938
- existing.setExpanded(this.toolOutputExpanded);
939
- this.toolPanels.replaceActiveForAction(toolCallId, existing, actionKey);
940
- this.ui.requestRender();
941
- return existing;
942
- }
943
- this.detachToolExecutionComponent(existing);
944
- existing.resetInvocation(toolName, toolCallId, args, toolDefinition, repair, deferResultUntilExpanded);
945
- existing.setExpanded(this.toolOutputExpanded);
946
- this.appendToolExecutionComponent(existing, true);
947
- this.toolPanels.register(toolCallId, existing, actionKey);
948
- return existing;
949
- }
950
920
  const component = new ToolExecutionComponent(toolName, toolCallId, args, {
951
921
  showImages: this.settingsManager.getShowImages(),
952
922
  imageWidthCells: this.settingsManager.getImageWidthCells(),
953
923
  repair,
954
924
  deferResultUntilExpanded,
955
925
  }, toolDefinition, this.ui, this.sessionManager.getCwd());
956
- component.setExpanded(this.toolOutputExpanded);
957
- this.appendToolExecutionComponent(component, true);
958
- this.toolPanels.register(toolCallId, component, actionKey);
926
+ this.appendTranscriptAction(component);
927
+ this.activeToolCalls.register(toolCallId, component);
959
928
  return component;
960
929
  }
961
930
  clearActiveToolCalls() {
962
- this.toolPanels.clearActive();
931
+ this.activeToolCalls.clearActive();
963
932
  }
964
- clearRenderedToolPanelState() {
965
- this.toolPanels.clearAll();
933
+ clearActiveToolCallState() {
934
+ this.activeToolCalls.clearActive();
966
935
  }
967
936
  getWorkingLoaderMessage() {
968
- return this.workingMessage ?? this.defaultWorkingMessage;
937
+ return this.runtimeStatus.getWorkingLoaderMessage();
969
938
  }
970
939
  createWorkingLoader() {
971
- return new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.workingIndicatorOptions);
940
+ return this.runtimeStatus.createWorkingLoader();
972
941
  }
973
942
  stopWorkingLoader() {
974
- if (this.loadingAnimation) {
975
- this.loadingAnimation.stop();
976
- this.loadingAnimation = undefined;
977
- }
978
- this.statusContainer.clear();
979
- this.activityLane?.remove("runtime:routing");
980
- this.activityLane?.remove("runtime:turn");
943
+ this.runtimeStatus.stopWorkingLoader();
981
944
  }
982
945
  setWorkingVisible(visible) {
983
- if (!this.hasHumanAudience) {
984
- this.workingVisible = false;
985
- this.stopWorkingLoader();
986
- return;
987
- }
988
- this.workingVisible = visible;
989
- if (!visible) {
990
- this.stopWorkingLoader();
991
- this.ui.requestRender();
992
- return;
993
- }
994
- if (this.session.isStreaming && !this.loadingAnimation) {
995
- if (this.workingIndicatorOptions) {
996
- this.statusContainer.clear();
997
- this.loadingAnimation = this.createWorkingLoader();
998
- this.statusContainer.addChild(this.loadingAnimation);
999
- }
1000
- else {
1001
- this.activityLane?.start({ id: "runtime:turn", kind: "runtime", label: this.getWorkingLoaderMessage() });
1002
- }
1003
- }
1004
- this.ui.requestRender();
946
+ this.runtimeStatus.setWorkingVisible(visible);
1005
947
  }
1006
948
  setWorkingIndicator(options) {
1007
- this.workingIndicatorOptions = options;
1008
- if (!this.hasHumanAudience) {
1009
- this.stopWorkingLoader();
1010
- return;
1011
- }
1012
- if (options) {
1013
- this.activityLane?.remove("runtime:turn");
1014
- if (this.session.isStreaming && this.workingVisible) {
1015
- this.stopWorkingLoader();
1016
- this.loadingAnimation = this.createWorkingLoader();
1017
- this.statusContainer.addChild(this.loadingAnimation);
1018
- }
1019
- }
1020
- else {
1021
- this.loadingAnimation?.stop();
1022
- this.loadingAnimation = undefined;
1023
- this.statusContainer.clear();
1024
- if (this.session.isStreaming && this.workingVisible) {
1025
- this.activityLane?.start({ id: "runtime:turn", kind: "runtime", label: this.getWorkingLoaderMessage() });
1026
- }
1027
- }
1028
- this.ui.requestRender();
949
+ this.runtimeStatus.setWorkingIndicator(options);
1029
950
  }
1030
951
  setHiddenThinkingLabel(label) {
1031
- this.hiddenThinkingLabel = label ?? this.defaultHiddenThinkingLabel;
1032
- for (const child of this.chatContainer.children) {
1033
- if (child instanceof AssistantMessageComponent) {
1034
- child.setHiddenThinkingLabel(this.hiddenThinkingLabel);
1035
- }
1036
- }
1037
- if (this.streamingComponent) {
1038
- this.streamingComponent.setHiddenThinkingLabel(this.hiddenThinkingLabel);
1039
- }
1040
- this.ui.requestRender();
952
+ this.runtimeStatus.setHiddenThinkingLabel(label);
953
+ if (this.streamingMessage)
954
+ this.updateRuntimeStatus(this.streamingMessage);
955
+ }
956
+ updateRuntimeStatus(message) {
957
+ this.runtimeStatus.updateRuntimeStatus(message);
1041
958
  }
1042
959
  /**
1043
960
  * Set the extension-provided working-loader message (undefined restores the default).
1044
961
  */
1045
962
  setWorkingMessage(message) {
1046
- this.workingMessage = message;
1047
- if (this.loadingAnimation) {
1048
- this.loadingAnimation.setMessage(message ?? this.defaultWorkingMessage);
1049
- }
1050
- this.activityLane?.update("runtime:turn", message ?? this.defaultWorkingMessage);
963
+ this.runtimeStatus.setWorkingMessage(message, this.streamingMessage);
1051
964
  }
1052
965
  /**
1053
966
  * Reset the working indicator and hidden-thinking label to their built-in defaults.
1054
967
  */
1055
968
  resetWorkingIndicators() {
1056
- this.workingMessage = undefined;
1057
- this.workingVisible = this.hasHumanAudience;
1058
- this.setWorkingIndicator();
1059
- if (this.loadingAnimation) {
1060
- this.loadingAnimation.setMessage(`${this.defaultWorkingMessage} (${keyText("app.interrupt")} to interrupt)`);
1061
- }
1062
- this.setHiddenThinkingLabel();
969
+ this.runtimeStatus.resetWorkingIndicators();
970
+ if (this.streamingMessage)
971
+ this.updateRuntimeStatus(this.streamingMessage);
1063
972
  }
1064
973
  async promptForMissingSessionCwd(error) {
1065
974
  const confirmed = await this.extensionUiHost.showExtensionConfirm("Session cwd not found", formatMissingSessionCwdPrompt(error.issue));
@@ -1537,7 +1446,7 @@ export class InteractiveMode {
1537
1446
  showDeferredHistoryPlaceholder(options = {}) {
1538
1447
  this.chatContainer.children = [];
1539
1448
  this.resetLiveTuiHistoryTrim();
1540
- this.clearRenderedToolPanelState();
1449
+ this.clearActiveToolCallState();
1541
1450
  const entryCount = this.getSessionEntryCount();
1542
1451
  if (entryCount > 0) {
1543
1452
  this.chatContainer.addChild(new Text(theme.fg("dim", `History hidden for typing performance (${entryCount} entries). Press ${keyText("app.history.load")} to load session history.`), 1, 0));
@@ -1609,30 +1518,27 @@ export class InteractiveMode {
1609
1518
  overlay.mount();
1610
1519
  }
1611
1520
  showTranscriptPager() {
1612
- let handle;
1613
- const pager = new TranscriptPager({
1521
+ openTranscriptOverlay({
1614
1522
  source: this.chatContainer,
1615
1523
  viewportRows: () => this.ui.terminal.rows,
1616
1524
  keybindings: this.keybindings,
1617
- onClose: () => handle?.hide(),
1618
- });
1619
- handle = this.ui.showOverlay(pager, {
1620
- width: "100%",
1621
- maxHeight: "100%",
1622
- row: 0,
1623
- col: 0,
1525
+ getToolsExpanded: () => this.toolOutputExpanded,
1526
+ setToolsExpanded: (expanded) => this.setToolsExpanded(expanded),
1527
+ getActionsExpanded: () => this.transcriptActionsExpanded,
1528
+ setActionsExpanded: (expanded) => this.setTranscriptActionsExpanded(expanded),
1529
+ showOverlay: (component, options) => this.ui.showOverlay(component, options),
1624
1530
  });
1625
1531
  }
1626
- attachStreamingToolPanels(message) {
1532
+ attachStreamingToolActions(message) {
1627
1533
  for (const content of message.content) {
1628
1534
  if (content.type !== "toolCall")
1629
1535
  continue;
1630
1536
  const repair = getToolCallRepairInfo(content);
1631
- if (!this.toolPanels.hasActive(content.id)) {
1537
+ if (!this.activeToolCalls.hasActive(content.id)) {
1632
1538
  this.attachToolExecutionComponent(content.name, content.id, content.arguments, repair);
1633
1539
  }
1634
1540
  else {
1635
- const component = this.toolPanels.getActive(content.id);
1541
+ const component = this.activeToolCalls.getActive(content.id);
1636
1542
  if (component) {
1637
1543
  component.updateArgs(content.arguments, repair);
1638
1544
  }
@@ -1641,6 +1547,7 @@ export class InteractiveMode {
1641
1547
  }
1642
1548
  applyStreamingMessageUpdate(message, options = {}) {
1643
1549
  this.streamingMessage = message;
1550
+ this.updateRuntimeStatus(message);
1644
1551
  if (!this.streamingComponent)
1645
1552
  return;
1646
1553
  const now = performance.now();
@@ -1651,7 +1558,7 @@ export class InteractiveMode {
1651
1558
  if (!this.streamingComponent || !this.streamingMessage)
1652
1559
  return;
1653
1560
  this.streamingComponent.updateContent(this.streamingMessage);
1654
- this.attachStreamingToolPanels(this.streamingMessage);
1561
+ this.attachStreamingToolActions(this.streamingMessage);
1655
1562
  this.lastStreamingUiUpdateAt = performance.now();
1656
1563
  this.ui.requestRender();
1657
1564
  };
@@ -1682,8 +1589,9 @@ export class InteractiveMode {
1682
1589
  protect(this.streamingComponent);
1683
1590
  protect(this.lastStatusSpacer);
1684
1591
  protect(this.lastStatusText);
1685
- for (const [, component] of this.toolPanels.activeEntries()) {
1686
- protect(component);
1592
+ for (const [, action] of this.activeToolCalls.activeEntries()) {
1593
+ const transcript = children.find((child) => child instanceof ActionTranscriptComponent && child.containsAction(action));
1594
+ protect(transcript);
1687
1595
  }
1688
1596
  const trimStart = children[0] === this.liveHistoryHiddenNotice ? 1 : 0;
1689
1597
  const targetTrimEnd = children.length - TUI_LIVE_HISTORY_TRIM_TO_COMPONENTS;
@@ -1798,7 +1706,7 @@ export class InteractiveMode {
1798
1706
  break;
1799
1707
  }
1800
1708
  case "assistant": {
1801
- const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
1709
+ const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings());
1802
1710
  this.chatContainer.addChild(assistantComponent);
1803
1711
  break;
1804
1712
  }
@@ -1836,7 +1744,7 @@ export class InteractiveMode {
1836
1744
  const stagingChatContainer = new Container();
1837
1745
  this.chatContainer = stagingChatContainer;
1838
1746
  this.resetLiveTuiHistoryTrim();
1839
- this.clearRenderedToolPanelState();
1747
+ this.clearActiveToolCallState();
1840
1748
  const renderedPendingTools = new Map();
1841
1749
  try {
1842
1750
  if (options.updateFooter) {
@@ -1874,7 +1782,7 @@ export class InteractiveMode {
1874
1782
  errorMessage = message.errorMessage || "Error";
1875
1783
  }
1876
1784
  component.updateResult({ content: [{ type: "text", text: errorMessage }], isError: true });
1877
- this.toolPanels.finish(content.id);
1785
+ this.activeToolCalls.finish(content.id);
1878
1786
  }
1879
1787
  else {
1880
1788
  renderedPendingTools.set(content.id, component);
@@ -1888,7 +1796,7 @@ export class InteractiveMode {
1888
1796
  if (component) {
1889
1797
  component.updateResult(message);
1890
1798
  renderedPendingTools.delete(message.toolCallId);
1891
- this.toolPanels.finish(message.toolCallId);
1799
+ this.activeToolCalls.finish(message.toolCallId);
1892
1800
  }
1893
1801
  }
1894
1802
  else {
@@ -2143,6 +2051,14 @@ export class InteractiveMode {
2143
2051
  }
2144
2052
  this.ui.requestRender();
2145
2053
  }
2054
+ setTranscriptActionsExpanded(expanded) {
2055
+ this.transcriptActionsExpanded = expanded;
2056
+ for (const child of this.chatContainer.children) {
2057
+ if (child instanceof ActionTranscriptComponent)
2058
+ child.setTranscriptExpanded(expanded);
2059
+ }
2060
+ this.ui.requestRender();
2061
+ }
2146
2062
  async toggleThinkingBlockVisibility() {
2147
2063
  this.hideThinkingBlock = !this.hideThinkingBlock;
2148
2064
  this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
@@ -2152,7 +2068,12 @@ export class InteractiveMode {
2152
2068
  if (this.streamingComponent && this.streamingMessage) {
2153
2069
  this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
2154
2070
  this.streamingComponent.updateContent(this.streamingMessage);
2071
+ this.updateRuntimeStatus(this.streamingMessage);
2155
2072
  this.chatContainer.addChild(this.streamingComponent);
2073
+ // Rebuilding the chat clears active call identity. Reattach
2074
+ // any tool calls that are still arriving so toggling thinking visibility
2075
+ // cannot make an in-flight tool disappear from the TUI.
2076
+ this.attachStreamingToolActions(this.streamingMessage);
2156
2077
  }
2157
2078
  this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
2158
2079
  }