@alpaca-editor/core 1.0.4018 → 1.0.4027

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 (179) hide show
  1. package/dist/components/SimpleLanguageSelector.d.ts +2 -1
  2. package/dist/components/SimpleLanguageSelector.js +9 -2
  3. package/dist/components/SimpleLanguageSelector.js.map +1 -1
  4. package/dist/components/ui/input.js +1 -1
  5. package/dist/components/ui/input.js.map +1 -1
  6. package/dist/components/ui/tooltip.d.ts +3 -1
  7. package/dist/components/ui/tooltip.js +2 -2
  8. package/dist/components/ui/tooltip.js.map +1 -1
  9. package/dist/config/config.js +4 -0
  10. package/dist/config/config.js.map +1 -1
  11. package/dist/config/types.d.ts +2 -0
  12. package/dist/editor/ContentTree.js +1 -1
  13. package/dist/editor/ContentTree.js.map +1 -1
  14. package/dist/editor/ContextMenu.js +26 -0
  15. package/dist/editor/ContextMenu.js.map +1 -1
  16. package/dist/editor/FieldHistory.js +1 -1
  17. package/dist/editor/FieldHistory.js.map +1 -1
  18. package/dist/editor/FieldListField.js +2 -2
  19. package/dist/editor/FieldListField.js.map +1 -1
  20. package/dist/editor/Terminal.js +3 -1
  21. package/dist/editor/Terminal.js.map +1 -1
  22. package/dist/editor/ai/Agents.js +37 -18
  23. package/dist/editor/ai/Agents.js.map +1 -1
  24. package/dist/editor/ai/AiResponseMessage.js +71 -5
  25. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  26. package/dist/editor/ai/AiTerminal.d.ts +3 -1
  27. package/dist/editor/ai/AiTerminal.js +53 -24
  28. package/dist/editor/ai/AiTerminal.js.map +1 -1
  29. package/dist/editor/ai/AiToolCall.js +3 -3
  30. package/dist/editor/ai/AiToolCall.js.map +1 -1
  31. package/dist/editor/ai/EditorAiTerminal.d.ts +2 -1
  32. package/dist/editor/ai/EditorAiTerminal.js +2 -2
  33. package/dist/editor/ai/EditorAiTerminal.js.map +1 -1
  34. package/dist/editor/client/EditorClient.js +5 -1
  35. package/dist/editor/client/EditorClient.js.map +1 -1
  36. package/dist/editor/client/editContext.d.ts +2 -0
  37. package/dist/editor/client/editContext.js.map +1 -1
  38. package/dist/editor/client/operations.d.ts +1 -0
  39. package/dist/editor/client/operations.js +7 -0
  40. package/dist/editor/client/operations.js.map +1 -1
  41. package/dist/editor/commands/componentCommands.js +1 -1
  42. package/dist/editor/commands/componentCommands.js.map +1 -1
  43. package/dist/editor/field-types/ImageFieldEditor.js +1 -1
  44. package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
  45. package/dist/editor/field-types/MultiLineText.js +1 -1
  46. package/dist/editor/field-types/MultiLineText.js.map +1 -1
  47. package/dist/editor/field-types/PictureFieldEditor.js +1 -1
  48. package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
  49. package/dist/editor/field-types/RawEditor.js +1 -1
  50. package/dist/editor/field-types/RawEditor.js.map +1 -1
  51. package/dist/editor/field-types/RichTextEditorComponent.js +16 -17
  52. package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
  53. package/dist/editor/field-types/SingleLineText.js +1 -1
  54. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  55. package/dist/editor/field-types/richtext/components/SimpleDropdown.d.ts +18 -0
  56. package/dist/editor/field-types/richtext/components/SimpleDropdown.js +71 -0
  57. package/dist/editor/field-types/richtext/components/SimpleDropdown.js.map +1 -0
  58. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.d.ts +5 -0
  59. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +359 -0
  60. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js.map +1 -0
  61. package/dist/editor/field-types/richtext/components/SimpleToolbar.d.ts +16 -0
  62. package/dist/editor/field-types/richtext/components/SimpleToolbar.js +181 -0
  63. package/dist/editor/field-types/richtext/components/SimpleToolbar.js.map +1 -0
  64. package/dist/editor/field-types/richtext/components/SimpleToolbarButton.d.ts +9 -0
  65. package/dist/editor/field-types/richtext/components/SimpleToolbarButton.js +14 -0
  66. package/dist/editor/field-types/richtext/components/SimpleToolbarButton.js.map +1 -0
  67. package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +4 -0
  68. package/dist/editor/field-types/richtext/contextMenuFactory.js +193 -0
  69. package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -0
  70. package/dist/editor/field-types/richtext/index.d.ts +6 -5
  71. package/dist/editor/field-types/richtext/index.js +6 -5
  72. package/dist/editor/field-types/richtext/index.js.map +1 -1
  73. package/dist/editor/field-types/richtext/types.d.ts +16 -16
  74. package/dist/editor/field-types/richtext/types.js +84 -84
  75. package/dist/editor/field-types/richtext/types.js.map +1 -1
  76. package/dist/editor/page-editor-chrome/CommentHighlighting.js +1 -1
  77. package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
  78. package/dist/editor/page-editor-chrome/FrameMenu.js +5 -5
  79. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  80. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  81. package/dist/editor/page-viewer/PageViewerFrame.js +3 -2
  82. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  83. package/dist/editor/services/agentService.d.ts +14 -4
  84. package/dist/editor/services/agentService.js.map +1 -1
  85. package/dist/editor/services/aiService.d.ts +1 -0
  86. package/dist/editor/services/aiService.js +1 -0
  87. package/dist/editor/services/aiService.js.map +1 -1
  88. package/dist/page-wizard/PageWizard.d.ts +2 -0
  89. package/dist/page-wizard/PageWizard.js +6 -13
  90. package/dist/page-wizard/PageWizard.js.map +1 -1
  91. package/dist/page-wizard/WizardSteps.js +3 -1
  92. package/dist/page-wizard/WizardSteps.js.map +1 -1
  93. package/dist/page-wizard/service.d.ts +1 -0
  94. package/dist/page-wizard/service.js +7 -0
  95. package/dist/page-wizard/service.js.map +1 -1
  96. package/dist/page-wizard/steps/ContentStep.js +210 -33
  97. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  98. package/dist/page-wizard/steps/FindItemsStep.js +11 -3
  99. package/dist/page-wizard/steps/FindItemsStep.js.map +1 -1
  100. package/dist/page-wizard/steps/LayoutStep.js +1 -1
  101. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  102. package/dist/page-wizard/steps/MetaDataStep.js +1 -1
  103. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  104. package/dist/page-wizard/steps/SchottSelectImagesStep.d.ts +2 -0
  105. package/dist/page-wizard/steps/SchottSelectImagesStep.js +55 -0
  106. package/dist/page-wizard/steps/SchottSelectImagesStep.js.map +1 -0
  107. package/dist/page-wizard/steps/StructureStep.js +20 -5
  108. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  109. package/dist/page-wizard/steps/TranslateStep.d.ts +2 -0
  110. package/dist/page-wizard/steps/TranslateStep.js +413 -0
  111. package/dist/page-wizard/steps/TranslateStep.js.map +1 -0
  112. package/dist/page-wizard/utils/dataAccessor.d.ts +7 -0
  113. package/dist/page-wizard/utils/dataAccessor.js +76 -0
  114. package/dist/page-wizard/utils/dataAccessor.js.map +1 -1
  115. package/dist/revision.d.ts +2 -2
  116. package/dist/revision.js +2 -2
  117. package/dist/splash-screen/NewPage.js +5 -4
  118. package/dist/splash-screen/NewPage.js.map +1 -1
  119. package/dist/splash-screen/OpenPage.js +2 -1
  120. package/dist/splash-screen/OpenPage.js.map +1 -1
  121. package/dist/splash-screen/RecentPages.js +3 -1
  122. package/dist/splash-screen/RecentPages.js.map +1 -1
  123. package/dist/styles.css +57 -0
  124. package/package.json +5 -4
  125. package/src/components/SimpleLanguageSelector.tsx +11 -1
  126. package/src/components/ui/input.tsx +1 -1
  127. package/src/components/ui/tooltip.tsx +3 -2
  128. package/src/config/config.tsx +4 -0
  129. package/src/config/types.ts +6 -0
  130. package/src/editor/ContentTree.tsx +1 -1
  131. package/src/editor/ContextMenu.tsx +39 -0
  132. package/src/editor/FieldHistory.tsx +1 -1
  133. package/src/editor/FieldListField.tsx +2 -6
  134. package/src/editor/Terminal.tsx +5 -1
  135. package/src/editor/ai/Agents.tsx +90 -46
  136. package/src/editor/ai/AiResponseMessage.tsx +185 -24
  137. package/src/editor/ai/AiTerminal.tsx +104 -50
  138. package/src/editor/ai/AiToolCall.tsx +14 -4
  139. package/src/editor/ai/EditorAiTerminal.tsx +3 -0
  140. package/src/editor/client/EditorClient.tsx +9 -1
  141. package/src/editor/client/editContext.ts +2 -0
  142. package/src/editor/client/operations.ts +9 -0
  143. package/src/editor/commands/componentCommands.tsx +1 -1
  144. package/src/editor/field-types/ImageFieldEditor.tsx +1 -0
  145. package/src/editor/field-types/MultiLineText.tsx +1 -0
  146. package/src/editor/field-types/PictureFieldEditor.tsx +1 -0
  147. package/src/editor/field-types/RawEditor.tsx +1 -0
  148. package/src/editor/field-types/RichTextEditorComponent.tsx +27 -25
  149. package/src/editor/field-types/SingleLineText.tsx +1 -0
  150. package/src/editor/field-types/richtext/components/SimpleDropdown.tsx +165 -0
  151. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.css +261 -0
  152. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.tsx +505 -0
  153. package/src/editor/field-types/richtext/components/SimpleToolbar.tsx +362 -0
  154. package/src/editor/field-types/richtext/components/SimpleToolbarButton.tsx +36 -0
  155. package/src/editor/field-types/richtext/contextMenuFactory.tsx +264 -0
  156. package/src/editor/field-types/richtext/index.ts +6 -5
  157. package/src/editor/field-types/richtext/types.ts +168 -148
  158. package/src/editor/page-editor-chrome/CommentHighlighting.tsx +1 -1
  159. package/src/editor/page-editor-chrome/FrameMenu.tsx +16 -11
  160. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
  161. package/src/editor/page-viewer/PageViewerFrame.tsx +4 -3
  162. package/src/editor/services/agentService.ts +16 -5
  163. package/src/editor/services/aiService.ts +4 -0
  164. package/src/page-wizard/PageWizard.tsx +10 -13
  165. package/src/page-wizard/WizardSteps.tsx +3 -1
  166. package/src/page-wizard/service.ts +11 -0
  167. package/src/page-wizard/steps/ContentStep.tsx +376 -43
  168. package/src/page-wizard/steps/FindItemsStep.tsx +23 -3
  169. package/src/page-wizard/steps/LayoutStep.tsx +1 -1
  170. package/src/page-wizard/steps/MetaDataStep.tsx +1 -1
  171. package/src/page-wizard/steps/SchottSelectImagesStep.tsx +141 -0
  172. package/src/page-wizard/steps/StructureStep.tsx +40 -5
  173. package/src/page-wizard/steps/TranslateStep.tsx +772 -0
  174. package/src/page-wizard/utils/dataAccessor.ts +85 -0
  175. package/src/revision.ts +2 -2
  176. package/src/splash-screen/NewPage.tsx +18 -3
  177. package/src/splash-screen/OpenPage.tsx +14 -1
  178. package/src/splash-screen/RecentPages.tsx +4 -2
  179. package/tsconfig.build.json +1 -0
