@parhelia/core 0.1.12523 → 0.1.12554

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 (144) hide show
  1. package/dist/agents-view/AgentCard.js +9 -9
  2. package/dist/agents-view/AgentCard.js.map +1 -1
  3. package/dist/agents-view/AgentsView.js +6 -6
  4. package/dist/agents-view/AgentsView.js.map +1 -1
  5. package/dist/config/config.d.ts +2 -0
  6. package/dist/config/config.js +35 -0
  7. package/dist/config/config.js.map +1 -1
  8. package/dist/config/types.d.ts +5 -0
  9. package/dist/config/types.js.map +1 -1
  10. package/dist/editor/Editor.js +17 -6
  11. package/dist/editor/Editor.js.map +1 -1
  12. package/dist/editor/ImageEditor.js +5 -2
  13. package/dist/editor/ImageEditor.js.map +1 -1
  14. package/dist/editor/ItemInfo.js +1 -1
  15. package/dist/editor/ItemInfo.js.map +1 -1
  16. package/dist/editor/MainLayout.js +61 -3
  17. package/dist/editor/MainLayout.js.map +1 -1
  18. package/dist/editor/PictureEditor.js +5 -2
  19. package/dist/editor/PictureEditor.js.map +1 -1
  20. package/dist/editor/ai/AgentTerminal.js +246 -57
  21. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  22. package/dist/editor/ai/Agents.js +63 -13
  23. package/dist/editor/ai/Agents.js.map +1 -1
  24. package/dist/editor/ai/ToolCallDisplay.d.ts +2 -1
  25. package/dist/editor/ai/ToolCallDisplay.js +152 -5
  26. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  27. package/dist/editor/ai/types.d.ts +1 -1
  28. package/dist/editor/ai/useAgentStatus.d.ts +1 -1
  29. package/dist/editor/ai/useAgentStatus.js +8 -4
  30. package/dist/editor/ai/useAgentStatus.js.map +1 -1
  31. package/dist/editor/client/EditorShell.d.ts +4 -1
  32. package/dist/editor/client/EditorShell.js +155 -24
  33. package/dist/editor/client/EditorShell.js.map +1 -1
  34. package/dist/editor/client/editContext.d.ts +6 -0
  35. package/dist/editor/client/editContext.js.map +1 -1
  36. package/dist/editor/client/navigation.d.ts +21 -0
  37. package/dist/editor/client/navigation.js +98 -0
  38. package/dist/editor/client/navigation.js.map +1 -0
  39. package/dist/editor/client/operations.d.ts +1 -0
  40. package/dist/editor/client/operations.js +18 -0
  41. package/dist/editor/client/operations.js.map +1 -1
  42. package/dist/editor/client/ui/DevModeIndicator.js +2 -2
  43. package/dist/editor/client/ui/DevModeIndicator.js.map +1 -1
  44. package/dist/editor/commands/handlers/uiActionHandlers.js +3 -4
  45. package/dist/editor/commands/handlers/uiActionHandlers.js.map +1 -1
  46. package/dist/editor/field-types/RichTextEditor.js +10 -4
  47. package/dist/editor/field-types/RichTextEditor.js.map +1 -1
  48. package/dist/editor/field-types/richtext/contextMenuFactory.js +5 -3
  49. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
  50. package/dist/editor/field-types/textContextMenuFactory.js +3 -2
  51. package/dist/editor/field-types/textContextMenuFactory.js.map +1 -1
  52. package/dist/editor/media-selector/AiImageSearchPrompt.js +4 -2
  53. package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
  54. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js +9 -2
  55. package/dist/editor/menubar/toolbar-sections/CustomCommandsToolbar.js.map +1 -1
  56. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +121 -5
  57. package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
  58. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +4 -2
  59. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  60. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +19 -4
  61. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  62. package/dist/editor/page-viewer/DeviceToolbar.js +1 -1
  63. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  64. package/dist/editor/page-viewer/EditorForm.js +9 -2
  65. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  66. package/dist/editor/page-viewer/PageViewerFrame.js +56 -6
  67. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  68. package/dist/editor/page-viewer/RenderingParametersSection.d.ts +6 -0
  69. package/dist/editor/page-viewer/RenderingParametersSection.js +148 -0
  70. package/dist/editor/page-viewer/RenderingParametersSection.js.map +1 -0
  71. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +7 -0
  72. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
  73. package/dist/editor/pageModel.d.ts +4 -0
  74. package/dist/editor/reviews/Comment.js +3 -1
  75. package/dist/editor/reviews/Comment.js.map +1 -1
  76. package/dist/editor/reviews/CommentDisplayPopover.js +3 -1
  77. package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
  78. package/dist/editor/reviews/SuggestedEdit.js +4 -1
  79. package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
  80. package/dist/editor/reviews/commentAi.js +4 -0
  81. package/dist/editor/reviews/commentAi.js.map +1 -1
  82. package/dist/editor/services/agentService.d.ts +10 -0
  83. package/dist/editor/services/agentService.js +20 -0
  84. package/dist/editor/services/agentService.js.map +1 -1
  85. package/dist/editor/services/editService.d.ts +19 -0
  86. package/dist/editor/services/editService.js +15 -0
  87. package/dist/editor/services/editService.js.map +1 -1
  88. package/dist/editor/services-server/api.d.ts +1 -2
  89. package/dist/editor/services-server/api.js +11 -6
  90. package/dist/editor/services-server/api.js.map +1 -1
  91. package/dist/editor/settings/About.js +1 -1
  92. package/dist/editor/settings/About.js.map +1 -1
  93. package/dist/editor/settings/SettingsView.js +2 -2
  94. package/dist/editor/settings/SettingsView.js.map +1 -1
  95. package/dist/editor/settings/Status.js +2 -2
  96. package/dist/editor/settings/Status.js.map +1 -1
  97. package/dist/editor/settings/panels/AgentsPanel.js +1 -1
  98. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  99. package/dist/editor/settings/panels/ModelsPanel.js +1 -1
  100. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
  101. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +1 -1
  102. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  103. package/dist/editor/settings/panels/ProvidersPanel.js +1 -1
  104. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  105. package/dist/editor/sidebar/EditHistory.js +17 -2
  106. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  107. package/dist/editor/sidebar/NavigationPanelItem.js +1 -1
  108. package/dist/editor/sidebar/NavigationPanelItem.js.map +1 -1
  109. package/dist/editor/sidebar/OperationItem.js +2 -1
  110. package/dist/editor/sidebar/OperationItem.js.map +1 -1
  111. package/dist/editor/sidebar/SidebarPanel.d.ts +3 -1
  112. package/dist/editor/sidebar/SidebarPanel.js +15 -6
  113. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  114. package/dist/editor/sidebar/SidebarStack.d.ts +2 -1
  115. package/dist/editor/sidebar/SidebarStack.js +3 -3
  116. package/dist/editor/sidebar/SidebarStack.js.map +1 -1
  117. package/dist/editor/template-wizard/TemplateStructureInlineEditor.js +10 -3
  118. package/dist/editor/template-wizard/TemplateStructureInlineEditor.js.map +1 -1
  119. package/dist/editor/utils/keyboardNavigation.js +1 -2
  120. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  121. package/dist/editor/views/CompareView.js +1 -1
  122. package/dist/editor/views/CompareView.js.map +1 -1
  123. package/dist/index.d.ts +2 -0
  124. package/dist/index.js +1 -0
  125. package/dist/index.js.map +1 -1
  126. package/dist/licensing/LicenseContext.d.ts +3 -1
  127. package/dist/licensing/LicenseContext.js +55 -38
  128. package/dist/licensing/LicenseContext.js.map +1 -1
  129. package/dist/revision.d.ts +2 -2
  130. package/dist/revision.js +2 -2
  131. package/dist/splash-screen/ModernSplashScreen.js +4 -2
  132. package/dist/splash-screen/ModernSplashScreen.js.map +1 -1
  133. package/dist/task-board/TaskBoardWorkspace.js +34 -6
  134. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  135. package/dist/task-board/components/AssignAgentDialog.js +13 -1
  136. package/dist/task-board/components/AssignAgentDialog.js.map +1 -1
  137. package/dist/task-board/components/TaskAgentPanel.js +11 -1
  138. package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
  139. package/dist/task-board/components/TaskAssigneePicker.js +14 -4
  140. package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
  141. package/dist/task-board/components/WizardCommunicationCenter.js +18 -9
  142. package/dist/task-board/components/WizardCommunicationCenter.js.map +1 -1
  143. package/dist/types.d.ts +7 -1
  144. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
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
- import { getAgent, startAgent, claimAgentBrowser, assignAgentSkill, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentAvailableTools, getAgentOperationAllowances, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, releaseAgentBrowser, revokeAgentSkill, } from "../services/agentService";
4
+ import { getAgent, startAgent, claimAgentBrowser, assignAgentSkill, persistDraftAgent, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentAvailableTools, getAgentOperationAllowances, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, releaseAgentBrowser, revokeAgentSkill, } from "../services/agentService";
5
5
  import { parseAgentStatus } from "../services/agentStatus";
