@parhelia/core 0.1.11151 → 0.1.11180

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 (224) hide show
  1. package/dist/agents-view/AgentsInbox.d.ts +2 -1
  2. package/dist/agents-view/AgentsInbox.js +2 -2
  3. package/dist/agents-view/AgentsInbox.js.map +1 -1
  4. package/dist/agents-view/AgentsView.js +30 -1
  5. package/dist/agents-view/AgentsView.js.map +1 -1
  6. package/dist/components/ui/card.d.ts +1 -1
  7. package/dist/components/ui/card.js +1 -1
  8. package/dist/components/ui/card.js.map +1 -1
  9. package/dist/components/ui/paste-button.d.ts +1 -1
  10. package/dist/components/ui/paste-button.js +79 -22
  11. package/dist/components/ui/paste-button.js.map +1 -1
  12. package/dist/config/config.js +83 -51
  13. package/dist/config/config.js.map +1 -1
  14. package/dist/config/types.d.ts +29 -4
  15. package/dist/editor/ContentTree.js +92 -22
  16. package/dist/editor/ContentTree.js.map +1 -1
  17. package/dist/editor/FieldActionsOverlay.d.ts +1 -0
  18. package/dist/editor/FieldActionsOverlay.js +17 -1
  19. package/dist/editor/FieldActionsOverlay.js.map +1 -1
  20. package/dist/editor/FieldListField.js +1 -1
  21. package/dist/editor/FieldListField.js.map +1 -1
  22. package/dist/editor/LinkEditorDialog.js +33 -24
  23. package/dist/editor/LinkEditorDialog.js.map +1 -1
  24. package/dist/editor/MainLayout.js +2 -2
  25. package/dist/editor/MainLayout.js.map +1 -1
  26. package/dist/editor/PictureEditor.js +1 -1
  27. package/dist/editor/PictureEditor.js.map +1 -1
  28. package/dist/editor/ai/AgentTerminal.js +63 -26
  29. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  30. package/dist/editor/ai/Agents.js +7 -2
  31. package/dist/editor/ai/Agents.js.map +1 -1
  32. package/dist/editor/client/EditorShell.js +178 -79
  33. package/dist/editor/client/EditorShell.js.map +1 -1
  34. package/dist/editor/client/OperationDialogContent.d.ts +13 -0
  35. package/dist/editor/client/OperationDialogContent.js +13 -0
  36. package/dist/editor/client/OperationDialogContent.js.map +1 -0
  37. package/dist/editor/client/editContext.d.ts +2 -0
  38. package/dist/editor/client/editContext.js.map +1 -1
  39. package/dist/editor/client/hooks/useGlobalEditorKeyDown.js +5 -2
  40. package/dist/editor/client/hooks/useGlobalEditorKeyDown.js.map +1 -1
  41. package/dist/editor/client/hooks/useQuota.d.ts +4 -0
  42. package/dist/editor/client/hooks/useQuota.js.map +1 -1
  43. package/dist/editor/client/hooks/useSocketMessageHandler.d.ts +2 -2
  44. package/dist/editor/client/hooks/useSocketMessageHandler.js +5 -7
  45. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  46. package/dist/editor/client/operations.d.ts +1 -0
  47. package/dist/editor/client/operations.js +332 -8
  48. package/dist/editor/client/operations.js.map +1 -1
  49. package/dist/editor/client/ui/EditorChrome.js +1 -1
  50. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  51. package/dist/editor/commands/itemCommands.d.ts +0 -1
  52. package/dist/editor/commands/itemCommands.js +1 -16
  53. package/dist/editor/commands/itemCommands.js.map +1 -1
  54. package/dist/editor/commands/undo.js +6 -2
  55. package/dist/editor/commands/undo.js.map +1 -1
  56. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
  57. package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
  58. package/dist/editor/page-editor-chrome/FieldActionIndicator.js +56 -2
  59. package/dist/editor/page-editor-chrome/FieldActionIndicator.js.map +1 -1
  60. package/dist/editor/page-editor-chrome/FrameMenu.js +5 -4
  61. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  62. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +5 -1
  63. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  64. package/dist/editor/page-viewer/PageViewerFrame.js +118 -13
  65. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  66. package/dist/editor/reviews/CreateReviewDialog.js +1 -1
  67. package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
  68. package/dist/editor/reviews/DecisionsMatrix.js +1 -1
  69. package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
  70. package/dist/editor/reviews/ReviewsList.js +1 -1
  71. package/dist/editor/reviews/ReviewsList.js.map +1 -1
  72. package/dist/editor/services/editService.d.ts +20 -3
  73. package/dist/editor/services/editService.js +17 -17
  74. package/dist/editor/services/editService.js.map +1 -1
  75. package/dist/editor/services/indexService.d.ts +4 -1
  76. package/dist/editor/services/indexService.js +12 -0
  77. package/dist/editor/services/indexService.js.map +1 -1
  78. package/dist/editor/services/serviceHelper.js +1 -0
  79. package/dist/editor/services/serviceHelper.js.map +1 -1
  80. package/dist/editor/settings/About.d.ts +1 -0
  81. package/dist/editor/settings/About.js +9 -0
  82. package/dist/editor/settings/About.js.map +1 -0
  83. package/dist/editor/settings/AllAgentsPanel.d.ts +5 -0
  84. package/dist/editor/settings/AllAgentsPanel.js +126 -0
  85. package/dist/editor/settings/AllAgentsPanel.js.map +1 -0
  86. package/dist/editor/settings/IndexOverview.d.ts +1 -0
  87. package/dist/editor/settings/IndexOverview.js +471 -0
  88. package/dist/editor/settings/IndexOverview.js.map +1 -0
  89. package/dist/editor/settings/Info.d.ts +1 -0
  90. package/dist/editor/settings/Info.js +11 -0
  91. package/dist/editor/settings/Info.js.map +1 -0
  92. package/dist/editor/settings/LatestFeedback.d.ts +1 -0
  93. package/dist/editor/settings/LatestFeedback.js +136 -0
  94. package/dist/editor/settings/LatestFeedback.js.map +1 -0
  95. package/dist/editor/settings/QuotaInfo.d.ts +1 -0
  96. package/dist/editor/settings/QuotaInfo.js +102 -0
  97. package/dist/editor/settings/QuotaInfo.js.map +1 -0
  98. package/dist/editor/settings/SettingsMenu.d.ts +1 -0
  99. package/dist/editor/settings/SettingsMenu.js +74 -0
  100. package/dist/editor/settings/SettingsMenu.js.map +1 -0
  101. package/dist/editor/settings/SettingsView.d.ts +1 -0
  102. package/dist/editor/settings/SettingsView.js +85 -0
  103. package/dist/editor/settings/SettingsView.js.map +1 -0
  104. package/dist/editor/settings/Setup.d.ts +1 -0
  105. package/dist/editor/settings/Setup.js +211 -0
  106. package/dist/editor/settings/Setup.js.map +1 -0
  107. package/dist/editor/settings/Status.d.ts +1 -0
  108. package/dist/editor/settings/Status.js +85 -0
  109. package/dist/editor/settings/Status.js.map +1 -0
  110. package/dist/editor/settings/WebSocketMessages.d.ts +1 -0
  111. package/dist/editor/settings/WebSocketMessages.js +71 -0
  112. package/dist/editor/settings/WebSocketMessages.js.map +1 -0
  113. package/dist/editor/settings/panels/AgentsPanel.d.ts +6 -0
  114. package/dist/editor/settings/panels/AgentsPanel.js +186 -0
  115. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -0
  116. package/dist/editor/settings/panels/DatabasePanel.d.ts +6 -0
  117. package/dist/editor/settings/panels/DatabasePanel.js +50 -0
  118. package/dist/editor/settings/panels/DatabasePanel.js.map +1 -0
  119. package/dist/editor/settings/panels/ItemConfigPanel.d.ts +13 -0
  120. package/dist/editor/settings/panels/ItemConfigPanel.js +52 -0
  121. package/dist/editor/settings/panels/ItemConfigPanel.js.map +1 -0
  122. package/dist/editor/settings/panels/ModelsPanel.d.ts +6 -0
  123. package/dist/editor/settings/panels/ModelsPanel.js +269 -0
  124. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -0
  125. package/dist/editor/settings/panels/ProvidersPanel.d.ts +6 -0
  126. package/dist/editor/settings/panels/ProvidersPanel.js +206 -0
  127. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -0
  128. package/dist/editor/settings/panels/SearchConfigPanel.d.ts +6 -0
  129. package/dist/editor/settings/panels/SearchConfigPanel.js +134 -0
  130. package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -0
  131. package/dist/editor/settings/panels/SettingsPanel.d.ts +6 -0
  132. package/dist/editor/settings/panels/SettingsPanel.js +39 -0
  133. package/dist/editor/settings/panels/SettingsPanel.js.map +1 -0
  134. package/dist/editor/settings/panels/StatusPanel.d.ts +6 -0
  135. package/dist/editor/settings/panels/StatusPanel.js +141 -0
  136. package/dist/editor/settings/panels/StatusPanel.js.map +1 -0
  137. package/dist/editor/settings/panels/ToolsPanel.d.ts +6 -0
  138. package/dist/editor/settings/panels/ToolsPanel.js +192 -0
  139. package/dist/editor/settings/panels/ToolsPanel.js.map +1 -0
  140. package/dist/editor/settings/panels/index.d.ts +14 -0
  141. package/dist/editor/settings/panels/index.js +15 -0
  142. package/dist/editor/settings/panels/index.js.map +1 -0
  143. package/dist/editor/settings/panels/useSidebarEditor.d.ts +15 -0
  144. package/dist/editor/settings/panels/useSidebarEditor.js +24 -0
  145. package/dist/editor/settings/panels/useSidebarEditor.js.map +1 -0
  146. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
  147. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
  148. package/dist/editor/settings/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
  149. package/dist/editor/settings/setup-steps/AiSetupStep/index.d.ts +2 -0
  150. package/dist/editor/settings/setup-steps/AiSetupStep/index.js +22 -0
  151. package/dist/editor/settings/setup-steps/AiSetupStep/index.js.map +1 -0
  152. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -0
  153. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js +233 -0
  154. package/dist/editor/settings/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -0
  155. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +15 -0
  156. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +14 -0
  157. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +1 -0
  158. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
  159. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
  160. package/dist/editor/settings/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
  161. package/dist/editor/settings/setup-steps/AiSetupStep/tools/GenerateToolsSection.d.ts +1 -0
  162. package/dist/editor/settings/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +367 -0
  163. package/dist/editor/settings/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -0
  164. package/dist/editor/settings/setup-steps/AiSetupStep/types.d.ts +1 -0
  165. package/dist/editor/settings/setup-steps/AiSetupStep/types.js +2 -0
  166. package/dist/editor/settings/setup-steps/AiSetupStep/types.js.map +1 -0
  167. package/dist/editor/settings/setup-steps/AiSetupStep/utils.d.ts +5 -0
  168. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js +44 -0
  169. package/dist/editor/settings/setup-steps/AiSetupStep/utils.js.map +1 -0
  170. package/dist/editor/settings/setup-steps/IndexSetupStep.d.ts +2 -0
  171. package/dist/editor/settings/setup-steps/IndexSetupStep.js +36 -0
  172. package/dist/editor/settings/setup-steps/IndexSetupStep.js.map +1 -0
  173. package/dist/editor/settings/setup-steps/SettingsSetupStep.d.ts +2 -0
  174. package/dist/editor/settings/setup-steps/SettingsSetupStep.js +111 -0
  175. package/dist/editor/settings/setup-steps/SettingsSetupStep.js.map +1 -0
  176. package/dist/editor/settings/setup-steps/SetupOverview.d.ts +14 -0
  177. package/dist/editor/settings/setup-steps/SetupOverview.js +38 -0
  178. package/dist/editor/settings/setup-steps/SetupOverview.js.map +1 -0
  179. package/dist/editor/settings/status/coreStatusChecks.d.ts +25 -0
  180. package/dist/editor/settings/status/coreStatusChecks.js +231 -0
  181. package/dist/editor/settings/status/coreStatusChecks.js.map +1 -0
  182. package/dist/editor/settings/status/index.d.ts +3 -0
  183. package/dist/editor/settings/status/index.js +3 -0
  184. package/dist/editor/settings/status/index.js.map +1 -0
  185. package/dist/editor/settings/status/useStartupChecks.d.ts +17 -0
  186. package/dist/editor/settings/status/useStartupChecks.js +54 -0
  187. package/dist/editor/settings/status/useStartupChecks.js.map +1 -0
  188. package/dist/editor/sidebar/EditHistory.js +18 -14
  189. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  190. package/dist/editor/sidebar/MainContentTree.js +0 -1
  191. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  192. package/dist/editor/sidebar/OperationItem.js +4 -3
  193. package/dist/editor/sidebar/OperationItem.js.map +1 -1
  194. package/dist/editor/ui/PerfectTree.js +1 -1
  195. package/dist/editor/ui/PerfectTree.js.map +1 -1
  196. package/dist/editor/ui/Section.js +3 -3
  197. package/dist/editor/ui/Section.js.map +1 -1
  198. package/dist/editor/ui/SimpleMenu.js +13 -4
  199. package/dist/editor/ui/SimpleMenu.js.map +1 -1
  200. package/dist/editor/ui/SimpleToolbar.js +1 -1
  201. package/dist/editor/ui/SimpleToolbar.js.map +1 -1
  202. package/dist/editor/utils/keyboardNavigation.js +89 -27
  203. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  204. package/dist/revision.d.ts +2 -2
  205. package/dist/revision.js +2 -2
  206. package/dist/setup/SetupWizardPage.js +2 -2
  207. package/dist/setup/SetupWizardPage.js.map +1 -1
  208. package/dist/setup/services/setupWizardService.d.ts +132 -12
  209. package/dist/setup/services/setupWizardService.js +82 -6
  210. package/dist/setup/services/setupWizardService.js.map +1 -1
  211. package/dist/setup/wizard/index.d.ts +5 -4
  212. package/dist/setup/wizard/index.js +6 -4
  213. package/dist/setup/wizard/index.js.map +1 -1
  214. package/dist/setup/wizard/steps/AddModelDialog.d.ts +10 -0
  215. package/dist/setup/wizard/steps/AddModelDialog.js +119 -0
  216. package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -0
  217. package/dist/setup/wizard/steps/ImportModelDialog.d.ts +10 -0
  218. package/dist/setup/wizard/steps/ImportModelDialog.js +351 -0
  219. package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -0
  220. package/dist/splash-screen/ModernSplashScreen.js +1 -1
  221. package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
  222. package/dist/styles.css +183 -10
  223. package/dist/types.d.ts +36 -1
  224. package/package.json +4 -4
