@parhelia/core 0.1.12638 → 0.1.12663
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/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog.js.map +1 -1
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/button.d.ts +2 -2
- package/dist/components/ui/dialog.d.ts +1 -1
- package/dist/components/ui/dialog.js +67 -3
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/config/config.js +3 -1
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ItemInfo.js +15 -3
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/ai/AgentDocumentList.js +16 -1
- package/dist/editor/ai/AgentDocumentList.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +197 -8
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.js +44 -0
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.d.ts +2 -0
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +2 -0
- package/dist/editor/ai/ToolCallDisplay.js +14 -8
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/agentDiagnostics.d.ts +3 -1
- package/dist/editor/ai/agentDiagnostics.js +20 -0
- package/dist/editor/ai/agentDiagnostics.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +1 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +15 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/operations.d.ts +1 -0
- package/dist/editor/client/operations.js +50 -2
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.js +28 -1
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/client/waitForEditOperationTerminal.d.ts +6 -0
- package/dist/editor/client/waitForEditOperationTerminal.js +54 -0
- package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
- package/dist/editor/commands/itemCommands.d.ts +2 -0
- package/dist/editor/commands/itemCommands.js +87 -4
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js +10 -10
- package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
- package/dist/editor/media-selector/TreeSelector.js +7 -1
- package/dist/editor/media-selector/TreeSelector.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +35 -0
- package/dist/editor/services/agentService.js +20 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/contentService.d.ts +2 -0
- package/dist/editor/services/contentService.js.map +1 -1
- package/dist/editor/settings/panels/AgentProfileConfigPanel.js +3 -2
- package/dist/editor/settings/panels/AgentProfileConfigPanel.js.map +1 -1
- package/dist/editor/settings/panels/GroupedFieldConfigPanel.d.ts +3 -1
- package/dist/editor/settings/panels/GroupedFieldConfigPanel.js +2 -2
- package/dist/editor/settings/panels/GroupedFieldConfigPanel.js.map +1 -1
- package/dist/editor/ui/InternalLink.d.ts +2 -2
- package/dist/editor/ui/InternalLink.js +2 -2
- package/dist/editor/ui/InternalLink.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/types.d.ts +11 -1
- package/package.json +1 -1
|
@@ -2,7 +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 { flushSync } from "react-dom";
|
|
4
4
|
import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, ArrowLeft, DollarSign, ExternalLink, Settings2, Target, X, Plus, } from "lucide-react";
|
|
5
|
-
import { getAgent, startAgent, claimAgentBrowser, assignAgentSkill, persistDraftAgent, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentAvailableTools, getAgentOperationAllowances, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, releaseAgentBrowser, revokeAgentSkill, } from "../services/agentService";
|
|
5
|
+
import { getAgent, startAgent, claimAgentBrowser, cancelAgentDialog, assignAgentSkill, emitAgentDocumentsChanged, persistDraftAgent, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentAvailableTools, getAgentOperationAllowances, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, releaseAgentBrowser, revokeAgentSkill, } from "../services/agentService";
|
|
6
6
|
import { parseAgentStatus } from "../services/agentStatus";
|
|
7
7
|
import { useEditContext, useFieldsEditContext } from "../client/editContext";
|
|
8
8
|
import { localStorageService } from "../services/localStorageService";
|
|
@@ -33,6 +33,52 @@ import { Splitter } from "../ui/Splitter";
|
|
|
33
33
|
import { ScrollingContentTree } from "../ScrollingContentTree";
|
|
34
34
|
import { MarkdownDisplay, } from "../../components/MarkdownDisplay";
|
|
35
35
|
const AGENT_HISTORY_LIMIT = 1000;
|
|
36
|
+
function parseToolResultPayload(value) {
|
|
37
|
+
if (!value) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "object") {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value !== "string") {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const parsed = JSON.parse(value);
|
|
48
|
+
return parsed && typeof parsed === "object" ? parsed : null;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function shouldRefreshDocumentsForToolResult(functionName, data) {
|
|
55
|
+
const normalizedName = (functionName || "").trim().toLowerCase();
|
|
56
|
+
const hasError = !!(data?.functionError || data?.error);
|
|
57
|
+
if (!normalizedName || hasError) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (normalizedName === "attach-media-item") {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (normalizedName === "detach-document") {
|
|
64
|
+
const parsed = parseToolResultPayload(data?.functionResult || data?.result);
|
|
65
|
+
return parsed?.Removed === true || parsed?.removed === true;
|
|
66
|
+
}
|
|
67
|
+
if (normalizedName === "extract-pdf-images") {
|
|
68
|
+
const parsed = parseToolResultPayload(data?.functionResult || data?.result);
|
|
69
|
+
if (!parsed) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const destination = String(parsed.Destination ?? parsed.destination ?? "");
|
|
73
|
+
const discoveryOnly = Boolean(parsed.DiscoveryOnly ?? parsed.discoveryOnly);
|
|
74
|
+
const createdImageCount = Number(parsed.CreatedImageCount ?? parsed.createdImageCount ?? 0);
|
|
75
|
+
return (!discoveryOnly &&
|
|
76
|
+
destination === "agentDocumentStore" &&
|
|
77
|
+
Number.isFinite(createdImageCount) &&
|
|
78
|
+
createdImageCount > 0);
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
36
82
|
function mergeAgentOperationHistory(existing, incoming, limit = AGENT_HISTORY_LIMIT) {
|
|
37
83
|
const merged = new Map(existing.map((operation) => [operation.id, operation]));
|
|
38
84
|
for (const operation of incoming) {
|
|
@@ -83,6 +129,8 @@ function buildPlaceholderAgentDetails(agentStub) {
|
|
|
83
129
|
function normalizeDialogAgentId(value) {
|
|
84
130
|
return value?.trim().toLowerCase() || "";
|
|
85
131
|
}
|
|
132
|
+
const MACHINE_CAPACITY_REASON = "machineCapacity";
|
|
133
|
+
const MACHINE_CAPACITY_DETAIL = "waitingForCapacity";
|
|
86
134
|
function formatAllowanceSource(source) {
|
|
87
135
|
const normalized = source?.trim();
|
|
88
136
|
if (!normalized)
|
|
@@ -116,6 +164,9 @@ function getAgentRunMessageDetail(type, payload) {
|
|
|
116
164
|
return payload?.type || null;
|
|
117
165
|
}
|
|
118
166
|
if (type === "agent:run:status") {
|
|
167
|
+
if (payload?.data?.reason === MACHINE_CAPACITY_REASON) {
|
|
168
|
+
return MACHINE_CAPACITY_DETAIL;
|
|
169
|
+
}
|
|
119
170
|
return payload?.data?.state || payload?.data?.status || null;
|
|
120
171
|
}
|
|
121
172
|
if (type === "agent:run:error") {
|
|
@@ -821,6 +872,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
821
872
|
const [agentMetadata, setAgentMetadata] = useState(null);
|
|
822
873
|
const [isBrowserClaimMutationPending, setIsBrowserClaimMutationPending] = useState(false);
|
|
823
874
|
const [pendingBrowserCaptureDialogType, setPendingBrowserCaptureDialogType] = useState(null);
|
|
875
|
+
const [pendingBrowserCaptureCallbackId, setPendingBrowserCaptureCallbackId] = useState(null);
|
|
824
876
|
// Ensure we always have an agent object for streaming handlers, even before `getAgent()` resolves.
|
|
825
877
|
// This prevents early tool calls (e.g., ask-questionnaire) from being dropped in compact/workspace UIs.
|
|
826
878
|
useEffect(() => {
|
|
@@ -965,6 +1017,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
965
1017
|
}
|
|
966
1018
|
// Server-driven state: true when agent is actively processing (set by WebSocket messages)
|
|
967
1019
|
const [isAgentThinking, setIsAgentThinking] = useState(false);
|
|
1020
|
+
const [lastRunStatusReason, setLastRunStatusReason] = useState(null);
|
|
968
1021
|
useEffect(() => {
|
|
969
1022
|
return () => {
|
|
970
1023
|
if (stopGuardReleaseTimeoutRef.current) {
|
|
@@ -1391,9 +1444,35 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1391
1444
|
}
|
|
1392
1445
|
}
|
|
1393
1446
|
};
|
|
1447
|
+
const refreshAssignedSkills = async () => {
|
|
1448
|
+
try {
|
|
1449
|
+
const latest = await getAgent(agent.id);
|
|
1450
|
+
if (!active)
|
|
1451
|
+
return;
|
|
1452
|
+
const latestSkillIds = latest?.assignedSkillIds;
|
|
1453
|
+
if (!Array.isArray(latestSkillIds))
|
|
1454
|
+
return;
|
|
1455
|
+
setAgent((prev) => {
|
|
1456
|
+
if (!prev)
|
|
1457
|
+
return prev;
|
|
1458
|
+
const prevIds = Array.isArray(prev.assignedSkillIds)
|
|
1459
|
+
? prev.assignedSkillIds
|
|
1460
|
+
: [];
|
|
1461
|
+
if (prevIds.length === latestSkillIds.length &&
|
|
1462
|
+
prevIds.every((id, i) => id === latestSkillIds[i])) {
|
|
1463
|
+
return prev;
|
|
1464
|
+
}
|
|
1465
|
+
return { ...prev, assignedSkillIds: latestSkillIds };
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
catch (e) {
|
|
1469
|
+
console.error("Failed to refresh assigned skills:", e);
|
|
1470
|
+
}
|
|
1471
|
+
};
|
|
1394
1472
|
void loadTriggerSubscriptions();
|
|
1395
1473
|
void loadAvailableTools();
|
|
1396
1474
|
void loadOperationAllowances();
|
|
1475
|
+
void refreshAssignedSkills();
|
|
1397
1476
|
return () => {
|
|
1398
1477
|
active = false;
|
|
1399
1478
|
};
|
|
@@ -1404,7 +1483,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1404
1483
|
agent?.userId,
|
|
1405
1484
|
agent?.profileId,
|
|
1406
1485
|
mode,
|
|
1407
|
-
selectedSkillIds,
|
|
1408
1486
|
]);
|
|
1409
1487
|
const activeTriggerSubscriptions = useMemo(() => triggerSubscriptions.filter((sub) => sub.isActive), [triggerSubscriptions]);
|
|
1410
1488
|
const allowanceGroups = useMemo(() => [
|
|
@@ -2684,7 +2762,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2684
2762
|
appendToolUiEvent("ui:tool-result-applied", `${extractedToolCall.functionName || "unknown"} toolCallId=${resultToolCallId} targetMessageId=${resultMessageId} completed=${matchingToolCall?.isCompleted ? "yes" : "no"} messageToolCalls=${messageWithToolResult?.toolCalls?.length || 0}`);
|
|
2685
2763
|
return updated;
|
|
2686
2764
|
});
|
|
2687
|
-
|
|
2765
|
+
const currentAgentId = agentData?.id || agent?.id || agentStub.id;
|
|
2766
|
+
if (currentAgentId &&
|
|
2767
|
+
shouldRefreshDocumentsForToolResult(extractedToolCall.functionName || "", message.data)) {
|
|
2768
|
+
emitAgentDocumentsChanged({
|
|
2769
|
+
agentId: currentAgentId,
|
|
2770
|
+
reason: extractedToolCall.functionName || "tool-result",
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
}, [agent?.id, agentStub.id, appendToolUiEvent]);
|
|
2688
2774
|
// Listen for local approval resolution to update UI
|
|
2689
2775
|
useEffect(() => {
|
|
2690
2776
|
const onApprovalResolved = (ev) => {
|
|
@@ -3292,6 +3378,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3292
3378
|
// Reset run-scoped deduplication so new run seq values (starting at 1)
|
|
3293
3379
|
// are not discarded due to previous run's lastSeqRef
|
|
3294
3380
|
lastSeqRef.current = 0;
|
|
3381
|
+
setLastRunStatusReason(null);
|
|
3295
3382
|
// Prep streaming UI state for the new run
|
|
3296
3383
|
setIsConnecting(true);
|
|
3297
3384
|
setIsWaitingForResponse(true);
|
|
@@ -3520,8 +3607,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3520
3607
|
// Normalize various status shapes and handle Cancelled uniformly
|
|
3521
3608
|
const normalizedStatus = parseAgentStatus(statusData?.state) ||
|
|
3522
3609
|
parseAgentStatus(statusData?.status);
|
|
3610
|
+
const statusReason = typeof statusData?.reason === "string"
|
|
3611
|
+
? statusData.reason.trim() || null
|
|
3612
|
+
: null;
|
|
3613
|
+
const statusMessage = typeof statusData?.message === "string"
|
|
3614
|
+
? statusData.message.trim() || null
|
|
3615
|
+
: null;
|
|
3523
3616
|
if (normalizedStatus === "idle") {
|
|
3524
3617
|
clearStopGuard();
|
|
3618
|
+
setLastRunStatusReason(null);
|
|
3525
3619
|
// Stop indicators and mark any in-progress streaming messages as completed
|
|
3526
3620
|
clearHeartbeatMessages();
|
|
3527
3621
|
setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
|
|
@@ -3628,6 +3722,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3628
3722
|
}
|
|
3629
3723
|
if (statusData?.state === "ToolApprovalsRequired") {
|
|
3630
3724
|
setPendingBrowserCaptureDialogType(null);
|
|
3725
|
+
setPendingBrowserCaptureCallbackId(null);
|
|
3726
|
+
setLastRunStatusReason(null);
|
|
3631
3727
|
const msgId = statusData.messageId;
|
|
3632
3728
|
const ids = statusData.toolCallIds || [];
|
|
3633
3729
|
if (msgId && Array.isArray(ids) && ids.length > 0) {
|
|
@@ -3662,7 +3758,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3662
3758
|
// Handle waiting states explicitly
|
|
3663
3759
|
if (normalizedStatus === "waitingForApproval") {
|
|
3664
3760
|
clearStopGuard();
|
|
3761
|
+
setLastRunStatusReason(null);
|
|
3665
3762
|
setPendingBrowserCaptureDialogType(null);
|
|
3763
|
+
setPendingBrowserCaptureCallbackId(null);
|
|
3666
3764
|
setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
|
|
3667
3765
|
setIsConnecting(false);
|
|
3668
3766
|
setIsWaitingForResponse(false);
|
|
@@ -3672,12 +3770,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3672
3770
|
}
|
|
3673
3771
|
if (normalizedStatus === "waitingForInput") {
|
|
3674
3772
|
clearStopGuard();
|
|
3773
|
+
setLastRunStatusReason(null);
|
|
3675
3774
|
const dialogType = typeof statusData?.dialogType === "string"
|
|
3676
3775
|
? statusData.dialogType
|
|
3677
3776
|
: null;
|
|
3678
3777
|
const isBrowserCaptureWait = dialogType === DIALOG_TYPES.CAPTURE_PAGE_DOM ||
|
|
3679
3778
|
dialogType === DIALOG_TYPES.CAPTURE_PAGE_SCREENSHOT;
|
|
3680
3779
|
setPendingBrowserCaptureDialogType(isBrowserCaptureWait ? dialogType : null);
|
|
3780
|
+
const captureCallbackId = isBrowserCaptureWait &&
|
|
3781
|
+
typeof statusData?.callbackId === "string" &&
|
|
3782
|
+
statusData.callbackId.trim()
|
|
3783
|
+
? statusData.callbackId.trim()
|
|
3784
|
+
: null;
|
|
3785
|
+
setPendingBrowserCaptureCallbackId(captureCallbackId);
|
|
3681
3786
|
setAgent((prev) => prev
|
|
3682
3787
|
? {
|
|
3683
3788
|
...prev,
|
|
@@ -3697,6 +3802,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3697
3802
|
if (normalizedStatus === "costLimitReached") {
|
|
3698
3803
|
clearStopGuard();
|
|
3699
3804
|
setPendingBrowserCaptureDialogType(null);
|
|
3805
|
+
setPendingBrowserCaptureCallbackId(null);
|
|
3700
3806
|
const totalCost = Number(statusData.totalCost) || 0;
|
|
3701
3807
|
const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
|
|
3702
3808
|
setCostLimitExceeded({
|
|
@@ -3775,6 +3881,24 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3775
3881
|
if (isStoppingRef.current) {
|
|
3776
3882
|
return;
|
|
3777
3883
|
}
|
|
3884
|
+
if (statusReason === MACHINE_CAPACITY_REASON) {
|
|
3885
|
+
clearHeartbeatMessages();
|
|
3886
|
+
setLastRunStatusReason(statusReason);
|
|
3887
|
+
setAgent((prev) => prev
|
|
3888
|
+
? {
|
|
3889
|
+
...prev,
|
|
3890
|
+
status: "running",
|
|
3891
|
+
statusMessage: statusMessage ||
|
|
3892
|
+
"Waiting for capacity. The agent will start automatically when a slot becomes available.",
|
|
3893
|
+
}
|
|
3894
|
+
: prev);
|
|
3895
|
+
setIsWaitingForResponse(false);
|
|
3896
|
+
isWaitingRef.current = false;
|
|
3897
|
+
setIsConnecting(false);
|
|
3898
|
+
setIsAgentThinking(false);
|
|
3899
|
+
return;
|
|
3900
|
+
}
|
|
3901
|
+
setLastRunStatusReason(null);
|
|
3778
3902
|
// Update agent status to running and clear any previous error statusMessage
|
|
3779
3903
|
setAgent((prev) => prev
|
|
3780
3904
|
? { ...prev, status: "running", statusMessage: undefined }
|
|
@@ -3787,6 +3911,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3787
3911
|
// Handle "Error" state
|
|
3788
3912
|
if (normalizedStatus === "error") {
|
|
3789
3913
|
clearStopGuard();
|
|
3914
|
+
setLastRunStatusReason(null);
|
|
3790
3915
|
const errorMsg = toUserFacingAgentErrorMessage(statusData?.statusMessage ?? statusData?.error) || "Unknown error";
|
|
3791
3916
|
clearHeartbeatMessages();
|
|
3792
3917
|
setAgent((prev) => prev
|
|
@@ -3808,6 +3933,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3808
3933
|
if (messageType === "agent:run:complete") {
|
|
3809
3934
|
// Reset deduplication for the next run
|
|
3810
3935
|
lastSeqRef.current = 0;
|
|
3936
|
+
setLastRunStatusReason(null);
|
|
3811
3937
|
clearHeartbeatMessages();
|
|
3812
3938
|
// Mark the last assistant message as completed
|
|
3813
3939
|
setMessages((prev) => {
|
|
@@ -3836,6 +3962,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3836
3962
|
const errorMsg = toUserFacingAgentErrorMessage(message.payload?.error) ||
|
|
3837
3963
|
"AI could not complete this request.";
|
|
3838
3964
|
clearHeartbeatMessages();
|
|
3965
|
+
setLastRunStatusReason(null);
|
|
3839
3966
|
// Reset deduplication for the next run after an error
|
|
3840
3967
|
lastSeqRef.current = 0;
|
|
3841
3968
|
setError(errorMsg);
|
|
@@ -4488,9 +4615,28 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
4488
4615
|
console.log("[AgentTerminal] Calling startAgent API for agent:", agentId);
|
|
4489
4616
|
const response = await startAgent(request);
|
|
4490
4617
|
console.log("[AgentTerminal] startAgent response:", response);
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4618
|
+
const isQueuedForCapacity = response.reason === MACHINE_CAPACITY_REASON ||
|
|
4619
|
+
response.message?.toLowerCase().includes("machine slot") ||
|
|
4620
|
+
false;
|
|
4621
|
+
// Check if prompt was queued because another execution was already active
|
|
4622
|
+
const wasQueued = !isQueuedForCapacity &&
|
|
4623
|
+
response.message?.toLowerCase().includes("queued");
|
|
4624
|
+
if (isQueuedForCapacity) {
|
|
4625
|
+
setLastRunStatusReason(MACHINE_CAPACITY_REASON);
|
|
4626
|
+
setAgent((prev) => prev
|
|
4627
|
+
? {
|
|
4628
|
+
...prev,
|
|
4629
|
+
status: "running",
|
|
4630
|
+
statusMessage: response.message ||
|
|
4631
|
+
"Waiting for capacity. The agent will start automatically when a slot becomes available.",
|
|
4632
|
+
}
|
|
4633
|
+
: prev);
|
|
4634
|
+
setIsWaitingForResponse(false);
|
|
4635
|
+
isWaitingRef.current = false;
|
|
4636
|
+
setIsConnecting(false);
|
|
4637
|
+
setIsAgentThinking(false);
|
|
4638
|
+
}
|
|
4639
|
+
else if (wasQueued) {
|
|
4494
4640
|
// Prompt was queued - show a brief notification but don't set waiting state
|
|
4495
4641
|
// The prompt will be processed when the agent becomes idle
|
|
4496
4642
|
console.log("[AgentTerminal] Prompt queued for processing");
|
|
@@ -4499,6 +4645,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
4499
4645
|
isWaitingRef.current = false;
|
|
4500
4646
|
}
|
|
4501
4647
|
else {
|
|
4648
|
+
setLastRunStatusReason(null);
|
|
4502
4649
|
clearSuppressedQueuedPrompt(suppressedQueuedPromptToken);
|
|
4503
4650
|
// Normal submission - set waiting state to show dancing dots immediately
|
|
4504
4651
|
setIsWaitingForResponse(true);
|
|
@@ -5332,6 +5479,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5332
5479
|
isWaitingForResponse,
|
|
5333
5480
|
isAgentThinking,
|
|
5334
5481
|
isExecuting,
|
|
5482
|
+
lastStatusReason: lastRunStatusReason,
|
|
5483
|
+
lastStatusMessage: agent?.statusMessage || null,
|
|
5335
5484
|
hasActiveStreaming: hasActiveStreaming(),
|
|
5336
5485
|
isSubscribed: normalizeDialogAgentId(subscribedAgentIdRef.current) ===
|
|
5337
5486
|
normalizeDialogAgentId(currentAgentId),
|
|
@@ -5359,10 +5508,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5359
5508
|
isExecuting,
|
|
5360
5509
|
isSubmitting,
|
|
5361
5510
|
isWaitingForResponse,
|
|
5511
|
+
lastRunStatusReason,
|
|
5362
5512
|
messagesWithToolCallsCount,
|
|
5363
5513
|
recentAgentRunEvents,
|
|
5364
5514
|
recentToolUiEvents,
|
|
5365
5515
|
totalToolCallCount,
|
|
5516
|
+
agent?.statusMessage,
|
|
5366
5517
|
]);
|
|
5367
5518
|
const showInitialThinkingSplash = messages.length === 0 &&
|
|
5368
5519
|
!error &&
|
|
@@ -5517,6 +5668,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5517
5668
|
const errorMessage = toUserFacingAgentErrorMessage(rawErrorMessage) || rawErrorMessage;
|
|
5518
5669
|
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 })] })] }) }));
|
|
5519
5670
|
};
|
|
5671
|
+
const renderCapacityBanner = () => {
|
|
5672
|
+
if (lastRunStatusReason !== MACHINE_CAPACITY_REASON) {
|
|
5673
|
+
return null;
|
|
5674
|
+
}
|
|
5675
|
+
const currentAgent = agent || agentStub;
|
|
5676
|
+
const message = currentAgent?.statusMessage ||
|
|
5677
|
+
"Waiting for capacity. The agent will start automatically when a slot becomes available.";
|
|
5678
|
+
return (_jsx("div", { className: "m-3 rounded border border-amber-300 bg-amber-50 p-3 text-[11px] text-amber-900", "data-testid": "agent-capacity-banner", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Waiting for capacity" }), _jsx("div", { className: "text-amber-800", children: message })] })] }) }));
|
|
5679
|
+
};
|
|
5520
5680
|
const renderBrowserClaimBanner = (variant = "inline") => {
|
|
5521
5681
|
if (!agent?.id || !editContext?.sessionId)
|
|
5522
5682
|
return null;
|
|
@@ -5567,13 +5727,42 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5567
5727
|
onAction: () => {
|
|
5568
5728
|
void handleClaimBrowser(isClaimedByAnotherBrowser);
|
|
5569
5729
|
},
|
|
5730
|
+
cancelLabel: "Cancel capture",
|
|
5731
|
+
onCancel: pendingBrowserCaptureCallbackId
|
|
5732
|
+
? () => {
|
|
5733
|
+
void handleCancelBrowserCapture();
|
|
5734
|
+
}
|
|
5735
|
+
: undefined,
|
|
5570
5736
|
}
|
|
5571
5737
|
: null;
|
|
5572
5738
|
useEffect(() => {
|
|
5573
5739
|
if (agent?.status !== "waitingForInput") {
|
|
5574
5740
|
setPendingBrowserCaptureDialogType(null);
|
|
5741
|
+
setPendingBrowserCaptureCallbackId(null);
|
|
5575
5742
|
}
|
|
5576
5743
|
}, [agent?.status]);
|
|
5744
|
+
const handleCancelBrowserCapture = useCallback(async () => {
|
|
5745
|
+
const callbackId = pendingBrowserCaptureCallbackId;
|
|
5746
|
+
if (!callbackId || !editContext?.sessionId)
|
|
5747
|
+
return;
|
|
5748
|
+
setIsBrowserClaimMutationPending(true);
|
|
5749
|
+
try {
|
|
5750
|
+
await cancelAgentDialog({
|
|
5751
|
+
callbackId,
|
|
5752
|
+
sessionId: editContext.sessionId,
|
|
5753
|
+
error: "Cancelled by user from the capture waiting banner.",
|
|
5754
|
+
});
|
|
5755
|
+
setPendingBrowserCaptureDialogType(null);
|
|
5756
|
+
setPendingBrowserCaptureCallbackId(null);
|
|
5757
|
+
}
|
|
5758
|
+
catch (err) {
|
|
5759
|
+
console.error("[AgentTerminal] Failed to cancel capture dialog:", err);
|
|
5760
|
+
editContext?.showErrorToast?.(err);
|
|
5761
|
+
}
|
|
5762
|
+
finally {
|
|
5763
|
+
setIsBrowserClaimMutationPending(false);
|
|
5764
|
+
}
|
|
5765
|
+
}, [pendingBrowserCaptureCallbackId, editContext]);
|
|
5577
5766
|
const renderInlineDialogContent = () => {
|
|
5578
5767
|
if (!activeInlineDialog)
|
|
5579
5768
|
return null;
|
|
@@ -5636,7 +5825,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5636
5825
|
return (_jsxs("div", { className: `flex h-full min-h-0 flex-col ${className || ""}`, children: [fixedBrowserClaimBanner, _jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error &&
|
|
5637
5826
|
!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 })] })] }) })), showInitialThinkingSplash && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [activeProfile?.svgIcon ? (_jsx("div", { className: "flex h-16 w-16 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
|
|
5638
5827
|
__html: sanitizeSvg(activeProfile.svgIcon),
|
|
5639
|
-
} })) : (_jsx(SecretAgentIcon, { size: 64, strokeWidth: 1, className: "text-gray-400" })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400" })] })] }) })), inlineBrowserClaimBanner, renderErrorBanner(), inlineDialog ? (inlineDialog) : latestSummaryAssistantGroup ? (_jsx("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: _jsx(AiResponseMessage, { messages: summaryMessages, finished: !latestSummaryAssistantGroup.isLastGroup || !isExecuting, editOperations: summaryOperations, defaultCollapseJson: defaultCollapseJson, profileSvgIcon: activeProfile?.svgIcon, agentId: agent?.id || agentStub.id, agentName: activeProfile?.agentName ||
|
|
5828
|
+
} })) : (_jsx(SecretAgentIcon, { size: 64, strokeWidth: 1, className: "text-gray-400" })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400" })] })] }) })), inlineBrowserClaimBanner, renderCapacityBanner(), renderErrorBanner(), inlineDialog ? (inlineDialog) : latestSummaryAssistantGroup ? (_jsx("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: _jsx(AiResponseMessage, { messages: summaryMessages, finished: !latestSummaryAssistantGroup.isLastGroup || !isExecuting, editOperations: summaryOperations, defaultCollapseJson: defaultCollapseJson, profileSvgIcon: activeProfile?.svgIcon, agentId: agent?.id || agentStub.id, agentName: activeProfile?.agentName ||
|
|
5640
5829
|
activeProfile?.displayTitle ||
|
|
5641
5830
|
activeProfile?.name, allPendingApprovals: allPendingApprovals, onSwitchToAutonomous: handleSwitchToAutonomous, browserCaptureInlinePrompt: browserCaptureInlinePrompt, onQuickAction: (action) => {
|
|
5642
5831
|
const text = (action.prompt ||
|
|
@@ -5762,7 +5951,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5762
5951
|
}, 0);
|
|
5763
5952
|
} })) })), showInitialThinkingSplash && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [activeProfile?.svgIcon ? (_jsx("div", { className: "flex h-16 w-16 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
|
|
5764
5953
|
__html: sanitizeSvg(activeProfile.svgIcon),
|
|
5765
|
-
} })) : (_jsx(SecretAgentIcon, { size: 64, strokeWidth: 1, className: "text-gray-400" })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400" })] })] }) })), inlineBrowserClaimBanner, renderErrorBanner(), _jsxs("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: [(() => {
|
|
5954
|
+
} })) : (_jsx(SecretAgentIcon, { size: 64, strokeWidth: 1, className: "text-gray-400" })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("span", { className: "h-2 w-2 animate-bounce rounded-full bg-gray-400" })] })] }) })), inlineBrowserClaimBanner, renderCapacityBanner(), renderErrorBanner(), _jsxs("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: [(() => {
|
|
5766
5955
|
const groups = groupConsecutiveMessages(messages);
|
|
5767
5956
|
return groups.map((group, groupIndex) => {
|
|
5768
5957
|
const isLastGroup = groupIndex === groups.length - 1;
|