6
6
  import { useEditContext, useFieldsEditContext } from "../client/editContext";
7
7
  import { localStorageService } from "../services/localStorageService";
@@ -31,14 +31,14 @@ import { Splitter } from "../ui/Splitter";
31
31
  import { ScrollingContentTree } from "../ScrollingContentTree";
32
32
  import { MarkdownDisplay, } from "../../components/MarkdownDisplay";
33
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" }),
34
+ h1: (props) => (_jsx("h1", { ...props, className: "mb-2 text-sm leading-5 font-semibold text-gray-900" })),
35
+ h2: (props) => (_jsx("h2", { ...props, className: "mb-1.5 text-[13px] leading-5 font-semibold text-gray-900" })),
36
+ h3: (props) => (_jsx("h3", { ...props, className: "mb-1 text-[12px] leading-5 font-semibold text-gray-900" })),
37
+ h4: (props) => (_jsx("h4", { ...props, className: "mb-1 text-[12px] leading-5 font-medium text-gray-800" })),
38
+ p: (props) => (_jsx("p", { ...props, className: "my-1 text-[12px] leading-5 text-gray-700" })),
39
39
  ul: (props) => (_jsx("ul", { ...props, className: "my-2 ml-5 list-disc space-y-1 text-[12px] leading-5 text-gray-700" })),
40
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" }),
41
+ li: (props) => (_jsx("li", { ...props, className: "text-[12px] leading-5 text-gray-700" })),
42
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
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
44
  };
