@parhelia/core 0.1.12496 → 0.1.12515

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 (152) hide show
  1. package/dist/agents-view/AgentCard.js +20 -19
  2. package/dist/agents-view/AgentCard.js.map +1 -1
  3. package/dist/agents-view/AgentsInbox.js +2 -13
  4. package/dist/agents-view/AgentsInbox.js.map +1 -1
  5. package/dist/agents-view/AgentsView.js +7 -55
  6. package/dist/agents-view/AgentsView.js.map +1 -1
  7. package/dist/agents-view/AgentsWorkspaceView.js +2 -11
  8. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  9. package/dist/components/ui/copy-button.d.ts +2 -1
  10. package/dist/components/ui/copy-button.js +2 -2
  11. package/dist/components/ui/copy-button.js.map +1 -1
  12. package/dist/components/ui/paste-button.d.ts +2 -1
  13. package/dist/components/ui/paste-button.js +2 -2
  14. package/dist/components/ui/paste-button.js.map +1 -1
  15. package/dist/config/config.js +40 -0
  16. package/dist/config/config.js.map +1 -1
  17. package/dist/config/types.d.ts +23 -5
  18. package/dist/config/types.js.map +1 -1
  19. package/dist/editor/ContentTree.js +36 -4
  20. package/dist/editor/ContentTree.js.map +1 -1
  21. package/dist/editor/FieldListField.js +4 -4
  22. package/dist/editor/FieldListField.js.map +1 -1
  23. package/dist/editor/FieldListFieldWithFallbacks.js +23 -2
  24. package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
  25. package/dist/editor/GlobalMenuBar.js +1 -1
  26. package/dist/editor/GlobalMenuBar.js.map +1 -1
  27. package/dist/editor/ItemInfo.js +36 -1
  28. package/dist/editor/ItemInfo.js.map +1 -1
  29. package/dist/editor/MainLayout.d.ts +0 -2
  30. package/dist/editor/MainLayout.js +0 -1
  31. package/dist/editor/MainLayout.js.map +1 -1
  32. package/dist/editor/Titlebar.js +2 -2
  33. package/dist/editor/Titlebar.js.map +1 -1
  34. package/dist/editor/ai/AgentStatusBadge.d.ts +0 -5
  35. package/dist/editor/ai/AgentStatusBadge.js +57 -71
  36. package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
  37. package/dist/editor/ai/AgentTerminal.js +51 -89
  38. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  39. package/dist/editor/ai/Agents.js +8 -63
  40. package/dist/editor/ai/Agents.js.map +1 -1
  41. package/dist/editor/ai/InlineAiDialog.js +1 -6
  42. package/dist/editor/ai/InlineAiDialog.js.map +1 -1
  43. package/dist/editor/ai/ToolCallDisplay.js +152 -63
  44. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  45. package/dist/editor/ai/useAgentStatus.js +12 -85
  46. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  47. package/dist/editor/client/EditorShell.js +49 -59
  48. package/dist/editor/client/EditorShell.js.map +1 -1
  49. package/dist/editor/client/editContext.d.ts +3 -15
  50. package/dist/editor/client/editContext.js.map +1 -1
  51. package/dist/editor/client/hooks/useEditorUrlSync.js +1 -2
  52. package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
  53. package/dist/editor/client/hooks/useSocketMessageHandler.js +19 -6
  54. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  55. package/dist/editor/client/operations.js +15 -3
  56. package/dist/editor/client/operations.js.map +1 -1
  57. package/dist/editor/client/ui/EditorChrome.d.ts +0 -4
  58. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  59. package/dist/editor/client/waitForEditOperationTerminal.d.ts +8 -3
  60. package/dist/editor/client/waitForEditOperationTerminal.js +5 -1
  61. package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
  62. package/dist/editor/commands/itemCommands.js +5 -0
  63. package/dist/editor/commands/itemCommands.js.map +1 -1
  64. package/dist/editor/content-tree/IndicatorSettings.d.ts +11 -0
  65. package/dist/editor/content-tree/IndicatorSettings.js +60 -0
  66. package/dist/editor/content-tree/IndicatorSettings.js.map +1 -0
  67. package/dist/editor/content-tree/TreeOptions.d.ts +6 -0
  68. package/dist/editor/content-tree/TreeOptions.js +8 -0
  69. package/dist/editor/content-tree/TreeOptions.js.map +1 -0
  70. package/dist/editor/content-tree/TreeSettingsMenu.d.ts +2 -0
  71. package/dist/editor/content-tree/TreeSettingsMenu.js +30 -0
  72. package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -0
  73. package/dist/editor/hooks/useNavigationPanelLogic.js +2 -6
  74. package/dist/editor/hooks/useNavigationPanelLogic.js.map +1 -1
  75. package/dist/editor/manualActionEvents.d.ts +8 -0
  76. package/dist/editor/manualActionEvents.js +48 -0
  77. package/dist/editor/manualActionEvents.js.map +1 -0
  78. package/dist/editor/menubar/PageSelector.js +9 -12
  79. package/dist/editor/menubar/PageSelector.js.map +1 -1
  80. package/dist/editor/menubar/WorkflowButton.js +23 -23
  81. package/dist/editor/menubar/WorkflowButton.js.map +1 -1
  82. package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
  83. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  84. package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +3 -9
  85. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +225 -71
  86. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
  87. package/dist/editor/notifications/WatchButton.js +2 -2
  88. package/dist/editor/notifications/WatchButton.js.map +1 -1
  89. package/dist/editor/page-viewer/EditorForm.js +2 -0
  90. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  91. package/dist/editor/page-viewer/PageViewer.js +8 -2
  92. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  93. package/dist/editor/reviews/CreateReviewDialog.js +0 -2
  94. package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
  95. package/dist/editor/services/agentService.d.ts +3 -2
  96. package/dist/editor/services/agentService.js.map +1 -1
  97. package/dist/editor/services/agentStatus.d.ts +12 -0
  98. package/dist/editor/services/agentStatus.js +59 -0
  99. package/dist/editor/services/agentStatus.js.map +1 -0
  100. package/dist/editor/settings/SettingsView.js +4 -4
  101. package/dist/editor/settings/SettingsView.js.map +1 -1
  102. package/dist/editor/settings/index/useIndexStatus.js +1 -1
  103. package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
  104. package/dist/editor/settings/panels/JavaScriptToolConfigPanel.js +1 -1
  105. package/dist/editor/settings/panels/JavaScriptToolConfigPanel.js.map +1 -1
  106. package/dist/editor/sidebar/ComponentTree.js +201 -40
  107. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  108. package/dist/editor/sidebar/MainContentTree.js +3 -2
  109. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  110. package/dist/editor/sidebar/MorePanelsButton.js +1 -1
  111. package/dist/editor/sidebar/MorePanelsButton.js.map +1 -1
  112. package/dist/editor/sidebar/NavigationPanelItem.js +2 -2
  113. package/dist/editor/sidebar/NavigationPanelItem.js.map +1 -1
  114. package/dist/editor/sidebar/SidebarPanel.js +20 -4
  115. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  116. package/dist/editor/sidebar/SidebarStack.js +1 -0
  117. package/dist/editor/sidebar/SidebarStack.js.map +1 -1
  118. package/dist/editor/sidebar/Workbox.js +53 -3
  119. package/dist/editor/sidebar/Workbox.js.map +1 -1
  120. package/dist/editor/tree-indicators/GutterContext.d.ts +4 -0
  121. package/dist/editor/tree-indicators/GutterContext.js +23 -0
  122. package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
  123. package/dist/editor/tree-indicators/index.d.ts +0 -1
  124. package/dist/editor/tree-indicators/index.js +0 -1
  125. package/dist/editor/tree-indicators/index.js.map +1 -1
  126. package/dist/editor/tree-indicators/types.d.ts +1 -1
  127. package/dist/editor/ui/HomeButton.js +1 -1
  128. package/dist/editor/ui/HomeButton.js.map +1 -1
  129. package/dist/editor/ui/ItemNameDialogNew.d.ts +2 -0
  130. package/dist/editor/ui/ItemNameDialogNew.js +17 -7
  131. package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
  132. package/dist/editor/ui/ItemSearch.js +7 -11
  133. package/dist/editor/ui/ItemSearch.js.map +1 -1
  134. package/dist/editor/ui/SimpleTabs.js +33 -16
  135. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  136. package/dist/editor/ui/Splitter.js +1 -1
  137. package/dist/editor/ui/Splitter.js.map +1 -1
  138. package/dist/revision.d.ts +2 -2
  139. package/dist/revision.js +2 -2
  140. package/dist/setup/wizard/steps/AddModelDialog.js +3 -2
  141. package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
  142. package/dist/task-board/components/AssignAgentDialog.js +0 -8
  143. package/dist/task-board/components/AssignAgentDialog.js.map +1 -1
  144. package/dist/task-board/components/ProjectAgentsPanel.js +1 -26
  145. package/dist/task-board/components/ProjectAgentsPanel.js.map +1 -1
  146. package/dist/task-board/components/TaskAgentPanel.js +2 -6
  147. package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
  148. package/dist/types.d.ts +2 -13
  149. package/package.json +1 -1
  150. package/dist/editor/tree-indicators/GutterSelector.d.ts +0 -5
  151. package/dist/editor/tree-indicators/GutterSelector.js +0 -91
  152. package/dist/editor/tree-indicators/GutterSelector.js.map +0 -1
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, useMemo, } from "react";
3
3
  import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, ArrowLeft, DollarSign, ExternalLink, Settings2, Target, X, Plus, } from "lucide-react";