@@ -559,6 +559,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
559
559
  useEffect(() => {
560
560
  isWaitingRef.current = isWaitingForResponse;
561
561
  }, [isWaitingForResponse]);
562
+ // Guard ref to prevent WebSocket handlers from re-enabling execution states
563
+ // while a stop operation is in progress. This prevents race conditions where
564
+ // messages arriving during the stop process could flip the UI back to "executing".
565
+ const isStoppingRef = useRef(false);
562
566
  // Server-driven state: true when agent is actively processing (set by WebSocket messages)
563
567
  const [isAgentThinking, setIsAgentThinking] = useState(false);
564
568
  const hasActiveStreaming = useCallback(() => {
@@ -679,7 +683,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
679
683
  const shouldCreateNewMessage = useRef(false);
680
684
  // Keep a ref to the current messages for immediate access
681
685
  const messagesRef = useRef([]);
682
- const abortControllerRef = useRef(null);
683
686
  const messagesEndRef = useRef(null);
684
687
  const textareaRef = useRef(null);
685
688
  const placeholderInputRef = useRef(null);
@@ -1705,6 +1708,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1705
1708
  return;
1706
1709
  // Handle agent:run:start
1707
1710
  if (messageType === "agent:run:start") {
1711
+ // If a stop operation is in progress, ignore this message to prevent
1712
+ // race conditions where the UI flips back to "executing" during stop
1713
+ if (isStoppingRef.current) {
1714
+ console.log("[AgentTerminal] Ignoring agent:run:start during stop operation");
1715
+ return;
1716
+ }
1708
1717
  // Reset run-scoped deduplication so new run seq values (starting at 1)
1709
1718
  // are not discarded due to previous run's lastSeqRef
1710
1719
  lastSeqRef.current = 0;
@@ -1820,6 +1829,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1820
1829
  }
1821
1830
  // Handle agent:run:delta (content, tools, etc.)
1822
1831
  if (messageType === "agent:run:delta") {
1832
+ // If a stop operation is in progress, ignore streaming deltas to prevent
1833
+ // new messages from being added during the stop process
1834
+ if (isStoppingRef.current) {
1835
+ return;
1836
+ }
1823
1837
  // Allow deltas if the agent is running OR if we already have an active streaming message
1824
1838
  // OR if the server provided a messageId for targeted updates.
1825
1839
  // This avoids dropping early deltas that may arrive before the 'running' status update.
@@ -2024,6 +2038,31 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2024
2038
  });
2025
2039
  return;
2026
2040
  }
