@kolisachint/hoocode-agent 0.4.112 → 0.4.113

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 (42) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/core/subagent-events.d.ts +21 -0
  3. package/dist/core/subagent-events.d.ts.map +1 -0
  4. package/dist/core/subagent-events.js +25 -0
  5. package/dist/core/subagent-events.js.map +1 -0
  6. package/dist/core/subagent-pool.d.ts +5 -4
  7. package/dist/core/subagent-pool.d.ts.map +1 -1
  8. package/dist/core/subagent-pool.js +7 -9
  9. package/dist/core/subagent-pool.js.map +1 -1
  10. package/dist/modes/interactive/components/assistant-message.d.ts +27 -1
  11. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  12. package/dist/modes/interactive/components/assistant-message.js +150 -7
  13. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  14. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  15. package/dist/modes/interactive/components/custom-editor.js +18 -0
  16. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  17. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  18. package/dist/modes/interactive/components/task-panel.js +5 -2
  19. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  20. package/dist/modes/interactive/components/tool-execution.d.ts +17 -0
  21. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  22. package/dist/modes/interactive/components/tool-execution.js +78 -5
  23. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  24. package/dist/modes/interactive/components/user-message.d.ts +4 -0
  25. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  26. package/dist/modes/interactive/components/user-message.js +12 -3
  27. package/dist/modes/interactive/components/user-message.js.map +1 -1
  28. package/dist/modes/interactive/interactive-mode.d.ts +12 -0
  29. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  30. package/dist/modes/interactive/interactive-mode.js +75 -4
  31. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  32. package/dist/modes/interactive/voice/voice-controller.d.ts.map +1 -1
  33. package/dist/modes/interactive/voice/voice-controller.js +9 -5
  34. package/dist/modes/interactive/voice/voice-controller.js.map +1 -1
  35. package/dist/modes/print-mode.d.ts.map +1 -1
  36. package/dist/modes/print-mode.js +10 -3
  37. package/dist/modes/print-mode.js.map +1 -1
  38. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  39. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  40. package/examples/extensions/sandbox/package.json +1 -1
  41. package/examples/extensions/with-deps/package.json +1 -1
  42. package/package.json +4 -4
@@ -62,6 +62,44 @@ function isDeadTerminalError(error) {
62
62
  const code = error.code;
63
63
  return code !== undefined && DEAD_TERMINAL_ERROR_CODES.has(code);
64
64
  }