4
4
  import { getAgent, startAgent, claimAgentBrowser, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentAvailableTools, getAgentOperationAllowances, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, releaseAgentBrowser, } from "../services/agentService";
5
+ import { parseAgentStatus } from "../services/agentStatus";
5
6
  import { useEditContext, useFieldsEditContext } from "../client/editContext";
6
7
  import { localStorageService } from "../services/localStorageService";
7
8
  import { Textarea } from "../../components/ui/textarea";
@@ -28,6 +29,19 @@ import { AgentTerminalStatusBar } from "./AgentTerminalStatusBar";
28
29
  import { SimpleTabs } from "../ui/SimpleTabs";
29
30
  import { Splitter } from "../ui/Splitter";
30
31
  import { ScrollingContentTree } from "../ScrollingContentTree";
32
+ import { MarkdownDisplay, } from "../../components/MarkdownDisplay";
33
+ const userMessageMarkdownComponents = {
34
+ h1: (props) => (_jsx("h1", { ...props, className: "mb-2 text-sm font-semibold leading-5 text-gray-900" })),
35
+ h2: (props) => (_jsx("h2", { ...props, className: "mb-1.5 text-[13px] font-semibold leading-5 text-gray-900" })),
36
+ h3: (props) => (_jsx("h3", { ...props, className: "mb-1 text-[12px] font-semibold leading-5 text-gray-900" })),
37
+ h4: (props) => (_jsx("h4", { ...props, className: "mb-1 text-[12px] font-medium leading-5 text-gray-800" })),
38
+ p: (props) => _jsx("p", { ...props, className: "my-1 text-[12px] leading-5 text-gray-700" }),
39
+ ul: (props) => (_jsx("ul", { ...props, className: "my-2 ml-5 list-disc space-y-1 text-[12px] leading-5 text-gray-700" })),
40
+ ol: (props) => (_jsx("ol", { ...props, className: "my-2 ml-5 list-decimal space-y-1 text-[12px] leading-5 text-gray-700" })),
41
+ li: (props) => _jsx("li", { ...props, className: "text-[12px] leading-5 text-gray-700" }),
42
+ pre: (props) => (_jsx("pre", { ...props, className: "my-2 overflow-auto rounded-md bg-slate-100 px-3 py-2 text-[11px] leading-4 text-slate-700" })),
43
+ code: ({ inline, className, ...props }) => inline ? (_jsx("code", { ...props, className: "rounded bg-slate-100 px-1 py-0.5 text-[11px] text-slate-700" })) : (_jsx("code", { ...props, className: className })),
44
+ };
31
45
  function buildPlaceholderAgentDetails(agentStub) {
32
46
  const now = new Date().toISOString();
33
47
  const updated = agentStub.updatedDate || now;
@@ -178,7 +192,7 @@ function toUserFacingAgentErrorMessage(value) {
178
192
  return cleaned;
179
193
  }
180
194
  function isAgentErrorStatusValue(status) {
181
- return status === "error" || status === 4;
195
+ return status === "error";
182
196
  }
183
197
  // Simple user message component
184
198
  const UserMessage = ({ message }) => {
@@ -191,7 +205,7 @@ const UserMessage = ({ message }) => {
191
205
  const triggerContent = triggerMatch?.[2] || "";
192
206
  const isTriggerMessage = triggerName.length > 0;
193
207
  if (isTriggerMessage) {
194
- return (_jsx("div", { className: "px-4 py-2", children: _jsxs("div", { className: "text-[11px]", children: [_jsxs("button", { type: "button", onClick: () => setIsTriggerExpanded((expanded) => !expanded), className: "text-theme-secondary hover:bg-theme-hover flex w-full items-center gap-2 rounded-md border-l-2 border-cyan-200 px-2 py-1 text-left transition-colors", "data-testid": "trigger-message-toggle", "data-expanded": isTriggerExpanded ? "true" : "false", children: [_jsx(Target, { className: "h-3.5 w-3.5 shrink-0", strokeWidth: 1.5 }), _jsxs("span", { className: "truncate font-medium", children: ["Trigger: ", triggerName] }), message.createdDate && (_jsx("span", { className: "ml-1 shrink-0 text-[10px] text-gray-400", children: formatTime(new Date(message.createdDate)) })), _jsx("span", { className: "ml-auto shrink-0", children: isTriggerExpanded ? (_jsx(ChevronUp, { className: "h-3.5 w-3.5" })) : (_jsx(ChevronDown, { className: "h-3.5 w-3.5" })) })] }), isTriggerExpanded && (_jsx("div", { className: "mt-1 border-l-2 border-cyan-100 pl-[1.35rem] text-[11px] text-gray-600", children: triggerContent }))] }) }));
208
+ return (_jsx("div", { className: "px-4 py-2", children: _jsxs("div", { className: "text-[11px]", children: [_jsxs("button", { type: "button", onClick: () => setIsTriggerExpanded((expanded) => !expanded), className: "text-theme-secondary hover:bg-theme-hover flex w-full items-center gap-2 rounded-md border-l-2 border-cyan-200 px-2 py-1 text-left transition-colors", "data-testid": "trigger-message-toggle", "data-expanded": isTriggerExpanded ? "true" : "false", children: [_jsx(Target, { className: "h-3.5 w-3.5 shrink-0", strokeWidth: 1.5 }), _jsxs("span", { className: "truncate font-medium", children: ["Trigger: ", triggerName] }), message.createdDate && (_jsx("span", { className: "ml-1 shrink-0 text-[10px] text-gray-400", children: formatTime(new Date(message.createdDate)) })), _jsx("span", { className: "ml-auto shrink-0", children: isTriggerExpanded ? (_jsx(ChevronUp, { className: "h-3.5 w-3.5" })) : (_jsx(ChevronDown, { className: "h-3.5 w-3.5" })) })] }), isTriggerExpanded && (_jsx("div", { className: "mt-1 border-l-2 border-cyan-100 pl-[1.35rem] text-[11px] text-gray-600", children: _jsx(MarkdownDisplay, { source: triggerContent, components: userMessageMarkdownComponents }) }))] }) }));
195
209
  }
196
210
  // Parse source agent name from content if it starts with "[From ...]:"
197
211
  // Backend formats messages from other agents as "[From {sourceAgentName}]: {content}"
@@ -219,7 +233,7 @@ const UserMessage = ({ message }) => {
219
233
  message.sourceAgent?.name;
220
234
  }
221
235
  const displayName = sourceAgentName ? `[From ${sourceAgentName}]` : "You";
222
- 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 })] })] }));
236
+ 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: _jsx(MarkdownDisplay, { source: displayContent, components: userMessageMarkdownComponents }) })] })] }));
223
237
  };
