@parhelia/core 0.1.11069 → 0.1.11141

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 (65) hide show
  1. package/README.md +34 -34
  2. package/dist/components/ui/dialog.js +2 -2
  3. package/dist/components/ui/dialog.js.map +1 -1
  4. package/dist/editor/ai/AgentTerminal.js +165 -43
  5. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  6. package/dist/editor/ai/Agents.js +3 -3
  7. package/dist/editor/ai/Agents.js.map +1 -1
  8. package/dist/editor/ai/ContextInfoBar.js +175 -37
  9. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  10. package/dist/editor/ai/EditOperationsPanel.d.ts +5 -0
  11. package/dist/editor/ai/EditOperationsPanel.js +64 -0
  12. package/dist/editor/ai/EditOperationsPanel.js.map +1 -0
  13. package/dist/editor/client/EditorShell.js +109 -35
  14. package/dist/editor/client/EditorShell.js.map +1 -1
  15. package/dist/editor/client/editContext.d.ts +4 -0
  16. package/dist/editor/client/editContext.js.map +1 -1
  17. package/dist/editor/client/operations.d.ts +3 -1
  18. package/dist/editor/client/operations.js +154 -52
  19. package/dist/editor/client/operations.js.map +1 -1
  20. package/dist/editor/commands/componentCommands.js +2 -2
  21. package/dist/editor/commands/componentCommands.js.map +1 -1
  22. package/dist/editor/commands/itemCommands.js +25 -25
  23. package/dist/editor/commands/itemCommands.js.map +1 -1
  24. package/dist/editor/commands/undo.d.ts +2 -2
  25. package/dist/editor/commands/undo.js +4 -2
  26. package/dist/editor/commands/undo.js.map +1 -1
  27. package/dist/editor/field-types/NameValueListEditor.js +14 -2
  28. package/dist/editor/field-types/NameValueListEditor.js.map +1 -1
  29. package/dist/editor/field-types/RichTextEditorComponent.js +15 -3
  30. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  31. package/dist/editor/field-types/richtext/components/ReactSlate.js +65 -2
  32. package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
  33. package/dist/editor/menubar/ApproveAndPublish.js +1 -1
  34. package/dist/editor/menubar/WorkflowButton.js +1 -1
  35. package/dist/editor/page-editor-chrome/FrameMenu.js +50 -13
  36. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  37. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +18 -4
  38. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  39. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +18 -39
  40. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  41. package/dist/editor/page-viewer/PageViewerFrame.js +34 -131
  42. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  43. package/dist/editor/services/agentService.d.ts +17 -0
  44. package/dist/editor/services/agentService.js +8 -0
  45. package/dist/editor/services/agentService.js.map +1 -1
  46. package/dist/editor/services/contextService.js +8 -27
  47. package/dist/editor/services/contextService.js.map +1 -1
  48. package/dist/editor/services/editService.d.ts +5 -2
  49. package/dist/editor/services/editService.js +19 -5
  50. package/dist/editor/services/editService.js.map +1 -1
  51. package/dist/editor/sidebar/ComponentPalette.js +4 -1
  52. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  53. package/dist/editor/sidebar/EditHistory.js +30 -55
  54. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  55. package/dist/editor/sidebar/OperationItem.d.ts +10 -0
  56. package/dist/editor/sidebar/OperationItem.js +102 -0
  57. package/dist/editor/sidebar/OperationItem.js.map +1 -0
  58. package/dist/editor/ui/DragPreview.d.ts +5 -0
  59. package/dist/editor/ui/DragPreview.js +41 -3
  60. package/dist/editor/ui/DragPreview.js.map +1 -1
  61. package/dist/revision.d.ts +2 -2
  62. package/dist/revision.js +2 -2
  63. package/dist/styles.css +38 -9
  64. package/dist/types.d.ts +24 -2
  65. package/package.json +1 -1
