@parhelia/core 0.1.11873 → 0.1.11955

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 (247) hide show
  1. package/dist/agents-view/AgentsInbox.d.ts +1 -1
  2. package/dist/agents-view/AgentsInbox.js +15 -2
  3. package/dist/agents-view/AgentsInbox.js.map +1 -1
  4. package/dist/agents-view/AgentsSidebar.d.ts +20 -0
  5. package/dist/agents-view/AgentsSidebar.js +21 -0
  6. package/dist/agents-view/AgentsSidebar.js.map +1 -0
  7. package/dist/agents-view/AgentsView.d.ts +6 -7
  8. package/dist/agents-view/AgentsView.js +63 -25
  9. package/dist/agents-view/AgentsView.js.map +1 -1
  10. package/dist/agents-view/AgentsWorkspaceView.d.ts +2 -6
  11. package/dist/agents-view/AgentsWorkspaceView.js +242 -112
  12. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  13. package/dist/components/ui/context-menu.js +24 -9
  14. package/dist/components/ui/context-menu.js.map +1 -1
  15. package/dist/components/ui/select.js +1 -1
  16. package/dist/components/ui/select.js.map +1 -1
  17. package/dist/config/config.js +15 -11
  18. package/dist/config/config.js.map +1 -1
  19. package/dist/editor/ContentTree.js +2 -2
  20. package/dist/editor/ContentTree.js.map +1 -1
  21. package/dist/editor/ContextMenu.js +11 -5
  22. package/dist/editor/ContextMenu.js.map +1 -1
  23. package/dist/editor/FieldListField.js +1 -1
  24. package/dist/editor/FieldListField.js.map +1 -1
  25. package/dist/editor/MainLayout.js.map +1 -1
  26. package/dist/editor/MobileLayout.js +19 -9
  27. package/dist/editor/MobileLayout.js.map +1 -1
  28. package/dist/editor/ai/AgentStatusBadge.d.ts +1 -1
  29. package/dist/editor/ai/AgentStatusBadge.js +18 -2
  30. package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
  31. package/dist/editor/ai/AgentTerminal.js +342 -55
  32. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  33. package/dist/editor/ai/AiResponseMessage.js +46 -4
  34. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  35. package/dist/editor/ai/ContextInfoBar.js +151 -5
  36. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  37. package/dist/editor/ai/EditOperationsPanel.d.ts +2 -1
  38. package/dist/editor/ai/EditOperationsPanel.js +6 -1
  39. package/dist/editor/ai/EditOperationsPanel.js.map +1 -1
  40. package/dist/editor/ai/dialogs/AgentDialogHandler.js +64 -15
  41. package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
  42. package/dist/editor/ai/dialogs/QuestionnaireInline.js +111 -20
  43. package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
  44. package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +24 -0
  45. package/dist/editor/ai/dialogs/agentDialogTypes.js.map +1 -1
  46. package/dist/editor/ai/useAgentStatus.d.ts +1 -0
  47. package/dist/editor/ai/useAgentStatus.js +74 -29
  48. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  49. package/dist/editor/client/EditorShell.js +72 -8
  50. package/dist/editor/client/EditorShell.js.map +1 -1
  51. package/dist/editor/client/hooks/useQuota.d.ts +7 -0
  52. package/dist/editor/client/hooks/useQuota.js.map +1 -1
  53. package/dist/editor/client/hooks/useSocketMessageHandler.js +10 -1
  54. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  55. package/dist/editor/client/pageModelBuilder.js +3 -30
  56. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  57. package/dist/editor/client/ui/EditorChrome.js +31 -1
  58. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  59. package/dist/editor/commands/componentCommands.js +106 -6
  60. package/dist/editor/commands/componentCommands.js.map +1 -1
  61. package/dist/editor/commands/itemCommands.d.ts +1 -0
  62. package/dist/editor/commands/itemCommands.js +28 -1
  63. package/dist/editor/commands/itemCommands.js.map +1 -1
  64. package/dist/editor/componentTreeHelper.js +22 -2
  65. package/dist/editor/componentTreeHelper.js.map +1 -1
  66. package/dist/editor/insertMenuItems.d.ts +4 -0
  67. package/dist/editor/insertMenuItems.js +66 -0
  68. package/dist/editor/insertMenuItems.js.map +1 -0
  69. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -1
  70. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  71. package/dist/editor/page-editor-chrome/FrameMenus.js +8 -1
  72. package/dist/editor/page-editor-chrome/FrameMenus.js.map +1 -1
  73. package/dist/editor/page-editor-chrome/InlineEditor.js +25 -11
  74. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  75. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +32 -17
  76. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  77. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +17 -11
  78. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  79. package/dist/editor/page-viewer/EditorForm.js +6 -5
  80. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  81. package/dist/editor/page-viewer/PageViewerFrame.js +49 -1
  82. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  83. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +5 -0
  84. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
  85. package/dist/editor/pageModel.d.ts +2 -0
  86. package/dist/editor/reviews/CreateReviewConfirmStep.d.ts +16 -0
  87. package/dist/editor/reviews/CreateReviewConfirmStep.js +37 -0
  88. package/dist/editor/reviews/CreateReviewConfirmStep.js.map +1 -0
  89. package/dist/editor/reviews/CreateReviewDetailsStep.d.ts +51 -0
  90. package/dist/editor/reviews/CreateReviewDetailsStep.js +121 -0
  91. package/dist/editor/reviews/CreateReviewDetailsStep.js.map +1 -0
  92. package/dist/editor/reviews/CreateReviewDialog.js +260 -173
  93. package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
  94. package/dist/editor/reviews/CreateReviewSuccessStep.d.ts +6 -0
  95. package/dist/editor/reviews/CreateReviewSuccessStep.js +8 -0
  96. package/dist/editor/reviews/CreateReviewSuccessStep.js.map +1 -0
  97. package/dist/editor/reviews/DecisionsMatrix.js +96 -25
  98. package/dist/editor/reviews/DecisionsMatrix.js.map +1 -1
  99. package/dist/editor/reviews/MultiReviewManager.js +25 -3
  100. package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
  101. package/dist/editor/reviews/PagesPanel.js +31 -15
  102. package/dist/editor/reviews/PagesPanel.js.map +1 -1
  103. package/dist/editor/reviews/ReviewCard.js +13 -7
  104. package/dist/editor/reviews/ReviewCard.js.map +1 -1
  105. package/dist/editor/reviews/ReviewDetail.js +2 -2
  106. package/dist/editor/reviews/ReviewDetail.js.map +1 -1
  107. package/dist/editor/reviews/ReviewsList.js +7 -3
  108. package/dist/editor/reviews/ReviewsList.js.map +1 -1
  109. package/dist/editor/services/agentService.d.ts +14 -1
  110. package/dist/editor/services/agentService.js +27 -1
  111. package/dist/editor/services/agentService.js.map +1 -1
  112. package/dist/editor/services/aiService.d.ts +39 -1
  113. package/dist/editor/services/aiService.js +12 -2
  114. package/dist/editor/services/aiService.js.map +1 -1
  115. package/dist/editor/services/serviceHelper.d.ts +1 -1
  116. package/dist/editor/services/serviceHelper.js +2 -1
  117. package/dist/editor/services/serviceHelper.js.map +1 -1
  118. package/dist/editor/settings/About.js +1 -1
  119. package/dist/editor/settings/About.js.map +1 -1
  120. package/dist/editor/settings/QuotaInfo.js +202 -4
  121. package/dist/editor/settings/QuotaInfo.js.map +1 -1
  122. package/dist/editor/settings/panels/SearchConfigPanel.js +11 -13
  123. package/dist/editor/settings/panels/SearchConfigPanel.js.map +1 -1
  124. package/dist/editor/settings/status/useStartupChecks.js +2 -1
  125. package/dist/editor/settings/status/useStartupChecks.js.map +1 -1
  126. package/dist/editor/sidebar/ComponentTree.js +26 -20
  127. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  128. package/dist/editor/sidebar/MobileWorkspacePopover.d.ts +16 -0
  129. package/dist/editor/sidebar/MobileWorkspacePopover.js +35 -0
  130. package/dist/editor/sidebar/MobileWorkspacePopover.js.map +1 -0
  131. package/dist/editor/sidebar/NavigationSidebar.js +30 -14
  132. package/dist/editor/sidebar/NavigationSidebar.js.map +1 -1
  133. package/dist/editor/ui/ItemNameDialogNew.js +8 -8
  134. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  135. package/dist/editor/ui/SharedFolderSelectorDialog.d.ts +11 -0
  136. package/dist/editor/ui/SharedFolderSelectorDialog.js +79 -0
  137. package/dist/editor/ui/SharedFolderSelectorDialog.js.map +1 -0
  138. package/dist/editor/ui/SimpleTabs.js +1 -1
  139. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  140. package/dist/editor/ui/Splitter.js +4 -2
  141. package/dist/editor/ui/Splitter.js.map +1 -1
  142. package/dist/editor/ui/TreeListSelector.d.ts +2 -1
  143. package/dist/editor/ui/TreeListSelector.js +2 -2
  144. package/dist/editor/ui/TreeListSelector.js.map +1 -1
  145. package/dist/editor/utils.js +42 -0
  146. package/dist/editor/utils.js.map +1 -1
  147. package/dist/editor/views/EditorSlot.js +7 -8
  148. package/dist/editor/views/EditorSlot.js.map +1 -1
  149. package/dist/index.d.ts +1 -0
  150. package/dist/index.js +1 -0
  151. package/dist/index.js.map +1 -1
  152. package/dist/revision.d.ts +2 -2
  153. package/dist/revision.js +2 -2
  154. package/dist/setup/wizard/steps/ImportModelDialog.js +24 -22
  155. package/dist/setup/wizard/steps/ImportModelDialog.js.map +1 -1
  156. package/dist/splash-screen/NewPage.js +2 -2
  157. package/dist/splash-screen/NewPage.js.map +1 -1
  158. package/dist/splash-screen/RecentPages.js +1 -1
  159. package/dist/splash-screen/RecentPages.js.map +1 -1
  160. package/dist/task-board/TaskBoardWorkspace.d.ts +1 -0
  161. package/dist/task-board/TaskBoardWorkspace.js +1094 -0
  162. package/dist/task-board/TaskBoardWorkspace.js.map +1 -0
  163. package/dist/task-board/components/AddDependencyDialog.d.ts +8 -0
  164. package/dist/task-board/components/AddDependencyDialog.js +53 -0
  165. package/dist/task-board/components/AddDependencyDialog.js.map +1 -0
  166. package/dist/task-board/components/AssignAgentDialog.d.ts +7 -0
  167. package/dist/task-board/components/AssignAgentDialog.js +96 -0
  168. package/dist/task-board/components/AssignAgentDialog.js.map +1 -0
  169. package/dist/task-board/components/CommentsList.d.ts +3 -0
  170. package/dist/task-board/components/CommentsList.js +36 -0
  171. package/dist/task-board/components/CommentsList.js.map +1 -0
  172. package/dist/task-board/components/CreateProjectDialog.d.ts +7 -0
  173. package/dist/task-board/components/CreateProjectDialog.js +175 -0
  174. package/dist/task-board/components/CreateProjectDialog.js.map +1 -0
  175. package/dist/task-board/components/CreateTaskDialog.d.ts +7 -0
  176. package/dist/task-board/components/CreateTaskDialog.js +76 -0
  177. package/dist/task-board/components/CreateTaskDialog.js.map +1 -0
  178. package/dist/task-board/components/ProjectAgentsPanel.d.ts +4 -0
  179. package/dist/task-board/components/ProjectAgentsPanel.js +159 -0
  180. package/dist/task-board/components/ProjectAgentsPanel.js.map +1 -0
  181. package/dist/task-board/components/ProjectDashboard.d.ts +25 -0
  182. package/dist/task-board/components/ProjectDashboard.js +91 -0
  183. package/dist/task-board/components/ProjectDashboard.js.map +1 -0
  184. package/dist/task-board/components/ProjectList.d.ts +7 -0
  185. package/dist/task-board/components/ProjectList.js +74 -0
  186. package/dist/task-board/components/ProjectList.js.map +1 -0
  187. package/dist/task-board/components/ProjectSettingsDialog.d.ts +8 -0
  188. package/dist/task-board/components/ProjectSettingsDialog.js +146 -0
  189. package/dist/task-board/components/ProjectSettingsDialog.js.map +1 -0
  190. package/dist/task-board/components/TaskAgentPanel.d.ts +10 -0
  191. package/dist/task-board/components/TaskAgentPanel.js +42 -0
  192. package/dist/task-board/components/TaskAgentPanel.js.map +1 -0
  193. package/dist/task-board/components/TaskAssigneePicker.d.ts +12 -0
  194. package/dist/task-board/components/TaskAssigneePicker.js +115 -0
  195. package/dist/task-board/components/TaskAssigneePicker.js.map +1 -0
  196. package/dist/task-board/components/TaskBoardTitlebar.d.ts +1 -0
  197. package/dist/task-board/components/TaskBoardTitlebar.js +60 -0
  198. package/dist/task-board/components/TaskBoardTitlebar.js.map +1 -0
  199. package/dist/task-board/components/TaskCard.d.ts +9 -0
  200. package/dist/task-board/components/TaskCard.js +24 -0
  201. package/dist/task-board/components/TaskCard.js.map +1 -0
  202. package/dist/task-board/components/TaskDetailDialog.d.ts +11 -0
  203. package/dist/task-board/components/TaskDetailDialog.js +8 -0
  204. package/dist/task-board/components/TaskDetailDialog.js.map +1 -0
  205. package/dist/task-board/components/TaskDetailPanel.d.ts +13 -0
  206. package/dist/task-board/components/TaskDetailPanel.js +322 -0
  207. package/dist/task-board/components/TaskDetailPanel.js.map +1 -0
  208. package/dist/task-board/components/TaskRow.d.ts +9 -0
  209. package/dist/task-board/components/TaskRow.js +25 -0
  210. package/dist/task-board/components/TaskRow.js.map +1 -0
  211. package/dist/task-board/index.d.ts +15 -0
  212. package/dist/task-board/index.js +18 -0
  213. package/dist/task-board/index.js.map +1 -0
  214. package/dist/task-board/services/taskService.d.ts +52 -0
  215. package/dist/task-board/services/taskService.js +74 -0
  216. package/dist/task-board/services/taskService.js.map +1 -0
  217. package/dist/task-board/taskAgentConfig.d.ts +7 -0
  218. package/dist/task-board/taskAgentConfig.js +43 -0
  219. package/dist/task-board/taskAgentConfig.js.map +1 -0
  220. package/dist/task-board/taskAgentLink.d.ts +2 -0
  221. package/dist/task-board/taskAgentLink.js +35 -0
  222. package/dist/task-board/taskAgentLink.js.map +1 -0
  223. package/dist/task-board/taskBoardNavStore.d.ts +35 -0
  224. package/dist/task-board/taskBoardNavStore.js +42 -0
  225. package/dist/task-board/taskBoardNavStore.js.map +1 -0
  226. package/dist/task-board/taskExecutionStatus.d.ts +12 -0
  227. package/dist/task-board/taskExecutionStatus.js +96 -0
  228. package/dist/task-board/taskExecutionStatus.js.map +1 -0
  229. package/dist/task-board/taskStatus.d.ts +2 -0
  230. package/dist/task-board/taskStatus.js +26 -0
  231. package/dist/task-board/taskStatus.js.map +1 -0
  232. package/dist/task-board/types.d.ts +169 -0
  233. package/dist/task-board/types.js +2 -0
  234. package/dist/task-board/types.js.map +1 -0
  235. package/dist/task-board/utils/projectHierarchy.d.ts +13 -0
  236. package/dist/task-board/utils/projectHierarchy.js +34 -0
  237. package/dist/task-board/utils/projectHierarchy.js.map +1 -0
  238. package/dist/task-board/views/KanbanView.d.ts +14 -0
  239. package/dist/task-board/views/KanbanView.js +136 -0
  240. package/dist/task-board/views/KanbanView.js.map +1 -0
  241. package/dist/task-board/views/ListView.d.ts +13 -0
  242. package/dist/task-board/views/ListView.js +74 -0
  243. package/dist/task-board/views/ListView.js.map +1 -0
  244. package/dist/task-board/views/PlanningView.d.ts +7 -0
  245. package/dist/task-board/views/PlanningView.js +112 -0
  246. package/dist/task-board/views/PlanningView.js.map +1 -0
  247. package/package.json +1 -1
