@parhelia/core 0.1.12638 → 0.1.12676

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 (67) 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 +156 -9
  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/EditorShell.js +24 -0
  27. package/dist/editor/client/EditorShell.js.map +1 -1
  28. package/dist/editor/client/editContext.d.ts +1 -0
  29. package/dist/editor/client/editContext.js.map +1 -1
  30. package/dist/editor/client/hooks/useSocketMessageHandler.js +15 -1
  31. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  32. package/dist/editor/client/operations.d.ts +1 -0
  33. package/dist/editor/client/operations.js +50 -2
  34. package/dist/editor/client/operations.js.map +1 -1
  35. package/dist/editor/client/ui/EditorChrome.js +28 -1
  36. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  37. package/dist/editor/client/waitForEditOperationTerminal.d.ts +6 -0
  38. package/dist/editor/client/waitForEditOperationTerminal.js +54 -0
  39. package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
  40. package/dist/editor/commands/itemCommands.d.ts +2 -0
  41. package/dist/editor/commands/itemCommands.js +87 -4
  42. package/dist/editor/commands/itemCommands.js.map +1 -1
  43. package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
  44. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  45. package/dist/editor/media-selector/MediaFolderBrowser.js +10 -10
  46. package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
  47. package/dist/editor/media-selector/TreeSelector.js +7 -1
  48. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  49. package/dist/editor/services/agentService.d.ts +35 -0
  50. package/dist/editor/services/agentService.js +20 -0
  51. package/dist/editor/services/agentService.js.map +1 -1
  52. package/dist/editor/services/contentService.d.ts +2 -0
  53. package/dist/editor/services/contentService.js.map +1 -1
  54. package/dist/editor/settings/panels/AgentProfileConfigPanel.js +3 -2
  55. package/dist/editor/settings/panels/AgentProfileConfigPanel.js.map +1 -1
  56. package/dist/editor/settings/panels/AgentsPanel.js +3 -2
  57. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  58. package/dist/editor/settings/panels/GroupedFieldConfigPanel.d.ts +3 -1
  59. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js +2 -2
  60. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js.map +1 -1
  61. package/dist/editor/ui/InternalLink.d.ts +2 -2
  62. package/dist/editor/ui/InternalLink.js +2 -2
  63. package/dist/editor/ui/InternalLink.js.map +1 -1
  64. package/dist/revision.d.ts +2 -2
  65. package/dist/revision.js +2 -2
  66. package/dist/types.d.ts +11 -1
  67. 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, 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";