@@ -149,25 +149,36 @@ function toUserFacingAgentErrorMessage(value) {
149
149
  if (!normalizedValue)
150
150
  return "";
151
151
  const trimmed = normalizedValue.trim();
152
- const maybeJson = trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith('"');
152
+ const maybeJson = trimmed.startsWith("{") ||
153
+ trimmed.startsWith("[") ||
154
+ trimmed.startsWith('"');
153
155
  if (maybeJson) {
154
156
  try {
155
157
  const parsed = JSON.parse(trimmed);
156
158
  const structuredMessage = typeof parsed === "string"
157
159
  ? parsed
158
- : typeof parsed?.error === "string"
159
- ? parsed.error
160
- : typeof parsed?.message === "string"
161
- ? parsed.message
162
- : typeof parsed?.detail === "string"
163
- ? parsed.detail
164
- : typeof parsed?.error_description === "string"
165
- ? parsed.error_description
166
- : typeof parsed?.error === "object" &&
167
- parsed?.error &&
168
- typeof parsed.error.message ===
169
- "string"
170
- ? String(parsed.error.message)
160
+ : typeof parsed?.error === "object" && parsed?.error
161
+ ? (() => {
162
+ const errObj = parsed.error;
163
+ // Extract detailed message from metadata.raw (OpenRouter-style nested errors)
164
+ if (typeof errObj.metadata?.raw ===
165
+ "string") {
166
+ return String(errObj.metadata.raw);
167
+ }
168
+ // Fall back to error.message
169
+ if (typeof errObj.message === "string") {
170
+ return errObj.message;
171
+ }
172
+ return "";
173
+ })()
174
+ : typeof parsed?.error === "string"
175
+ ? parsed.error
176
+ : typeof parsed?.message === "string"
177
+ ? parsed.message
178
+ : typeof parsed?.detail === "string"
179
+ ? parsed.detail
180
+ : typeof parsed?.error_description === "string"
181
+ ? parsed.error_description
171
182
  : "";
172
183
  if (structuredMessage.trim()) {
173
184
  value = structuredMessage;
@@ -607,7 +618,8 @@ const groupConsecutiveMessages = (agentMessages) => {
607
618
  // Add user message
608
619
  groups.push({ type: "user", messages: [message] });
609
620
  }
610
- else if (message.messageType === "heartbeat" || message.role === "system") {
621
+ else if (message.messageType === "heartbeat" ||
622
+ message.role === "system") {
611
623
  if (currentAssistantGroup.length > 0) {
612
624
  groups.push({
613
625
  type: "assistant-group",
@@ -720,6 +732,35 @@ const stringifyToolField = (value) => {
720
732
  return String(value);
721
733
  }
722
734
  };
735
+ const parseToolResultValue = (value) => {
736
+ if (value === undefined || value === null) {
737
+ return undefined;
738
+ }
739
+ if (typeof value === "object") {
740
+ return value;
741
+ }
742
+ if (typeof value !== "string") {
743
+ return String(value);
744
+ }
745
+ const trimmed = value.trim();
746
+ if (!trimmed) {
747
+ return undefined;
748
+ }
749
+ try {
750
+ let parsed = JSON.parse(trimmed);
751
+ if (typeof parsed === "string" &&
752
+ (parsed.startsWith("{") || parsed.startsWith("["))) {
753
+ parsed = JSON.parse(parsed);
754
+ }
755
+ if (parsed && typeof parsed === "object") {
756
+ return parsed;
757
+ }
758
+ }
759
+ catch {
760
+ // Fall back to the original string when the payload is plain text.
761
+ }
762
+ return value;
763
+ };
723
764
  const getFirstToolCallEnvelope = (data) => {
724
765
  if (!data || typeof data !== "object")
725
766
  return undefined;
@@ -779,13 +820,14 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
779
820
  ? agentMessage.toolCalls.map((toolCall) => {
780
821
  const isPruned = !!toolCall.isPruned ||
781
822
  /^PRUNED$/i.test(toolCall.functionError || "");
823
+ const displayResult = parseToolResultValue(toolCall.functionResultRichContent) ?? toolCall.functionResult;
782
824
  return {
783
825
  id: toolCall.toolCallId,
784
826
  displayName: toolCall.functionName,
785
827
  function: {
786
828
  name: toolCall.functionName,
787
829
  arguments: toolCall.functionArguments,
788
- result: toolCall.functionResult,
830
+ result: displayResult,
789
831
  error: toolCall.functionError,
790
832
  },
791
833
  // Pass through approval info if present on the tool call
@@ -798,7 +840,7 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
798
840
  // Tool call is streaming if message is not completed and tool call has no result yet
799
841
  isStreaming: !agentMessage.isCompleted &&
800
842
  !toolCall.isCompleted &&
801
- !toolCall.functionResult &&
843
+ !displayResult &&
802
844
  !toolCall.functionError &&
803
845
  !isPruned,
804
846
  // Pass through message IDs for approval/rejection events
@@ -1103,7 +1145,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1103
1145
  const [toolsSectionExpanded, setToolsSectionExpanded] = useState(false);
1104
1146
  const [allowancesSectionExpanded, setAllowancesSectionExpanded] = useState(false);
1105
1147
  const [subscribedTriggersSectionExpanded, setSubscribedTriggersSectionExpanded,] = useState(false);
1106
- const isNewAgent = agent?.status === "new";
1148
+ const isPersistedAgent = !!agent?.userId;
1149
+ const isLocalOnlyDraftAgent = agent?.status === "new" && !isPersistedAgent;
1107
1150
  const hasSpawnedAgents = useMemo(() => {
1108
1151
  if (!agentMetadata)
1109
1152
  return false;
@@ -1291,7 +1334,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1291
1334
  }, [activeProfile?.preloadSkills]);
1292
1335
  const autoAssignedSkillIds = useMemo(() => {
1293
1336
  const preloadedIdSet = new Set(preloadedSkillIds.map((id) => id.toLowerCase()));
1294
- const all = backendAssignedSkillIds.filter((id) => preloadedIdSet.has(id.toLowerCase()));
1337
+ const all = isLocalOnlyDraftAgent
1338
+ ? preloadedSkillIds
1339
+ : backendAssignedSkillIds.filter((id) => preloadedIdSet.has(id.toLowerCase()));
1295
1340
  const seen = new Set();
1296
1341
  const unique = [];
1297
1342
  for (const id of all) {
@@ -1302,9 +1347,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1302
1347
  unique.push(id);
1303
1348
  }
1304
1349
  return unique;
1305
- }, [backendAssignedSkillIds, preloadedSkillIds]);
1350
+ }, [backendAssignedSkillIds, isLocalOnlyDraftAgent, preloadedSkillIds]);
1306
1351
  const selectedSkillIds = useMemo(() => {
1307
- const all = [...autoAssignedSkillIds, ...metadataSelectedSkillIds];
1352
+ const all = [
1353
+ ...autoAssignedSkillIds,
1354
+ ...backendAssignedSkillIds,
1355
+ ...metadataSelectedSkillIds,
1356
+ ];
1308
1357
  const seen = new Set();
1309
1358
  const unique = [];
1310
1359
  for (const id of all) {
@@ -1315,7 +1364,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1315
1364
  unique.push(id);
1316
1365
  }
1317
1366
  return unique;
1318
- }, [autoAssignedSkillIds, metadataSelectedSkillIds]);
1367
+ }, [autoAssignedSkillIds, backendAssignedSkillIds, metadataSelectedSkillIds]);
1319
1368
  useEffect(() => {
1320
1369
  let active = true;
1321
1370
  if (!showAgentSettings) {
@@ -1323,7 +1372,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1323
1372
  active = false;
1324
1373
  };
1325
1374
  }
1326
- if (!agent?.id || agent.status === "new") {
1375
+ if (!agent?.id || isLocalOnlyDraftAgent) {
1327
1376
  setTriggerSubscriptions([]);
1328
1377
  setTriggerSubscriptionsLoading(false);
1329
1378
  setTriggerSubscriptionsError(null);
@@ -1407,6 +1456,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1407
1456
  showAgentSettings,
1408
1457
  agent?.id,
1409
1458
  agent?.status,
1459
+ agent?.userId,
1410
1460
  agent?.profileId,
1411
1461
  mode,
1412
1462
  selectedSkillIds,
@@ -1455,8 +1505,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1455
1505
  const autoAssignedSkillSet = useMemo(() => new Set(autoAssignedSkillIds.map((id) => id.toLowerCase())), [autoAssignedSkillIds]);
1456
1506
  const previewAvailableTools = useMemo(() => {
1457
1507
  const baseToolNames = mode === "read-only"
1458
- ? activeProfile?.readOnlyToolNames ?? []
1459
- : activeProfile?.allowedToolNames ?? [];
1508
+ ? (activeProfile?.readOnlyToolNames ?? [])
1509
+ : (activeProfile?.allowedToolNames ?? []);
1460
1510
  const toolNames = new Set();
1461
1511
  for (const toolName of baseToolNames) {
1462
1512
  const normalized = String(toolName || "").trim();
@@ -1479,13 +1529,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1479
1529
  mode,
1480
1530
  selectedSkills,
1481
1531
  ]);
1482
- const displayedAvailableTools = isNewAgent
1532
+ const displayedAvailableTools = isLocalOnlyDraftAgent
1483
1533
  ? previewAvailableTools
1484
1534
  : availableTools;
1485
- const displayedAvailableToolsLoading = isNewAgent
1535
+ const displayedAvailableToolsLoading = isLocalOnlyDraftAgent
1486
1536
  ? false
1487
1537
  : availableToolsLoading;
1488
- const displayedAvailableToolsError = isNewAgent ? null : availableToolsError;
1538
+ const displayedAvailableToolsError = isLocalOnlyDraftAgent
1539
+ ? null
1540
+ : availableToolsError;
1489
1541
  // Remove deprecated cost limit fields from metadata to avoid confusion with agent/profile settings
1490
1542
  const sanitizeAgentMetadata = useCallback((meta) => {
1491
1543
  try {
@@ -1525,7 +1577,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1525
1577
  return;
1526
1578
  }
1527
1579
  const current = agentMetadata || {};
1528
- const currentAdditionalData = current.additionalData || {};
1580
+ const currentAdditionalData = current.additionalData ||
1581
+ {};
1529
1582
  const nextAdditionalData = Object.fromEntries(Object.entries(currentAdditionalData).filter(([key]) => key.toLowerCase() !== "skillids"));
1530
1583
  const next = {
1531
1584
  ...current,
@@ -1551,6 +1604,86 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1551
1604
  setAgent,
1552
1605
  setAgentMetadata,
1553
1606
  ]);
1607
+ const parsePersistedAgentContext = (contextJson) => {
1608
+ try {
1609
+ if (!contextJson)
1610
+ return null;
1611
+ const parsedContext = JSON.parse(contextJson);
1612
+ if (!parsedContext || typeof parsedContext !== "object") {
1613
+ return null;
1614
+ }
1615
+ return sanitizeAgentMetadata(parsedContext);
1616
+ }
1617
+ catch {
1618
+ return null;
1619
+ }
1620
+ };
1621
+ const buildDraftPersistenceContext = () => {
1622
+ let effectiveContext = agentMetadata;
1623
+ try {
1624
+ const normalizedAgentProfileId = agent?.profileId?.toLowerCase();
1625
+ const profile = activeProfile ||
1626
+ profiles.find((p) => p.id?.toLowerCase() === normalizedAgentProfileId);
1627
+ const isLiveMode = profile?.editorContextMode === "live";
1628
+ if (isLiveMode && typeof buildCurrentContext === "function") {
1629
+ const freshContext = buildCurrentContext();
1630
+ if (freshContext) {
1631
+ effectiveContext = {
1632
+ ...(agentMetadata || {}),
1633
+ items: freshContext.items,
1634
+ currentItemId: freshContext.currentItemId,
1635
+ components: freshContext.components,
1636
+ field: freshContext.field,
1637
+ activeWorkspace: freshContext.activeWorkspace,
1638
+ hasPageLoaded: freshContext.hasPageLoaded,
1639
+ openSidebars: freshContext.openSidebars,
1640
+ };
1641
+ }
1642
+ }
1643
+ }
1644
+ catch (e) {
1645
+ console.warn("[AgentTerminal] Failed to compute draft context:", e);
1646
+ }
1647
+ return sanitizeAgentMetadata(effectiveContext || null);
1648
+ };
1649
+ const ensureDraftAgentPersisted = async () => {
1650
+ if (!agent?.id) {
1651
+ throw new Error("Agent not ready. Please try again.");
1652
+ }
1653
+ if (!isLocalOnlyDraftAgent) {
1654
+ return agent;
1655
+ }
1656
+ const requestSettings = getPendingRequestSettings();
1657
+ if (!requestSettings.profileId) {
1658
+ throw new Error("Select an agent profile before adding a skill.");
1659
+ }
1660
+ const effectiveContext = buildDraftPersistenceContext();
1661
+ const persistedAgent = await persistDraftAgent({
1662
+ agentId: agent.id,
1663
+ sessionId: editContext?.sessionId || undefined,
1664
+ profileId: requestSettings.profileId,
1665
+ mode: requestSettings.mode,
1666
+ model: requestSettings.modelId || undefined,
1667
+ name: agent.name,
1668
+ context: effectiveContext,
1669
+ });
1670
+ pendingSettingsRef.current = null;
1671
+ const persistedMetadata = parsePersistedAgentContext(persistedAgent.agentContext) ??
1672
+ effectiveContext;
1673
+ setAgentMetadata(persistedMetadata ? { ...persistedMetadata } : null);
1674
+ setAgent((prev) => {
1675
+ const next = {
1676
+ ...(prev || {}),
1677
+ ...persistedAgent,
1678
+ };
1679
+ if (prev?.messages?.length && !persistedAgent.messages?.length) {
1680
+ next.messages = prev.messages;
1681
+ }
1682
+ return next;
1683
+ });
1684
+ onAgentUpdate?.(persistedAgent);
1685
+ return persistedAgent;
1686
+ };
1554
1687
  const handleAddSkill = useCallback(async (skillId) => {
1555
1688
  if (selectedSkillSet.has(skillId.toLowerCase()))
1556
1689
  return;
@@ -1558,7 +1691,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1558
1691
  return;
1559
1692
  try {
1560
1693
  setSkillActionError(null);
1561
- await assignAgentSkill({ agentId: agent.id, skillId });
1694
+ const persistedAgent = await ensureDraftAgentPersisted();
1695
+ await assignAgentSkill({ agentId: persistedAgent.id, skillId });
1562
1696
  setAgent((prev) => {
1563
1697
  if (!prev)
1564
1698
  return prev;
@@ -1584,6 +1718,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1584
1718
  agent?.id,
1585
1719
  assignAgentSkill,
1586
1720
  clearLegacySelectedSkillsFromMetadata,
1721
+ ensureDraftAgentPersisted,
1587
1722
  getSkillActionErrorMessage,
1588
1723
  setAgent,
1589
1724
  selectedSkillSet,
@@ -2297,7 +2432,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2297
2432
  if (toolCallMessageId && message.data && toolCallId) {
2298
2433
  const toolCallError = message.data.functionError || message.data.error || "";
2299
2434
  const isPruned = !!message.data?.isPruned || /^PRUNED$/i.test(String(toolCallError));
2300
- const toolCallCreatedDate = message.data.createdDate || message.timestamp || new Date().toISOString();
2435
+ const toolCallCreatedDate = message.data.createdDate ||
2436
+ message.timestamp ||
2437
+ new Date().toISOString();
2301
2438
  const toolCall = {
2302
2439
  id: toolCallId,
2303
2440
  messageId: toolCallMessageId,
@@ -2306,6 +2443,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2306
2443
  functionName: extractedToolCall.functionName,
2307
2444
  functionArguments: extractedToolCall.functionArguments,
2308
2445
  functionResult: message.data.functionResult || message.data.result || "",
2446
+ functionResultRichContent: message.data.richContent || undefined,
2309
2447
  functionError: toolCallError,
2310
2448
  isPruned,
2311
2449
  isCompleted: false,
@@ -2355,12 +2493,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2355
2493
  newArgsText !== existingArgsText) ||
2356
2494
  (existingArgsText === "{}" && newArgsText !== "{}");
2357
2495
  const hasNewResult = toolCall.functionResult && !existingToolCall.functionResult;
2496
+ const hasNewRichContent = toolCall.functionResultRichContent &&
2497
+ !existingToolCall.functionResultRichContent;
2358
2498
  const hasNewError = toolCall.functionError && !existingToolCall.functionError;
2359
2499
  const hasNewApprovalInfo = toolCall.requiresApproval && !existingToolCall.requiresApproval;
2360
2500
  const hasNewDbMessageId = toolCall.dbMessageId && !existingToolCall.dbMessageId;
2361
2501
  // Only update if there's meaningful new data
2362
2502
  if (hasMoreCompleteArgs ||
2363
2503
  hasNewResult ||
2504
+ hasNewRichContent ||
2364
2505
  hasNewError ||
2365
2506
  hasNewApprovalInfo ||
2366
2507
  hasNewDbMessageId) {
@@ -2380,6 +2521,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2380
2521
  ? newArgsText
2381
2522
  : existingArgsText || existing.functionArguments,
2382
2523
  functionResult: toolCall.functionResult || existing.functionResult,
2524
+ functionResultRichContent: toolCall.functionResultRichContent ||
2525
+ existing.functionResultRichContent,
2383
2526
  functionError: toolCall.functionError || existing.functionError,
2384
2527
  requiresApproval: toolCall.requiresApproval || existing.requiresApproval,
2385
2528
  };
@@ -2540,6 +2683,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2540
2683
  ? nextArgsText
2541
2684
  : existingToolCall.functionArguments,
2542
2685
  functionResult: message.data.functionResult || message.data.result || "",
2686
+ functionResultRichContent: message.data.richContent ||
2687
+ existingToolCall.functionResultRichContent,
2543
2688
  functionError: message.data.functionError || message.data.error || "",
2544
2689
  isCompleted: true,
2545
2690
  responseTimeMs: message.data.responseTimeMs,
@@ -2556,7 +2701,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2556
2701
  }
2557
2702
  else if (message.data && resultToolCallId && resultMessageId) {
2558
2703
  // Create new tool call if it doesn't exist
2559
- const toolCallCreatedDate = message.data.createdDate || message.timestamp || new Date().toISOString();
2704
+ const toolCallCreatedDate = message.data.createdDate ||
2705
+ message.timestamp ||
2706
+ new Date().toISOString();
2560
2707
  const toolCall = {
2561
2708
  id: resultToolCallId,
2562
2709
  messageId: resultMessageId,
@@ -2564,6 +2711,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2564
2711
  functionName: extractedToolCall.functionName,
2565
2712
  functionArguments: extractedToolCall.functionArguments,
2566
2713
  functionResult: message.data.functionResult || message.data.result || "",
2714
+ functionResultRichContent: message.data.richContent || undefined,
2567
2715
  functionError: message.data.functionError || message.data.error || "",
2568
2716
  isCompleted: true,
2569
2717
  responseTimeMs: message.data.responseTimeMs,
@@ -2658,7 +2806,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2658
2806
  // The agent might have been persisted after sending a prompt
2659
2807
  // Only treat as "new" if backend returns 404
2660
2808
  const hasExistingMessages = messagesRef.current.length > 0;
2661
- if (agentStub.status === "new" && !hasExistingMessages) {
2809
+ if (agentStub.status === "new" &&
2810
+ !agentStub.userId &&
2811
+ !hasExistingMessages) {
2662
2812
  // Only initialize as new if we have no messages yet (initial mount)
2663
2813
  // Derive initial profile from provided metadata if present
2664
2814
  const initialProfileIdFromMeta = (() => {
@@ -4004,14 +4154,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4004
4154
  return prev;
4005
4155
  return candidate;
4006
4156
  });
4007
- }, [profiles, agent?.id, agent?.profileId, agentStub.id, agentStub.profileId]);
4157
+ }, [
4158
+ profiles,
4159
+ agent?.id,
4160
+ agent?.profileId,
4161
+ agentStub.id,
4162
+ agentStub.profileId,
4163
+ ]);
4008
4164
  // Clear queued prompts when agent changes or is new;
4009
4165
  // initial fetch is handled by loadAgent() for better performance and reliability
4010
4166
  useEffect(() => {
4011
- if (!agent?.id || agent.status === "new") {
4167
+ if (!agent?.id || isLocalOnlyDraftAgent) {
4012
4168
  setQueuedPrompts([]);
4013
4169
  }
4014
- }, [agent?.id, agent?.status]);
4170
+ }, [agent?.id, isLocalOnlyDraftAgent]);
4015
4171
  // Update selected model when the active profile or agent model changes
4016
4172
  useEffect(() => {
4017
4173
  if (!activeProfile)
@@ -5266,9 +5422,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5266
5422
  try {
5267
5423
  // Extend cost limit - backend will automatically resume the agent
5268
5424
  const result = await updateAgentCostLimit(agent.id, "extend");
5269
- // Update the agent's cost limit in local state
5425
+ // Update the agent's cost limit and clear the costLimitReached
5426
+ // status in local state so the useEffect watcher doesn't
5427
+ // immediately re-show the banner before the backend status
5428
+ // update arrives.
5270
5429
  if (result.success && result.costLimit !== undefined) {
5271
- setAgent((prev) => prev ? { ...prev, costLimit: result.costLimit } : prev);
5430
+ setAgent((prev) => prev
5431
+ ? {
5432
+ ...prev,
5433
+ costLimit: result.costLimit,
5434
+ status: prev.status === "costLimitReached"
5435
+ ? "running"
5436
+ : prev.status,
5437
+ }
5438
+ : prev);
5272
5439
  }
5273
5440
  // Clear the banner and set waiting state
5274
5441
  // Agent will resume automatically via backend's ResumeAgentAsync
@@ -5289,9 +5456,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5289
5456
  const renderErrorBanner = () => {
5290
5457
  const currentAgent = agent || agentStub;
5291
5458
  const isErrorStatus = currentAgent?.status === "error";
5292
- const errorMessage = (isErrorStatus ? currentAgent?.statusMessage : null) || error;
5293
- if (!errorMessage)
5459
+ const rawErrorMessage = (isErrorStatus ? currentAgent?.statusMessage : null) || error;
5460
+ if (!rawErrorMessage)
5294
5461
  return null;
5462
+ // Clean the error message (statusMessage from DB may contain raw JSON)
5463
+ const errorMessage = toUserFacingAgentErrorMessage(rawErrorMessage) || rawErrorMessage;
5295
5464
  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 })] })] }) }));
5296
5465
  };
5297
5466
  const renderBrowserClaimBanner = (variant = "inline") => {
@@ -5326,7 +5495,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5326
5495
  const inlineBrowserClaimBanner = null;
5327
5496
  const browserCaptureInlinePrompt = isPendingBrowserCaptureWait && !isClaimedByCurrentSession
5328
5497
  ? {
5329
- toolNames: ["capture-page-screenshot", "capture-page-dom"],
5498
+ toolNames: [
5499
+ "capture-page-screenshot",
5500
+ "capture-parhelia-ui-screenshot",
5501
+ "capture-page-dom",
5502
+ ],
5330
5503
  label: isClaimedByAnotherBrowser
5331
5504
  ? "Attached in another browser"
5332
5505
  : "No browser attached",
@@ -5793,7 +5966,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5793
5966
  mode: nextMode,
5794
5967
  };
5795
5968
  try {
5796
- if (!agent?.id || agent.status === "new") {
5969
+ if (!agent?.id || isLocalOnlyDraftAgent) {
5797
5970
  setMode(nextMode);
5798
5971
  setAgentMetadata(nextMeta);
5799
5972
  pendingSettingsRef.current = {
@@ -5805,7 +5978,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5805
5978
  const result = await updateAgentSettings(agent.id, {
5806
5979
  mode: nextMode,
5807
5980
  });
5808
- if (result.success === false || result.updates?.mode === false) {
5981
+ if (result.success === false ||
5982
+ result.updates?.mode === false) {
5809
5983
  throw new Error("Mode change was not applied");
5810
5984
  }
5811
5985
  setMode(nextMode);
@@ -5826,13 +6000,28 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5826
6000
  if (!open) {
5827
6001
  setShowSkillPicker(false);
5828
6002
  }
5829
- }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { size: "xs", variant: "outline", className: "h-5 rounded border px-1.5 text-[11px] text-gray-600", "data-testid": "agent-settings-popover-trigger", children: [_jsx(Settings2, { className: "mr-1 h-3 w-3", strokeWidth: 1 }), "Agent settings"] }) }), _jsx(PopoverContent, { className: "w-80 p-3", align: "start", children: _jsxs("div", { className: "space-y-3", children: [profiles?.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[11px] font-medium text-gray-700", children: "Agent profile" }), _jsx(Select, { size: "xs", maxWidth: 300, searchable: profiles.length > 5, searchPlaceholder: "Filter profiles...", className: "h-6 w-full rounded border px-1.5 text-[11px] text-gray-500", value: activeProfile?.id || "", options: profileOptions, "data-testid": "agent-profile-selector", onValueChange: async (val) => {
6003
+ }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { size: "xs", variant: "outline", className: "h-5 rounded border px-1.5 text-[11px] text-gray-600", "data-testid": "agent-settings-popover-trigger", children: [_jsx(Settings2, { className: "mr-1 h-3 w-3", strokeWidth: 1 }), "Agent settings"] }) }), _jsx(PopoverContent, { className: "w-80 p-3", align: "start", onInteractOutside: (e) => {
6004
+ const target = e.target;
6005
+ if (target?.closest('[data-help-panel="true"]')) {
6006
+ e.preventDefault();
6007
+ }
6008
+ }, onPointerDownOutside: (e) => {
6009
+ const target = e.target;
6010
+ if (target?.closest('[data-help-panel="true"]')) {
6011
+ e.preventDefault();
6012
+ }
6013
+ }, onFocusOutside: (e) => {
6014
+ const target = e.target;
6015
+ if (target?.closest('[data-help-panel="true"]')) {
6016
+ e.preventDefault();
6017
+ }
6018
+ }, children: _jsxs("div", { className: "space-y-3", children: [profiles?.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[11px] font-medium text-gray-700", children: "Agent profile" }), _jsx(Select, { size: "xs", maxWidth: 300, searchable: profiles.length > 5, searchPlaceholder: "Filter profiles...", className: "h-6 w-full rounded border px-1.5 text-[11px] text-gray-500", value: activeProfile?.id || "", options: profileOptions, "data-testid": "agent-profile-selector", onValueChange: async (val) => {
5830
6019
  const nextProfile = profiles.find((x) => x.id === val);
5831
6020
  if (!nextProfile)
5832
6021
  return;
5833
6022
  setActiveProfile(nextProfile);
5834
6023
  try {
5835
- if (agent?.id && agent.status !== "new") {
6024
+ if (agent?.id && !isLocalOnlyDraftAgent) {
5836
6025
  await updateAgentSettings(agent.id, {
5837
6026
  profileId: nextProfile.id,
5838
6027
  profileName: nextProfile.name,
@@ -5884,13 +6073,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5884
6073
  }, "data-testid": "agent-profile-edit-button", children: "Edit" }), _jsxs("button", { type: "button", className: "inline-flex items-center gap-1 text-[10px] text-gray-500 hover:text-gray-700", onClick: () => {
5885
6074
  void handleOpenProfileSettings();
5886
6075
  setShowAgentSettings(false);
5887
- }, children: ["Open profile settings", _jsx(ExternalLink, { className: "h-2.5 w-2.5", strokeWidth: 1.5 })] })] }))] })), activeProfile?.models?.length ? (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[11px] font-medium text-gray-700", children: "Model" }), _jsx(Select, { size: "xs", maxWidth: 300, searchable: activeProfile.models.length > 5, searchPlaceholder: "Filter models...", className: "h-6 w-full rounded border px-1.5 text-[11px] text-gray-500", value: selectedModelId || "", options: modelOptions, onValueChange: async (val) => {
6076
+ }, children: ["Open profile settings", _jsx(ExternalLink, { className: "h-2.5 w-2.5", strokeWidth: 1.5 })] })] }))] })), activeProfile?.models?.length ? (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[11px] font-medium text-gray-700", children: "Model" }), _jsx(Select, { "data-testid": "agent-model-selector", size: "xs", maxWidth: 300, searchable: activeProfile.models.length > 5, searchPlaceholder: "Filter models...", className: "h-6 w-full rounded border px-1.5 text-[11px] text-gray-500", value: selectedModelId || "", options: modelOptions, onValueChange: async (val) => {
5888
6077
  const nextId = val;
5889
6078
  setSelectedModelId(nextId);
5890
6079
  const modelName = activeProfile?.models?.find((m) => m.id === nextId)?.name || "";
5891
6080
  setAgent((prev) => prev ? { ...prev, model: modelName } : prev);
5892
6081
  try {
5893
- if (agent?.id && agent.status !== "new") {
6082
+ if (agent?.id && !isLocalOnlyDraftAgent) {
5894
6083
  await updateAgentSettings(agent.id, {
5895
6084
  model: modelName,
5896
6085
  });
@@ -5945,7 +6134,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5945
6134
  }, children: _jsx(ExternalLink, { className: "h-2.5 w-2.5", strokeWidth: 1.5 }) }), autoAssignedSkillSet.has(skillId.toLowerCase()) ? (_jsx("span", { className: "text-[9px] text-gray-500", children: "auto" })) : (_jsx("button", { type: "button", className: "rounded p-0.5 text-gray-500 hover:bg-gray-200 hover:text-gray-700", onClick: () => {
5946
6135
  void handleRemoveSkill(skillId);
5947
6136
  }, title: "Remove skill", "aria-label": `Remove ${skill?.name || skillId}`, children: _jsx(X, { className: "h-2.5 w-2.5", strokeWidth: 1 }) }))] }, skillId));