@@ -21,6 +21,32 @@ import { cn } from "../../lib/utils";
21
21
  import { Select } from "../../components/ui/select";
22
22
  import { AgentTerminalStatusBar } from "./AgentTerminalStatusBar";
23
23
  import { useMediaQuery } from "../client/hooks/useMediaQuery";
24
+ import { SimpleTabs } from "../ui/SimpleTabs";
25
+ function buildPlaceholderAgentDetails(agentStub) {
26
+ const now = new Date().toISOString();
27
+ const updated = agentStub.updatedDate || now;
28
+ // AgentDetails has required fields, but some workspaces only pass an Agent stub initially.
29
+ // This placeholder keeps streaming/tool-call UI working until `getAgent()` returns full details.
30
+ return {
31
+ ...agentStub,
32
+ name: agentStub.name || "Agent",
33
+ userId: agentStub.userId || "",
34
+ updatedDate: updated,
35
+ profileName: agentStub.profileName || "",
36
+ model: agentStub.model || "",
37
+ createdDate: agentStub.createdDate || updated,
38
+ totalTokensUsed: 0,
39
+ totalInputTokens: 0,
40
+ totalOutputTokens: 0,
41
+ totalCachedInputTokens: 0,
42
+ totalInputTokenCost: 0,
43
+ totalOutputTokenCost: 0,
44
+ totalCachedInputTokenCost: 0,
45
+ totalCost: 0,
46
+ currency: agentStub.currency || "USD",
47
+ messageCount: agentStub.messageCount || 0,
48
+ };
49
+ }
24
50
  // Simple user message component