package/README.md CHANGED
@@ -1,34 +1,34 @@
1
- # @parhelia/core
2
-
3
- Core components and utilities for the Parhelia visual content editor for Sitecore.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @parhelia/core
9
- ```
10
-
11
- ## Usage
12
-
13
- ```typescript
14
- import { /* components */ } from '@parhelia/core';
15
- import '@parhelia/core/styles.css';
16
- ```
17
-
18
- ## Features
19
-
20
- - Visual editor components
21
- - UI component library
22
- - Content management utilities
23
- - Agent-based AI assistance
24
- - Page wizard functionality
25
- - Field editing capabilities
26
-
27
- ## License
28
-
29
- See LICENSE file for details.
30
-
31
- ## Documentation
32
-
33
- For complete documentation, visit [https://parhelia.ai](https://parhelia.ai)
34
-
1
+ # @parhelia/core
2
+
3
+ Core components and utilities for the Parhelia visual content editor for Sitecore.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @parhelia/core
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { /* components */ } from '@parhelia/core';
15
+ import '@parhelia/core/styles.css';
16
+ ```
17
+
18
+ ## Features
19
+
20
+ - Visual editor components
21
+ - UI component library
22
+ - Content management utilities
23
+ - Agent-based AI assistance
24
+ - Page wizard functionality
25
+ - Field editing capabilities
26
+
27
+ ## License
28
+
29
+ See LICENSE file for details.
30
+
31
+ ## Documentation
32
+
33
+ For complete documentation, visit [https://parhelia.ai](https://parhelia.ai)
34
+
@@ -16,10 +16,10 @@ function DialogClose({ ...props }) {
16
16
  return _jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
17
17
  }
18
18
  function DialogOverlay({ className, ...props }) {
19
- return (_jsx(DialogPrimitive.Overlay, { "data-slot": "dialog-overlay", className: cn("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", className), ...props }));
19
+ return (_jsx(DialogPrimitive.Overlay, { "data-slot": "dialog-overlay", className: cn("data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[100] bg-black/50", className), ...props }));
20
20
  }
21
21
  function DialogContent({ className, children, showCloseButton = true, overlayClassName, ...props }) {
22
- return (_jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 flex w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] flex-col rounded-lg border shadow-lg duration-200", className), "data-testid": "dialog-content", ...props, children: [children, showCloseButton && (_jsxs(DialogPrimitive.Close, { "data-slot": "dialog-close", className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "data-testid": "dialog-close", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }));
22
+ return (_jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [_jsx(DialogOverlay, { className: overlayClassName }), _jsxs(DialogPrimitive.Content, { "data-slot": "dialog-content", className: cn("bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-[101] flex w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] flex-col rounded-lg border shadow-lg duration-200", className), "data-testid": "dialog-content", ...props, children: [children, showCloseButton && (_jsxs(DialogPrimitive.Close, { "data-slot": "dialog-close", className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "data-testid": "dialog-close", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Close" })] }))] })] }));
23
23
  }
24
24
  function DialogHeader({ className, ...props }) {
25
25
  return (_jsx("div", { "data-slot": "dialog-header", className: cn("border-gray-3 flex flex-col gap-2 border-b px-6 py-5 text-center sm:text-left", className), ...props }));
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","sourceRoot":"","sources":["../../../src/components/ui/dialog.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dialog.js","sourceRoot":"","sources":["../../../src/components/ui/dialog.tsx"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { AiResponseMessage } from "./AiResponseMessage";
10
10
  import { AgentCostDisplay } from "./AgentCostDisplay";
11
11
  import { ContextInfoBar } from "./ContextInfoBar";
12
12
  import { AgentDocumentList } from "./AgentDocumentList";
13
+ import { AgentEditOperationsPanel } from "./EditOperationsPanel";
13
14
  import { getComponentById } from "../componentTreeHelper";
14
15
  import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
15
16
  import { SecretAgentIcon } from "../ui/Icons";
@@ -553,6 +554,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
553
554
  const recognitionRef = useRef(null);
554
555
  const prevPlaceholderRef = useRef(null);
555
556
  const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
557
+ const [showCompressionPopover, setShowCompressionPopover] = useState(false);
556
558
  const isWaitingRef = useRef(false);
557
559
  useEffect(() => {
558
560
  isWaitingRef.current = isWaitingForResponse;
@@ -581,7 +583,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
581
583
  const hasPendingSuffix = (tc.functionName || "").includes("(pending approval)");
582
584
  const isApproved = (tc.functionName || "").includes("(approved)");
583
585
  const isRejected = (tc.functionName || "").includes("(rejected)");
584
- if ((hasApprovalMetadata || hasPendingSuffix) && !isApproved && !isRejected) {
586
+ if ((hasApprovalMetadata || hasPendingSuffix) &&
587
+ !isApproved &&
588
+ !isRejected) {
585
589
  pending.push({
586
590
  messageId: tc.messageId || msg.id,
587
591
  dbMessageId: tc.dbMessageId,
@@ -669,6 +673,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
669
673
  const [costLimitExceeded, setCostLimitExceeded] = useState(null);
670
674
  // Live running totals from backend status updates (tokenUsage)
671
675
  const [liveTotals, setLiveTotals] = useState(null);
676
+ // Context window status from backend (extracted from delta cost object)
677
+ const [contextWindowStatus, setContextWindowStatus] = useState(null);
672
678
  // Flag to track when we should create a new message
673
679
  const shouldCreateNewMessage = useRef(false);
674
680
  // Keep a ref to the current messages for immediate access
@@ -685,6 +691,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
685
691
  const subscribedAgentIdRef = useRef(null);
686
692
  // Cache mode/model changes made while the agent is still "new" (not yet persisted)
687
693
  const pendingSettingsRef = useRef(null);
694
+ // Track whether textarea should maintain focus during re-renders
695
+ const shouldMaintainFocusRef = useRef(false);
688
696
  // Auto-scroll to bottom when new messages arrive
689
697
  const scrollToBottom = useCallback(() => {
690
698
  const container = messagesContainerRef.current;
@@ -936,6 +944,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
936
944
  setIsWaitingForResponse(false);
937
945
  shouldCreateNewMessage.current = false;
938
946
  }
947
+ // Extract context window info from cost object
948
+ if (cost.contextWindow && cost.contextUsed) {
949
+ const contextWindowValue = Number(cost.contextWindow);
950
+ const contextUsedValue = Number(cost.contextUsed);
951
+ if (contextWindowValue > 0 && contextUsedValue >= 0) {
952
+ setContextWindowStatus({
953
+ contextWindowTokens: contextWindowValue,
954
+ estimatedInputTokens: contextUsedValue,
955
+ contextUsedPercent: (contextUsedValue / contextWindowValue) * 100,
956
+ model: agentData?.model || agent?.model || "",
957
+ });
958
+ }
959
+ }
939
960
  }
940
961
  // Always call setMessages and handle all logic in the callback with latest messages
941
962
  setMessages((prev) => {
@@ -1104,6 +1125,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1104
1125
  if (anyNonZero) {
1105
1126
  setLiveTotals(nextTotals);
1106
1127
  }
1128
+ // Extract context window info from cost object
1129
+ if (cost.contextWindow && cost.contextUsed) {
1130
+ const contextWindowValue = Number(cost.contextWindow);
1131
+ const contextUsedValue = Number(cost.contextUsed);
1132
+ if (contextWindowValue > 0 && contextUsedValue >= 0) {
1133
+ setContextWindowStatus({
1134
+ contextWindowTokens: contextWindowValue,
1135
+ estimatedInputTokens: contextUsedValue,
1136
+ contextUsedPercent: (contextUsedValue / contextWindowValue) * 100,
1137
+ model: agentData?.model || agent?.model || "",
1138
+ });
1139
+ }
1140
+ }
1107
1141
  }
1108
1142
  else {
1109
1143
  // Fallback: legacy aggregated totals included in the tool result data
@@ -1373,6 +1407,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1373
1407
  language: item.language,
1374
1408
  version: item.version,
1375
1409
  name: editContext?.contentEditorItem?.name,
1410
+ path: editContext?.contentEditorItem?.path,
1376
1411
  },
1377
1412
  ],
1378
1413
  components: editContext?.selection?.length && item
@@ -1571,6 +1606,18 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1571
1606
  })();
1572
1607
  // For existing agents, use database metadata or none
1573
1608
  setAgentMetadata(sanitizeAgentMetadata(parsedMeta));
1609
+ // Initialize context window status from loaded agent data
1610
+ if (agentData.contextUsedTokens !== undefined) {
1611
+ setContextWindowStatus({
1612
+ contextWindowTokens: agentData.contextWindowTokens ?? 0,
1613
+ estimatedInputTokens: agentData.contextUsedTokens,
1614
+ contextUsedPercent: agentData.contextWindowTokens
1615
+ ? (agentData.contextUsedTokens / agentData.contextWindowTokens) *
1616
+ 100
1617
+ : 0,
1618
+ model: agentData.model,
1619
+ });
1620
+ }
1574
1621
  }
1575
1622
  catch (err) {
1576
1623
  console.error("❌ Failed to load agent:", err);
@@ -1962,19 +2009,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1962
2009
  setIsConnecting(false);
1963
2010
  return;
1964
2011
  }
1965
- if (statusData?.state === "contextWindow") {
1966
- window.__agentContextWindowStatus = {
1967
- model: statusData.model,
1968
- normalizedModel: statusData.normalizedModel,
1969
- contextWindowTokens: statusData.contextWindowTokens,
1970
- maxCompletionTokens: statusData.maxCompletionTokens,
1971
- estimatedInputTokens: statusData.estimatedInputTokens,
1972
- messageCount: statusData.messageCount,
1973
- contextUsedPercent: statusData.contextUsedPercent,
1974
- };
1975
- setMessages((prev) => [...prev]);
1976
- return;
1977
- }
1978
2012
  if (statusData?.state === "contextChanged") {
1979
2013
  // Server sends additionalData directly (with todoList inside)
1980
2014
  const serverAdditionalData = statusData.additionalData || statusData.AdditionalData || {};
@@ -2234,6 +2268,14 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2234
2268
  scrollToBottom();
2235
2269
  }
2236
2270
  }, [messages, scrollToBottom, shouldAutoScroll]);
2271
+ // Maintain focus on textarea when messages update (prevents focus loss during agent responses)
2272
+ useEffect(() => {
2273
+ if (shouldMaintainFocusRef.current &&
2274
+ textareaRef.current &&
2275
+ !activePlaceholderInput) {
2276
+ textareaRef.current.focus();
2277
+ }
2278
+ }, [messages, activePlaceholderInput]);
2237
2279
  // Persist any pending settings (mode/model) once an agent exists server-side
2238
2280
  const persistPendingSettingsIfNeeded = useCallback(async () => {
2239
2281
  try {
@@ -2345,6 +2387,31 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2345
2387
  console.warn(`Context factory not found: ${factoryName}. Proceeding without it.`);
2346
2388
  }
2347
2389
  }
2390
+ // In live context mode, compute fresh context from editor state to avoid stale agentMetadata
2391
+ // The UI (ContextInfoBar) always shows live context, so we must send matching context to AI
2392
+ let effectiveContext = agentMetadata;
2393
+ try {
2394
+ const normalizedAgentProfileId = agent?.profileId?.toLowerCase();
2395
+ const profile = activeProfile ||
2396
+ profiles.find((p) => p.id?.toLowerCase() === normalizedAgentProfileId);
2397
+ const isLiveMode = profile?.editorContextMode === "live";
2398
+ if (isLiveMode && typeof buildCurrentContext === "function") {
2399
+ const freshContext = buildCurrentContext();
2400
+ if (freshContext) {
2401
+ // Merge fresh live context with existing metadata to preserve comments, additionalData, etc.
2402
+ effectiveContext = {
2403
+ ...(agentMetadata || {}),
2404
+ items: freshContext.items,
2405
+ currentItemId: freshContext.currentItemId,
2406
+ components: freshContext.components,
2407
+ field: freshContext.field,
2408
+ };
2409
+ }
2410
+ }
2411
+ }
2412
+ catch (e) {
2413
+ console.warn("[AgentTerminal] Failed to compute live context:", e);
2414
+ }
2348
2415
  const request = {
2349
2416
  agentId: agentId,
2350
2417
  message: savedPrompt,
@@ -2353,7 +2420,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2353
2420
  profile: activeProfile?.name || profiles[0]?.name || "",
2354
2421
  model: selectedModelId,
2355
2422
  mode: mode,
2356
- context: canonicalizeAgentMetadata(agentMetadata), // Canonicalize to ensure complete field structure
2423
+ context: canonicalizeAgentMetadata(effectiveContext), // Use fresh live context when in live mode
2357
2424
  deterministic: deterministicFlags.deterministic,
2358
2425
  seed: deterministicFlags.seed,
2359
2426
  };
@@ -2533,6 +2600,30 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2533
2600
  console.warn(`Context factory not found: ${factoryName}. Proceeding without it.`);
2534
2601
  }
2535
2602
  }
2603
+ // In live context mode, compute fresh context from editor state to avoid stale agentMetadata
2604
+ let effectiveContext = agentMetadata;
2605
+ try {
2606
+ const normalizedAgentProfileId = agent?.profileId?.toLowerCase();
2607
+ const profile = activeProfile ||
2608
+ profiles.find((p) => p.id?.toLowerCase() === normalizedAgentProfileId);
2609
+ const isLiveMode = profile?.editorContextMode === "live";
2610
+ if (isLiveMode && typeof buildCurrentContext === "function") {
2611
+ const freshContext = buildCurrentContext();
2612
+ if (freshContext) {
2613
+ // Merge fresh live context with existing metadata to preserve comments, additionalData, etc.
2614
+ effectiveContext = {
2615
+ ...(agentMetadata || {}),
2616
+ items: freshContext.items,
2617
+ currentItemId: freshContext.currentItemId,
2618
+ components: freshContext.components,
2619
+ field: freshContext.field,
2620
+ };
2621
+ }
2622
+ }
2623
+ }
2624
+ catch (e) {
2625
+ console.warn("[AgentTerminal] Failed to compute live context for quick message:", e);
2626
+ }
2536
2627
  const request = {
2537
2628
  agentId: agent.id,
2538
2629
  message: savedPrompt,
@@ -2541,7 +2632,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2541
2632
  profile: activeProfile?.name || profiles[0]?.name || "",
2542
2633
  model: selectedModelId,
2543
2634
  mode: mode,
2544
- context: canonicalizeAgentMetadata(agentMetadata), // Canonicalize to ensure complete field structure
2635
+ context: canonicalizeAgentMetadata(effectiveContext), // Use fresh live context when in live mode
2545
2636
  deterministic: deterministicFlags.deterministic,
2546
2637
  seed: deterministicFlags.seed,
2547
2638
  };
@@ -2686,8 +2777,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2686
2777
  language: item.language,
2687
2778
  version: item.version,
2688
2779
  name: editContext?.contentEditorItem?.name,
2780
+ path: editContext?.contentEditorItem?.path,
2689
2781
  },
2690
2782
  ],
2783
+ currentItemId: item.id, // ID of the currently loaded item user is viewing
2691
2784
  components: editContext?.selection?.length && item
2692
2785
  ? editContext.selection.map((componentId) => ({
2693
2786
  componentId,
@@ -2764,6 +2857,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2764
2857
  const merged = {
2765
2858
  ...existingMeta,
2766
2859
  items: currentCtx.items ? [...currentCtx.items] : undefined,
2860
+ currentItemId: currentCtx.currentItemId,
2767
2861
  components: currentCtx.components
2768
2862
  ? [...currentCtx.components]
2769
2863
  : undefined,
@@ -2784,8 +2878,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2784
2878
  const sanitized = sanitizeAgentMetadata(merged);
2785
2879
  setAgentMetadata(sanitized ? { ...sanitized } : null);
2786
2880
  // If the agent exists server-side, persist context as well
2881
+ // Defer the server update to avoid blocking rendering
2787
2882
  if (agent?.id && agent.status !== "new") {
2788
- await updateAgentContext(agent.id, merged);
2883
+ // Use requestIdleCallback or setTimeout to defer the update, allowing React to render first
2884
+ if (typeof requestIdleCallback !== "undefined") {
2885
+ requestIdleCallback(async () => {
2886
+ await updateAgentContext(agent.id, merged);
2887
+ }, { timeout: 1000 });
2888
+ }
2889
+ else {
2890
+ // Fallback for browsers without requestIdleCallback
2891
+ setTimeout(async () => {
2892
+ await updateAgentContext(agent.id, merged);
2893
+ }, 0);
2894
+ }
2789
2895
  }
2790
2896
  }
2791
2897
  catch (err) {
@@ -3019,7 +3125,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3019
3125
  }
3020
3126
  // Content exists - show dots WITHOUT icon (inline at bottom)
3021
3127
  return (_jsxs("div", { className: "flex gap-3 px-4 pb-4", children: [_jsx("div", { className: "w-7 flex-shrink-0" }), _jsx("div", { className: "min-w-0 flex-1", children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400" })] }) })] }));
3022
- })(), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && agent?.id && activeProfile && (_jsx(AgentDocumentList, { agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), queuedPrompts.length > 0 && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-xs font-semibold text-amber-900", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "space-y-2", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-xs", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[10px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", children: qp.prompt }), qp.createdDate && (_jsx("div", { className: "mt-1.5 text-[10px] text-gray-400", children: formatTime(new Date(qp.createdDate)) }))] }) }) }, qp.id))) })] }) })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
3128
+ })(), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && agent?.id && activeProfile && (_jsx(AgentDocumentList, { agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), !hideContext && agent?.id && (_jsx(AgentEditOperationsPanel, { agentId: agent.id })), queuedPrompts.length > 0 && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-xs font-semibold text-amber-900", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "space-y-2", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-xs", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[10px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", children: qp.prompt }), qp.createdDate && (_jsx("div", { className: "mt-1.5 text-[10px] text-gray-400", children: formatTime(new Date(qp.createdDate)) }))] }) }) }, qp.id))) })] }) })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
3023
3129
  // Placeholder Input (from quick actions)
3024
3130
  // Show buttons when hideBottomControls is true (e.g., splash screen) since normal submit area is hidden
3025
3131
  _jsx(PlaceholderInput, { ref: placeholderInputRef, text: activePlaceholderInput.text, showButtons: hideBottomControls, buttonsClassName: hideBottomControls ? "justify-end" : "", onFilledChange: setAllPlaceholdersFilled, onComplete: (filledText) => {
@@ -3081,7 +3187,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3081
3187
  if (currentHistoryIndex !== -1) {
3082
3188
  setCurrentHistoryIndex(-1);
3083
3189
  }
3084
- }, onKeyDown: handleKeyPress, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-xs", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) })), !hideBottomControls && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-stretch justify-between gap-2", children: [_jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-start gap-2", children: [_jsxs(Tooltip, { delayDuration: 400, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("select", { className: `h-5 rounded border px-1.5 text-[10px] ${mode === "read-only"
3190
+ }, onKeyDown: handleKeyPress, onFocus: () => {
3191
+ shouldMaintainFocusRef.current = true;
3192
+ }, onBlur: () => {
3193
+ shouldMaintainFocusRef.current = false;
3194
+ }, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-xs", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) })), !hideBottomControls && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-stretch justify-between gap-2", children: [_jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-start gap-2", children: [_jsxs(Tooltip, { delayDuration: 400, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("select", { className: `h-5 rounded border px-1.5 text-[10px] ${mode === "read-only"
3085
3195
  ? "border-green-300 bg-green-50 text-green-700"
3086
3196
  : mode === "supervised"
3087
3197
  ? "border-amber-300 bg-amber-50 text-amber-700"
@@ -3198,7 +3308,41 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3198
3308
  (!!prompt &&
3199
3309
  /\{([^}]+)\}|<([^>]+)>/.test(prompt) &&
3200
3310
  !allPlaceholdersFilled) ||
3201
- (!!activePlaceholderInput && !allPlaceholdersFilled)), size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isExecuting ? "Stop" : "Send", "aria-label": isExecuting ? "Stop" : "Send", "data-testid": "agent-send-stop-button", "data-executing": isExecuting ? "true" : "false", children: isExecuting ? (_jsx(Square, { className: "size-3", strokeWidth: 1 })) : (_jsx(Send, { className: "size-3", strokeWidth: 1 })) })] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-gray-500", children: [_jsx(AgentCostDisplay, { totalTokens: liveTotals
3311
+ (!!activePlaceholderInput && !allPlaceholdersFilled)), size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isExecuting ? "Stop" : "Send", "aria-label": isExecuting ? "Stop" : "Send", "data-testid": "agent-send-stop-button", "data-executing": isExecuting ? "true" : "false", children: isExecuting ? (_jsx(Square, { className: "size-3", strokeWidth: 1 })) : (_jsx(Send, { className: "size-3", strokeWidth: 1 })) })] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-gray-500", children: [agent?.id &&
3312
+ (() => {
3313
+ const hasData = contextWindowStatus &&
3314
+ contextWindowStatus.contextWindowTokens;
3315
+ const percentValue = hasData
3316
+ ? typeof contextWindowStatus.contextUsedPercent === "number"
3317
+ ? contextWindowStatus.contextUsedPercent
3318
+ : 0
3319
+ : 0;
3320
+ const pct = hasData ? `${percentValue.toFixed(1)}%` : "—";
3321
+ // Color based on usage level
3322
+ const getContextColor = (percent) => {
3323
+ if (percent < 50)
3324
+ return "#22c55e"; // green-500
3325
+ if (percent < 80)
3326
+ return "#f59e0b"; // amber-500
3327
+ return "#ef4444"; // red-500
3328
+ };
3329
+ const contextColor = hasData
3330
+ ? getContextColor(percentValue)
3331
+ : "#9ca3af"; // gray-400 for no data
3332
+ // SVG circle parameters - radius chosen so circumference ≈ 100
3333
+ const radius = 15.915;
3334
+ // Helper function to format tokens as "k"
3335
+ const formatTokens = (tokens) => {
3336
+ if (tokens >= 1000) {
3337
+ return `${(tokens / 1000).toFixed(1)}k`;
3338
+ }
3339
+ return tokens.toString();
3340
+ };
3341
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "flex cursor-help items-center", children: _jsxs("svg", { className: "h-3 w-3", viewBox: "0 0 36 36", "aria-hidden": "true", children: [_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: "#e5e7eb", strokeWidth: "4" }), hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: `${percentValue} 100`, strokeLinecap: "round", style: {
3342
+ transformOrigin: "center",
3343
+ transform: "rotate(-90deg)",
3344
+ } })), !hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: "0 100", strokeLinecap: "round", opacity: 0.5 }))] }) }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: hasData && contextWindowStatus ? (_jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [contextWindowStatus.model && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", contextWindowStatus.model] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(contextWindowStatus.estimatedInputTokens || 0), " ", "/", " ", formatTokens(contextWindowStatus.contextWindowTokens), " ", "tokens"] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] })) : (_jsx("div", { className: "max-w-[320px] text-xs", children: "Context window usage will appear here when the agent starts processing." })) })] }));
3345
+ })(), agent?.compressionMarkerIndex != null && (_jsxs(Popover, { open: showCompressionPopover, onOpenChange: setShowCompressionPopover, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "cursor-pointer rounded border border-blue-200 bg-blue-50 px-2 py-0.5 text-[10px] text-blue-700 transition-colors hover:bg-blue-100", onClick: () => setShowCompressionPopover(!showCompressionPopover), children: "Compressed" }) }), _jsx(PopoverContent, { className: "w-96 p-4", align: "start", side: "top", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Conversation Compressed" }), _jsxs("p", { className: "mt-1 text-xs text-gray-600", children: ["First ", agent.compressionMarkerIndex, " messages have been summarized to reduce context usage."] })] }), agent.compressedSummary && (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "text-xs font-medium text-gray-700", children: "Summary:" }), _jsx("div", { className: "max-h-64 overflow-y-auto rounded border border-gray-200 bg-gray-50 p-3 text-xs whitespace-pre-wrap text-gray-700", children: agent.compressedSummary })] }))] }) })] })), _jsx(AgentCostDisplay, { totalTokens: liveTotals
3202
3346
  ? {
3203
3347
  input: liveTotals.input,
3204
3348
  output: liveTotals.output,
@@ -3210,29 +3354,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3210
3354
  cacheWriteCost: liveTotals.cacheWriteCost ?? 0,
3211
3355
  totalCost: liveTotals.totalCost,
3212
3356
  }
3213
- : totalTokens, costLimit: effectiveCostLimit }), (() => {
3214
- try {
3215
- const s = window.__agentContextWindowStatus;
3216
- if (!s || !s.contextWindowTokens)
3217
- return null;
3218
- const pct = typeof s.contextUsedPercent === "number"
3219
- ? `${s.contextUsedPercent.toFixed(1)}%`
3220
- : undefined;
3221
- // Helper function to format tokens as "k"
3222
- const formatTokens = (tokens) => {
3223
- if (tokens >= 1000) {
3224
- return `${(tokens / 1000).toFixed(1)}k`;
3225
- }
3226
- return tokens.toString();
3227
- };
3228
- if (!pct)
3229
- return null;
3230
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "cursor-help rounded border border-gray-200 bg-gray-50 px-2 py-0.5", children: ["Context: ", pct] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", s.model, s.normalizedModel && ` (${s.normalizedModel})`] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(s.estimatedInputTokens || 0), " /", " ", formatTokens(s.contextWindowTokens), " tokens"] }), typeof s.maxCompletionTokens === "number" && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Max completion:" }), " ", formatTokens(s.maxCompletionTokens), " tokens"] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] }) })] }));
3231
- }
3232
- catch {
3233
- return null;
3234
- }
3235
- })(), activeProfile && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex items-center gap-1 text-gray-400 hover:text-gray-600", onClick: async () => {
3357
+ : totalTokens, costLimit: effectiveCostLimit }), activeProfile && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex items-center gap-1 text-gray-400 hover:text-gray-600", onClick: async () => {
3236
3358
  if (!editContext || !activeProfile?.id)
3237
3359
  return;
3238
3360
  // Load the profile item using editContext