@@ -26,6 +26,7 @@ type Response = {
26
26
  numOutputTokens: number;
27
27
  numCachedTokens: number;
28
28
  state: string;
29
+ agentName?: string; // Updated agent name (only sent when the agent name has been updated)
29
30
  };
30
31
 
31
32
  export type ToolCall = {
@@ -44,7 +45,7 @@ export type Message = {
44
45
  name: string;
45
46
  role: string;
46
47
  tool_calls?: ToolCall[];
47
- tool_call_id?: string;
48
+ tool_call_id?: string; // For tool response messages
48
49
  };
49
50
 
50
51
  export type AiContext = {
@@ -64,28 +65,34 @@ export function AiTerminal({
64
65
  createAiContext,
65
66
  defaultProfile,
66
67
  options,
68
+ onAgentNameUpdate,
67
69
  }: {
68
70
  closeButton?: React.ReactNode;
69
71
  createAiContext: ({ editContext }: { editContext: any }) => AiContext;
70
72
  defaultProfile?: string;
71
73
  options?: AiTerminalOptions;
74
+ onAgentNameUpdate?: (name: string) => void;
72
75
  }) {
73
76
  const editContext = useEditContext();
74
77
  const [showPredefined, setShowPredefined] = useState(false);
75
78
 
76
79
  if (!editContext) return null;
77
80
 
78
- const [messages, setMessages] = useState<Message[]>(options?.initialMessages || []);
81
+ const [messages, setMessages] = useState<Message[]>(
82
+ options?.initialMessages || [],
83
+ );
79
84
  const [response, setResponse] = useState<Response>();
80
85
  const [model, setModel] = useState<string>();
81
86
  const [prompt, setPrompt] = useState("");
82
87
  const [profiles, setProfiles] = useState<AiProfile[]>([]);
83
88
  const [activeProfile, setActiveProfile] = useState<AiProfile>();
84
89
  const [initialPromptExecuted, setInitialPromptExecuted] = useState(false);
85
- const [agentId] = useState<string>(() => crypto.randomUUID());
90
+ const [agentId, setAgentId] = useState<string>(() => crypto.randomUUID());
86
91
  const selection = editContext.selection;
87
92
  const terminalRef = useRef<{ submit: () => void }>(null);
88
- const [responseMessages, setResponseMessages] = useState<Message[]>(options?.initialMessages || []);
93
+ const [responseMessages, setResponseMessages] = useState<Message[]>(
94
+ options?.initialMessages || [],
95
+ );
89
96
  const [showSettings, setShowSettings] = useState(false);
90
97
  const settingsRef = useRef<HTMLDivElement>(null);
91
98
 
@@ -125,20 +132,29 @@ export function AiTerminal({
125
132
  }, [responseMessages]);
126
133
 
127
134
  // State for initial messages to pass to Terminal
128
- type TerminalMessage = {text: React.ReactNode, type: "command" | "response"};
129
- const [initialTerminalMessages, setInitialTerminalMessages] = useState<TerminalMessage[] | undefined>(undefined);
135
+ type TerminalMessage = {
136
+ text: React.ReactNode;
137
+ type: "command" | "response";
138
+ };
139
+ const [initialTerminalMessages, setInitialTerminalMessages] = useState<
140
+ TerminalMessage[] | undefined
141
+ >(undefined);
130
142
 
131
- // Effect to set up initial messages for display
143
+ // Effect to set up initial messages for display
132
144
  useEffect(() => {
133
145
  if (options?.initialMessages && options.initialMessages.length > 0) {
134
- console.log("AiTerminal: Loading initial messages", options.initialMessages);
135
-
146
+ console.log(
147
+ "AiTerminal: Loading initial messages",
148
+ options.initialMessages,
149
+ );
150
+
136
151
  // Format the initial messages for display
137
152
  const formattedMessages = options.initialMessages.map((message) => {
138
- const formattedContent = message.content
139
- ?.trim()
140
- ?.replaceAll("\n", "<br>")
141
- ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
153
+ const formattedContent =
154
+ message.content
155
+ ?.trim()
156
+ ?.replaceAll("\n", "<br>")
157
+ ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
142
158
 
143
159
  return {
144
160
  ...message,
@@ -153,7 +169,7 @@ export function AiTerminal({
153
169
  // Update the internal message states
154
170
  setMessages(formattedMessages);
155
171
  setResponseMessages(formattedMessages);
156
-
172
+
157
173
  // Create a response object for internal state
158
174
  const initialResponse: Response = {
159
175
  messages: formattedMessages,
@@ -161,50 +177,76 @@ export function AiTerminal({
161
177
  numInputTokens: 0,
162
178
  numOutputTokens: 0,
163
179
  numCachedTokens: 0,
164
- state: "loaded"
180
+ state: "loaded",
165
181
  };
166
-
182
+
167
183
  console.log("AiTerminal: Setting response", initialResponse);
168
184
  setResponse(initialResponse);
169
-
185
+
170
186
  // Create individual Terminal messages for each conversation message
171
187
  const terminalMessages: TerminalMessage[] = [];
172
-
173
- formattedMessages.forEach((message) => {
188
+
189
+ // Group messages by conversation turns (user + assistant pairs)
190
+ let i = 0;
191
+ while (i < formattedMessages.length) {
192
+ const message = formattedMessages[i];
193
+ if (!message) {
194
+ i++;
195
+ continue;
196
+ }
197
+
174
198
  if (message.role === "user") {
175
199
  // User messages appear as commands
176
200
  terminalMessages.push({
177
201
  type: "command",
178
- text: message.content
202
+ text: message.content,
179
203
  });
204
+ i++;
205
+
206
+ // Look for following assistant messages to group together
207
+ const assistantMessages: Message[] = [];
208
+ while (i < formattedMessages.length) {
209
+ const assistantMessage = formattedMessages[i];
210
+ if (assistantMessage && assistantMessage.role === "assistant") {
211
+ assistantMessages.push(assistantMessage);
212
+ i++;
213
+ } else {
214
+ break;
215
+ }
216
+ }
217
+
218
+ // If we have assistant messages, render them with AiResponseMessage
219
+ if (assistantMessages.length > 0) {
220
+ terminalMessages.push({
221
+ type: "response",
222
+ text: (
223
+ <AiResponseMessage
224
+ messages={assistantMessages}
225
+ editOperations={[]} // No edit operations for historical messages
226
+ finished={true}
227
+ />
228
+ ),
229
+ });
230
+ }
180
231
  } else if (message.role === "assistant") {
181
- // Assistant messages appear as responses
232
+ // Handle standalone assistant messages
182
233
  terminalMessages.push({
183
234
  type: "response",
184
235
  text: (
185
- <div
186
- dangerouslySetInnerHTML={{
187
- __html: message.formattedContent || message.content || "",
188
- }}
236
+ <AiResponseMessage
237
+ messages={[message]}
238
+ editOperations={[]} // No edit operations for historical messages
239
+ finished={true}
189
240
  />
190
- )
191
- });
192
- }
193
- // Add tool calls if present
194
- if (message.tool_calls && message.tool_calls.length > 0) {
195
- message.tool_calls.forEach((toolCall) => {
196
- terminalMessages.push({
197
- type: "response",
198
- text: (
199
- <div className="text-xs text-gray-400">
200
- 🔧 {toolCall.displayName}
201
- </div>
202
- )
203
- });
241
+ ),
204
242
  });
243
+ i++;
244
+ } else {
245
+ // Skip other message types (like tool messages)
246
+ i++;
205
247
  }
206
- });
207
-
248
+ }
249
+
208
250
  setInitialTerminalMessages(terminalMessages);
209
251
  }
210
252
  }, [options?.initialMessages]);
@@ -238,10 +280,11 @@ export function AiTerminal({
238
280
  // Replace the conversation history with the authoritative response from AI
239
281
  if (updatedMessages && Array.isArray(updatedMessages)) {
240
282
  const formattedMessages = updatedMessages.map((message) => {
241
- const formattedContent = message.content
242
- ?.trim()
243
- ?.replaceAll("\n", "<br>")
244
- ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
283
+ const formattedContent =
284
+ message.content
285
+ ?.trim()
286
+ ?.replaceAll("\n", "<br>")
287
+ ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
245
288
 
246
289
  return {
247
290
  ...message,
@@ -294,8 +337,7 @@ export function AiTerminal({
294
337
  const selectedText = editContext?.selectedRange?.text || null;
295
338
  if (!activeProfile || !model) return;
296
339
 
297
- // Build complete message history for API call
298
- const conversationHistory = [...messagesRef.current, userMessage];
340
+ // Only send the new user message - message history will be loaded from database
299
341
  const messages = [
300
342
  ...(options?.hiddenSystemPrompt
301
343
  ? [
@@ -308,9 +350,13 @@ export function AiTerminal({
308
350
  },
309
351
  ]
310
352
  : []),
311
- ...conversationHistory,
353
+ userMessage, // Send only the new user message
312
354
  ];
313
355
 
356
+ // Update local state to include the new user message for UI display
357
+ setMessages((prevMessages) => [...prevMessages, userMessage]);
358
+ setResponseMessages((prevMessages) => [...prevMessages, userMessage]);
359
+
314
360
  const response = await executePrompt(
315
361
  messages,
316
362
  context,
@@ -332,6 +378,12 @@ export function AiTerminal({
332
378
 
333
379
  if (response) {
334
380
  handleResponse(response, callback, true);
381
+
382
+ // Handle agent name update
383
+ if ((response as any).agentName && onAgentNameUpdate) {
384
+ onAgentNameUpdate((response as any).agentName);
385
+ }
386
+
335
387
  if (context.callback) context.callback(response);
336
388
  editContext?.requestRefresh("immediate");
337
389
  }
@@ -371,10 +423,12 @@ export function AiTerminal({
371
423
  setResponseMessages([]);
372
424
  setResponse(undefined);
373
425
  setInitialTerminalMessages(undefined);
426
+ // Generate a new agentId when clearing the terminal to start fresh
427
+ setAgentId(crypto.randomUUID());
374
428
  }}
375
429
  initialMessages={initialTerminalMessages}
376
430
  infobar={
377
- response?.numInputTokens && (
431
+ response?.numInputTokens && response?.numInputTokens > 0 ? (
378
432
  <div
379
433
  className="text-right text-gray-400"
380
434
  style={{ fontSize: "10px" }}
@@ -386,7 +440,7 @@ export function AiTerminal({
386
440
  : ""}
387
441
  {response?.state}
388
442
  </div>
389
- )
443
+ ) : null
390
444
  }
391
445
  prompt={prompt}
392
446
  setPrompt={setPrompt}
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useState } from "react";
2
2
 
3
- import { JsonView, defaultStyles } from "react-json-view-lite";
3
+ import JSONPretty from "react-json-pretty";
4
+
4
5
  import { Message, ToolCall } from "./AiTerminal";
5
6
  import { ProgressSpinner } from "primereact/progressspinner";
6
7
  export function AiToolCall({
@@ -34,12 +35,21 @@ export function AiToolCall({
34
35
  {!result && (
35
36
  <ProgressSpinner style={{ width: "1rem", height: "1rem" }} />
36
37
  )}
37
- {toolCall.displayName}
38
+ {toolCall.displayName || toolCall.function.name}
38
39
  </div>
39
40
  </div>
40
41
  {expanded && (
41
42
  <div className="ml-4">
42
- <div>{renderJsonOrText(toolCall.function.arguments)}</div>
43
+ <div className="mb-2">
44
+ <div className="font-semibold text-gray-600">Arguments:</div>
45
+ <div className="ml-2">{renderJsonOrText(toolCall.function.arguments)}</div>
46
+ </div>
47
+ {result && (
48
+ <div className="mb-2">
49
+ <div className="font-semibold text-gray-600">Result:</div>
50
+ <div className="ml-2">{renderJsonOrText(result.content || "")}</div>
51
+ </div>
52
+ )}
43
53
  {error && (
44
54
  <div className="ml-4 text-red-500">
45
55
  <div className="italic">Error:</div>
@@ -54,7 +64,7 @@ export function AiToolCall({
54
64
 
55
65
  function renderJsonOrText(json: string) {
56
66
  try {
57
- return <JsonView data={JSON.parse(json)} style={defaultStyles} />;
67
+ return <JSONPretty data={JSON.parse(json)} />;
58
68
  } catch (e) {
59
69
  return <div>{json}</div>;
60
70
  }
@@ -5,9 +5,11 @@ import { createEditorAiContext } from "./editorAiContext";
5
5
  export function EditorAiTerminal({
6
6
  closeButton,
7
7
  options,
8
+ onAgentNameUpdate,
8
9
  }: {
9
10
  closeButton?: React.ReactNode;
10
11
  options?: AiTerminalOptions;
12
+ onAgentNameUpdate?: (name: string) => void;
11
13
  }) {
12
14
  return (
13
15
  <AiTerminal
@@ -15,6 +17,7 @@ export function EditorAiTerminal({
15
17
  closeButton={closeButton}
16
18
  createAiContext={createEditorAiContext}
17
19
  defaultProfile="Editor"
20
+ onAgentNameUpdate={onAgentNameUpdate}
18
21
  />
19
22
  );
20
23
  }
@@ -248,6 +248,9 @@ export function EditorClient({
248
248
  configuration.editor.views[0]?.name ??
249
249
  "splash-screen",
250
250
  );
251
+ const [previousViewName, setPreviousViewName] = useState<string | undefined>(
252
+ undefined,
253
+ );
251
254
 
252
255
  const [compareMode, setCompareMode] = useState(false);
253
256
  const [compareTo, setCompareTo] = useState<ItemDescriptor>();
@@ -368,7 +371,7 @@ export function EditorClient({
368
371
 
369
372
  useEffect(() => {
370
373
  if (mode === "suggestions") {
371
- setViewName("reviews");
374
+ setViewName("comments");
372
375
  }
373
376
  }, [mode]);
374
377
 
@@ -1681,6 +1684,10 @@ export function EditorClient({
1681
1684
  const result = await currentView.beforeClose(editContext);
1682
1685
  if (!result) return;
1683
1686
  }
1687
+
1688
+ // Track previous view name before switching
1689
+ setPreviousViewName(editContext.viewName);
1690
+
1684
1691
  if (typeof document.startViewTransition === "function") {
1685
1692
  document.startViewTransition(() => {
1686
1693
  flushSync(() => {
@@ -2123,6 +2130,7 @@ export function EditorClient({
2123
2130
  },
2124
2131
  executeCommand,
2125
2132
  viewName,
2133
+ previousViewName,
2126
2134
  switchView,
2127
2135
  compareMode,
2128
2136
  setCompareMode,
@@ -134,6 +134,7 @@ export type EditContextType = {
134
134
  name: string,
135
135
  ) => Promise<ItemDescriptor | undefined>;
136
136
  createVersion: (item: ItemDescriptor) => Promise<void>;
137
+ onFieldBlur: () => void;
137
138
  undoing: boolean;
138
139
  };
139
140
  comments: Comment[];
@@ -154,6 +155,7 @@ export type EditContextType = {
154
155
  view?: EditorView;
155
156
 
156
157
  viewName: string;
158
+ previousViewName?: string;
157
159
  switchView: (
158
160
  viewName: string,
159
161
  options?: { skipConfirmation?: boolean },
@@ -684,6 +684,13 @@ export function getOperationsContext(
684
684
  },
685
685
  [state.itemsRepository],
686
686
  );
687
+
688
+ const onFieldBlur = useCallback(() => {
689
+ // Reset the last operation to force creation of a new operation
690
+ // when the user returns to edit any field after losing focus
691
+ lastOp.current = undefined;
692
+ }, []);
693
+
687
694
  const ops = useMemo(
688
695
  () => ({
689
696
  addComponent,
@@ -704,6 +711,7 @@ export function getOperationsContext(
704
711
  moveItems,
705
712
  copyItems,
706
713
  duplicateItem,
714
+ onFieldBlur,
707
715
  }),
708
716
  [
709
717
  addComponent,
@@ -726,6 +734,7 @@ export function getOperationsContext(
726
734
  state.page,
727
735
  copyItems,
728
736
  duplicateItem,
737
+ onFieldBlur,
729
738
  ],
730
739
  );
731
740
 
@@ -418,7 +418,7 @@ function getCreateCommentCommand(
418
418
  visibilityScopes: ["contextMenu"],
419
419
  execute: async (context: CommandContext<any>) => {
420
420
  context.editContext.addComment();
421
- context.editContext.switchView("reviews");
421
+ context.editContext.switchView("comments");
422
422
  },
423
423
  };
424
424
  }
@@ -58,6 +58,7 @@ export function ImageFieldEditor({
58
58
  refresh: "waitForQuietPeriod",
59
59
  });
60
60
  }}
61
+ onBlur={editContext.operations.onFieldBlur}
61
62
  />
62
63
  </div>
63
64
  </div>
@@ -81,6 +81,7 @@ export function MultiLineText({
81
81
  setValue(e.target.value);
82
82
  updateFieldValue(e.target.value as string);
83
83
  }}
84
+ onBlur={editContextRef.current?.operations.onFieldBlur}
84
85
  />
85
86
  );
86
87
  }
@@ -114,6 +114,7 @@ export function PictureFieldEditor({
114
114
  refresh: "waitForQuietPeriod",
115
115
  });
116
116
  }}
117
+ onBlur={editContext.operations.onFieldBlur}
117
118
  />
118
119
  </div>
119
120
  </div>
@@ -48,6 +48,7 @@ export function RawEditor({
48
48
  debouncedSetFieldvalue(e.target.value as string);
49
49
  // field.value = e.target.value;
50
50
  }}
51
+ onBlur={editContext?.operations.onFieldBlur}
51
52
  />
52
53
  );
53
54
  }
@@ -8,8 +8,8 @@ import {
8
8
  import { useThrottledCallback } from "use-debounce";
9
9
  import { useEffect, useRef, useState, useMemo } from "react";
10
10
 
11
- import { classNames } from "primereact/utils";
12
11
  import { ReactSlate } from "./richtext";
12
+ import { SimpleRichTextEditor } from "./richtext/components/SimpleRichTextEditor";
13
13
  import { RichTextField, RichTextEditorProfile } from "./richtext/types";
14
14
 
15
15
  // Minimal fallback profile for when profile is null or undefined
@@ -17,24 +17,21 @@ const FALLBACK_PROFILE: RichTextEditorProfile = {
17
17
  toolbar: {
18
18
  groups: [
19
19
  {
20
- id: 'basic-formatting',
21
- label: 'Basic Formatting',
22
- display: 'buttons' as const,
20
+ id: "basic-formatting",
21
+ label: "Basic Formatting",
22
+ display: "buttons" as const,
23
23
  showIconsOnly: true,
24
- options: [
25
- ]
24
+ options: [],
26
25
  },
27
26
  {
28
- id: 'basic-format',
29
- label: '',
30
- display: 'dropdown' as const,
27
+ id: "basic-format",
28
+ label: "",
29
+ display: "dropdown" as const,
31
30
  showIconsOnly: false,
32
- options: [
33
- { type: 'block' as const, id: 'no-tag' }
34
- ]
35
- }
36
- ]
37
- }
31
+ options: [{ type: "block" as const, id: "no-tag" }],
32
+ },
33
+ ],
34
+ },
38
35
  };
39
36
 
40
37
  export function RichTextEditorComponent({
@@ -49,11 +46,11 @@ export function RichTextEditorComponent({
49
46
  updateFieldValue?: (value: string) => void;
50
47
  }) {
51
48
  const editContextRef = useEditContextRef();
52
- const modifiedFieldsContext = useModifiedFieldsContext();
49
+ const modifiedFieldsContext = useModifiedFieldsContext();
53
50
  const [focused, setFocused] = useState(false);
54
51
  const [value, setValue] = useState(field.value as string);
55
52
  const editorRef = useRef<HTMLDivElement>(null);
56
-
53
+
57
54
  if (!editContextRef.current) return null;
58
55
 
59
56
  const fieldItem = field.descriptor.item;
@@ -69,11 +66,12 @@ export function RichTextEditorComponent({
69
66
 
70
67
  useEffect(() => {
71
68
  // Only update if the editor is not currently being edited by the user
72
- const isEditorActive = focused && editorRef.current?.contains(document.activeElement);
73
- const newValue = field.isHistoric
74
- ? field.value as string
75
- : modifiedField?.value ?? (field.value as string);
76
-
69
+ const isEditorActive =
70
+ focused && editorRef.current?.contains(document.activeElement);
71
+ const newValue = field.isHistoric
72
+ ? (field.value as string)
73
+ : (modifiedField?.value ?? (field.value as string));
74
+
77
75
  if (!isEditorActive && newValue !== value) {
78
76
  setValue(newValue);
79
77
  }
@@ -95,7 +93,11 @@ export function RichTextEditorComponent({
95
93
 
96
94
  const handleChange = (newValue: string) => {
97
95
  // Skip empty content patterns for both paragraph and no-tag blocks
98
- if ((newValue === "<p><br></p>" || newValue === "<br>" || newValue === "") && !field.value) return;
96
+ if (
97
+ (newValue === "<p><br></p>" || newValue === "<br>" || newValue === "") &&
98
+ !field.value
99
+ )
100
+ return;
99
101
  if (newValue !== value && !readOnly) {
100
102
  setValue(newValue);
101
103
  debouncedSetFieldvalue(newValue);
@@ -104,13 +106,13 @@ export function RichTextEditorComponent({
104
106
 
105
107
  // Use the profile directly or fall back to the minimal profile
106
108
  const editorProfile = profile ?? FALLBACK_PROFILE;
107
-
109
+
108
110
  // const editorProfile = getDebugProfile(); // Debug profile with all options
109
111
  // console.log(editorProfile);
110
112
 
111
113
  return (
112
114
  <div ref={editorRef}>
113
- <ReactSlate
115
+ <SimpleRichTextEditor
114
116
  value={value}
115
117
  onChange={handleChange}
116
118
  onFocus={() => setFocused(true)}
@@ -172,6 +172,7 @@ export function SingleLineText({
172
172
  style={{ width: "100%" }}
173
173
  onChange={handleChange}
174
174
  onSelect={handleSelect}
175
+ onBlur={editContextRef.current?.operations.onFieldBlur}
175
176
  />
176
177
  </div>
177
178
  );