@alpaca-editor/core 1.0.4026 → 1.0.4030
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ActionButton.js +2 -2
- package/dist/components/ActionButton.js.map +1 -1
- package/dist/components/SimpleLanguageSelector.js +3 -1
- package/dist/components/SimpleLanguageSelector.js.map +1 -1
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/config/config.js +1 -1
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +1 -1
- package/dist/editor/ContextMenu.js +0 -1
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/Editor.js +9 -3
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FieldListField.js +16 -24
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ImageEditButton.js +1 -1
- package/dist/editor/ImageEditButton.js.map +1 -1
- package/dist/editor/ImageEditor.js +1 -1
- package/dist/editor/ImageEditor.js.map +1 -1
- package/dist/editor/MainLayout.js +2 -2
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/Terminal.js +1 -1
- package/dist/editor/Terminal.js.map +1 -1
- package/dist/editor/Titlebar.js +0 -1
- package/dist/editor/Titlebar.js.map +1 -1
- package/dist/editor/ai/AgentCostDisplay.d.ts +26 -0
- package/dist/editor/ai/AgentCostDisplay.js +65 -0
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -0
- package/dist/editor/ai/Agents.js +83 -29
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiPromptPopover.d.ts +7 -0
- package/dist/editor/ai/AiPromptPopover.js +111 -0
- package/dist/editor/ai/AiPromptPopover.js.map +1 -0
- package/dist/editor/ai/AiResponseMessage.d.ts +1 -0
- package/dist/editor/ai/AiResponseMessage.js +104 -18
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/AiTerminal.d.ts +18 -2
- package/dist/editor/ai/AiTerminal.js +423 -63
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/ai/EditorAiTerminal.d.ts +2 -1
- package/dist/editor/ai/EditorAiTerminal.js +2 -2
- package/dist/editor/ai/EditorAiTerminal.js.map +1 -1
- package/dist/editor/ai/editorAiContext.d.ts +0 -1
- package/dist/editor/ai/editorAiContext.js +0 -2
- package/dist/editor/ai/editorAiContext.js.map +1 -1
- package/dist/editor/client/EditorClient.d.ts +3 -2
- package/dist/editor/client/EditorClient.js +326 -68
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +6 -4
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/fieldModificationStore.d.ts +19 -0
- package/dist/editor/client/fieldModificationStore.js +125 -0
- package/dist/editor/client/fieldModificationStore.js.map +1 -0
- package/dist/editor/client/itemsRepository.d.ts +1 -1
- package/dist/editor/client/itemsRepository.js +38 -28
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/operations.d.ts +1 -0
- package/dist/editor/client/operations.js +39 -31
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +5 -3
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/commands/itemCommands.js.map +1 -1
- package/dist/editor/component-designer/aiContext.js +0 -2
- package/dist/editor/component-designer/aiContext.js.map +1 -1
- package/dist/editor/field-types/DropLinkEditor.js +1 -1
- package/dist/editor/field-types/DropLinkEditor.js.map +1 -1
- package/dist/editor/field-types/MultiLineText.js +5 -7
- package/dist/editor/field-types/MultiLineText.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +5 -7
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +5 -7
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/hooks/useEditorSettings.d.ts +17 -0
- package/dist/editor/hooks/useEditorSettings.js +61 -0
- package/dist/editor/hooks/useEditorSettings.js.map +1 -0
- package/dist/editor/menubar/ItemActionsMenu.js +2 -2
- package/dist/editor/menubar/ItemActionsMenu.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +1 -1
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/InsertControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/FieldEditedIndicators.js +4 -3
- package/dist/editor/page-editor-chrome/FieldEditedIndicators.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +9 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js +0 -1
- package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +1 -1
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +9 -8
- package/dist/editor/page-viewer/PageViewer.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +7 -1
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/page-viewer/pageViewContext.js +40 -6
- package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
- package/dist/editor/reviews/Comment.js +7 -6
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +84 -12
- package/dist/editor/services/agentService.js +256 -15
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +18 -3
- package/dist/editor/services/aiService.js +5 -3
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/contextService.js +0 -1
- package/dist/editor/services/contextService.js.map +1 -1
- package/dist/editor/services/systemService.d.ts +2 -1
- package/dist/editor/services/systemService.js +3 -0
- package/dist/editor/services/systemService.js.map +1 -1
- package/dist/editor/sidebar/ComponentPalette.js +1 -1
- package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
- package/dist/editor/sidebar/EditHistory.js +2 -2
- package/dist/editor/sidebar/EditHistory.js.map +1 -1
- package/dist/editor/sidebar/GraphQL.d.ts +1 -0
- package/dist/editor/sidebar/GraphQL.js +8 -2
- package/dist/editor/sidebar/GraphQL.js.map +1 -1
- package/dist/editor/sidebar/MainContentTree.js +1 -1
- package/dist/editor/sidebar/MainContentTree.js.map +1 -1
- package/dist/editor/sidebar/SEOInfo.js +1 -1
- package/dist/editor/sidebar/SEOInfo.js.map +1 -1
- package/dist/editor/sidebar/ViewSelector.d.ts +4 -1
- package/dist/editor/sidebar/ViewSelector.js +64 -48
- package/dist/editor/sidebar/ViewSelector.js.map +1 -1
- package/dist/editor/ui/PerfectTree.js +2 -11
- package/dist/editor/ui/PerfectTree.js.map +1 -1
- package/dist/editor/ui/SimpleIconButton.d.ts +2 -0
- package/dist/editor/ui/SimpleIconButton.js +8 -4
- package/dist/editor/ui/SimpleIconButton.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.js +1 -1
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/page-wizard/steps/StructureStep.js +1 -1
- package/dist/page-wizard/steps/StructureStep.js.map +1 -1
- package/dist/page-wizard/steps/TranslateStep.js +233 -18
- package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/RecentPages.js +1 -13
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/splash-screen/SplashScreen.js +1 -1
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +88 -3
- package/dist/types.d.ts +6 -0
- package/package.json +2 -2
- package/src/components/ActionButton.tsx +3 -2
- package/src/components/SimpleLanguageSelector.tsx +6 -1
- package/src/config/config.tsx +1 -1
- package/src/config/types.ts +1 -1
- package/src/editor/ContextMenu.tsx +0 -3
- package/src/editor/Editor.tsx +11 -3
- package/src/editor/FieldListField.tsx +22 -31
- package/src/editor/ImageEditButton.tsx +1 -0
- package/src/editor/ImageEditor.tsx +1 -0
- package/src/editor/MainLayout.tsx +2 -2
- package/src/editor/Terminal.tsx +1 -1
- package/src/editor/Titlebar.tsx +0 -2
- package/src/editor/ai/AgentCostDisplay.tsx +237 -0
- package/src/editor/ai/Agents.tsx +147 -65
- package/src/editor/ai/AiPromptPopover.tsx +209 -0
- package/src/editor/ai/AiResponseMessage.tsx +232 -45
- package/src/editor/ai/AiTerminal.tsx +559 -88
- package/src/editor/ai/EditorAiTerminal.tsx +3 -0
- package/src/editor/ai/editorAiContext.ts +0 -3
- package/src/editor/client/EditorClient.tsx +409 -117
- package/src/editor/client/editContext.ts +7 -5
- package/src/editor/client/fieldModificationStore.ts +196 -0
- package/src/editor/client/itemsRepository.ts +41 -31
- package/src/editor/client/operations.ts +95 -76
- package/src/editor/commands/componentCommands.tsx +9 -3
- package/src/editor/commands/itemCommands.tsx +0 -1
- package/src/editor/component-designer/aiContext.ts +0 -2
- package/src/editor/field-types/DropLinkEditor.tsx +1 -1
- package/src/editor/field-types/MultiLineText.tsx +9 -9
- package/src/editor/field-types/RichTextEditorComponent.tsx +8 -8
- package/src/editor/field-types/SingleLineText.tsx +9 -9
- package/src/editor/hooks/useEditorSettings.ts +68 -0
- package/src/editor/menubar/ItemActionsMenu.tsx +3 -2
- package/src/editor/menubar/PageSelector.tsx +1 -1
- package/src/editor/menubar/toolbar-sections/EditControls.tsx +1 -0
- package/src/editor/menubar/toolbar-sections/InsertControls.tsx +1 -0
- package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +2 -0
- package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +2 -0
- package/src/editor/page-editor-chrome/FieldEditedIndicators.tsx +4 -3
- package/src/editor/page-editor-chrome/FrameMenu.tsx +10 -1
- package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +0 -1
- package/src/editor/page-viewer/EditorForm.tsx +1 -0
- package/src/editor/page-viewer/PageViewer.tsx +9 -8
- package/src/editor/page-viewer/PageViewerFrame.tsx +7 -1
- package/src/editor/page-viewer/pageViewContext.ts +40 -5
- package/src/editor/reviews/Comment.tsx +7 -7
- package/src/editor/services/agentService.ts +405 -31
- package/src/editor/services/aiService.ts +24 -5
- package/src/editor/services/contextService.ts +0 -1
- package/src/editor/services/systemService.ts +7 -1
- package/src/editor/sidebar/ComponentPalette.tsx +4 -1
- package/src/editor/sidebar/EditHistory.tsx +2 -0
- package/src/editor/sidebar/GraphQL.tsx +19 -7
- package/src/editor/sidebar/MainContentTree.tsx +1 -1
- package/src/editor/sidebar/SEOInfo.tsx +1 -1
- package/src/editor/sidebar/ViewSelector.tsx +80 -64
- package/src/editor/ui/PerfectTree.tsx +2 -18
- package/src/editor/ui/SimpleIconButton.tsx +56 -38
- package/src/index.ts +2 -0
- package/src/page-wizard/steps/CollectStep.tsx +0 -2
- package/src/page-wizard/steps/StructureStep.tsx +3 -0
- package/src/page-wizard/steps/TranslateStep.tsx +473 -62
- package/src/revision.ts +2 -2
- package/src/splash-screen/RecentPages.tsx +0 -14
- package/src/splash-screen/SplashScreen.tsx +3 -2
- package/src/types.ts +7 -0
- package/dist/editor/ai/AiPopup.d.ts +0 -10
- package/dist/editor/ai/AiPopup.js +0 -23
- package/dist/editor/ai/AiPopup.js.map +0 -1
- package/dist/editor/ai/AiToolCall.d.ts +0 -5
- package/dist/editor/ai/AiToolCall.js +0 -28
- package/dist/editor/ai/AiToolCall.js.map +0 -1
- package/src/editor/ai/AiPopup.tsx +0 -59
- package/src/editor/ai/AiToolCall.tsx +0 -71
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import {
|
|
5
|
+
Popover,
|
|
6
|
+
PopoverContent,
|
|
7
|
+
PopoverTrigger,
|
|
8
|
+
} from "../../components/ui/popover";
|
|
9
|
+
import { useEditorSettings } from "../hooks/useEditorSettings";
|
|
10
|
+
|
|
11
|
+
import { ExecutePromptResponse } from "../services/aiService";
|
|
12
|
+
|
|
13
|
+
interface AgentCostDisplayProps {
|
|
14
|
+
/** Optional className for styling */
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Current response data with token usage */
|
|
17
|
+
response?: {
|
|
18
|
+
numInputTokens: number;
|
|
19
|
+
numOutputTokens: number;
|
|
20
|
+
numCachedTokens: number;
|
|
21
|
+
totalCost?: number;
|
|
22
|
+
inputCost?: number;
|
|
23
|
+
outputCost?: number;
|
|
24
|
+
cachedCost?: number;
|
|
25
|
+
} | null;
|
|
26
|
+
/** Cumulative token usage across all messages in the session */
|
|
27
|
+
totalTokens?: {
|
|
28
|
+
input: number;
|
|
29
|
+
output: number;
|
|
30
|
+
cached: number;
|
|
31
|
+
totalCost: number;
|
|
32
|
+
inputCost: number;
|
|
33
|
+
outputCost: number;
|
|
34
|
+
cachedCost: number;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function AgentCostDisplay({
|
|
39
|
+
className = "",
|
|
40
|
+
response,
|
|
41
|
+
totalTokens,
|
|
42
|
+
}: AgentCostDisplayProps) {
|
|
43
|
+
const [showCostPopover, setShowCostPopover] = useState(false);
|
|
44
|
+
const costPopoverRef = useRef<HTMLDivElement>(null);
|
|
45
|
+
const editorSettings = useEditorSettings();
|
|
46
|
+
const currency = editorSettings?.currency || "USD";
|
|
47
|
+
|
|
48
|
+
// Handle click outside for cost popover
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
function handleClickOutside(event: MouseEvent) {
|
|
51
|
+
if (
|
|
52
|
+
costPopoverRef.current &&
|
|
53
|
+
!costPopoverRef.current.contains(event.target as Node)
|
|
54
|
+
) {
|
|
55
|
+
setShowCostPopover(false);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (showCostPopover) {
|
|
60
|
+
document.addEventListener("click", handleClickOutside);
|
|
61
|
+
return () => {
|
|
62
|
+
document.removeEventListener("click", handleClickOutside);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}, [showCostPopover]);
|
|
66
|
+
|
|
67
|
+
// Calculate estimated cost based on typical pricing (rough estimates)
|
|
68
|
+
// Claude 3.5 Sonnet pricing: ~$3/MTok input, ~$15/MTok output
|
|
69
|
+
const calculateEstimatedCost = (
|
|
70
|
+
inputTokens: number,
|
|
71
|
+
outputTokens: number,
|
|
72
|
+
cachedTokens: number,
|
|
73
|
+
) => {
|
|
74
|
+
const inputCost = (inputTokens / 1000000) * 3; // $3 per million tokens
|
|
75
|
+
const outputCost = (outputTokens / 1000000) * 15; // $15 per million tokens
|
|
76
|
+
const cachedCost = (cachedTokens / 1000000) * 0.3; // Cached tokens are typically much cheaper
|
|
77
|
+
return {
|
|
78
|
+
inputCost,
|
|
79
|
+
outputCost,
|
|
80
|
+
cachedCost,
|
|
81
|
+
totalCost: inputCost + outputCost + cachedCost,
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Use actual cost data if available, otherwise calculate estimates
|
|
86
|
+
const currentCost = response
|
|
87
|
+
? response.totalCost !== undefined
|
|
88
|
+
? {
|
|
89
|
+
inputCost: response.inputCost ?? 0,
|
|
90
|
+
outputCost: response.outputCost ?? 0,
|
|
91
|
+
cachedCost: response.cachedCost ?? 0,
|
|
92
|
+
totalCost: response.totalCost,
|
|
93
|
+
}
|
|
94
|
+
: calculateEstimatedCost(
|
|
95
|
+
response.numInputTokens,
|
|
96
|
+
response.numOutputTokens,
|
|
97
|
+
response.numCachedTokens,
|
|
98
|
+
)
|
|
99
|
+
: null;
|
|
100
|
+
|
|
101
|
+
const displayTotalCost =
|
|
102
|
+
totalTokens?.totalCost ?? currentCost?.totalCost ?? 0;
|
|
103
|
+
const hasTokenData =
|
|
104
|
+
response &&
|
|
105
|
+
(response.numInputTokens > 0 ||
|
|
106
|
+
response.numOutputTokens > 0 ||
|
|
107
|
+
response.numCachedTokens > 0);
|
|
108
|
+
const hasTotalData =
|
|
109
|
+
totalTokens &&
|
|
110
|
+
(totalTokens.input > 0 || totalTokens.output > 0 || totalTokens.cached > 0);
|
|
111
|
+
const hasCostData =
|
|
112
|
+
(response && response.totalCost && response.totalCost > 0) ||
|
|
113
|
+
(totalTokens && totalTokens.totalCost && totalTokens.totalCost > 0);
|
|
114
|
+
|
|
115
|
+
if (!hasTokenData && !hasTotalData && !hasCostData) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div className={`relative ${className}`} ref={costPopoverRef}>
|
|
121
|
+
<Popover open={showCostPopover} onOpenChange={setShowCostPopover}>
|
|
122
|
+
<PopoverTrigger asChild>
|
|
123
|
+
<div
|
|
124
|
+
className="cursor-pointer text-right text-gray-400 hover:text-gray-600"
|
|
125
|
+
style={{ fontSize: "10px" }}
|
|
126
|
+
onClick={() => setShowCostPopover(!showCostPopover)}
|
|
127
|
+
>
|
|
128
|
+
Total Cost: {displayTotalCost.toFixed(2)} {currency}
|
|
129
|
+
</div>
|
|
130
|
+
</PopoverTrigger>
|
|
131
|
+
<PopoverContent className="w-80 p-4" align="end" side="bottom">
|
|
132
|
+
<div className="space-y-4">
|
|
133
|
+
<div className="border-b pb-2">
|
|
134
|
+
<h4 className="text-sm font-semibold">Cost Breakdown</h4>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div className="space-y-3">
|
|
138
|
+
{/* Session Cost Breakdown */}
|
|
139
|
+
{(hasTotalData || hasTokenData) && (
|
|
140
|
+
<>
|
|
141
|
+
<div className="flex items-center justify-between">
|
|
142
|
+
<span className="text-sm font-semibold text-gray-600">
|
|
143
|
+
Session Cost:
|
|
144
|
+
</span>
|
|
145
|
+
<span className="text-sm font-semibold">
|
|
146
|
+
{displayTotalCost.toFixed(2)} {currency}
|
|
147
|
+
</span>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div className="space-y-2 border-t pt-2">
|
|
151
|
+
{hasTotalData ? (
|
|
152
|
+
<>
|
|
153
|
+
<div className="flex items-center justify-between">
|
|
154
|
+
<span className="text-xs text-gray-500">
|
|
155
|
+
Input tokens:
|
|
156
|
+
</span>
|
|
157
|
+
<span className="text-xs">
|
|
158
|
+
{totalTokens.input.toLocaleString()} (
|
|
159
|
+
{totalTokens.inputCost.toFixed(2)} {currency})
|
|
160
|
+
</span>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<div className="flex items-center justify-between">
|
|
164
|
+
<span className="text-xs text-gray-500">
|
|
165
|
+
Output tokens:
|
|
166
|
+
</span>
|
|
167
|
+
<span className="text-xs">
|
|
168
|
+
{totalTokens.output.toLocaleString()} (
|
|
169
|
+
{totalTokens.outputCost.toFixed(2)} {currency})
|
|
170
|
+
</span>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
{totalTokens.cached > 0 && (
|
|
174
|
+
<div className="flex items-center justify-between">
|
|
175
|
+
<span className="text-xs text-gray-500">
|
|
176
|
+
Cached tokens:
|
|
177
|
+
</span>
|
|
178
|
+
<span className="text-xs">
|
|
179
|
+
{totalTokens.cached.toLocaleString()} (
|
|
180
|
+
{totalTokens.cachedCost.toFixed(2)} {currency})
|
|
181
|
+
</span>
|
|
182
|
+
</div>
|
|
183
|
+
)}
|
|
184
|
+
</>
|
|
185
|
+
) : (
|
|
186
|
+
response &&
|
|
187
|
+
currentCost && (
|
|
188
|
+
<>
|
|
189
|
+
<div className="flex items-center justify-between">
|
|
190
|
+
<span className="text-xs text-gray-500">
|
|
191
|
+
Input tokens:
|
|
192
|
+
</span>
|
|
193
|
+
<span className="text-xs">
|
|
194
|
+
{response.numInputTokens.toLocaleString()}(
|
|
195
|
+
{currentCost.inputCost.toFixed(2)} {currency})
|
|
196
|
+
</span>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<div className="flex items-center justify-between">
|
|
200
|
+
<span className="text-xs text-gray-500">
|
|
201
|
+
Output tokens:
|
|
202
|
+
</span>
|
|
203
|
+
<span className="text-xs">
|
|
204
|
+
{response.numOutputTokens.toLocaleString()}(
|
|
205
|
+
{currentCost.outputCost.toFixed(2)} {currency})
|
|
206
|
+
</span>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
{response.numCachedTokens > 0 && (
|
|
210
|
+
<div className="flex items-center justify-between">
|
|
211
|
+
<span className="text-xs text-gray-500">
|
|
212
|
+
Cached tokens:
|
|
213
|
+
</span>
|
|
214
|
+
<span className="text-xs">
|
|
215
|
+
{response.numCachedTokens.toLocaleString()}(
|
|
216
|
+
{currentCost.cachedCost.toFixed(2)} {currency})
|
|
217
|
+
</span>
|
|
218
|
+
</div>
|
|
219
|
+
)}
|
|
220
|
+
|
|
221
|
+
<div className="mt-2 text-xs text-gray-400">
|
|
222
|
+
* Estimated costs based on typical Claude 3.5
|
|
223
|
+
pricing
|
|
224
|
+
</div>
|
|
225
|
+
</>
|
|
226
|
+
)
|
|
227
|
+
)}
|
|
228
|
+
</div>
|
|
229
|
+
</>
|
|
230
|
+
)}
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
</PopoverContent>
|
|
234
|
+
</Popover>
|
|
235
|
+
</div>
|
|
236
|
+
);
|
|
237
|
+
}
|
package/src/editor/ai/Agents.tsx
CHANGED
|
@@ -4,7 +4,13 @@ import { EditorAiTerminal } from "./EditorAiTerminal";
|
|
|
4
4
|
import { SimpleIconButton } from "../ui/SimpleIconButton";
|
|
5
5
|
import { Plus, X, History } from "lucide-react";
|
|
6
6
|
import { cn } from "../../lib/utils";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
getAgents,
|
|
9
|
+
getAgent,
|
|
10
|
+
getChatHistory,
|
|
11
|
+
AgentChat,
|
|
12
|
+
AgentChatMessage,
|
|
13
|
+
} from "../services/agentService";
|
|
8
14
|
import { Message } from "./AiTerminal";
|
|
9
15
|
import {
|
|
10
16
|
Popover,
|
|
@@ -12,6 +18,8 @@ import {
|
|
|
12
18
|
PopoverTrigger,
|
|
13
19
|
} from "../../components/ui/popover";
|
|
14
20
|
import { Button } from "../../components/ui/button";
|
|
21
|
+
import { useEditContext } from "../client/editContext";
|
|
22
|
+
import { AiContext } from "./AiTerminal";
|
|
15
23
|
|
|
16
24
|
interface TerminalInstance {
|
|
17
25
|
id: string;
|
|
@@ -21,32 +29,41 @@ interface TerminalInstance {
|
|
|
21
29
|
messages?: Message[];
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
function convertAgentMessagesToTerminalMessages(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
function convertAgentMessagesToTerminalMessages(
|
|
33
|
+
agentMessages: AgentChatMessage[],
|
|
34
|
+
): Message[] {
|
|
35
|
+
return (
|
|
36
|
+
agentMessages
|
|
37
|
+
// Keep all messages including tool results for complete conversation context
|
|
38
|
+
.map((msg) => ({
|
|
39
|
+
id: msg.id,
|
|
40
|
+
content: msg.content,
|
|
41
|
+
name: msg.name,
|
|
42
|
+
role: msg.role,
|
|
43
|
+
tool_calls:
|
|
44
|
+
msg.toolCalls?.map((toolCall: any) => ({
|
|
45
|
+
id: toolCall.toolCallId,
|
|
46
|
+
displayName: toolCall.functionName,
|
|
47
|
+
function: {
|
|
48
|
+
name: toolCall.functionName,
|
|
49
|
+
arguments: toolCall.functionArguments || "",
|
|
50
|
+
result: toolCall.functionResult,
|
|
51
|
+
},
|
|
52
|
+
})) || [],
|
|
53
|
+
tool_call_id: msg.toolCallId,
|
|
54
|
+
}))
|
|
55
|
+
);
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
function formatDateToLocalTime(dateString: string): string {
|
|
45
59
|
// Ensure the date string is treated as UTC if it doesn't have timezone info
|
|
46
|
-
const normalizedDate =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
const normalizedDate =
|
|
61
|
+
dateString.includes("Z") ||
|
|
62
|
+
dateString.includes("+") ||
|
|
63
|
+
dateString.includes("-", 19)
|
|
64
|
+
? dateString
|
|
65
|
+
: dateString + "Z";
|
|
66
|
+
|
|
50
67
|
return new Date(normalizedDate).toLocaleString();
|
|
51
68
|
}
|
|
52
69
|
|
|
@@ -63,53 +80,80 @@ export function Agents({
|
|
|
63
80
|
const [historyPopoverOpen, setHistoryPopoverOpen] = useState(false);
|
|
64
81
|
const [loadingAgents, setLoadingAgents] = useState(true);
|
|
65
82
|
const nextTerminalNumber = useRef(1);
|
|
83
|
+
const editContext = useEditContext();
|
|
84
|
+
|
|
85
|
+
// Create AI context for service calls
|
|
86
|
+
const createAgentContext = (): AiContext => ({
|
|
87
|
+
promptData: {
|
|
88
|
+
itemid: editContext?.currentItemDescriptor?.id,
|
|
89
|
+
language: editContext?.currentItemDescriptor?.language || "en",
|
|
90
|
+
version: editContext?.currentItemDescriptor?.version || 1,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
66
93
|
|
|
67
94
|
// Load agents from backend on mount
|
|
68
95
|
useEffect(() => {
|
|
69
96
|
loadAgentsFromBackend();
|
|
70
97
|
}, []);
|
|
71
98
|
|
|
72
|
-
|
|
73
|
-
|
|
74
99
|
const loadAgentsFromBackend = async () => {
|
|
75
100
|
try {
|
|
76
101
|
setLoadingAgents(true);
|
|
77
|
-
|
|
102
|
+
const context = createAgentContext();
|
|
103
|
+
|
|
78
104
|
// Load active agents
|
|
79
|
-
const activeAgentsResult = await getAgents("active");
|
|
80
|
-
|
|
105
|
+
const activeAgentsResult = await getAgents(context, "active");
|
|
106
|
+
|
|
81
107
|
// Load inactive agents for history
|
|
82
|
-
const inactiveAgentsResult = await getChatHistory(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
108
|
+
const inactiveAgentsResult = await getChatHistory(
|
|
109
|
+
context,
|
|
110
|
+
"completed",
|
|
111
|
+
20,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (activeAgentsResult && Array.isArray(activeAgentsResult)) {
|
|
115
|
+
const activeAgents = activeAgentsResult;
|
|
116
|
+
|
|
87
117
|
// Create terminals for active agents
|
|
88
118
|
const activeTerminals: TerminalInstance[] = await Promise.all(
|
|
89
|
-
activeAgents.map(async (agent, index) => {
|
|
119
|
+
activeAgents.map(async (agent: any, index: number) => {
|
|
90
120
|
// Load messages for each active agent
|
|
91
121
|
const agentWithMessages = await loadAgentMessages(agent.id);
|
|
92
|
-
|
|
122
|
+
|
|
93
123
|
return {
|
|
94
124
|
id: `agent-${agent.id}`,
|
|
95
|
-
title: agent.name ||
|
|
125
|
+
title: agent.name || "New Agent",
|
|
96
126
|
agentId: agent.id,
|
|
97
|
-
options:
|
|
98
|
-
|
|
127
|
+
options: {
|
|
128
|
+
...initialOptions,
|
|
129
|
+
// Pass cost information from loaded agent
|
|
130
|
+
totalCost: agentWithMessages?.totalCost,
|
|
131
|
+
totalInputTokenCost: agentWithMessages?.totalInputTokenCost,
|
|
132
|
+
totalOutputTokenCost: agentWithMessages?.totalOutputTokenCost,
|
|
133
|
+
totalCachedTokenCost:
|
|
134
|
+
agentWithMessages?.totalCachedInputTokenCost,
|
|
135
|
+
totalInputTokens: agentWithMessages?.totalInputTokens,
|
|
136
|
+
totalOutputTokens: agentWithMessages?.totalOutputTokens,
|
|
137
|
+
totalCachedTokens: agentWithMessages?.totalCachedInputTokens,
|
|
138
|
+
},
|
|
139
|
+
messages: agentWithMessages?.messages
|
|
140
|
+
? convertAgentMessagesToTerminalMessages(
|
|
141
|
+
agentWithMessages.messages,
|
|
142
|
+
)
|
|
143
|
+
: [],
|
|
99
144
|
};
|
|
100
|
-
})
|
|
145
|
+
}),
|
|
101
146
|
);
|
|
102
|
-
|
|
103
|
-
setTerminals(activeTerminals);
|
|
104
|
-
|
|
147
|
+
|
|
105
148
|
// Set the first active terminal as active, or create a new one if none exist
|
|
106
149
|
if (activeTerminals.length > 0) {
|
|
150
|
+
setTerminals(activeTerminals);
|
|
107
151
|
setActiveTerminalId(activeTerminals[0]!.id);
|
|
108
152
|
} else {
|
|
109
153
|
// Create a default terminal if no active agents
|
|
110
154
|
const defaultTerminal: TerminalInstance = {
|
|
111
155
|
id: `terminal-${nextTerminalNumber.current}`,
|
|
112
|
-
title:
|
|
156
|
+
title: "New Agent",
|
|
113
157
|
options: initialOptions,
|
|
114
158
|
};
|
|
115
159
|
setTerminals([defaultTerminal]);
|
|
@@ -117,11 +161,10 @@ export function Agents({
|
|
|
117
161
|
nextTerminalNumber.current++;
|
|
118
162
|
}
|
|
119
163
|
}
|
|
120
|
-
|
|
121
|
-
if (inactiveAgentsResult
|
|
122
|
-
setInactiveAgents(inactiveAgentsResult
|
|
164
|
+
|
|
165
|
+
if (inactiveAgentsResult && Array.isArray(inactiveAgentsResult)) {
|
|
166
|
+
setInactiveAgents(inactiveAgentsResult);
|
|
123
167
|
}
|
|
124
|
-
|
|
125
168
|
} catch (error) {
|
|
126
169
|
console.error("Failed to load agents:", error);
|
|
127
170
|
// Create a default terminal on error
|
|
@@ -138,11 +181,14 @@ export function Agents({
|
|
|
138
181
|
}
|
|
139
182
|
};
|
|
140
183
|
|
|
141
|
-
const loadAgentMessages = async (
|
|
184
|
+
const loadAgentMessages = async (
|
|
185
|
+
agentId: string,
|
|
186
|
+
): Promise<AgentChat | null> => {
|
|
142
187
|
try {
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
188
|
+
const context = createAgentContext();
|
|
189
|
+
const result = await getAgent(agentId, context);
|
|
190
|
+
if (result && result.id) {
|
|
191
|
+
return result;
|
|
146
192
|
}
|
|
147
193
|
} catch (error) {
|
|
148
194
|
console.error(`Failed to load messages for agent ${agentId}:`, error);
|
|
@@ -161,6 +207,17 @@ export function Agents({
|
|
|
161
207
|
nextTerminalNumber.current++;
|
|
162
208
|
};
|
|
163
209
|
|
|
210
|
+
const createNewAgent = (options: AiTerminalOptions) => {
|
|
211
|
+
const newTerminal: TerminalInstance = {
|
|
212
|
+
id: `terminal-${nextTerminalNumber.current}`,
|
|
213
|
+
title: `Agent ${nextTerminalNumber.current}`,
|
|
214
|
+
options: options,
|
|
215
|
+
};
|
|
216
|
+
setTerminals((prev) => [...prev, newTerminal]);
|
|
217
|
+
setActiveTerminalId(newTerminal.id);
|
|
218
|
+
nextTerminalNumber.current++;
|
|
219
|
+
};
|
|
220
|
+
|
|
164
221
|
const closeTerminal = (terminalId: string) => {
|
|
165
222
|
if (terminals.length <= 1) {
|
|
166
223
|
// Don't close the last terminal
|
|
@@ -181,8 +238,8 @@ export function Agents({
|
|
|
181
238
|
|
|
182
239
|
const openAgentFromHistory = async (agent: AgentChat) => {
|
|
183
240
|
// Check if this agent is already open as a terminal
|
|
184
|
-
const existingTerminal = terminals.find(t => t.agentId === agent.id);
|
|
185
|
-
|
|
241
|
+
const existingTerminal = terminals.find((t) => t.agentId === agent.id);
|
|
242
|
+
|
|
186
243
|
if (existingTerminal) {
|
|
187
244
|
// Switch to existing terminal
|
|
188
245
|
setActiveTerminalId(existingTerminal.id);
|
|
@@ -192,14 +249,26 @@ export function Agents({
|
|
|
192
249
|
|
|
193
250
|
// Load the agent with messages
|
|
194
251
|
const agentWithMessages = await loadAgentMessages(agent.id);
|
|
195
|
-
|
|
252
|
+
|
|
196
253
|
// Create new terminal for this agent
|
|
197
254
|
const newTerminal: TerminalInstance = {
|
|
198
255
|
id: `agent-${agent.id}`,
|
|
199
256
|
title: agent.name,
|
|
200
257
|
agentId: agent.id,
|
|
201
|
-
options:
|
|
202
|
-
|
|
258
|
+
options: {
|
|
259
|
+
...initialOptions,
|
|
260
|
+
// Pass cost information from loaded agent
|
|
261
|
+
totalCost: agentWithMessages?.totalCost,
|
|
262
|
+
totalInputTokenCost: agentWithMessages?.totalInputTokenCost,
|
|
263
|
+
totalOutputTokenCost: agentWithMessages?.totalOutputTokenCost,
|
|
264
|
+
totalCachedTokenCost: agentWithMessages?.totalCachedInputTokenCost,
|
|
265
|
+
totalInputTokens: agentWithMessages?.totalInputTokens,
|
|
266
|
+
totalOutputTokens: agentWithMessages?.totalOutputTokens,
|
|
267
|
+
totalCachedTokens: agentWithMessages?.totalCachedInputTokens,
|
|
268
|
+
},
|
|
269
|
+
messages: agentWithMessages?.messages
|
|
270
|
+
? convertAgentMessagesToTerminalMessages(agentWithMessages.messages)
|
|
271
|
+
: [],
|
|
203
272
|
};
|
|
204
273
|
|
|
205
274
|
setTerminals((prev) => [...prev, newTerminal]);
|
|
@@ -249,7 +318,10 @@ export function Agents({
|
|
|
249
318
|
|
|
250
319
|
{/* History Popover */}
|
|
251
320
|
<div className="flex items-center px-1">
|
|
252
|
-
<Popover
|
|
321
|
+
<Popover
|
|
322
|
+
open={historyPopoverOpen}
|
|
323
|
+
onOpenChange={setHistoryPopoverOpen}
|
|
324
|
+
>
|
|
253
325
|
<PopoverTrigger asChild>
|
|
254
326
|
<SimpleIconButton
|
|
255
327
|
onClick={() => {}}
|
|
@@ -259,7 +331,7 @@ export function Agents({
|
|
|
259
331
|
/>
|
|
260
332
|
</PopoverTrigger>
|
|
261
333
|
<PopoverContent className="w-64 p-0" align="end">
|
|
262
|
-
<div className="px-3 py-2 text-xs font-medium text-gray-500
|
|
334
|
+
<div className="border-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-500">
|
|
263
335
|
Agent History
|
|
264
336
|
</div>
|
|
265
337
|
<div className="max-h-80 overflow-y-auto">
|
|
@@ -271,16 +343,16 @@ export function Agents({
|
|
|
271
343
|
inactiveAgents.map((agent) => (
|
|
272
344
|
<div
|
|
273
345
|
key={agent.id}
|
|
274
|
-
className="cursor-pointer px-3 py-2 text-xs hover:bg-gray-50
|
|
346
|
+
className="cursor-pointer border-b border-gray-50 px-3 py-2 text-xs hover:bg-gray-50"
|
|
275
347
|
onClick={() => openAgentFromHistory(agent)}
|
|
276
348
|
>
|
|
277
|
-
<div className="font-medium text-gray-900
|
|
349
|
+
<div className="truncate font-medium text-gray-900">
|
|
278
350
|
{agent.name}
|
|
279
351
|
</div>
|
|
280
|
-
<div className="text-gray-500
|
|
352
|
+
<div className="truncate text-gray-500">
|
|
281
353
|
{agent.profileName}
|
|
282
354
|
</div>
|
|
283
|
-
<div className="text-gray-400
|
|
355
|
+
<div className="text-xs text-gray-400">
|
|
284
356
|
{formatDateToLocalTime(agent.updatedDate)}
|
|
285
357
|
</div>
|
|
286
358
|
</div>
|
|
@@ -317,12 +389,22 @@ export function Agents({
|
|
|
317
389
|
activeTerminalId === terminal.id ? "block" : "hidden",
|
|
318
390
|
)}
|
|
319
391
|
>
|
|
320
|
-
<EditorAiTerminal
|
|
392
|
+
<EditorAiTerminal
|
|
321
393
|
options={{
|
|
322
394
|
...terminal.options,
|
|
323
395
|
// Pass the pre-loaded messages to the terminal
|
|
324
|
-
initialMessages: terminal.messages
|
|
325
|
-
|
|
396
|
+
initialMessages: terminal.messages,
|
|
397
|
+
// Pass the agentId to maintain continuity
|
|
398
|
+
agentId: terminal.agentId,
|
|
399
|
+
}}
|
|
400
|
+
onAgentNameUpdate={(name) => {
|
|
401
|
+
// Update the terminal title when agent name is updated
|
|
402
|
+
setTerminals((prev) =>
|
|
403
|
+
prev.map((t) =>
|
|
404
|
+
t.id === terminal.id ? { ...t, title: name } : t,
|
|
405
|
+
),
|
|
406
|
+
);
|
|
407
|
+
}}
|
|
326
408
|
/>
|
|
327
409
|
</div>
|
|
328
410
|
))}
|