@@ -83,6 +83,8 @@ function buildPlaceholderAgentDetails(agentStub) {
83
83
  function normalizeDialogAgentId(value) {
84
84
  return value?.trim().toLowerCase() || "";
85
85
  }
86
+ const MACHINE_CAPACITY_REASON = "machineCapacity";
87
+ const MACHINE_CAPACITY_DETAIL = "waitingForCapacity";
86
88
  function formatAllowanceSource(source) {
87
89
  const normalized = source?.trim();
88
90
  if (!normalized)
@@ -116,6 +118,9 @@ function getAgentRunMessageDetail(type, payload) {
116
118
  return payload?.type || null;
117
119
  }
118
120
  if (type === "agent:run:status") {
121
+ if (payload?.data?.reason === MACHINE_CAPACITY_REASON) {
122
+ return MACHINE_CAPACITY_DETAIL;
123
+ }
119
124
  return payload?.data?.state || payload?.data?.status || null;
120
125
  }
121
126
  if (type === "agent:run:error") {
@@ -821,6 +826,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
821
826
  const [agentMetadata, setAgentMetadata] = useState(null);
822
827
  const [isBrowserClaimMutationPending, setIsBrowserClaimMutationPending] = useState(false);
823
828
  const [pendingBrowserCaptureDialogType, setPendingBrowserCaptureDialogType] = useState(null);
829
+ const [pendingBrowserCaptureCallbackId, setPendingBrowserCaptureCallbackId] = useState(null);
824
830
  // Ensure we always have an agent object for streaming handlers, even before `getAgent()` resolves.
825
831
  // This prevents early tool calls (e.g., ask-questionnaire) from being dropped in compact/workspace UIs.
826
832
  useEffect(() => {
@@ -965,6 +971,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
965
971
  }
966
972
  // Server-driven state: true when agent is actively processing (set by WebSocket messages)
967
973
  const [isAgentThinking, setIsAgentThinking] = useState(false);
974
+ const [lastRunStatusReason, setLastRunStatusReason] = useState(null);
968
975
  useEffect(() => {
969
976
  return () => {
970
977
  if (stopGuardReleaseTimeoutRef.current) {
@@ -1391,9 +1398,35 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1391
1398
  }
1392
1399
  }
1393
1400
  };
1401
+ const refreshAssignedSkills = async () => {
1402
+ try {
1403
+ const latest = await getAgent(agent.id);
1404
+ if (!active)
1405
+ return;
1406
+ const latestSkillIds = latest?.assignedSkillIds;
1407
+ if (!Array.isArray(latestSkillIds))
1408
+ return;
1409
+ setAgent((prev) => {
1410
+ if (!prev)
1411
+ return prev;
1412
+ const prevIds = Array.isArray(prev.assignedSkillIds)
1413
+ ? prev.assignedSkillIds
1414
+ : [];
1415
+ if (prevIds.length === latestSkillIds.length &&
1416
+ prevIds.every((id, i) => id === latestSkillIds[i])) {
1417
+ return prev;
1418
+ }
1419
+ return { ...prev, assignedSkillIds: latestSkillIds };
1420
+ });
1421
+ }
1422
+ catch (e) {
1423
+ console.error("Failed to refresh assigned skills:", e);
1424
+ }
1425
+ };
1394
1426
  void loadTriggerSubscriptions();
1395
1427
  void loadAvailableTools();
1396
1428
  void loadOperationAllowances();
1429
+ void refreshAssignedSkills();
1397
1430
  return () => {
1398
1431
  active = false;
1399
1432
  };
@@ -1404,7 +1437,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1404
1437
  agent?.userId,
1405
1438
  agent?.profileId,
1406
1439
  mode,
1407
- selectedSkillIds,
1408
1440
  ]);
1409
1441
  const activeTriggerSubscriptions = useMemo(() => triggerSubscriptions.filter((sub) => sub.isActive), [triggerSubscriptions]);
1410
1442
  const allowanceGroups = useMemo(() => [
@@ -2684,7 +2716,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2684
2716
  appendToolUiEvent("ui:tool-result-applied", `${extractedToolCall.functionName || "unknown"} toolCallId=${resultToolCallId} targetMessageId=${resultMessageId} completed=${matchingToolCall?.isCompleted ? "yes" : "no"} messageToolCalls=${messageWithToolResult?.toolCalls?.length || 0}`);
2685
2717
  return updated;
2686
2718
  });
2687
- }, [appendToolUiEvent]);
2719
+ // Document-store refresh is now triggered by the backend agent:documents:changed
2720
+ // WebSocket message (fired from AgentDocumentRepository), bridged to the in-process
2721
+ // emitAgentDocumentsChanged event in EditorShell. No per-tool allow-list here.
2722
+ }, [agent?.id, agentStub.id, appendToolUiEvent]);
2688
2723
  // Listen for local approval resolution to update UI