25
51
  const UserMessage = ({ message }) => {
26
52
  // Parse source agent name from content if it starts with "[From ...]:"
@@ -50,7 +76,7 @@ const UserMessage = ({ message }) => {
50
76
  message.sourceAgent?.name;
51
77
  }
52
78
  const displayName = sourceAgentName ? `[From ${sourceAgentName}]` : "You";
53
- return (_jsxs("div", { className: "flex gap-3 p-4", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(User, { className: "text-theme-secondary h-5 w-5", strokeWidth: 1 }) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-[12px] font-medium text-gray-900", children: displayName }), message.createdDate && (_jsx("span", { className: "text-[12px] text-gray-400", "data-testid": "user-message-timestamp", "data-timestamp": message.createdDate, children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose max-w-none text-[12px] text-gray-700 select-text", children: displayContent })] })] }));
79
+ return (_jsxs("div", { className: "flex gap-3 p-4", children: [_jsx("div", { className: "shrink-0", children: _jsx(User, { className: "text-theme-secondary h-5 w-5", strokeWidth: 1 }) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-[12px] font-medium text-gray-900", children: displayName }), message.createdDate && (_jsx("span", { className: "text-[12px] text-gray-400", "data-testid": "user-message-timestamp", "data-timestamp": message.createdDate, children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose max-w-none text-[12px] text-gray-700 select-text", children: displayContent })] })] }));
54
80
  };
55
81
  // Helper to extract todos from potentially incomplete JSON during streaming
56
82
  const extractPartialTodos = (jsonText) => {
@@ -408,7 +434,7 @@ const TodoListPanel = ({ messages, agentMetadata, }) => {
408
434
  return "text-gray-900";
409
435
  }
410
436
  };