5948
- }) }))] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setToolsSectionExpanded((open) => !open), className: "mb-0.5 flex w-full items-center justify-between rounded px-0.5 py-0.5 text-left text-[11px] font-medium text-gray-700 hover:bg-gray-100/80", "aria-expanded": toolsSectionExpanded, "data-testid": "agent-tools-section-toggle", children: [_jsxs("span", { children: ["Available tools (", displayedAvailableTools.length, ")"] }), toolsSectionExpanded ? (_jsx(ChevronUp, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 })) : (_jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 }))] }), toolsSectionExpanded && (_jsx("div", { className: "max-h-36 overflow-y-auto rounded border border-gray-100 bg-gray-50/50 p-1", "data-testid": "agent-tools-section", children: displayedAvailableToolsLoading ? (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Loading available tools..." })) : displayedAvailableTools.length > 0 ? (_jsxs("div", { className: "space-y-0.5", children: [isNewAgent && (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Preview based on the current profile, mode, and selected skills." })), displayedAvailableTools.map((toolName) => (_jsx("div", { className: "rounded px-1 py-0.5 transition-colors hover:bg-white/60", "data-testid": "agent-tool-row", title: toolName, children: _jsx("div", { className: "truncate text-[10px] text-gray-700", children: toolName }) }, toolName)))] })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isNewAgent
6137
+ }) }))] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setToolsSectionExpanded((open) => !open), className: "mb-0.5 flex w-full items-center justify-between rounded px-0.5 py-0.5 text-left text-[11px] font-medium text-gray-700 hover:bg-gray-100/80", "aria-expanded": toolsSectionExpanded, "data-testid": "agent-tools-section-toggle", children: [_jsxs("span", { children: ["Available tools (", displayedAvailableTools.length, ")"] }), toolsSectionExpanded ? (_jsx(ChevronUp, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 })) : (_jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 }))] }), toolsSectionExpanded && (_jsx("div", { className: "max-h-36 overflow-y-auto rounded border border-gray-100 bg-gray-50/50 p-1", "data-testid": "agent-tools-section", children: displayedAvailableToolsLoading ? (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Loading available tools..." })) : displayedAvailableTools.length > 0 ? (_jsxs("div", { className: "space-y-0.5", children: [isLocalOnlyDraftAgent && (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Preview based on the current profile, mode, and selected skills." })), displayedAvailableTools.map((toolName) => (_jsx("div", { className: "rounded px-1 py-0.5 transition-colors hover:bg-white/60", "data-testid": "agent-tool-row", title: toolName, children: _jsx("div", { className: "truncate text-[10px] text-gray-700", children: toolName }) }, toolName)))] })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isLocalOnlyDraftAgent
5949
6138
  ? "No available tools for this profile and mode"