2689
2724
  useEffect(() => {
2690
2725
  const onApprovalResolved = (ev) => {
@@ -3292,6 +3327,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3292
3327
  // Reset run-scoped deduplication so new run seq values (starting at 1)
3293
3328
  // are not discarded due to previous run's lastSeqRef
3294
3329
  lastSeqRef.current = 0;
3330
+ setLastRunStatusReason(null);
3295
3331
  // Prep streaming UI state for the new run
3296
3332
  setIsConnecting(true);
3297
3333
  setIsWaitingForResponse(true);
@@ -3520,8 +3556,16 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3520
3556
  // Normalize various status shapes and handle Cancelled uniformly
3521
3557
  const normalizedStatus = parseAgentStatus(statusData?.state) ||
3522
3558
  parseAgentStatus(statusData?.status);
3559
+ const statusReason = typeof statusData?.reason === "string"
3560
+ ? statusData.reason.trim() || null
3561
+ : null;
3562
+ const statusMessage = typeof statusData?.message === "string"
3563
+ ? statusData.message.trim() || null
3564
+ : null;
3523
3565
  if (normalizedStatus === "idle") {
3524
3566
  clearStopGuard();
3567
+ setLastRunStatusReason(null);
3568
+ setError(null);
3525
3569
  // Stop indicators and mark any in-progress streaming messages as completed
3526
3570
  clearHeartbeatMessages();
3527
3571
  setAgent((prev) => (prev ? { ...prev, status: "idle" } : prev));
@@ -3628,6 +3672,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3628
3672
  }
3629
3673
  if (statusData?.state === "ToolApprovalsRequired") {
3630
3674
  setPendingBrowserCaptureDialogType(null);
3675
+ setPendingBrowserCaptureCallbackId(null);
3676
+ setLastRunStatusReason(null);
3631
3677
  const msgId = statusData.messageId;
3632
3678
  const ids = statusData.toolCallIds || [];
3633
3679
  if (msgId && Array.isArray(ids) && ids.length > 0) {
@@ -3662,7 +3708,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3662
3708
  // Handle waiting states explicitly
3663
3709
  if (normalizedStatus === "waitingForApproval") {
3664
3710
  clearStopGuard();
3711
+ setLastRunStatusReason(null);
3712
+ setError(null);
3665
3713
  setPendingBrowserCaptureDialogType(null);
3714
+ setPendingBrowserCaptureCallbackId(null);
3666
3715
  setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
3667
3716
  setIsConnecting(false);
3668
3717
  setIsWaitingForResponse(false);
@@ -3672,12 +3721,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3672
3721
  }
3673
3722
  if (normalizedStatus === "waitingForInput") {
3674
3723
  clearStopGuard();
3724
+ setLastRunStatusReason(null);
3725
+ setError(null);
3675
3726
  const dialogType = typeof statusData?.dialogType === "string"
3676
3727
  ? statusData.dialogType
3677
3728
  : null;
3678
3729
  const isBrowserCaptureWait = dialogType === DIALOG_TYPES.CAPTURE_PAGE_DOM ||
3679
3730
  dialogType === DIALOG_TYPES.CAPTURE_PAGE_SCREENSHOT;
3680
3731
  setPendingBrowserCaptureDialogType(isBrowserCaptureWait ? dialogType : null);
3732
+ const captureCallbackId = isBrowserCaptureWait &&
3733
+ typeof statusData?.callbackId === "string" &&
3734
+ statusData.callbackId.trim()
3735
+ ? statusData.callbackId.trim()
3736
+ : null;
3737
+ setPendingBrowserCaptureCallbackId(captureCallbackId);
3681
3738
  setAgent((prev) => prev
3682
3739
  ? {
3683
3740
  ...prev,
@@ -3696,7 +3753,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3696
3753
  }
3697
3754
  if (normalizedStatus === "costLimitReached") {
3698
3755
  clearStopGuard();
3756
+ setError(null);
3699
3757
  setPendingBrowserCaptureDialogType(null);
3758
+ setPendingBrowserCaptureCallbackId(null);
3700
3759
  const totalCost = Number(statusData.totalCost) || 0;
3701
3760
  const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
3702
3761
  setCostLimitExceeded({
@@ -3745,6 +3804,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3745
3804
  // Handle "completed" state (fallback for legacy code paths that send status instead of lifecycle event)
3746
3805
  if (normalizedStatus === "completed") {
3747
3806
  clearStopGuard();
3807
+ setError(null);
3748
3808
  // Reset deduplication for the next run
3749
3809
  lastSeqRef.current = 0;
3750
3810
  clearHeartbeatMessages();
@@ -3775,6 +3835,25 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3775
3835
  if (isStoppingRef.current) {
3776
3836
  return;
3777
3837
  }
3838
+ if (statusReason === MACHINE_CAPACITY_REASON) {
3839
+ clearHeartbeatMessages();
3840
+ setLastRunStatusReason(statusReason);
3841
+ setAgent((prev) => prev
3842
+ ? {
3843
+ ...prev,
3844
+ status: "running",
3845
+ statusMessage: statusMessage ||
3846
+ "Waiting for capacity. The agent will start automatically when a slot becomes available.",
3847
+ }
3848
+ : prev);
3849
+ setIsWaitingForResponse(false);
3850
+ isWaitingRef.current = false;
3851
+ setIsConnecting(false);
3852
+ setIsAgentThinking(false);
3853
+ return;
3854
+ }
3855
+ setLastRunStatusReason(null);
3856
+ setError(null);
3778
3857
  // Update agent status to running and clear any previous error statusMessage
3779
3858
  setAgent((prev) => prev
3780
3859
  ? { ...prev, status: "running", statusMessage: undefined }
@@ -3787,8 +3866,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3787
3866
  // Handle "Error" state
3788
3867
  if (normalizedStatus === "error") {
3789
3868
  clearStopGuard();
3790
- const errorMsg = toUserFacingAgentErrorMessage(statusData?.statusMessage ?? statusData?.error) || "Unknown error";
3869
+ setLastRunStatusReason(null);
3870
+ const errorMsg = toUserFacingAgentErrorMessage(statusData?.statusMessage ??
3871
+ statusData?.message ??
3872
+ statusData?.error) || "Unknown error";
3791
3873
  clearHeartbeatMessages();
3874
+ setError(errorMsg);
3792
3875
  setAgent((prev) => prev
3793
3876
  ? { ...prev, status: "error", statusMessage: errorMsg }
3794
3877
  : prev);
@@ -3808,6 +3891,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3808
3891
  if (messageType === "agent:run:complete") {
3809
3892
  // Reset deduplication for the next run
3810
3893
  lastSeqRef.current = 0;
3894
+ setLastRunStatusReason(null);
3811
3895
  clearHeartbeatMessages();
3812
3896
  // Mark the last assistant message as completed
3813
3897
  setMessages((prev) => {
@@ -3836,6 +3920,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3836
3920
  const errorMsg = toUserFacingAgentErrorMessage(message.payload?.error) ||
3837
3921
  "AI could not complete this request.";
3838
3922
  clearHeartbeatMessages();
3923
+ setLastRunStatusReason(null);
3839
3924
  // Reset deduplication for the next run after an error
3840
3925
  lastSeqRef.current = 0;
3841
3926
  setError(errorMsg);
@@ -4488,9 +4573,28 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4488
4573
  console.log("[AgentTerminal] Calling startAgent API for agent:", agentId);
4489
4574
  const response = await startAgent(request);
4490
4575
  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) {
4576
+ const isQueuedForCapacity = response.reason === MACHINE_CAPACITY_REASON ||
4577
+ response.message?.toLowerCase().includes("machine slot") ||
4578
+ false;
4579
+ // Check if prompt was queued because another execution was already active
4580
+ const wasQueued = !isQueuedForCapacity &&
4581
+ response.message?.toLowerCase().includes("queued");
4582
+ if (isQueuedForCapacity) {
4583
+ setLastRunStatusReason(MACHINE_CAPACITY_REASON);
4584
+ setAgent((prev) => prev
4585
+ ? {
4586
+ ...prev,
4587
+ status: "running",
4588
+ statusMessage: response.message ||
4589
+ "Waiting for capacity. The agent will start automatically when a slot becomes available.",
4590
+ }
4591
+ : prev);
4592
+ setIsWaitingForResponse(false);
4593
+ isWaitingRef.current = false;
4594
+ setIsConnecting(false);
4595
+ setIsAgentThinking(false);
4596
+ }
4597
+ else if (wasQueued) {
4494
4598
  // Prompt was queued - show a brief notification but don't set waiting state
4495
4599
  // The prompt will be processed when the agent becomes idle
4496
4600
  console.log("[AgentTerminal] Prompt queued for processing");
@@ -4499,6 +4603,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4499
4603
  isWaitingRef.current = false;
4500
4604
  }
4501
4605
  else {
4606
+ setLastRunStatusReason(null);
4502
4607
  clearSuppressedQueuedPrompt(suppressedQueuedPromptToken);
4503
4608
  // Normal submission - set waiting state to show dancing dots immediately
4504
4609
  setIsWaitingForResponse(true);
@@ -5332,6 +5437,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5332
5437
  isWaitingForResponse,
5333
5438
  isAgentThinking,
5334
5439
  isExecuting,
5440
+ lastStatusReason: lastRunStatusReason,
5441
+ lastStatusMessage: agent?.statusMessage || null,
5335
5442
  hasActiveStreaming: hasActiveStreaming(),
5336
5443
  isSubscribed: normalizeDialogAgentId(subscribedAgentIdRef.current) ===
5337
5444
  normalizeDialogAgentId(currentAgentId),
@@ -5359,10 +5466,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5359
5466
  isExecuting,
5360
5467
  isSubmitting,
5361
5468
  isWaitingForResponse,
5469
+ lastRunStatusReason,
5362
5470
  messagesWithToolCallsCount,
5363
5471
  recentAgentRunEvents,
5364
5472
  recentToolUiEvents,
5365
5473
  totalToolCallCount,
5474
+ agent?.statusMessage,
5366
5475
  ]);
5367
5476
  const showInitialThinkingSplash = messages.length === 0 &&
5368
5477
  !error &&
@@ -5517,6 +5626,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5517
5626
  const errorMessage = toUserFacingAgentErrorMessage(rawErrorMessage) || rawErrorMessage;
5518
5627
  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
5628
  };
5629
+ const renderCapacityBanner = () => {
5630
+ if (lastRunStatusReason !== MACHINE_CAPACITY_REASON) {
5631
+ return null;
5632
+ }
5633
+ const currentAgent = agent || agentStub;
5634
+ const message = currentAgent?.statusMessage ||
5635
+ "Waiting for capacity. The agent will start automatically when a slot becomes available.";
5636
+ 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 })] })] }) }));
5637
+ };
5520
5638
  const renderBrowserClaimBanner = (variant = "inline") => {
5521
5639
  if (!agent?.id || !editContext?.sessionId)
5522
5640
  return null;
@@ -5567,13 +5685,42 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5567
5685
  onAction: () => {
5568
5686
  void handleClaimBrowser(isClaimedByAnotherBrowser);
5569
5687
  },
5688
+ cancelLabel: "Cancel capture",
5689
+ onCancel: pendingBrowserCaptureCallbackId
5690
+ ? () => {
5691
+ void handleCancelBrowserCapture();
5692
+ }
5693
+ : undefined,
5570
5694
  }
5571
5695
  : null;
5572
5696
  useEffect(() => {
5573
5697
  if (agent?.status !== "waitingForInput") {
5574
5698
  setPendingBrowserCaptureDialogType(null);
5699
+ setPendingBrowserCaptureCallbackId(null);
5575
5700
  }
5576
5701
  }, [agent?.status]);
5702
+ const handleCancelBrowserCapture = useCallback(async () => {
5703
+ const callbackId = pendingBrowserCaptureCallbackId;
5704
+ if (!callbackId || !editContext?.sessionId)
5705
+ return;
5706
+ setIsBrowserClaimMutationPending(true);
5707
+ try {
5708
+ await cancelAgentDialog({
5709
+ callbackId,
5710
+ sessionId: editContext.sessionId,
5711
+ error: "Cancelled by user from the capture waiting banner.",
5712
+ });
5713
+ setPendingBrowserCaptureDialogType(null);
5714
+ setPendingBrowserCaptureCallbackId(null);
5715
+ }
5716
+ catch (err) {
5717
+ console.error("[AgentTerminal] Failed to cancel capture dialog:", err);
5718
+ editContext?.showErrorToast?.(err);
5719
+ }
5720
+ finally {
5721
+ setIsBrowserClaimMutationPending(false);
5722
+ }
5723
+ }, [pendingBrowserCaptureCallbackId, editContext]);
5577
5724
  const renderInlineDialogContent = () => {
5578
5725
  if (!activeInlineDialog)
5579
5726
  return null;
@@ -5636,7 +5783,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5636
5783
  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
5784
  !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
5785
  __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 ||
5786
+ } })) : (_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
5787
  activeProfile?.displayTitle ||
5641
5788
  activeProfile?.name, allPendingApprovals: allPendingApprovals, onSwitchToAutonomous: handleSwitchToAutonomous, browserCaptureInlinePrompt: browserCaptureInlinePrompt, onQuickAction: (action) => {
5642
5789
  const text = (action.prompt ||
@@ -5762,7 +5909,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
5762
5909
  }, 0);
5763
5910
  } })) })), 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
5911
  __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: [(() => {
5912
+ } })) : (_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
5913
  const groups = groupConsecutiveMessages(messages);
5767
5914
  return groups.map((group, groupIndex) => {
5768
5915
  const isLastGroup = groupIndex === groups.length - 1;