@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.
Files changed (224) hide show
  1. package/dist/components/ActionButton.js +2 -2
  2. package/dist/components/ActionButton.js.map +1 -1
  3. package/dist/components/SimpleLanguageSelector.js +3 -1
  4. package/dist/components/SimpleLanguageSelector.js.map +1 -1
  5. package/dist/components/ui/button.d.ts +1 -1
  6. package/dist/config/config.js +1 -1
  7. package/dist/config/config.js.map +1 -1
  8. package/dist/config/types.d.ts +1 -1
  9. package/dist/editor/ContextMenu.js +0 -1
  10. package/dist/editor/ContextMenu.js.map +1 -1
  11. package/dist/editor/Editor.js +9 -3
  12. package/dist/editor/Editor.js.map +1 -1
  13. package/dist/editor/FieldListField.js +16 -24
  14. package/dist/editor/FieldListField.js.map +1 -1
  15. package/dist/editor/ImageEditButton.js +1 -1
  16. package/dist/editor/ImageEditButton.js.map +1 -1
  17. package/dist/editor/ImageEditor.js +1 -1
  18. package/dist/editor/ImageEditor.js.map +1 -1
  19. package/dist/editor/MainLayout.js +2 -2
  20. package/dist/editor/MainLayout.js.map +1 -1
  21. package/dist/editor/Terminal.js +1 -1
  22. package/dist/editor/Terminal.js.map +1 -1
  23. package/dist/editor/Titlebar.js +0 -1
  24. package/dist/editor/Titlebar.js.map +1 -1
  25. package/dist/editor/ai/AgentCostDisplay.d.ts +26 -0
  26. package/dist/editor/ai/AgentCostDisplay.js +65 -0
  27. package/dist/editor/ai/AgentCostDisplay.js.map +1 -0
  28. package/dist/editor/ai/Agents.js +83 -29
  29. package/dist/editor/ai/Agents.js.map +1 -1
  30. package/dist/editor/ai/AiPromptPopover.d.ts +7 -0
  31. package/dist/editor/ai/AiPromptPopover.js +111 -0
  32. package/dist/editor/ai/AiPromptPopover.js.map +1 -0
  33. package/dist/editor/ai/AiResponseMessage.d.ts +1 -0
  34. package/dist/editor/ai/AiResponseMessage.js +104 -18
  35. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  36. package/dist/editor/ai/AiTerminal.d.ts +18 -2
  37. package/dist/editor/ai/AiTerminal.js +423 -63
  38. package/dist/editor/ai/AiTerminal.js.map +1 -1
  39. package/dist/editor/ai/EditorAiTerminal.d.ts +2 -1
  40. package/dist/editor/ai/EditorAiTerminal.js +2 -2
  41. package/dist/editor/ai/EditorAiTerminal.js.map +1 -1
  42. package/dist/editor/ai/editorAiContext.d.ts +0 -1
  43. package/dist/editor/ai/editorAiContext.js +0 -2
  44. package/dist/editor/ai/editorAiContext.js.map +1 -1
  45. package/dist/editor/client/EditorClient.d.ts +3 -2
  46. package/dist/editor/client/EditorClient.js +326 -68
  47. package/dist/editor/client/EditorClient.js.map +1 -1
  48. package/dist/editor/client/editContext.d.ts +6 -4
  49. package/dist/editor/client/editContext.js.map +1 -1
  50. package/dist/editor/client/fieldModificationStore.d.ts +19 -0
  51. package/dist/editor/client/fieldModificationStore.js +125 -0
  52. package/dist/editor/client/fieldModificationStore.js.map +1 -0
  53. package/dist/editor/client/itemsRepository.d.ts +1 -1
  54. package/dist/editor/client/itemsRepository.js +38 -28
  55. package/dist/editor/client/itemsRepository.js.map +1 -1
  56. package/dist/editor/client/operations.d.ts +1 -0
  57. package/dist/editor/client/operations.js +39 -31
  58. package/dist/editor/client/operations.js.map +1 -1
  59. package/dist/editor/commands/componentCommands.js +5 -3
  60. package/dist/editor/commands/componentCommands.js.map +1 -1
  61. package/dist/editor/commands/itemCommands.js.map +1 -1
  62. package/dist/editor/component-designer/aiContext.js +0 -2
  63. package/dist/editor/component-designer/aiContext.js.map +1 -1
  64. package/dist/editor/field-types/DropLinkEditor.js +1 -1
  65. package/dist/editor/field-types/DropLinkEditor.js.map +1 -1
  66. package/dist/editor/field-types/MultiLineText.js +5 -7
  67. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  68. package/dist/editor/field-types/RichTextEditorComponent.js +5 -7
  69. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  70. package/dist/editor/field-types/SingleLineText.js +5 -7
  71. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  72. package/dist/editor/hooks/useEditorSettings.d.ts +17 -0
  73. package/dist/editor/hooks/useEditorSettings.js +61 -0
  74. package/dist/editor/hooks/useEditorSettings.js.map +1 -0
  75. package/dist/editor/menubar/ItemActionsMenu.js +2 -2
  76. package/dist/editor/menubar/ItemActionsMenu.js.map +1 -1
  77. package/dist/editor/menubar/PageSelector.js +1 -1
  78. package/dist/editor/menubar/PageSelector.js.map +1 -1
  79. package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
  80. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  81. package/dist/editor/menubar/toolbar-sections/InsertControls.js +1 -1
  82. package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -1
  83. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -1
  84. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  85. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
  86. package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
  87. package/dist/editor/page-editor-chrome/FieldEditedIndicators.js +4 -3
  88. package/dist/editor/page-editor-chrome/FieldEditedIndicators.js.map +1 -1
  89. package/dist/editor/page-editor-chrome/FrameMenu.js +9 -1
  90. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  91. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +0 -1
  92. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  93. package/dist/editor/page-viewer/EditorForm.js +1 -1
  94. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  95. package/dist/editor/page-viewer/PageViewer.js +9 -8
  96. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  97. package/dist/editor/page-viewer/PageViewerFrame.js +7 -1
  98. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  99. package/dist/editor/page-viewer/pageViewContext.js +40 -6
  100. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  101. package/dist/editor/reviews/Comment.js +7 -6
  102. package/dist/editor/reviews/Comment.js.map +1 -1
  103. package/dist/editor/services/agentService.d.ts +84 -12
  104. package/dist/editor/services/agentService.js +256 -15
  105. package/dist/editor/services/agentService.js.map +1 -1
  106. package/dist/editor/services/aiService.d.ts +18 -3
  107. package/dist/editor/services/aiService.js +5 -3
  108. package/dist/editor/services/aiService.js.map +1 -1
  109. package/dist/editor/services/contextService.js +0 -1
  110. package/dist/editor/services/contextService.js.map +1 -1
  111. package/dist/editor/services/systemService.d.ts +2 -1
  112. package/dist/editor/services/systemService.js +3 -0
  113. package/dist/editor/services/systemService.js.map +1 -1
  114. package/dist/editor/sidebar/ComponentPalette.js +1 -1
  115. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  116. package/dist/editor/sidebar/EditHistory.js +2 -2
  117. package/dist/editor/sidebar/EditHistory.js.map +1 -1
  118. package/dist/editor/sidebar/GraphQL.d.ts +1 -0
  119. package/dist/editor/sidebar/GraphQL.js +8 -2
  120. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  121. package/dist/editor/sidebar/MainContentTree.js +1 -1
  122. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  123. package/dist/editor/sidebar/SEOInfo.js +1 -1
  124. package/dist/editor/sidebar/SEOInfo.js.map +1 -1
  125. package/dist/editor/sidebar/ViewSelector.d.ts +4 -1
  126. package/dist/editor/sidebar/ViewSelector.js +64 -48
  127. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  128. package/dist/editor/ui/PerfectTree.js +2 -11
  129. package/dist/editor/ui/PerfectTree.js.map +1 -1
  130. package/dist/editor/ui/SimpleIconButton.d.ts +2 -0
  131. package/dist/editor/ui/SimpleIconButton.js +8 -4
  132. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  133. package/dist/index.d.ts +2 -0
  134. package/dist/index.js +2 -0
  135. package/dist/index.js.map +1 -1
  136. package/dist/page-wizard/steps/CollectStep.js +1 -1
  137. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  138. package/dist/page-wizard/steps/StructureStep.js +1 -1
  139. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  140. package/dist/page-wizard/steps/TranslateStep.js +233 -18
  141. package/dist/page-wizard/steps/TranslateStep.js.map +1 -1
  142. package/dist/revision.d.ts +2 -2
  143. package/dist/revision.js +2 -2
  144. package/dist/splash-screen/RecentPages.js +1 -13
  145. package/dist/splash-screen/RecentPages.js.map +1 -1
  146. package/dist/splash-screen/SplashScreen.js +1 -1
  147. package/dist/splash-screen/SplashScreen.js.map +1 -1
  148. package/dist/styles.css +88 -3
  149. package/dist/types.d.ts +6 -0
  150. package/package.json +2 -2
  151. package/src/components/ActionButton.tsx +3 -2
  152. package/src/components/SimpleLanguageSelector.tsx +6 -1
  153. package/src/config/config.tsx +1 -1
  154. package/src/config/types.ts +1 -1
  155. package/src/editor/ContextMenu.tsx +0 -3
  156. package/src/editor/Editor.tsx +11 -3
  157. package/src/editor/FieldListField.tsx +22 -31
  158. package/src/editor/ImageEditButton.tsx +1 -0
  159. package/src/editor/ImageEditor.tsx +1 -0
  160. package/src/editor/MainLayout.tsx +2 -2
  161. package/src/editor/Terminal.tsx +1 -1
  162. package/src/editor/Titlebar.tsx +0 -2
  163. package/src/editor/ai/AgentCostDisplay.tsx +237 -0
  164. package/src/editor/ai/Agents.tsx +147 -65
  165. package/src/editor/ai/AiPromptPopover.tsx +209 -0
  166. package/src/editor/ai/AiResponseMessage.tsx +232 -45
  167. package/src/editor/ai/AiTerminal.tsx +559 -88
  168. package/src/editor/ai/EditorAiTerminal.tsx +3 -0
  169. package/src/editor/ai/editorAiContext.ts +0 -3
  170. package/src/editor/client/EditorClient.tsx +409 -117
  171. package/src/editor/client/editContext.ts +7 -5
  172. package/src/editor/client/fieldModificationStore.ts +196 -0
  173. package/src/editor/client/itemsRepository.ts +41 -31
  174. package/src/editor/client/operations.ts +95 -76
  175. package/src/editor/commands/componentCommands.tsx +9 -3
  176. package/src/editor/commands/itemCommands.tsx +0 -1
  177. package/src/editor/component-designer/aiContext.ts +0 -2
  178. package/src/editor/field-types/DropLinkEditor.tsx +1 -1
  179. package/src/editor/field-types/MultiLineText.tsx +9 -9
  180. package/src/editor/field-types/RichTextEditorComponent.tsx +8 -8
  181. package/src/editor/field-types/SingleLineText.tsx +9 -9
  182. package/src/editor/hooks/useEditorSettings.ts +68 -0
  183. package/src/editor/menubar/ItemActionsMenu.tsx +3 -2
  184. package/src/editor/menubar/PageSelector.tsx +1 -1
  185. package/src/editor/menubar/toolbar-sections/EditControls.tsx +1 -0
  186. package/src/editor/menubar/toolbar-sections/InsertControls.tsx +1 -0
  187. package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +2 -0
  188. package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +2 -0
  189. package/src/editor/page-editor-chrome/FieldEditedIndicators.tsx +4 -3
  190. package/src/editor/page-editor-chrome/FrameMenu.tsx +10 -1
  191. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +0 -1
  192. package/src/editor/page-viewer/EditorForm.tsx +1 -0
  193. package/src/editor/page-viewer/PageViewer.tsx +9 -8
  194. package/src/editor/page-viewer/PageViewerFrame.tsx +7 -1
  195. package/src/editor/page-viewer/pageViewContext.ts +40 -5
  196. package/src/editor/reviews/Comment.tsx +7 -7
  197. package/src/editor/services/agentService.ts +405 -31
  198. package/src/editor/services/aiService.ts +24 -5
  199. package/src/editor/services/contextService.ts +0 -1
  200. package/src/editor/services/systemService.ts +7 -1
  201. package/src/editor/sidebar/ComponentPalette.tsx +4 -1
  202. package/src/editor/sidebar/EditHistory.tsx +2 -0
  203. package/src/editor/sidebar/GraphQL.tsx +19 -7
  204. package/src/editor/sidebar/MainContentTree.tsx +1 -1
  205. package/src/editor/sidebar/SEOInfo.tsx +1 -1
  206. package/src/editor/sidebar/ViewSelector.tsx +80 -64
  207. package/src/editor/ui/PerfectTree.tsx +2 -18
  208. package/src/editor/ui/SimpleIconButton.tsx +56 -38
  209. package/src/index.ts +2 -0
  210. package/src/page-wizard/steps/CollectStep.tsx +0 -2
  211. package/src/page-wizard/steps/StructureStep.tsx +3 -0
  212. package/src/page-wizard/steps/TranslateStep.tsx +473 -62
  213. package/src/revision.ts +2 -2
  214. package/src/splash-screen/RecentPages.tsx +0 -14
  215. package/src/splash-screen/SplashScreen.tsx +3 -2
  216. package/src/types.ts +7 -0
  217. package/dist/editor/ai/AiPopup.d.ts +0 -10
  218. package/dist/editor/ai/AiPopup.js +0 -23
  219. package/dist/editor/ai/AiPopup.js.map +0 -1
  220. package/dist/editor/ai/AiToolCall.d.ts +0 -5
  221. package/dist/editor/ai/AiToolCall.js +0 -28
  222. package/dist/editor/ai/AiToolCall.js.map +0 -1
  223. package/src/editor/ai/AiPopup.tsx +0 -59
  224. 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
