@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.
Files changed (63) hide show
  1. package/dist/components/ui/alert-dialog.js +2 -2
  2. package/dist/components/ui/alert-dialog.js.map +1 -1
  3. package/dist/components/ui/badge.d.ts +1 -1
  4. package/dist/components/ui/button.d.ts +2 -2
  5. package/dist/components/ui/dialog.d.ts +1 -1
  6. package/dist/components/ui/dialog.js +67 -3
  7. package/dist/components/ui/dialog.js.map +1 -1
  8. package/dist/config/config.js +3 -1
  9. package/dist/config/config.js.map +1 -1
  10. package/dist/editor/ItemInfo.js +15 -3
  11. package/dist/editor/ItemInfo.js.map +1 -1
  12. package/dist/editor/ai/AgentDocumentList.js +16 -1
  13. package/dist/editor/ai/AgentDocumentList.js.map +1 -1
  14. package/dist/editor/ai/AgentTerminal.js +197 -8
  15. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  16. package/dist/editor/ai/AgentTerminalStatusBar.js +44 -0
  17. package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
  18. package/dist/editor/ai/AiResponseMessage.d.ts +2 -0
  19. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  20. package/dist/editor/ai/ToolCallDisplay.d.ts +2 -0
  21. package/dist/editor/ai/ToolCallDisplay.js +14 -8
  22. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  23. package/dist/editor/ai/agentDiagnostics.d.ts +3 -1
  24. package/dist/editor/ai/agentDiagnostics.js +20 -0
  25. package/dist/editor/ai/agentDiagnostics.js.map +1 -1
  26. package/dist/editor/client/editContext.d.ts +1 -0
  27. package/dist/editor/client/editContext.js.map +1 -1
  28. package/dist/editor/client/hooks/useSocketMessageHandler.js +15 -1
  29. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  30. package/dist/editor/client/operations.d.ts +1 -0
  31. package/dist/editor/client/operations.js +50 -2
  32. package/dist/editor/client/operations.js.map +1 -1
  33. package/dist/editor/client/ui/EditorChrome.js +28 -1
  34. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  35. package/dist/editor/client/waitForEditOperationTerminal.d.ts +6 -0
  36. package/dist/editor/client/waitForEditOperationTerminal.js +54 -0
  37. package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
  38. package/dist/editor/commands/itemCommands.d.ts +2 -0
  39. package/dist/editor/commands/itemCommands.js +87 -4
  40. package/dist/editor/commands/itemCommands.js.map +1 -1
  41. package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
  42. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  43. package/dist/editor/media-selector/MediaFolderBrowser.js +10 -10
  44. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  45. package/dist/editor/media-selector/TreeSelector.js +7 -1
  46. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  47. package/dist/editor/services/agentService.d.ts +35 -0
  48. package/dist/editor/services/agentService.js +20 -0
  49. package/dist/editor/services/agentService.js.map +1 -1
  50. package/dist/editor/services/contentService.d.ts +2 -0
  51. package/dist/editor/services/contentService.js.map +1 -1
  52. package/dist/editor/settings/panels/AgentProfileConfigPanel.js +3 -2
  53. package/dist/editor/settings/panels/AgentProfileConfigPanel.js.map +1 -1
  54. package/dist/editor/settings/panels/GroupedFieldConfigPanel.d.ts +3 -1
  55. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js +2 -2
  56. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js.map +1 -1
  57. package/dist/editor/ui/InternalLink.d.ts +2 -2
  58. package/dist/editor/ui/InternalLink.js +2 -2
  59. package/dist/editor/ui/InternalLink.js.map +1 -1
  60. package/dist/revision.d.ts +2 -2
  61. package/dist/revision.js +2 -2
  62. package/dist/types.d.ts +11 -1
  63. 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
- }, [appendToolUiEvent]);
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
- // Check if prompt was queued (agent was already running)
4492
- const wasQueued = response.message?.toLowerCase().includes("queued");
4493
- if (wasQueued) {
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;