224
238
  const HeartbeatMessage = ({ message }) => {
225
239
  return (_jsx("div", { className: "px-4 py-2", "data-testid": "agent-heartbeat-message", children: _jsxs("div", { className: "flex items-center gap-2 rounded-md border border-sky-100 bg-sky-50/80 px-3 py-2 text-[11px] text-sky-700", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin", strokeWidth: 1.5 }), _jsx("span", { className: "min-w-0 flex-1", children: message.content }), message.createdDate && (_jsx("span", { className: "shrink-0 text-[10px] text-sky-500", children: formatTime(new Date(message.createdDate)) }))] }) }));
@@ -463,12 +477,9 @@ const TodoListPanel = ({ messages, agentMetadata, }) => {
463
477
  const [isExpanded, setIsExpanded] = useState(true);
464
478
  // First try to get todos from agent metadata (real-time updates)
465
479
  // Server sends additionalData.todoList directly via contextChanged status
466
- // Also check top-level todoList for backward compatibility with stored contexts
467
480
  const metadataTodos = (() => {
468
481
  try {
469
- // Check both additionalData.todoList and top-level todoList (from [JsonExtensionData] serialization)
470
- const todoList = agentMetadata?.additionalData?.todoList ||
471
- agentMetadata?.todoList;
482
+ const todoList = agentMetadata?.additionalData?.todoList;
472
483
  if (todoList?.items && Array.isArray(todoList.items)) {
473
484
  const rawItems = todoList.items
474
485
  .map((item, idx) => ({
@@ -1061,11 +1072,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1061
1072
  value === "supervised") {
1062
1073
  return value;
1063
1074
  }
1064
- // Backend task/spawned agents persist raw "agent", which behaves like
1065
- // autonomous in the frontend's current 3-mode model.
1066
- if (value === "agent") {
1067
- return "autonomous";
1068
- }
1069
1075
  return null;
1070
1076
  };
1071
1077
  const [mode, setMode] = useState("supervised");
@@ -1108,8 +1114,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1108
1114
  const hasTodoContent = useMemo(() => {
1109
1115
  const metadataTodos = (() => {
1110
1116
  try {
1111
- const todoList = agentMetadata?.additionalData?.todoList ||
1112
- agentMetadata?.todoList;
1117
+ const todoList = agentMetadata?.additionalData?.todoList;
1113
1118
  if (todoList?.items && Array.isArray(todoList.items)) {
1114
1119
  const raw = todoList.items.filter((item) => item?.title || item?.text || item?.label || item?.task);
1115
1120
  return raw.length > 0;
@@ -1257,9 +1262,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1257
1262
  label: m.name,
1258
1263
  })) || []).sort((a, b) => a.label.localeCompare(b.label)), [activeProfile]);
1259
1264
  const metadataSelectedSkillIds = useMemo(() => {
1260
- const rawSkillIds = agentMetadata?.additionalData?.skillIds ??
1261
- agentMetadata?.skillIds ??
1262
- [];
1265
+ const rawSkillIds = agentMetadata?.additionalData?.skillIds ?? [];
1263
1266
  if (!Array.isArray(rawSkillIds)) {
1264
1267
  return [];
1265
1268
  }
@@ -1682,7 +1685,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1682
1685
  // Auto-focus terminal input on mount
1683
1686
  useEffect(() => {
1684
1687
  if (textareaRef.current) {
1685
- textareaRef.current.focus();
1688
+ try {
1689
+ textareaRef.current.focus({ preventScroll: true });
1690
+ }
1691
+ catch {
1692
+ textareaRef.current.focus();
1693
+ }
1686
1694
  }
1687
1695
  }, []);
1688
1696
  // Start voice recognition
@@ -2012,7 +2020,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2012
2020
  // If the agent isn't currently running (e.g., we switched tabs after the run
2013
2021
  // completed), skip creating a new streaming message to avoid duplicates.
2014
2022
  const currentAgentStatus = (agentData || agent)?.status;
2015
- const isAgentRunning = currentAgentStatus === "running" || currentAgentStatus === 1;
2023
+ const isAgentRunning = currentAgentStatus === "running";
2016
2024
  if (!isAgentRunning) {
2017
2025
  return;
2018
2026
  }
@@ -2819,29 +2827,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2819
2827
  if (!contextJson)
2820
2828
  return null;
2821
2829
  const parsedContext = JSON.parse(contextJson);
2822
- // Context is stored as flat structure with top-level properties.
2823
- // Due to C# [JsonExtensionData], AdditionalData entries can be serialized at top level.
2824
- // Normalize well-known extension keys back under additionalData for consistent UI behavior.
2825
2830
  if (parsedContext && typeof parsedContext === "object") {
2826
- const normalized = { ...parsedContext };
2827
- const additionalData = {
2828
- ...(normalized.additionalData || {}),
2829
- };
2830
- let additionalDataUpdated = false;
2831
- // If todoList is at top level but not in additionalData, move it
2832
- if (normalized.todoList && !normalized.additionalData?.todoList) {
2833
- additionalData.todoList = normalized.todoList;
2834
- additionalDataUpdated = true;
2835
- }
2836
- // Planner/task skill selections may also be flattened from JsonExtensionData.
2837
- if (normalized.skillIds && !normalized.additionalData?.skillIds) {
2838
- additionalData.skillIds = normalized.skillIds;
2839
- additionalDataUpdated = true;
2840
- }
2841
- if (additionalDataUpdated) {
2842
- normalized.additionalData = additionalData;
2843
- }
2844
- return normalized;
2831
+ return parsedContext;
2845
2832
  }
2846
2833
  return null;
2847
2834
  }
@@ -2927,7 +2914,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2927
2914
  return;
2928
2915
  }
2929
2916
  // Check if cost limit exceeded based on status or cost values
2930
- const statusIndicatesLimit = agent.status === "costLimitReached" || agent.status === 7;
2917
+ const statusIndicatesLimit = agent.status === "costLimitReached";
2931
2918
  // Use liveTotals.totalCost as fallback if agent.totalCost is missing or 0
2932
2919
  const effectiveTotalCost = agent.totalCost || liveTotals?.totalCost || 0;
2933
2920
  const costExceedsLimit = agent.costLimit &&
@@ -3294,12 +3281,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3294
3281
  // Route based on statusData.state
3295
3282
  try {
3296
3283
  // Normalize various status shapes and handle Cancelled uniformly
3297
- const normalizedStatus = statusData?.state ||
3298
- statusData?.status;
3299
- if (normalizedStatus === "Cancelled" ||
3300
- normalizedStatus === "canceled" ||
3301
- normalizedStatus === "stopped" ||
3302
- normalizedStatus === "Stopped") {
3284
+ const normalizedStatus = parseAgentStatus(statusData?.state) ||
3285
+ parseAgentStatus(statusData?.status);
3286
+ if (normalizedStatus === "idle") {
3303
3287
  // Stop indicators and mark any in-progress streaming messages as completed
3304
3288
  clearHeartbeatMessages();
3305
3289
  setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
@@ -3437,8 +3421,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3437
3421
  return;
3438
3422
  }
3439
3423
  // Handle waiting states explicitly
3440
- if (statusData?.state === "WaitingForApproval" ||
3441
- statusData?.state === "waitingForApproval") {
3424
+ if (normalizedStatus === "waitingForApproval") {
3442
3425
  setPendingBrowserCaptureDialogType(null);
3443
3426
  setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
3444
3427
  setIsConnecting(false);
@@ -3446,8 +3429,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3446
3429
  setIsAgentThinking(false);
3447
3430
  return;
3448
3431
  }
3449
- if (statusData?.state === "WaitingForInput" ||
3450
- statusData?.state === "waitingForInput") {
3432
+ if (normalizedStatus === "waitingForInput") {
3451
3433
  const dialogType = typeof statusData?.dialogType === "string"
3452
3434
  ? statusData.dialogType
3453
3435
  : null;
@@ -3470,7 +3452,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3470
3452
  setIsAgentThinking(false);
3471
3453
  return;
3472
3454
  }
3473
- if (statusData?.state === "CostLimitReached") {
3455
+ if (normalizedStatus === "costLimitReached") {
3474
3456
  setPendingBrowserCaptureDialogType(null);
3475
3457
  const totalCost = Number(statusData.totalCost) || 0;
3476
3458
  const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
@@ -3518,8 +3500,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3518
3500
  return;
3519
3501
  }
3520
3502
  // Handle "completed" state (fallback for legacy code paths that send status instead of lifecycle event)
3521
- if (normalizedStatus === "completed" ||
3522
- normalizedStatus === "Completed") {
3503
+ if (normalizedStatus === "completed") {
3523
3504
  // Reset deduplication for the next run
3524
3505
  lastSeqRef.current = 0;
3525
3506
  clearHeartbeatMessages();
@@ -3545,21 +3526,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3545
3526
  setIsAgentThinking(false);
3546
3527
  return;
3547
3528
  }
3548
- // Handle "Idle" state - agent has finished processing
3549
- if (normalizedStatus === "idle" || normalizedStatus === "Idle") {
3550
- // Update agent status to idle
3551
- clearHeartbeatMessages();
3552
- setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
3553
- setIsWaitingForResponse(false);
3554
- isWaitingRef.current = false;
3555
- setIsConnecting(false);
3556
- shouldCreateNewMessage.current = false;
3557
- setIsAgentThinking(false);
3558
- return;
3559
- }
3560
3529
  // Handle "Running" state - agent is actively processing
3561
- if (normalizedStatus === "running" ||
3562
- normalizedStatus === "Running") {
3530
+ if (normalizedStatus === "running") {
3563
3531
  // Update agent status to running
3564
3532
  setAgent((prev) => (prev ? { ...prev, status: "running" } : prev));
3565
3533
  setIsWaitingForResponse(true);
@@ -3568,7 +3536,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3568
3536
  return;
3569
3537
  }
3570
3538
  // Handle "Error" state
3571
- if (normalizedStatus === "error" || normalizedStatus === "Error") {
3539
+ if (normalizedStatus === "error") {
3572
3540
  const errorMsg = statusData?.statusMessage || statusData?.error || "Unknown error";
3573
3541
  clearHeartbeatMessages();
3574
3542
  setAgent((prev) => prev
@@ -3840,9 +3808,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3840
3808
  }
3841
3809
  setTimeout(() => {
3842
3810
  if (request.dialogType === "questionnaire") {
3843
- inlineDialogContainerRef.current?.scrollIntoView({
3844
- block: "start",
3845
- });
3811
+ scrollToBottomRefForDialogs.current?.();
3846
3812
  return;
3847
3813
  }
3848
3814
  scrollToBottomRefForDialogs.current?.();
@@ -3910,11 +3876,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3910
3876
  // Use case-insensitive comparison for GUID matching (backend may return different casing)
3911
3877
  const normalizedProfileId = profileIdToUse?.toLowerCase();
3912
3878
  const candidate = normalizedProfileId
3913
- ? (profiles.find((p) => p.id?.toLowerCase() === normalizedProfileId) ??
3914
- profiles[0])
3915
- : profiles[0];
3916
- if (!candidate)
3879
+ ? profiles.find((p) => p.id?.toLowerCase() === normalizedProfileId)
3880
+ : undefined;
3881
+ if (!candidate) {
3882
+ setActiveProfile(undefined);
3917
3883
  return;
3884
+ }
3918
3885
  // Keep active profile in sync whenever the matching entry in `profiles` changes —
3919
3886
  // not only when the profile id changes. Otherwise availableSkills (and similar fields)
3920
3887
  // that are merged in the parent after async loads never update (e.g. Template Builder
@@ -3936,7 +3903,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3936
3903
  return prev;
3937
3904
  return candidate;
3938
3905
  });
3939
- }, [profiles, agent?.profileId, agentStub.profileId]);
3906
+ }, [profiles, agent?.id, agent?.profileId, agentStub.id, agentStub.profileId]);
3940
3907
  // Clear queued prompts when agent changes or is new;
3941
3908
  // initial fetch is handled by loadAgent() for better performance and reliability
3942
3909
  useEffect(() => {
@@ -4265,8 +4232,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4265
4232
  const response = await startAgent(request);
4266
4233
  console.log("[AgentTerminal] startAgent response:", response);
4267
4234
  // Check if prompt was queued (agent was already running)
4268
- const wasQueued = response.message?.toLowerCase().includes("queued") ||
4269
- response.status === "Queued";
4235
+ const wasQueued = response.message?.toLowerCase().includes("queued");
4270
4236
  if (wasQueued) {
4271
4237
  // Prompt was queued - show a brief notification but don't set waiting state
4272
4238
  // The prompt will be processed when the agent becomes idle
@@ -5221,11 +5187,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5221
5187
  };
5222
5188
  const renderErrorBanner = () => {
5223
5189
  const currentAgent = agent || agentStub;
5224
- const isErrorStatus = currentAgent?.status === "error" || currentAgent?.status === 4;
5190
+ const isErrorStatus = currentAgent?.status === "error";
5225
5191
  const errorMessage = (isErrorStatus ? currentAgent?.statusMessage : null) || error;
5226
5192
  if (!errorMessage)
5227
5193
  return null;
5228
- 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 })] })] }) }));
5194
+ return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-[11px] text-red-900", "data-testid": "agent-error-banner", 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 })] })] }) }));
5229
5195
  };
5230
5196
  const renderBrowserClaimBanner = (variant = "inline") => {
5231
5197
  if (!agent?.id || !editContext?.sessionId)
@@ -5254,12 +5220,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5254
5220
  ? "Take over browser control"
5255
5221
  : "Attach to this browser" })) })] }) }));