2041
+ // Handle "completed" state (fallback for legacy code paths that send status instead of lifecycle event)
2042
+ if (normalizedStatus === "completed" ||
2043
+ normalizedStatus === "Completed") {
2044
+ // Reset deduplication for the next run
2045
+ lastSeqRef.current = 0;
2046
+ // Mark the last assistant message as completed
2047
+ setMessages((prev) => {
2048
+ const updated = prev.map((msg) => msg.role === "assistant" && !msg.isCompleted
2049
+ ? {
2050
+ ...msg,
2051
+ isCompleted: true,
2052
+ messageType: "completed",
2053
+ }
2054
+ : msg);
2055
+ messagesRef.current = updated;
2056
+ return updated;
2057
+ });
2058
+ setIsWaitingForResponse(false);
2059
+ isWaitingRef.current = false;
2060
+ setIsConnecting(false);
2061
+ shouldCreateNewMessage.current = false;
2062
+ // Server says agent finished thinking
2063
+ setIsAgentThinking(false);
2064
+ return;
2065
+ }
2027
2066
  }
2028
2067
  catch (err) {
2029
2068
  console.error("[AgentTerminal] Error handling status update:", err);
@@ -2232,14 +2271,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2232
2271
  }
2233
2272
  setSelectedModelId(nextModelId || undefined);