+ }
@@ -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 { getAgents, getAgent, getChatHistory, AgentChat, AgentChatMessage } from "../services/agentService";
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(agentMessages: AgentChatMessage[]): Message[] {
25
- return agentMessages
26
- // Keep all messages including tool results for complete conversation context
27
- .map(msg => ({
28
- id: msg.id,
29
- content: msg.content,
30
- name: msg.name,
31
- role: msg.role,
32
- tool_calls: msg.toolCalls?.map(toolCall => ({
33
- id: toolCall.toolCallId,
34
- displayName: toolCall.functionName,
35
- function: {
36
- name: toolCall.functionName,
37
- arguments: toolCall.functionArguments || ""
38
- }
39
- })) || [],
40
- tool_call_id: msg.toolCallId
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 = dateString.includes('Z') || dateString.includes('+') || dateString.includes('-', 19)
47
- ? dateString
48
- : dateString + 'Z';
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("completed", 20);
83
-
84
- if (activeAgentsResult.type === "success" && activeAgentsResult.data) {
85
- const activeAgents = activeAgentsResult.data;
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 || `Agent ${index + 1}`,
125
+ title: agent.name || "New Agent",
96
126
  agentId: agent.id,
97
- options: initialOptions,
98
- messages: agentWithMessages?.messages ? convertAgentMessagesToTerminalMessages(agentWithMessages.messages) : []
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: `Agent ${nextTerminalNumber.current}`,
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.type === "success" && inactiveAgentsResult.data) {
122
- setInactiveAgents(inactiveAgentsResult.data);
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 (agentId: string): Promise<AgentChat | null> => {
184
+ const loadAgentMessages = async (
185
+ agentId: string,
186
+ ): Promise<AgentChat | null> => {
142
187
  try {
143
- const result = await getAgent(agentId);
144
- if (result.type === "success" && result.data) {
145
- return result.data;
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: initialOptions,
202
- messages: agentWithMessages?.messages ? convertAgentMessagesToTerminalMessages(agentWithMessages.messages) : []
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 open={historyPopoverOpen} onOpenChange={setHistoryPopoverOpen}>
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 border-b border-gray-100">
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 border-b border-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 truncate">
349
+ <div className="truncate font-medium text-gray-900">
278
350
  {agent.name}
279
351
  </div>
280
- <div className="text-gray-500 truncate">
352
+ <div className="truncate text-gray-500">
281
353
  {agent.profileName}
282
354
  </div>
283
- <div className="text-gray-400 text-xs">
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
  ))}