5950
6139
  : "No available tools" })) })), displayedAvailableToolsError && (_jsx("div", { className: "mt-1 text-[10px] text-red-600", children: displayedAvailableToolsError }))] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setAllowancesSectionExpanded((open) => !open), className: "mb-0.5 flex w-full items-center justify-between rounded px-0.5 py-0.5 text-left text-[11px] font-medium text-gray-700 hover:bg-gray-100/80", "aria-expanded": allowancesSectionExpanded, "data-testid": "agent-allowances-section-toggle", children: [_jsxs("span", { children: ["Allowances (", allowancesTotalCount, ")"] }), allowancesSectionExpanded ? (_jsx(ChevronUp, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 })) : (_jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 }))] }), allowancesSectionExpanded && (_jsx("div", { className: "max-h-36 overflow-y-auto rounded border border-gray-100 bg-gray-50/50 p-1", "data-testid": "agent-allowances-section", children: operationAllowancesLoading ? (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Loading allowances..." })) : hasAnyAllowances ? (_jsx("div", { className: "space-y-1", children: allowanceGroups.map((group) => group.rows.length > 0 ? (_jsxs("div", { className: "space-y-0.5", children: [_jsx("div", { className: "px-1 text-[9px] font-medium tracking-wide text-gray-400 uppercase", children: group.label }), group.rows.map((allowance, index) => {
5951
6140
  const sourceLabel = formatAllowanceSource(allowance.source);
@@ -5960,12 +6149,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5960
6149
  ]
5961
6150
  .filter(Boolean)
5962
6151
  .join(" · ") }))] }, `${group.key}-${allowance.operationType}-${pathLabel}-${index}`));
