@parhelia/core 0.1.12496 → 0.1.12517
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.
- package/dist/agents-view/AgentCard.js +20 -19
- package/dist/agents-view/AgentCard.js.map +1 -1
- package/dist/agents-view/AgentsInbox.js +2 -13
- package/dist/agents-view/AgentsInbox.js.map +1 -1
- package/dist/agents-view/AgentsView.js +7 -55
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/AgentsWorkspaceView.js +2 -11
- package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
- package/dist/components/ui/copy-button.d.ts +2 -1
- package/dist/components/ui/copy-button.js +2 -2
- package/dist/components/ui/copy-button.js.map +1 -1
- package/dist/components/ui/paste-button.d.ts +2 -1
- package/dist/components/ui/paste-button.js +2 -2
- package/dist/components/ui/paste-button.js.map +1 -1
- package/dist/config/config.js +40 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +23 -5
- package/dist/config/types.js.map +1 -1
- package/dist/editor/ContentTree.js +36 -4
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldListField.js +4 -4
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/FieldListFieldWithFallbacks.js +23 -2
- package/dist/editor/FieldListFieldWithFallbacks.js.map +1 -1
- package/dist/editor/GlobalMenuBar.js +1 -1
- package/dist/editor/GlobalMenuBar.js.map +1 -1
- package/dist/editor/ItemInfo.js +36 -1
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/MainLayout.d.ts +0 -2
- package/dist/editor/MainLayout.js +0 -1
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/Titlebar.js +2 -2
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AgentStatusBadge.d.ts +0 -5
- package/dist/editor/ai/AgentStatusBadge.js +57 -71
- package/dist/editor/ai/AgentStatusBadge.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +88 -90
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +8 -63
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.js +1 -6
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.js +152 -63
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/useAgentStatus.js +12 -85
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/client/EditorShell.js +49 -59
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +3 -15
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/useEditorUrlSync.js +1 -2
- package/dist/editor/client/hooks/useEditorUrlSync.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +19 -6
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/operations.js +20 -6
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.d.ts +0 -4
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.d.ts +8 -3
- package/dist/editor/client/waitForEditOperationTerminal.js +5 -1
- package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +5 -0
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/content-tree/IndicatorSettings.d.ts +11 -0
- package/dist/editor/content-tree/IndicatorSettings.js +60 -0
- package/dist/editor/content-tree/IndicatorSettings.js.map +1 -0
- package/dist/editor/content-tree/TreeOptions.d.ts +6 -0
- package/dist/editor/content-tree/TreeOptions.js +8 -0
- package/dist/editor/content-tree/TreeOptions.js.map +1 -0
- package/dist/editor/content-tree/TreeSettingsMenu.d.ts +2 -0
- package/dist/editor/content-tree/TreeSettingsMenu.js +30 -0
- package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -0
- package/dist/editor/content-tree/index.d.ts +3 -0
- package/dist/editor/content-tree/index.js +4 -0
- package/dist/editor/content-tree/index.js.map +1 -0
- package/dist/editor/hooks/useNavigationPanelLogic.js +2 -6
- package/dist/editor/hooks/useNavigationPanelLogic.js.map +1 -1
- package/dist/editor/manualActionEvents.d.ts +8 -0
- package/dist/editor/manualActionEvents.js +48 -0
- package/dist/editor/manualActionEvents.js.map +1 -0
- package/dist/editor/menubar/PageSelector.js +9 -12
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/WorkflowButton.js +23 -23
- package/dist/editor/menubar/WorkflowButton.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.d.ts +3 -9
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js +225 -71
- package/dist/editor/menubar/toolbar-sections/ManualBrowser.js.map +1 -1
- package/dist/editor/notifications/WatchButton.js +2 -2
- package/dist/editor/notifications/WatchButton.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +2 -0
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +8 -2
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/reviews/CreateReviewDialog.js +0 -2
- package/dist/editor/reviews/CreateReviewDialog.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +31 -3
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js +31 -5
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +3 -2
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/agentStatus.d.ts +12 -0
- package/dist/editor/services/agentStatus.js +59 -0
- package/dist/editor/services/agentStatus.js.map +1 -0
- package/dist/editor/settings/SettingsView.js +4 -4
- package/dist/editor/settings/SettingsView.js.map +1 -1
- package/dist/editor/settings/index/useIndexStatus.js +1 -1
- package/dist/editor/settings/index/useIndexStatus.js.map +1 -1
- package/dist/editor/settings/panels/JavaScriptToolConfigPanel.js +1 -1
- package/dist/editor/settings/panels/JavaScriptToolConfigPanel.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +201 -40
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +3 -2
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/sidebar/MorePanelsButton.js +1 -1
- package/dist/editor/sidebar/MorePanelsButton.js.map +1 -1
- package/dist/editor/sidebar/NavigationPanelItem.js +2 -2
- package/dist/editor/sidebar/NavigationPanelItem.js.map +1 -1
- package/dist/editor/sidebar/SidebarPanel.js +20 -4
- package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
- package/dist/editor/sidebar/SidebarStack.js +1 -0
- package/dist/editor/sidebar/SidebarStack.js.map +1 -1
- package/dist/editor/sidebar/Workbox.js +53 -3
- package/dist/editor/sidebar/Workbox.js.map +1 -1
- package/dist/editor/tree-indicators/GutterContext.d.ts +4 -0
- package/dist/editor/tree-indicators/GutterContext.js +23 -0
- package/dist/editor/tree-indicators/GutterContext.js.map +1 -1
- package/dist/editor/tree-indicators/index.d.ts +0 -1
- package/dist/editor/tree-indicators/index.js +0 -1
- package/dist/editor/tree-indicators/index.js.map +1 -1
- package/dist/editor/tree-indicators/types.d.ts +1 -1
- package/dist/editor/ui/HomeButton.js +1 -1
- package/dist/editor/ui/HomeButton.js.map +1 -1
- package/dist/editor/ui/ItemNameDialogNew.d.ts +2 -0
- package/dist/editor/ui/ItemNameDialogNew.js +17 -7
- package/dist/editor/ui/ItemNameDialogNew.js.map +1 -1
- package/dist/editor/ui/ItemSearch.js +7 -11
- package/dist/editor/ui/ItemSearch.js.map +1 -1
- package/dist/editor/ui/SimpleTabs.js +33 -16
- package/dist/editor/ui/SimpleTabs.js.map +1 -1
- package/dist/editor/ui/Splitter.js +1 -1
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/setup/wizard/steps/AddModelDialog.js +3 -2
- package/dist/setup/wizard/steps/AddModelDialog.js.map +1 -1
- package/dist/task-board/components/AssignAgentDialog.js +0 -8
- package/dist/task-board/components/AssignAgentDialog.js.map +1 -1
- package/dist/task-board/components/ProjectAgentsPanel.js +1 -26
- package/dist/task-board/components/ProjectAgentsPanel.js.map +1 -1
- package/dist/task-board/components/TaskAgentPanel.js +2 -6
- package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
- package/dist/types.d.ts +2 -13
- package/package.json +1 -1
- package/dist/editor/tree-indicators/GutterSelector.d.ts +0 -5
- package/dist/editor/tree-indicators/GutterSelector.js +0 -91
- 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"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -1999,6 +2007,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1999
2007
|
// If no messageId is provided, we'll use the last assistant message or create a new one
|
|
2000
2008
|
let messageId = message.data?.messageId;
|
|
2001
2009
|
if (!messageId && agentData?.id) {
|
|
2010
|
+
console.warn("[AgentTerminal] Content chunk missing messageId; falling back to local resolution", {
|
|
2011
|
+
agentId: agentData.id,
|
|
2012
|
+
isIncremental: message.data?.isIncremental,
|
|
2013
|
+
previousContentLength: message.data?.previousContentLength,
|
|
2014
|
+
totalContentLength: message.data?.totalContentLength,
|
|
2015
|
+
});
|
|
2002
2016
|
// For backward compatibility: if no messageId, find or create the current streaming message
|
|
2003
2017
|
// This handles cases where the backend doesn't send messageId
|
|
2004
2018
|
const currentMessages = messagesRef.current;
|
|
@@ -2012,7 +2026,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2012
2026
|
// If the agent isn't currently running (e.g., we switched tabs after the run
|
|
2013
2027
|
// completed), skip creating a new streaming message to avoid duplicates.
|
|
2014
2028
|
const currentAgentStatus = (agentData || agent)?.status;
|
|
2015
|
-
const isAgentRunning = currentAgentStatus === "running"
|
|
2029
|
+
const isAgentRunning = currentAgentStatus === "running";
|
|
2016
2030
|
if (!isAgentRunning) {
|
|
2017
2031
|
return;
|
|
2018
2032
|
}
|
|
@@ -2099,6 +2113,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2099
2113
|
const existingMessageIndex = prev.findIndex((msg) => msg.id === messageId);
|
|
2100
2114
|
if (existingMessageIndex === -1) {
|
|
2101
2115
|
// Message doesn't exist - create new streaming message
|
|
2116
|
+
const previousContentLength = message.data?.previousContentLength || 0;
|
|
2117
|
+
if (message.data?.isIncremental && previousContentLength > 0) {
|
|
2118
|
+
console.warn("[AgentTerminal] Incremental chunk arrived before its base message existed", {
|
|
2119
|
+
messageId,
|
|
2120
|
+
previousContentLength,
|
|
2121
|
+
totalContentLength: message.data?.totalContentLength,
|
|
2122
|
+
deltaLength: (message.data?.deltaContent || "").length,
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2102
2125
|
const newStreamMessage = createNewStreamMessage(messageId, agentData);
|
|
2103
2126
|
// Set the content for the new message
|
|
2104
2127
|
const updatedNewMessage = { ...newStreamMessage };
|
|
@@ -2121,8 +2144,21 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2121
2144
|
return prev;
|
|
2122
2145
|
// Check if existing content is already longer than what we're trying to stream
|
|
2123
2146
|
const currentContentLength = existingMessage.content?.length || 0;
|
|
2147
|
+
const previousContentLength = message.data?.previousContentLength || 0;
|
|
2124
2148
|
const totalContentLength = message.data?.totalContentLength || 0;
|
|
2125
|
-
if (
|
|
2149
|
+
if (message.data?.isIncremental &&
|
|
2150
|
+
previousContentLength !== currentContentLength &&
|
|
2151
|
+
(previousContentLength > 0 || currentContentLength > 0)) {
|
|
2152
|
+
console.warn("[AgentTerminal] Content chunk length mismatch", {
|
|
2153
|
+
messageId,
|
|
2154
|
+
previousContentLength,
|
|
2155
|
+
currentContentLength,
|
|
2156
|
+
totalContentLength,
|
|
2157
|
+
deltaLength: (message.data?.deltaContent || "").length,
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
if (message.data?.isIncremental &&
|
|
2161
|
+
currentContentLength >= totalContentLength &&
|
|
2126
2162
|
totalContentLength > 0) {
|
|
2127
2163
|
return prev;
|
|
2128
2164
|
}
|
|
@@ -2151,6 +2187,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2151
2187
|
// Prefer provided messageId, otherwise fall back to the last streaming assistant message
|
|
2152
2188
|
let toolCallMessageId = message.data?.messageId;
|
|
2153
2189
|
if (!toolCallMessageId) {
|
|
2190
|
+
console.warn("[AgentTerminal] Tool call missing messageId; falling back", {
|
|
2191
|
+
toolCallId,
|
|
2192
|
+
toolName: message.data?.name || message.data?.displayName,
|
|
2193
|
+
});
|
|
2154
2194
|
const current = messagesRef.current;
|
|
2155
2195
|
const lastStreaming = [...current]
|
|
2156
2196
|
.reverse()
|
|
@@ -2314,6 +2354,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2314
2354
|
// Prefer provided messageId, otherwise fall back to the last streaming assistant message
|
|
2315
2355
|
let resultMessageId = message.data?.messageId;
|
|
2316
2356
|
if (!resultMessageId) {
|
|
2357
|
+
console.warn("[AgentTerminal] Tool result missing messageId; falling back", {
|
|
2358
|
+
toolCallId: resultToolCallId,
|
|
2359
|
+
toolName: message.data?.functionName || message.data?.displayName,
|
|
2360
|
+
});
|
|
2317
2361
|
const current = messagesRef.current;
|
|
2318
2362
|
const lastStreaming = [...current]
|
|
2319
2363
|
.reverse()
|
|
@@ -2819,29 +2863,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2819
2863
|
if (!contextJson)
|
|
2820
2864
|
return null;
|
|
2821
2865
|
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
2866
|
if (parsedContext && typeof parsedContext === "object") {
|
|
2826
|
-
|
|
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;
|
|
2867
|
+
return parsedContext;
|
|
2845
2868
|
}
|
|
2846
2869
|
return null;
|
|
2847
2870
|
}
|
|
@@ -2927,7 +2950,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2927
2950
|
return;
|
|
2928
2951
|
}
|
|
2929
2952
|
// Check if cost limit exceeded based on status or cost values
|
|
2930
|
-
const statusIndicatesLimit = agent.status === "costLimitReached"
|
|
2953
|
+
const statusIndicatesLimit = agent.status === "costLimitReached";
|
|
2931
2954
|
// Use liveTotals.totalCost as fallback if agent.totalCost is missing or 0
|
|
2932
2955
|
const effectiveTotalCost = agent.totalCost || liveTotals?.totalCost || 0;
|
|
2933
2956
|
const costExceedsLimit = agent.costLimit &&
|
|
@@ -3294,12 +3317,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3294
3317
|
// Route based on statusData.state
|
|
3295
3318
|
try {
|
|
3296
3319
|
// Normalize various status shapes and handle Cancelled uniformly
|
|
3297
|
-
const normalizedStatus = statusData?.state ||
|
|
3298
|
-
statusData?.status;
|
|
3299
|
-
if (normalizedStatus === "
|
|
3300
|
-
normalizedStatus === "canceled" ||
|
|
3301
|
-
normalizedStatus === "stopped" ||
|
|
3302
|
-
normalizedStatus === "Stopped") {
|
|
3320
|
+
const normalizedStatus = parseAgentStatus(statusData?.state) ||
|
|
3321
|
+
parseAgentStatus(statusData?.status);
|
|
3322
|
+
if (normalizedStatus === "idle") {
|
|
3303
3323
|
// Stop indicators and mark any in-progress streaming messages as completed
|
|
3304
3324
|
clearHeartbeatMessages();
|
|
3305
3325
|
setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
|
|
@@ -3437,8 +3457,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3437
3457
|
return;
|
|
3438
3458
|
}
|
|
3439
3459
|
// Handle waiting states explicitly
|
|
3440
|
-
if (
|
|
3441
|
-
statusData?.state === "waitingForApproval") {
|
|
3460
|
+
if (normalizedStatus === "waitingForApproval") {
|
|
3442
3461
|
setPendingBrowserCaptureDialogType(null);
|
|
3443
3462
|
setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
|
|
3444
3463
|
setIsConnecting(false);
|
|
@@ -3446,8 +3465,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3446
3465
|
setIsAgentThinking(false);
|
|
3447
3466
|
return;
|
|
3448
3467
|
}
|
|
3449
|
-
if (
|
|
3450
|
-
statusData?.state === "waitingForInput") {
|
|
3468
|
+
if (normalizedStatus === "waitingForInput") {
|
|
3451
3469
|
const dialogType = typeof statusData?.dialogType === "string"
|
|
3452
3470
|
? statusData.dialogType
|
|
3453
3471
|
: null;
|
|
@@ -3470,7 +3488,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3470
3488
|
setIsAgentThinking(false);
|
|
3471
3489
|
return;
|
|
3472
3490
|
}
|
|
3473
|
-
if (
|
|
3491
|
+
if (normalizedStatus === "costLimitReached") {
|
|
3474
3492
|
setPendingBrowserCaptureDialogType(null);
|
|
3475
3493
|
const totalCost = Number(statusData.totalCost) || 0;
|
|
3476
3494
|
const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
|
|
@@ -3518,8 +3536,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3518
3536
|
return;
|
|
3519
3537
|
}
|
|
3520
3538
|
// Handle "completed" state (fallback for legacy code paths that send status instead of lifecycle event)
|
|
3521
|
-
if (normalizedStatus === "completed"
|
|
3522
|
-
normalizedStatus === "Completed") {
|
|
3539
|
+
if (normalizedStatus === "completed") {
|
|
3523
3540
|
// Reset deduplication for the next run
|
|
3524
3541
|
lastSeqRef.current = 0;
|
|
3525
3542
|
clearHeartbeatMessages();
|
|
@@ -3545,21 +3562,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3545
3562
|
setIsAgentThinking(false);
|
|
3546
3563
|
return;
|
|
3547
3564
|
}
|
|
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
3565
|
// Handle "Running" state - agent is actively processing
|
|
3561
|
-
if (normalizedStatus === "running"
|
|
3562
|
-
normalizedStatus === "Running") {
|
|
3566
|
+
if (normalizedStatus === "running") {
|
|
3563
3567
|
// Update agent status to running
|
|
3564
3568
|
setAgent((prev) => (prev ? { ...prev, status: "running" } : prev));
|
|
3565
3569
|
setIsWaitingForResponse(true);
|
|
@@ -3568,7 +3572,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3568
3572
|
return;
|
|
3569
3573
|
}
|
|
3570
3574
|
// Handle "Error" state
|
|
3571
|
-
if (normalizedStatus === "error"
|
|
3575
|
+
if (normalizedStatus === "error") {
|
|
3572
3576
|
const errorMsg = statusData?.statusMessage || statusData?.error || "Unknown error";
|
|
3573
3577
|
clearHeartbeatMessages();
|
|
3574
3578
|
setAgent((prev) => prev
|
|
@@ -3840,9 +3844,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3840
3844
|
}
|
|
3841
3845
|
setTimeout(() => {
|
|
3842
3846
|
if (request.dialogType === "questionnaire") {
|
|
3843
|
-
|
|
3844
|
-
block: "start",
|
|
3845
|
-
});
|
|
3847
|
+
scrollToBottomRefForDialogs.current?.();
|
|
3846
3848
|
return;
|
|
3847
3849
|
}
|
|
3848
3850
|
scrollToBottomRefForDialogs.current?.();
|
|
@@ -3910,11 +3912,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3910
3912
|
// Use case-insensitive comparison for GUID matching (backend may return different casing)
|
|
3911
3913
|
const normalizedProfileId = profileIdToUse?.toLowerCase();
|
|
3912
3914
|
const candidate = normalizedProfileId
|
|
3913
|
-
?
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3915
|
+
? profiles.find((p) => p.id?.toLowerCase() === normalizedProfileId)
|
|
3916
|
+
: undefined;
|
|
3917
|
+
if (!candidate) {
|
|
3918
|
+
setActiveProfile(undefined);
|
|
3917
3919
|
return;
|
|
3920
|
+
}
|
|
3918
3921
|
// Keep active profile in sync whenever the matching entry in `profiles` changes —
|
|
3919
3922
|
// not only when the profile id changes. Otherwise availableSkills (and similar fields)
|
|
3920
3923
|
// that are merged in the parent after async loads never update (e.g. Template Builder
|
|
@@ -3936,7 +3939,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3936
3939
|
return prev;
|
|
3937
3940
|
return candidate;
|
|
3938
3941
|
});
|
|
3939
|
-
}, [profiles, agent?.profileId, agentStub.profileId]);
|
|
3942
|
+
}, [profiles, agent?.id, agent?.profileId, agentStub.id, agentStub.profileId]);
|
|
3940
3943
|
// Clear queued prompts when agent changes or is new;
|
|
3941
3944
|
// initial fetch is handled by loadAgent() for better performance and reliability
|
|
3942
3945
|
useEffect(() => {
|
|
@@ -4265,8 +4268,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
4265
4268
|
const response = await startAgent(request);
|
|
4266
4269
|
console.log("[AgentTerminal] startAgent response:", response);
|
|
4267
4270
|
// Check if prompt was queued (agent was already running)
|
|
4268
|
-
const wasQueued = response.message?.toLowerCase().includes("queued")
|
|
4269
|
-
response.status === "Queued";
|
|
4271
|
+
const wasQueued = response.message?.toLowerCase().includes("queued");
|
|
4270
4272
|
if (wasQueued) {
|
|
4271
4273
|
// Prompt was queued - show a brief notification but don't set waiting state
|
|
4272
4274
|
// The prompt will be processed when the agent becomes idle
|
|
@@ -5221,11 +5223,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5221
5223
|
};
|
|
5222
5224
|
const renderErrorBanner = () => {
|
|
5223
5225
|
const currentAgent = agent || agentStub;
|
|
5224
|
-
const isErrorStatus = currentAgent?.status === "error"
|
|
5226
|
+
const isErrorStatus = currentAgent?.status === "error";
|
|
5225
5227
|
const errorMessage = (isErrorStatus ? currentAgent?.statusMessage : null) || error;
|
|
5226
5228
|
if (!errorMessage)
|
|
5227
5229
|
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 })] })] }) }));
|
|
5230
|
+
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
5231
|
};
|
|
5230
5232
|
const renderBrowserClaimBanner = (variant = "inline") => {
|
|
5231
5233
|
if (!agent?.id || !editContext?.sessionId)
|
|
@@ -5254,12 +5256,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5254
5256
|
? "Take over browser control"
|
|
5255
5257
|
: "Attach to this browser" })) })] }) }));
|
|
5256
5258
|
};
|
|
5257
|
-
const fixedBrowserClaimBanner =
|
|
5258
|
-
|
|
5259
|
-
: null;
|
|
5260
|
-
const inlineBrowserClaimBanner = !isClaimedByCurrentSession
|
|
5261
|
-
? renderBrowserClaimBanner("inline")
|
|
5262
|
-
: null;
|
|
5259
|
+
const fixedBrowserClaimBanner = renderBrowserClaimBanner("fixed");
|
|
5260
|
+
const inlineBrowserClaimBanner = null;
|
|
5263
5261
|
useEffect(() => {
|
|
5264
5262
|
if (agent?.status !== "waitingForInput") {
|
|
5265
5263
|
setPendingBrowserCaptureDialogType(null);
|
|
@@ -5438,7 +5436,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5438
5436
|
})()
|
|
5439
5437
|
: null;
|
|
5440
5438
|
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: [
|
|
5439
|
+
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
5440
|
setPrompt(p);
|
|
5443
5441
|
// Use setTimeout to ensure state is updated before submission
|
|
5444
5442
|
setTimeout(() => {
|