@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.
- package/README.md +34 -34
- package/dist/components/ui/dialog.js +2 -2
- package/dist/components/ui/dialog.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +165 -43
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +3 -3
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +175 -37
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/EditOperationsPanel.d.ts +5 -0
- package/dist/editor/ai/EditOperationsPanel.js +64 -0
- package/dist/editor/ai/EditOperationsPanel.js.map +1 -0
- package/dist/editor/client/EditorShell.js +109 -35
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +4 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/operations.d.ts +3 -1
- package/dist/editor/client/operations.js +154 -52
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +2 -2
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/commands/itemCommands.js +25 -25
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/commands/undo.d.ts +2 -2
- package/dist/editor/commands/undo.js +4 -2
- package/dist/editor/commands/undo.js.map +1 -1
- package/dist/editor/field-types/NameValueListEditor.js +14 -2
- package/dist/editor/field-types/NameValueListEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +15 -3
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +65 -2
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/menubar/ApproveAndPublish.js +1 -1
- package/dist/editor/menubar/WorkflowButton.js +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +50 -13
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +18 -4
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js +18 -39
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +34 -131
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +17 -0
- package/dist/editor/services/agentService.js +8 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/contextService.js +8 -27
- package/dist/editor/services/contextService.js.map +1 -1
- package/dist/editor/services/editService.d.ts +5 -2
- package/dist/editor/services/editService.js +19 -5
- package/dist/editor/services/editService.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +4 -1
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/EditHistory.js +30 -55
- package/dist/editor/sidebar/EditHistory.js.map +1 -1
- package/dist/editor/sidebar/OperationItem.d.ts +10 -0
- package/dist/editor/sidebar/OperationItem.js +102 -0
- package/dist/editor/sidebar/OperationItem.js.map +1 -0
- package/dist/editor/ui/DragPreview.d.ts +5 -0
- package/dist/editor/ui/DragPreview.js +41 -3
- package/dist/editor/ui/DragPreview.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +38 -9
- package/dist/types.d.ts +24 -2
- 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-
|
|
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-
|
|
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":"AAAA,YAAY,CAAC;;AAGb,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC,SAAS,MAAM,CAAC,EACd,GAAG,KAAK,EAC0C;IAClD,OAAO,KAAC,eAAe,CAAC,IAAI,iBAAW,QAAQ,KAAK,KAAK,GAAI,CAAC;AAChE,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,GAAG,KAAK,EAC6C;IACrD,OAAO,KAAC,eAAe,CAAC,OAAO,iBAAW,gBAAgB,KAAK,KAAK,GAAI,CAAC;AAC3E,CAAC;AAED,SAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EAC4C;IACpD,OAAO,KAAC,eAAe,CAAC,MAAM,iBAAW,eAAe,KAAK,KAAK,GAAI,CAAC;AACzE,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EAC2C;IACnD,OAAO,KAAC,eAAe,CAAC,KAAK,iBAAW,cAAc,KAAK,KAAK,GAAI,CAAC;AACvE,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,SAAS,EACT,GAAG,KAAK,EAC6C;IACrD,OAAO,CACL,KAAC,eAAe,CAAC,OAAO,iBACZ,gBAAgB,EAC1B,SAAS,EAAE,EAAE,CACX,
|
|
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) &&
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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: [
|
|
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
|