5963
- })] }, group.key)) : null) })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isNewAgent
6152
+ })] }, group.key)) : null) })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isLocalOnlyDraftAgent
5964
6153
  ? "Allowances are shown after the agent is created"
5965
6154
  : "No active allowances" })) })), operationAllowancesError && (_jsx("div", { className: "mt-1 text-[10px] text-red-600", children: operationAllowancesError }))] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setSubscribedTriggersSectionExpanded((open) => !open), className: "mb-0.5 flex w-full items-center justify-between rounded px-0.5 py-0.5 text-left text-[11px] font-medium text-gray-700 hover:bg-gray-100/80", "aria-expanded": subscribedTriggersSectionExpanded, "data-testid": "agent-subscribed-triggers-section-toggle", children: [_jsx("span", { children: `Subscribed triggers (${activeTriggerSubscriptions.length})` }), subscribedTriggersSectionExpanded ? (_jsx(ChevronUp, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 })) : (_jsx(ChevronDown, { className: "h-3 w-3 shrink-0 text-gray-400", strokeWidth: 1.5 }))] }), subscribedTriggersSectionExpanded && (_jsx("div", { className: "max-h-28 overflow-y-auto rounded border border-gray-100 bg-gray-50/50 p-1", "data-testid": "agent-subscribed-triggers-section", children: triggerSubscriptionsLoading ? (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: "Loading subscribed triggers..." })) : activeTriggerSubscriptions.length > 0 ? (_jsx("div", { className: "space-y-0.5", children: activeTriggerSubscriptions.map((sub) => {
5966
6155
  const filterText = (sub.filter || "").trim();
5967
6156
  return (_jsxs("div", { className: "flex items-baseline gap-1.5 rounded px-1 py-0.5 transition-colors hover:bg-white/60", children: [_jsx("div", { className: "shrink-0 text-[10px] font-medium text-gray-700", children: sub.triggerName }), filterText.length > 0 && (_jsx("div", { className: "truncate text-[9px] text-gray-400", title: filterText, children: filterText }))] }, sub.id));
5968
- }) })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isNewAgent
6157
+ }) })) : (_jsx("div", { className: "px-1 text-[10px] text-gray-500", children: isLocalOnlyDraftAgent
5969
6158
  ? "Subscribed triggers are shown after the agent is created"
5970
6159
  : "No active trigger subscriptions" })) })), triggerSubscriptionsError && (_jsx("div", { className: "mt-1 text-[10px] text-red-600", children: triggerSubscriptionsError }))] })] }) })] }), activeProfile?.prompts?.length ? (_jsxs(Popover, { open: showPredefined, onOpenChange: setShowPredefined, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "rounded p-1 hover:bg-gray-100", onClick: () => { }, title: "Predefined prompts", "aria-label": "Predefined prompts", type: "button", children: _jsx(Wand2, { className: "h-3 w-3", strokeWidth: 1 }) }) }), _jsx(PopoverContent, { className: "w-64 p-0", align: "start", children: _jsx("div", { className: "max-h-56 overflow-y-auto p-2", children: activeProfile.prompts.map((p, index) => (_jsx("div", { className: "cursor-pointer rounded p-1.5 text-[10px] text-gray-700 hover:bg-gray-100", onClick: () => {
5971
6160
  setPrompt(p.prompt);