411
- return (_jsxs("div", { className: "border-t border-gray-200 bg-gray-50", children: [_jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "flex w-full cursor-pointer items-center justify-between px-4 py-2 text-left transition-colors hover:bg-gray-100", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ListTodo, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }), _jsx("span", { className: "text-[11px] font-medium text-gray-700", children: "Todo List" }), isUpdating ? (_jsxs("span", { className: "text-theme-secondary flex items-center gap-1 text-[11px]", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), "Updating..."] })) : (_jsxs("span", { className: "text-[11px] text-gray-500", children: [completedCount, "/", totalCount, " completed"] }))] }), isExpanded ? (_jsx(ChevronUp, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 })) : (_jsx(ChevronDown, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }))] }), isExpanded && (_jsxs("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: [todos.length > 0 && (_jsx("div", { className: "space-y-1.5", children: todos.map((todo, idx) => (_jsxs("div", { className: "flex items-start gap-2 rounded bg-white p-2 text-[11px]", children: [_jsx("div", { className: "flex-shrink-0 pt-0.5", children: getStatusIcon(todo.status) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: getTextClass(todo.status), children: todo.title }), todo.instructions && (_jsx("div", { className: "mt-0.5 text-[11px] text-gray-500", children: todo.instructions }))] })] }, todo.id || `${todo.messageId}-${idx}`))) })), isUpdating && (_jsxs("div", { className: `flex items-center gap-2 rounded px-3 py-2 text-[11px] ${todos.length > 0
437
+ return (_jsxs("div", { className: "border-t border-gray-200 bg-gray-50", children: [_jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "flex w-full cursor-pointer items-center justify-between px-4 py-2 text-left transition-colors hover:bg-gray-100", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ListTodo, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }), _jsx("span", { className: "text-[11px] font-medium text-gray-700", children: "Todo List" }), isUpdating ? (_jsxs("span", { className: "text-theme-secondary flex items-center gap-1 text-[11px]", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), "Updating..."] })) : (_jsxs("span", { className: "text-[11px] text-gray-500", children: [completedCount, "/", totalCount, " completed"] }))] }), isExpanded ? (_jsx(ChevronUp, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 })) : (_jsx(ChevronDown, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }))] }), isExpanded && (_jsxs("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: [todos.length > 0 && (_jsx("div", { className: "space-y-1.5", children: todos.map((todo, idx) => (_jsxs("div", { className: "flex items-start gap-2 rounded bg-white p-2 text-[11px]", children: [_jsx("div", { className: "shrink-0 pt-0.5", children: getStatusIcon(todo.status) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: getTextClass(todo.status), children: todo.title }), todo.instructions && (_jsx("div", { className: "mt-0.5 text-[11px] text-gray-500", children: todo.instructions }))] })] }, todo.id || `${todo.messageId}-${idx}`))) })), isUpdating && (_jsxs("div", { className: `flex items-center gap-2 rounded px-3 py-2 text-[11px] ${todos.length > 0
412
438
  ? "bg-theme-secondary-light text-theme-secondary mt-2"
413
439
  : "justify-center bg-white text-gray-500"}`, children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), _jsx("span", { children: todos.length > 0
414
440
  ? "Updating todo list..."
@@ -520,6 +546,59 @@ const getOperationsForMessageGroup = (messages, agentOperations) => {
520
546
  const matched = agentOperations.filter((op) => op.toolCallId && toolCallIds.has(op.toolCallId));
521
547
  return matched;
522
548
  };
549
+ const stringifyToolField = (value) => {
550
+ if (value === undefined || value === null)
551
+ return undefined;
552
+ if (typeof value === "string") {
553
+ return value.trim().length > 0 ? value : undefined;
554
+ }
555
+ try {
556
+ return JSON.stringify(value);
557
+ }
558
+ catch {
559
+ return String(value);
560
+ }
561
+ };
562
+ const getFirstToolCallEnvelope = (data) => {
563
+ if (!data || typeof data !== "object")
564
+ return undefined;
565
+ const direct = data.toolCall || data.tool_call || data.ToolCall;
566
+ if (direct)
567
+ return direct;
568
+ const arrayCandidates = [data.tool_calls, data.toolCalls, data.ToolCalls];
569
+ for (const candidate of arrayCandidates) {
570
+ if (Array.isArray(candidate) && candidate.length > 0) {
571
+ return candidate[0];
572
+ }
573
+ }
574
+ return undefined;
575
+ };
576
+ const extractToolCallFields = (data) => {
577
+ const envelope = getFirstToolCallEnvelope(data);
578
+ const functionPayload = data?.function || data?.Function || envelope?.function || envelope?.Function;
579
+ const functionName = data?.functionName ||
580
+ data?.name ||
581
+ functionPayload?.name ||
582
+ functionPayload?.Name ||
583
+ envelope?.functionName ||
584
+ envelope?.name ||
585
+ envelope?.FunctionName ||
586
+ envelope?.Name ||
587
+ "unknown";
588
+ const toolCallId = data?.toolCallId || data?.id || envelope?.id || envelope?.Id;
589
+ const functionArguments = stringifyToolField(data?.functionArguments) ||
590
+ stringifyToolField(data?.arguments) ||
591
+ stringifyToolField(functionPayload?.arguments) ||
592
+ stringifyToolField(functionPayload?.Arguments) ||
593
+ stringifyToolField(envelope?.functionArguments) ||
594
+ stringifyToolField(envelope?.arguments) ||
595
+ "{}";
596
+ return {
597
+ toolCallId,
598
+ functionName,
599
+ functionArguments,
600
+ };
601
+ };
523
602
  // Convert agent messages to AI terminal format for a response group
524
603
  const convertAgentMessagesToAiFormat = (agentMessages) => {
525
604
  return agentMessages.map((agentMessage) => {
@@ -576,7 +655,7 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
576
655
  export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, compact = false, hideContext = false, hideBottomControls = false, hideGreeting = false, simpleMode = false, className, initialPrompt, onAgentUpdate, }) {
577
656
  const editContext = useEditContext();
578
657
  const fieldsContext = useFieldsEditContext();
579
- const [agent, setAgent] = useState(undefined);
658
+ const [agent, setAgent] = useState(() => buildPlaceholderAgentDetails(agentStub));
580
659
  const [messages, setMessages] = useState([]);
581
660
  const [agentOperations, setAgentOperations] = useState([]);
582
661
  const [prompt, setPrompt] = useState("");
@@ -587,6 +666,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
587
666
  const [activePlaceholderInput, setActivePlaceholderInput] = useState(null);
588
667
  const [allPlaceholdersFilled, setAllPlaceholdersFilled] = useState(false);
589
668
  const [agentMetadata, setAgentMetadata] = useState(null);
669
+ // Ensure we always have an agent object for streaming handlers, even before `getAgent()` resolves.
670
+ // This prevents early tool calls (e.g., ask-questionnaire) from being dropped in compact/workspace UIs.
671
+ useEffect(() => {
672
+ setAgent((prev) => {
673
+ if (prev?.id === agentStub.id)
674
+ return prev;
675
+ return buildPlaceholderAgentDetails(agentStub);
676
+ });
677
+ }, [agentStub.id]);
590
678
  // Generate a stable clientSessionId per component instance for stream deduplication
591
679
  const clientSessionIdRef = useRef(null);
592
680
  if (!clientSessionIdRef.current) {
@@ -680,7 +768,103 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
680
768
  const [mode, setMode] = useState("supervised");
681
769
  const [queuedPrompts, setQueuedPrompts] = useState([]);
682
770
  const isMobile = useMediaQuery("(max-width: 768px)");
771
+ const [contextPanelsActiveTab, setContextPanelsActiveTab] = useState(0);
772
+ const [hiddenContextPanelTabIds, setHiddenContextPanelTabIds] = useState(new Set());
683
773
  const [showCostAndAgent, setShowCostAndAgent] = useState(false);
774
+ const hasSpawnedAgents = useMemo(() => {
775
+ if (!agentMetadata)
776
+ return false;
777
+ const childAgents = agentMetadata?.ChildAgents ||
778
+ agentMetadata?.childAgents;
779
+ if (!Array.isArray(childAgents) || childAgents.length === 0)
780
+ return false;
781
+ return childAgents.some((a) => a != null && typeof a === "object" && (a.AgentId || a.agentId));
782
+ }, [agentMetadata]);
783
+ const hasTodoContent = useMemo(() => {
784
+ const metadataTodos = (() => {
785
+ try {
786
+ const todoList = agentMetadata?.additionalData?.todoList ||
787
+ agentMetadata?.todoList;
788
+ if (todoList?.items && Array.isArray(todoList.items)) {
789
+ const raw = todoList.items.filter((item) => item?.title || item?.text || item?.label || item?.task);
790
+ return raw.length > 0;
791
+ }
792
+ }
793
+ catch {
794
+ // ignore
795
+ }
796
+ return false;
797
+ })();
798
+ if (metadataTodos)
799
+ return true;
800
+ const fromMessages = extractTodosFromMessages(messages);
801
+ if (fromMessages.length > 0)
802
+ return true;
803
+ const isUpdating = messages.some((msg) => msg.role === "assistant" &&
804
+ !msg.isCompleted &&
805
+ (msg.content || "").includes("todo_list"));
806
+ return isUpdating;
807
+ }, [agentMetadata, messages]);
808
+ const prevAgentIdRef = useRef(undefined);
809
+ const [hasHistoryContent, setHasHistoryContent] = useState(false);
810
+ useEffect(() => {
811
+ const currentId = agent?.id;
812
+ if (prevAgentIdRef.current !== currentId) {
813
+ prevAgentIdRef.current = currentId;
814
+ setHiddenContextPanelTabIds((prev) => {
815
+ if (prev.has("history")) {
816
+ const next = new Set(prev);
817
+ next.delete("history");
818
+ return next;
819
+ }
820
+ return prev;
821
+ });
822
+ }
823
+ }, [agent?.id]);
824
+ useEffect(() => {
825
+ if (!agent?.id) {
826
+ setHasHistoryContent(false);
827
+ return;
828
+ }
829
+ setHasHistoryContent(false);
830
+ let cancelled = false;
831
+ getAgentHistory(agent.id, 10)
832
+ .then((result) => {
833
+ if (cancelled)
834
+ return;
835
+ if (result.type === "success" &&
836
+ result.data &&
837
+ result.data.length > 0) {
838
+ setHasHistoryContent(true);
839
+ }
840
+ else {
841
+ setHasHistoryContent(false);
842
+ }
843
+ })
844
+ .catch(() => {
845
+ if (!cancelled)
846
+ setHasHistoryContent(false);
847
+ });
848
+ return () => {
849
+ cancelled = true;
850
+ };
851
+ }, [agent?.id]);
852
+ const agentIdForHistoryRef = useRef(agent?.id);
853
+ agentIdForHistoryRef.current = agent?.id;
854
+ useEffect(() => {
855
+ if (!agent?.id || !editContext?.addSocketMessageListener)
856
+ return;
857
+ const unsubscribe = editContext.addSocketMessageListener((message) => {
858
+ if (message.type !== "edit-operation")
859
+ return;
860
+ const op = message.payload;
861
+ const operationAgentId = op.agentId || op.user?.agentId;
862
+ if (operationAgentId === agentIdForHistoryRef.current) {
863
+ setHasHistoryContent(true);
864
+ }
865
+ });
866
+ return () => unsubscribe();
867
+ }, [agent?.id, editContext?.addSocketMessageListener]);
684
868
  const modeOptions = useMemo(() => [
685
869
  {
686
870
  value: "supervised",
@@ -1053,25 +1237,18 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1053
1237
  // Shared stream message handlers with messageId support
1054
1238
  const createNewStreamMessage = useCallback((messageId, agentData) => {
1055
1239
  const currentAgent = agentData || agent;
1056
- if (!currentAgent) {
1057
- console.error("❌ createNewStreamMessage: No agent available", {
1058
- messageId,
1059
- agentData: !!agentData,
1060
- agent: !!agent,
1061
- });
1062
- throw new Error("No agent available");
1063
- }
1240
+ const effectiveAgentId = currentAgent?.id || agentStub.id;
1064
1241
  // Reduced: avoid verbose logging during streaming
1065
1242
  return {
1066
1243
  id: messageId,
1067
- agentId: currentAgent.id,
1244
+ agentId: effectiveAgentId,
1068
1245
  messageIndex: -1,
1069
1246
  role: "assistant",
1070
1247
  content: "",
1071
1248
  name: "agent",
1072
1249
  messageType: "streaming",
1073
1250
  isCompleted: false,
1074
- model: currentAgent.model || "",
1251
+ model: currentAgent?.model || "",
1075
1252
  tokensUsed: 0,
1076
1253
  inputTokens: 0,
1077
1254
  outputTokens: 0,
@@ -1080,11 +1257,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1080
1257
  outputTokenCost: 0,
1081
1258
  cachedInputTokenCost: 0,
1082
1259
  totalCost: 0,
1083
- currency: currentAgent.currency || "USD",
1260
+ currency: currentAgent?.currency || "USD",
1084
1261
  createdDate: new Date().toISOString(),
1085
1262
  toolCalls: [],
1086
1263
  };
1087
- }, [agent]);
1264
+ }, [agent, agentStub.id]);
1088
1265
  const handleContentChunk = useCallback((message, agentData) => {
1089
1266
  // Get messageId from data, or generate one from agent ID (for backward compatibility)
1090
1267
  // If no messageId is provided, we'll use the last assistant message or create a new one
@@ -1226,7 +1403,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1226
1403
  });
1227
1404
  }, [createNewStreamMessage, agent]);
1228
1405
  const handleToolCall = useCallback((message, agentData) => {
1229
- const toolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
1406
+ const extractedToolCall = extractToolCallFields(message.data);
1407
+ const toolCallId = extractedToolCall.toolCallId || crypto.randomUUID();
1230
1408
  // Prefer provided messageId, otherwise fall back to the last streaming assistant message
1231
1409
  let toolCallMessageId = message.data?.messageId;
1232
1410
  if (!toolCallMessageId) {
@@ -1237,6 +1415,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1237
1415
  if (lastStreaming?.id) {
1238
1416
  toolCallMessageId = lastStreaming.id;
1239
1417
  }
1418
+ else {
1419
+ // Tool calls can arrive before any assistant content chunk (common for dialog tools like ask-questionnaire).
1420
+ // Create a synthetic streaming message so the UI can render the tool call immediately.
1421
+ toolCallMessageId = crypto.randomUUID();
1422
+ }
1240
1423
  }
1241
1424
  // Find or create the target message for this tool call
1242
1425
  if (toolCallMessageId) {
@@ -1264,19 +1447,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1264
1447
  }
1265
1448
  // Add tool call to the message in the array
1266
1449
  if (toolCallMessageId && message.data && toolCallId) {
1267
- const functionName = message.data.functionName ||
1268
- message.data.name ||
1269
- message.data.function?.name ||
1270
- "unknown";
1271
1450
  const toolCall = {
1272
1451
  id: toolCallId,
1273
1452
  messageId: toolCallMessageId,
1274
1453
  dbMessageId: message.data.messageId, // Database message ID for approval/rejection
1275
1454
  toolCallId: toolCallId,
1276
- functionName: functionName,
1277
- functionArguments: message.data.functionArguments ||
1278
- message.data.arguments ||
1279
- JSON.stringify(message.data.function?.arguments || {}),
1455
+ functionName: extractedToolCall.functionName,
1456
+ functionArguments: extractedToolCall.functionArguments,
1280
1457
  functionResult: message.data.functionResult || message.data.result || "",
1281
1458
  functionError: message.data.functionError || message.data.error || "",
1282
1459
  isCompleted: false,
@@ -1320,7 +1497,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1320
1497
  // Check if the new data has more information than what we have
1321
1498
  const newArgs = toolCall.functionArguments;
1322
1499
  const existingArgs = existingToolCall.functionArguments;
1323
- const hasMoreCompleteArgs = newArgs && newArgs.length > (existingArgs?.length || 0);
1500
+ const newArgsText = stringifyToolField(newArgs) || "";
1501
+ const existingArgsText = stringifyToolField(existingArgs) || "";
1502
+ const hasMoreCompleteArgs = (newArgsText.length > existingArgsText.length &&
1503
+ newArgsText !== existingArgsText) ||
1504
+ (existingArgsText === "{}" && newArgsText !== "{}");
1324
1505
  const hasNewResult = toolCall.functionResult && !existingToolCall.functionResult;
1325
1506
  const hasNewError = toolCall.functionError && !existingToolCall.functionError;
1326
1507
  const hasNewApprovalInfo = toolCall.requiresApproval && !existingToolCall.requiresApproval;
@@ -1344,8 +1525,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1344
1525
  updatedToolCalls[idx] = {
1345
1526
  ...existing,
1346
1527
  functionArguments: hasMoreCompleteArgs
1347
- ? newArgs
1348
- : existing.functionArguments,
1528
+ ? newArgsText
1529
+ : existingArgsText || existing.functionArguments,
1349
1530
  functionResult: toolCall.functionResult || existing.functionResult,
1350
1531
  functionError: toolCall.functionError || existing.functionError,
1351
1532
  requiresApproval: toolCall.requiresApproval || existing.requiresApproval,
@@ -1381,7 +1562,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1381
1562
  }
1382
1563
  }, [createNewStreamMessage]);
1383
1564
  const handleToolResult = useCallback((message, agentData) => {
1384
- const resultToolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
1565
+ const extractedToolCall = extractToolCallFields(message.data);
1566
+ const resultToolCallId = extractedToolCall.toolCallId || crypto.randomUUID();
1385
1567
  // Prefer provided messageId, otherwise fall back to the last streaming assistant message
1386
1568
  let resultMessageId = message.data?.messageId;
1387
1569
  if (!resultMessageId) {
@@ -1500,18 +1682,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1500
1682
  }
1501
1683
  else if (message.data && resultToolCallId && resultMessageId) {
1502
1684
  // Create new tool call if it doesn't exist
1503
- const functionName = message.data.functionName ||
1504
- message.data.name ||
1505
- message.data.function?.name ||
1506
- "unknown";
1507
1685
  const toolCall = {
1508
1686
  id: resultToolCallId,
1509
1687
  messageId: resultMessageId,
1510
1688
  toolCallId: resultToolCallId,
1511
- functionName: functionName,
1512
- functionArguments: message.data.functionArguments ||
1513
- message.data.arguments ||
1514
- JSON.stringify(message.data.function?.arguments || {}),
1689
+ functionName: extractedToolCall.functionName,
1690
+ functionArguments: extractedToolCall.functionArguments,
1515
1691
  functionResult: message.data.functionResult || message.data.result || "",
1516
1692
  functionError: message.data.functionError || message.data.error || "",
1517
1693
  isCompleted: true,
@@ -1806,8 +1982,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1806
1982
  seenMessageIdsRef.current.add(msg.id.toLowerCase());
1807
1983
  }
1808
1984
  });
1809
- // Keep local streaming only if the agent is still running; otherwise discard locals
1985
+ // Keep local streaming if the agent is still active (running/waiting); otherwise discard locals.
1986
+ // This is important for dialog-style tools (e.g., ask-questionnaire) where the agent may be
1987
+ // "waiting" but we still want to keep the in-flight tool call UI visible.
1810
1988
  const isRunning = agentData.status === "running" || agentData.status === 1;
1989
+ const isWaiting = agentData.status === "waitingForApproval" ||
1990
+ agentData.status === 2 ||
1991
+ agentData.status === "costLimitReached" ||
1992
+ agentData.status === 7;
1993
+ const keepLocalStreaming = isRunning || isWaiting;
1811
1994
  // Filter local messages to only include streaming/incomplete messages that aren't in DB
1812
1995
  // This prevents duplicates when reloading - DB messages are source of truth for completed messages
1813
1996
  const localStreaming = isRunning
@@ -1825,7 +2008,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1825
2008
  // Don't keep completed messages from local state - DB is source of truth
1826
2009
  return false;
1827
2010
  })
1828
- : [];
2011
+ : keepLocalStreaming
2012
+ ? messagesRef.current.filter((localMsg) => {
2013
+ if (!localMsg.id)
2014
+ return false;
2015
+ if (!localMsg.isCompleted &&
2016
+ localMsg.messageType === "streaming") {
2017
+ const existsInDb = dbMessages.some((dbMsg) => dbMsg.id &&
2018
+ dbMsg.id.toLowerCase() === localMsg.id.toLowerCase());
2019
+ return !existsInDb;
2020
+ }
2021
+ return false;
2022
+ })
2023
+ : [];
1829
2024
  const merged = mergeMessagesById(dbMessages, localStreaming);
1830
2025
  messagesRef.current = merged;
1831
2026
  setMessages(merged);
@@ -2731,26 +2926,57 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2731
2926
  window.addEventListener("editor:focusAgentPrompt", focusHandler);
2732
2927
  return () => window.removeEventListener("editor:focusAgentPrompt", focusHandler);
2733
2928
  }, []);
2929
+ // Keep stable refs so we don't miss window events during effect re-runs.
2930
+ const agentIdRefForDialogs = useRef(null);
2931
+ const agentStubIdRefForDialogs = useRef(agentStub.id);
2932
+ const isActiveRefForDialogs = useRef(isActive);
2933
+ const scrollToBottomRefForDialogs = useRef(scrollToBottom);
2934
+ useEffect(() => {
2935
+ agentIdRefForDialogs.current = agent?.id ?? null;
2936
+ }, [agent?.id]);
2937
+ useEffect(() => {
2938
+ agentStubIdRefForDialogs.current = agentStub.id;
2939
+ }, [agentStub.id]);
2940
+ useEffect(() => {
2941
+ isActiveRefForDialogs.current = isActive;
2942
+ }, [isActive]);
2943
+ useEffect(() => {
2944
+ scrollToBottomRefForDialogs.current = scrollToBottom;
2945
+ }, [scrollToBottom]);
2734
2946
  // Listen for agent inline dialog requests from AgentDialogHandler
2735
2947
  useEffect(() => {
2736
2948
  const handleDialogShow = (event) => {
2737
- const { request, onComplete, onCancel } = event.detail;
2738
- // Only handle dialog requests for this agent
2739
- if (request.agentId && agent?.id && request.agentId !== agent.id) {
2949
+ const detail = event?.detail;
2950
+ const request = detail?.request;
2951
+ const onComplete = detail?.onComplete;
2952
+ const onCancel = detail?.onCancel;
2953
+ const terminalAgentId = agentIdRefForDialogs.current;
2954
+ const terminalAgentStubId = agentStubIdRefForDialogs.current;
2955
+ const isActiveNow = isActiveRefForDialogs.current;
2956
+ if (!isActiveNow)
2957
+ return;
2958
+ if (!request)
2959
+ return;
2960
+ // Only handle dialog requests for this terminal's agent stub
2961
+ if (request.agentId && terminalAgentStubId && request.agentId !== terminalAgentStubId) {
2740
2962
  return;
2741
2963
  }
2742
2964
  console.log("[AgentTerminal] Received inline dialog request:", request);
2743
2965
  setActiveInlineDialog({ request, onComplete, onCancel });
2744
2966
  // Notify AgentDialogHandler that we accepted the dialog (stops retry mechanism)
2745
- window.dispatchEvent(new CustomEvent("agent:dialog:accepted", {
2746
- detail: { callbackId: request.callbackId },
2747
- }));
2967
+ if (request.callbackId) {
2968
+ window.dispatchEvent(new CustomEvent("agent:dialog:accepted", {
2969
+ detail: { callbackId: request.callbackId },
2970
+ }));
2971
+ }
2748
2972
  // Scroll to bottom to show the dialog
2749
- setTimeout(scrollToBottom, 100);
2973
+ setTimeout(() => scrollToBottomRefForDialogs.current?.(), 100);
2750
2974
  };
2751
2975
  window.addEventListener("agent:dialog:show", handleDialogShow);
2752
- return () => window.removeEventListener("agent:dialog:show", handleDialogShow);
2753
- }, [agent?.id, scrollToBottom]);
2976
+ return () => {
2977
+ window.removeEventListener("agent:dialog:show", handleDialogShow);
2978
+ };
2979
+ }, []);
2754
2980
  // Announce when this terminal is ready to accept dialogs
2755
2981
  // This allows AgentDialogHandler to re-dispatch pending dialogs when switching to an agent
2756
2982
  useEffect(() => {
@@ -2868,6 +3094,17 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2868
3094
  console.error("Failed to persist pending settings", e);
2869
3095
  }
2870
3096
  }, [agent?.id]);
3097
+ const getSubmitErrorMessage = (error) => {
3098
+ const fallback = "Failed to submit prompt. Please try again.";
3099
+ if (!(error instanceof Error))
3100
+ return fallback;
3101
+ const cleaned = error.message
3102
+ .replace(/^Failed to start agent:\s*/i, "")
3103
+ .replace(/^Unknown error\s*/i, "")
3104
+ .replace(/^Error:\s*/i, "")
3105
+ .trim();
3106
+ return cleaned || fallback;
3107
+ };
2871
3108
  const handleSubmit = async () => {
2872
3109
  // Guard against double-submit and missing context
2873
3110
  if (isSubmitting) {
@@ -3044,7 +3281,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3044
3281
  }
3045
3282
  catch (err) {
3046
3283
  console.error("[AgentTerminal] Failed to submit prompt:", err);
3047
- setError("Failed to submit prompt. Please try again.");
3284
+ setError(getSubmitErrorMessage(err));
3048
3285
  setIsWaitingForResponse(false);
3049
3286
  isWaitingRef.current = false;
3050
3287
  // Remove the optimistic user message on API error
@@ -3276,7 +3513,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3276
3513
  }
3277
3514
  catch (err) {
3278
3515
  console.error("[AgentTerminal] Failed to submit quick message:", err);
3279
- setError("Failed to submit prompt. Please try again.");
3516
+ setError(getSubmitErrorMessage(err));
3280
3517
  setIsWaitingForResponse(false);
3281
3518
  isWaitingRef.current = false;
3282
3519
  // Remove the optimistic user message on API error
@@ -3827,7 +4064,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3827
4064
  const errorMessage = currentAgent?.statusMessage;
3828
4065
  if (!isErrorStatus || !errorMessage)
3829
4066
  return null;
3830
- return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-[11px] text-red-900", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-red-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Agent Error" }), _jsx("div", { className: "text-red-800", children: errorMessage })] })] }) }));
4067
+ return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-[11px] text-red-900", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 shrink-0 text-red-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Agent Error" }), _jsx("div", { className: "text-red-800", children: errorMessage })] })] }) }));
3831
4068
  };
3832
4069
  return (_jsxs("div", { className: `flex h-full flex-col ${className || ""}`, children: [parentAgentId && !simpleMode && (_jsx("div", { className: "border-b border-gray-200 bg-gray-50 px-4 py-2", children: _jsxs("button", { onClick: handleBackToParent, className: "flex items-center gap-2 text-[11px] text-gray-600 transition-colors hover:text-gray-900", title: "Back to parent agent", children: [_jsx(ArrowLeft, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), _jsx("span", { children: "Back to parent agent" })] }) })), _jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error && (_jsx("div", { className: "m-4 rounded-lg border-l-4 border-red-500 bg-red-50 p-3 select-text", children: _jsxs("div", { className: "flex items-start", children: [_jsx(AlertCircle, { className: "mt-0.5 h-5 w-5 text-red-400", strokeWidth: 1 }), _jsxs("div", { className: "ml-3", children: [_jsx("p", { className: "text-[11px] font-medium text-red-800", children: "Error" }), _jsx("p", { className: "mt-1 text-[11px] text-red-700", children: error })] })] }) })), messages.length === 0 && !error && !hideGreeting && (_jsx("div", { className: "flex h-full items-center justify-center", children: !activeProfile ? (_jsx(Loader2, { className: "mx-auto h-8 w-8 animate-spin text-gray-400" })) : (_jsx(AgentGreeting, { profile: activeProfile, onPromptClick: (p) => {
3833
4070
  setPrompt(p);
@@ -3916,12 +4153,62 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3916
4153
  } }, groupIndex));
3917
4154
  }
3918
4155
  });
3919
- })(), shouldShowThinkingDots && (_jsxs("div", { className: "flex gap-3 px-4 py-3", "data-testid": "agent-thinking-dots", children: [_jsx("div", { className: "flex-shrink-0", children: activeProfile?.svgIcon ? (_jsx("div", { className: "text-gray-2 flex h-6 w-6 items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
4156
+ })(), shouldShowThinkingDots && (_jsxs("div", { className: "flex gap-3 px-4 py-3", "data-testid": "agent-thinking-dots", children: [_jsx("div", { className: "shrink-0", children: activeProfile?.svgIcon ? (_jsx("div", { className: "text-gray-2 flex h-6 w-6 items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
3920
4157
  __html: activeProfile.svgIcon,
3921
4158
  } })) : (_jsx(SecretAgentIcon, { size: 20, strokeWidth: 1, className: "text-gray-2" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-dark text-xs font-medium", children: activeProfile?.agentName ||
3922
4159
  activeProfile?.displayTitle ||
3923
4160
  activeProfile?.name ||
3924
- "Agent" }), _jsx("span", { className: "text-xs text-gray-400", children: formatTime(new Date()) })] }), _jsxs("div", { className: "flex items-center gap-1 pt-2", children: [_jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400" })] })] })] }))] }), !simpleMode && renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && !simpleMode && renderContextInfoBar(), !hideContext && !simpleMode && agent?.id && activeProfile && (_jsx(AgentDocumentList, { ref: documentListRef, agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && !simpleMode && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), !hideContext && !simpleMode && (_jsx(SpawnedAgentsPanel, { agentMetadata: agentMetadata })), !hideContext && !simpleMode && agent?.id && (_jsx(AgentEditOperationsPanel, { agentId: agent.id })), queuedPrompts.length > 0 && !simpleMode && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", "data-testid": "queued-prompts-section", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-[11px] font-semibold text-amber-900", "data-testid": "queued-prompts-count", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "max-h-64 space-y-2 overflow-y-auto", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-[11px]", "data-testid": "queued-prompt-item", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[11px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", "data-testid": "queued-prompt-text", children: qp.prompt }), _jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-gray-400", children: [qp.createdDate && (_jsxs("span", { children: ["Queued ", formatTime(new Date(qp.createdDate))] })), qp.scheduledFor &&
4161
+ "Agent" }), _jsx("span", { className: "text-xs text-gray-400", children: formatTime(new Date()) })] }), _jsxs("div", { className: "flex items-center gap-1 pt-2", children: [_jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400" })] })] })] }))] }), !simpleMode && renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext &&
4162
+ !simpleMode &&
4163
+ (isMobile ? (_jsx("div", { className: "border-t border-gray-200 bg-gray-50", "data-testid": "agent-context-panel-tabs", children: _jsx(SimpleTabs, { tabs: [
4164
+ {
4165
+ id: "context",
4166
+ label: "Context",
4167
+ content: renderContextInfoBar(),
4168
+ },
4169
+ ...(agent?.id && activeProfile
4170
+ ? [
4171
+ {
4172
+ id: "documents",
4173
+ label: "Documents",
4174
+ content: (_jsx(AgentDocumentList, { ref: documentListRef, agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)),
4175
+ },
4176
+ ]
4177
+ : []),
4178
+ ...(hasTodoContent
4179
+ ? [
4180
+ {
4181
+ id: "todos",
4182
+ label: "Todos",
4183
+ content: (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })),
4184
+ },
4185
+ ]
4186
+ : []),
4187
+ ...(hasSpawnedAgents
4188
+ ? [
4189
+ {
4190
+ id: "agents",
4191
+ label: "Spawned",
4192
+ content: (_jsx(SpawnedAgentsPanel, { agentMetadata: agentMetadata })),
4193
+ },
4194
+ ]
4195
+ : []),
4196
+ ...(agent?.id && hasHistoryContent
4197
+ ? [
4198
+ {
4199
+ id: "history",
4200
+ label: "History",
4201
+ content: (_jsx(AgentEditOperationsPanel, { agentId: agent.id })),
4202
+ },
4203
+ ]
4204
+ : []),
4205
+ ], activeTab: Math.max(0, Math.min(contextPanelsActiveTab, [
4206
+ true,
4207
+ agent?.id && activeProfile,
4208
+ hasTodoContent,
4209
+ hasSpawnedAgents,
4210
+ agent?.id && hasHistoryContent,
4211
+ ].filter(Boolean).length - 1)), setActiveTab: setContextPanelsActiveTab, className: "justify-start px-4" }) })) : (_jsxs(_Fragment, { children: [renderContextInfoBar(), agent?.id && activeProfile && (_jsx(AgentDocumentList, { ref: documentListRef, agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), _jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata }), _jsx(SpawnedAgentsPanel, { agentMetadata: agentMetadata }), agent?.id && _jsx(AgentEditOperationsPanel, { agentId: agent.id })] }))), queuedPrompts.length > 0 && !simpleMode && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", "data-testid": "queued-prompts-section", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-[11px] font-semibold text-amber-900", "data-testid": "queued-prompts-count", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "max-h-64 space-y-2 overflow-y-auto", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-[11px]", "data-testid": "queued-prompt-item", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[11px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "wrap-break-word whitespace-pre-wrap text-gray-600", "data-testid": "queued-prompt-text", children: qp.prompt }), _jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] text-gray-400", children: [qp.createdDate && (_jsxs("span", { children: ["Queued ", formatTime(new Date(qp.createdDate))] })), qp.scheduledFor &&
3925
4212
  new Date(qp.scheduledFor).getTime() >
3926
4213
  new Date(qp.createdDate || 0).getTime() + 1000 && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-gray-300", children: "\u2022" }), _jsxs("span", { className: "font-medium text-amber-600", children: ["Scheduled for", " ", new Date(qp.scheduledFor).toDateString() ===
3927
4214
  new Date().toDateString()
@@ -4020,10 +4307,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4020
4307
  return (_jsxs("div", { className: cn("mt-2 flex items-stretch gap-2", hideBottomControls || simpleMode || isInPlaceholderMode
4021
4308
  ? "justify-end"
4022
4309
  : "justify-between"), children: [!hideBottomControls && !simpleMode && !isInPlaceholderMode && (_jsxs("div", { className: "flex flex-wrap items-center justify-start gap-2", children: [_jsx(Select, { size: "xs", maxWidth: 240, className: cn("h-5 w-auto min-w-[95px] rounded border px-1.5 text-[11px] font-normal", mode === "read-only"
4023
- ? "border-green-300 !bg-green-50 text-green-700 hover:!bg-green-100"
4310
+ ? "border-green-300 bg-green-50! text-green-700 hover:bg-green-100!"
4024
4311
  : mode === "supervised"
4025
- ? "border-amber-300 !bg-amber-50 text-amber-700 hover:!bg-amber-100"
4026
- : "border-red-300 !bg-red-50 text-red-700 hover:!bg-red-100"), value: mode, options: modeOptions, onValueChange: async (val) => {
4312
+ ? "border-amber-300 bg-amber-50! text-amber-700 hover:bg-amber-100!"
4313
+ : "border-red-300 bg-red-50! text-red-700 hover:bg-red-100!"), value: mode, options: modeOptions, onValueChange: async (val) => {
4027
4314
  const nextMode = val || "supervised";
4028
4315
  // Optimistic UI update
4029
4316
  setMode(nextMode);