65
+ // How often the streaming assistant message re-parses its markdown. Deltas can
66
+ // arrive far faster than this; every application re-lexes the growing tail
67
+ // block, so applying per-delta made streaming cost O(message²).
68
+ const STREAM_RENDER_THROTTLE_MS = 100;
69
+ // Task-store mutations (subagent tool progress, usage ticks) arrive in bursts;
70
+ // each render they trigger reassembles the whole component tree, so cap them.
71
+ const TASK_RENDER_THROTTLE_MS = 50;
72
+ // Finished tool blocks beyond this many (oldest first) are frozen to release
73
+ // their retained output/image payloads (see ToolExecutionComponent.freeze).
74
+ // Generous so nothing near the viewport is ever frozen; the cap bounds the
75
+ // view layer's memory across a long session heavy on tool output.
76
+ const LIVE_TOOL_WINDOW = 50;
77
+ /**
78
+ * Leading+trailing throttle: the first call runs immediately, calls landing
79
+ * inside the window coalesce into one trailing run with the latest state.
80
+ */
81
+ function throttled(ms, fn) {
82
+ let timer;
83
+ let pending = false;
84
+ const run = () => {
85
+ fn();
86
+ timer = setTimeout(() => {
87
+ timer = undefined;
88
+ if (pending) {
89
+ pending = false;
90
+ run();
91
+ }
92
+ }, ms);
93
+ timer.unref?.();
94
+ };
95
+ return () => {
96
+ if (timer) {
97
+ pending = true;
98
+ return;
99
+ }
100
+ run();
101
+ };
102
+ }
65
103
  export class InteractiveMode {
66
104
  options;
67
105
  runtimeHost;
@@ -101,6 +139,17 @@ export class InteractiveMode {
101
139
  // Streaming message tracking
102
140
  streamingComponent = undefined;
103
141
  streamingMessage = undefined;
142
+ /** Throttled re-parse/re-render of the in-flight assistant message. The
143
+ * guard makes a trailing run after message_end/agent_end a no-op; a direct
144
+ * updateContent on message_end flushes the final state regardless. */
145
+ scheduleStreamingRender = throttled(STREAM_RENDER_THROTTLE_MS, () => {
146
+ if (!this.streamingComponent || !this.streamingMessage)
147
+ return;
148
+ // streaming=true: large blocks render segmented so only the tail chunk
149
+ // re-parses; message_end's direct updateContent renders the canonical form.
150
+ this.streamingComponent.updateContent(this.streamingMessage, true);
151
+ this.ui.requestRender();
152
+ });
104
153
  // Tool execution tracking: toolCallId -> component
105
154
  pendingTools = new Map();
106
155
  // Tool output expansion state
@@ -582,10 +631,12 @@ export class InteractiveMode {
582
631
  this.footerDataProvider.onBranchChange(() => {
583
632
  this.ui.requestRender();
584
633
  });
585
- // Re-render the UI when the task list changes (task panel shows active tasks).
586
- this.taskStoreUnsubscribe = taskStore.subscribe(() => {
634
+ // Re-render the UI when the task list changes (task panel shows active
635
+ // tasks). Throttled: subagent progress mutates the store in bursts, and
636
+ // each resulting render reassembles the entire component tree.
637
+ this.taskStoreUnsubscribe = taskStore.subscribe(throttled(TASK_RENDER_THROTTLE_MS, () => {
587
638
  this.ui.requestRender();
588
- });
639
+ }));
589
640
  // Initialize available provider count for footer display
590
641
  await this.modelController.updateAvailableProviderCount();
591
642
  }
@@ -826,6 +877,25 @@ export class InteractiveMode {
826
877
  this.pendingTools.clear();
827
878
  this.renderInitialMessages();
828
879
  }
880
+ /**
881
+ * Bound the view layer's memory: freeze finished tool blocks once more than
882
+ * LIVE_TOOL_WINDOW of them are live, releasing their retained tool output and
883
+ * base64 image copies. Runs on tool completion (infrequent) and only ever
884
+ * freezes blocks far above the viewport. The session data stays intact, so a
885
+ * later full rebuild (theme toggle / reload) restores full fidelity.
886
+ */
887
+ trimTranscriptMemory() {
888
+ const freezable = [];
889
+ for (const child of this.chatContainer.children) {
890
+ if (child instanceof ToolExecutionComponent && child.isFreezable()) {
891
+ freezable.push(child);
892
+ }
893
+ }
894
+ const excess = freezable.length - LIVE_TOOL_WINDOW;
895
+ for (let i = 0; i < excess; i++) {
896
+ freezable[i].freeze();
897
+ }
898
+ }
829
899
  /**
830
900
  * Get a registered tool definition by name (for custom rendering).
831
901
  */
@@ -1537,7 +1607,7 @@ export class InteractiveMode {
1537
1607
  case "message_update":
1538
1608
  if (this.streamingComponent && event.message.role === "assistant") {
1539
1609
  this.streamingMessage = event.message;
1540
- this.streamingComponent.updateContent(this.streamingMessage);
1610
+ this.scheduleStreamingRender();
1541
1611
  for (const content of this.streamingMessage.content) {
1542
1612
  if (content.type === "toolCall") {
1543
1613
  if (!this.pendingTools.has(content.id)) {
@@ -1627,6 +1697,7 @@ export class InteractiveMode {
1627
1697
  if (component) {
1628
1698
  component.updateResult({ ...event.result, isError: event.isError });
1629
1699
  this.pendingTools.delete(event.toolCallId);
1700
+ this.trimTranscriptMemory();
1630
1701
  this.ui.requestRender();
1631
1702
  }
1632
1703
  break;