2234
2273
  }, [activeProfile?.id, agent?.model]);
2235
- // Cleanup stream connection when component unmounts or agent changes
2236
- useEffect(() => {
2237
- return () => {
2238
- if (abortControllerRef.current) {
2239
- abortControllerRef.current.abort();
2240
- }
2241
- };
2242
- }, [agent?.id]);
2243
2274
  // Initialize mode from metadata; fall back to agent.Mode from server
2244
2275
  useEffect(() => {
2245
2276
  try {
@@ -2929,39 +2960,45 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2929
2960
  // Stop current execution/stream safely
2930
2961
  const handleStop = useCallback(async () => {
2931
2962
  try {
2963
+ // 1. Set the stopping guard to prevent WebSocket handlers from re-enabling states
2964
+ // This must happen FIRST, before any other state changes
2965
+ isStoppingRef.current = true;
2966
+ // 2. Update all UI state to reflect stopped status
2932
2967
  setIsWaitingForResponse(false);
2933
2968
  isWaitingRef.current = false;
2969
+ setIsConnecting(false);
2970
+ setIsSubmitting(false);
2934
2971
  // User stopped the agent, hide thinking dots
2935
2972
  setIsAgentThinking(false);
2936
- // Request backend to stop the current execution (does NOT close the agent)
2973
+ // 3. Mark any in-progress streaming messages as completed in UI
2974
+ setMessages((prev) => {
2975
+ const updated = prev.map((msg) => !msg.isCompleted && msg.messageType === "streaming"
2976
+ ? { ...msg, isCompleted: true, messageType: "completed" }
2977
+ : msg);
2978
+ messagesRef.current = updated;
2979
+ return updated;
2980
+ });
2981
+ // 4. Request backend to stop the current execution (does NOT close the agent)
2982
+ // Wait for backend confirmation to ensure agent actually stopped
2937
2983
  if (agentStub?.id) {
2938
2984
  try {
2939
2985
  await cancelAgent(agentStub.id);
2940
2986
  }
2941
2987
  catch (err) {
2942
2988
  console.error("Failed to cancel agent on backend:", err);
2943
- // Continue with UI cleanup even if backend call fails
2989
+ // Continue - UI is already in stopped state, but backend may still be running
2990
+ // The isStoppingRef guard will be cleared below so future runs can proceed
2944
2991
  }
2945
2992
  }
2946
- // Disconnect from the stream
2947
- if (abortControllerRef.current) {
2948
- abortControllerRef.current.abort();
2949
- abortControllerRef.current = null;
2950
- }
2951
- setIsConnecting(false);
2952
- setIsSubmitting(false);
2953
- // Mark any in-progress streaming messages as completed in UI
2954
- setMessages((prev) => {
2955
- const updated = prev.map((msg) => !msg.isCompleted && msg.messageType === "streaming"
2956
- ? { ...msg, isCompleted: true, messageType: "completed" }
2957
- : msg);
2958
- messagesRef.current = updated;
2959
- return updated;
2960
- });
2961
2993
  }
2962
2994
  catch (e) {
2963
2995
  console.error("Failed to stop agent execution", e);
2964
2996
  }
2997
+ finally {
2998
+ // Clear the stopping guard so future runs can proceed normally
2999
+ // This happens after backend confirmation (or error)
3000
+ isStoppingRef.current = false;
3001
+ }
2965
3002
  }, []);
2966
3003
  // Determine effective cost limit from agent, profile, or metadata so the cost display
2967
3004
  // is visible immediately even before any messages or server-side persistence.