5256
5222
  };
5257
- const fixedBrowserClaimBanner = isClaimedByCurrentSession
5258
- ? renderBrowserClaimBanner("fixed")
5259
- : null;
5260
- const inlineBrowserClaimBanner = !isClaimedByCurrentSession
5261
- ? renderBrowserClaimBanner("inline")
5262
- : null;
5223
+ const fixedBrowserClaimBanner = renderBrowserClaimBanner("fixed");
5224
+ const inlineBrowserClaimBanner = null;
5263
5225
  useEffect(() => {
5264
5226
  if (agent?.status !== "waitingForInput") {
5265
5227
  setPendingBrowserCaptureDialogType(null);
@@ -5438,7 +5400,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5438
5400
  })()
5439
5401
  : null;
5440
5402
  const fullModeInlineDialog = displayMode === "full" ? renderInlineDialogContent() : null;
5441
- const fullModeUpperContent = (_jsxs("div", { className: "flex h-full min-h-0 flex-1 flex-col", children: [fixedBrowserClaimBanner, _jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error && !isAgentErrorStatusValue((agent || agentStub)?.status) && (_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) => {
5403
+ const fullModeUpperContent = (_jsxs("div", { className: "flex h-full min-h-0 flex-1 flex-col", children: [fixedBrowserClaimBanner, _jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [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) => {
5442
5404
  setPrompt(p);
5443
5405
  // Use setTimeout to ensure state is updated before submission
5444
5406
  setTimeout(() => {