@alpaca-editor/core 1.0.4013 → 1.0.4015

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 (79) hide show
  1. package/dist/components/ui/popover.js +6 -3
  2. package/dist/components/ui/popover.js.map +1 -1
  3. package/dist/editor/Terminal.d.ts +6 -0
  4. package/dist/editor/Terminal.js +10 -4
  5. package/dist/editor/Terminal.js.map +1 -1
  6. package/dist/editor/ai/Agents.js +133 -13
  7. package/dist/editor/ai/Agents.js.map +1 -1
  8. package/dist/editor/ai/AiTerminal.d.ts +2 -1
  9. package/dist/editor/ai/AiTerminal.js +86 -139
  10. package/dist/editor/ai/AiTerminal.js.map +1 -1
  11. package/dist/editor/media-selector/AiImageSearch.js +2 -1
  12. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  13. package/dist/editor/media-selector/AiImageSearchPrompt.js +2 -1
  14. package/dist/editor/media-selector/AiImageSearchPrompt.js.map +1 -1
  15. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +4 -2
  16. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  17. package/dist/editor/services/agentService.d.ts +59 -0
  18. package/dist/editor/services/agentService.js +26 -0
  19. package/dist/editor/services/agentService.js.map +1 -0
  20. package/dist/editor/services/aiService.d.ts +22 -4
  21. package/dist/editor/services/aiService.js +131 -20
  22. package/dist/editor/services/aiService.js.map +1 -1
  23. package/dist/editor/services/contextService.js +6 -4
  24. package/dist/editor/services/contextService.js.map +1 -1
  25. package/dist/editor/sidebar/SidebarView.js +2 -5
  26. package/dist/editor/sidebar/SidebarView.js.map +1 -1
  27. package/dist/editor/sidebar/ViewSelector.js +1 -1
  28. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  29. package/dist/editor/ui/SimpleIconButton.d.ts +2 -2
  30. package/dist/editor/ui/SimpleIconButton.js +5 -3
  31. package/dist/editor/ui/SimpleIconButton.js.map +1 -1
  32. package/dist/editor/utils/jsonCleaner.d.ts +8 -0
  33. package/dist/editor/utils/jsonCleaner.js +76 -0
  34. package/dist/editor/utils/jsonCleaner.js.map +1 -0
  35. package/dist/editor/views/CompareView.js +2 -2
  36. package/dist/editor/views/CompareView.js.map +1 -1
  37. package/dist/page-wizard/steps/ContentStep.js +7 -2
  38. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  39. package/dist/page-wizard/steps/FindItemsStep.js +4 -1
  40. package/dist/page-wizard/steps/FindItemsStep.js.map +1 -1
  41. package/dist/page-wizard/steps/ImagesStep.js +13 -7
  42. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  43. package/dist/page-wizard/steps/LayoutStep.d.ts +1 -1
  44. package/dist/page-wizard/steps/LayoutStep.js +22 -20
  45. package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
  46. package/dist/page-wizard/steps/MetaDataStep.js +8 -15
  47. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  48. package/dist/page-wizard/steps/SelectStep.js +9 -4
  49. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  50. package/dist/page-wizard/steps/StructureStep.js +3 -1
  51. package/dist/page-wizard/steps/StructureStep.js.map +1 -1
  52. package/dist/revision.d.ts +2 -2
  53. package/dist/revision.js +2 -2
  54. package/dist/styles.css +10 -11
  55. package/package.json +1 -1
  56. package/src/components/ui/popover.tsx +6 -3
  57. package/src/editor/Terminal.tsx +12 -3
  58. package/src/editor/ai/Agents.tsx +212 -16
  59. package/src/editor/ai/AiTerminal.tsx +113 -173
  60. package/src/editor/ai/GhostWriter.tsx_ +3 -3
  61. package/src/editor/media-selector/AiImageSearch.tsx +2 -2
  62. package/src/editor/media-selector/AiImageSearchPrompt.tsx +2 -2
  63. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +5 -5
  64. package/src/editor/services/agentService.ts +83 -0
  65. package/src/editor/services/aiService.ts +176 -33
  66. package/src/editor/services/contextService.ts +5 -6
  67. package/src/editor/sidebar/SidebarView.tsx +10 -6
  68. package/src/editor/sidebar/ViewSelector.tsx +2 -2
  69. package/src/editor/ui/SimpleIconButton.tsx +20 -14
  70. package/src/editor/utils/jsonCleaner.ts +92 -0
  71. package/src/editor/views/CompareView.tsx +2 -2
  72. package/src/page-wizard/steps/ContentStep.tsx +10 -9
  73. package/src/page-wizard/steps/FindItemsStep.tsx +7 -5
  74. package/src/page-wizard/steps/ImagesStep.tsx +16 -11
  75. package/src/page-wizard/steps/LayoutStep.tsx +24 -28
  76. package/src/page-wizard/steps/MetaDataStep.tsx +11 -21
  77. package/src/page-wizard/steps/SelectStep.tsx +11 -8
  78. package/src/page-wizard/steps/StructureStep.tsx +4 -5
  79. package/src/revision.ts +2 -2
@@ -8,10 +8,13 @@ import { Terminal } from "../Terminal";
8
8
  import { useEditContext } from "../client/editContext";
9
9
  import { Dropdown } from "primereact/dropdown";
10
10
 
11
- import Cookies from "universal-cookie";
12
11
  import { WizardIcon } from "../ui/Icons";
13
12
  import { AiResponseMessage } from "./AiResponseMessage";
14
- import { AiProfile, loadAiProfiles } from "../services/aiService";
13
+ import {
14
+ AiProfile,
15
+ loadAiProfiles,
16
+ executePrompt,
17
+ } from "../services/aiService";
15
18
  import { EditOperation } from "../../types";
16
19
  import { SimpleIconButton } from "../ui/SimpleIconButton";
17
20
  import { Settings } from "lucide-react";
@@ -35,7 +38,7 @@ export type ToolCall = {
35
38
  };
36
39
 
37
40
  export type Message = {
38
- id: number;
41
+ id: string; // Changed from number to string for UUID support
39
42
  content: string;
40
43
  formattedContent?: string;
41
44
  name: string;
@@ -53,6 +56,7 @@ export type AiContext = {
53
56
  export type AiTerminalOptions = {
54
57
  initialPrompt?: string;
55
58
  hiddenSystemPrompt?: string;
59
+ initialMessages?: Message[];
56
60
  };
57
61
 
58
62
  export function AiTerminal({
@@ -71,7 +75,7 @@ export function AiTerminal({
71
75
 
72
76
  if (!editContext) return null;
73
77
 
74
- const [messages, setMessages] = useState<Message[]>([]);
78
+ const [messages, setMessages] = useState<Message[]>(options?.initialMessages || []);
75
79
  const [response, setResponse] = useState<Response>();
76
80
  const [model, setModel] = useState<string>();
77
81
  const [prompt, setPrompt] = useState("");
@@ -81,7 +85,7 @@ export function AiTerminal({
81
85
  const [agentId] = useState<string>(() => crypto.randomUUID());
82
86
  const selection = editContext.selection;
83
87
  const terminalRef = useRef<{ submit: () => void }>(null);
84
- const [responseMessages, setResponseMessages] = useState<Message[]>([]);
88
+ const [responseMessages, setResponseMessages] = useState<Message[]>(options?.initialMessages || []);
85
89
  const [showSettings, setShowSettings] = useState(false);
86
90
  const settingsRef = useRef<HTMLDivElement>(null);
87
91
 
@@ -120,6 +124,91 @@ export function AiTerminal({
120
124
  messagesRef.current = responseMessages;
121
125
  }, [responseMessages]);
122
126
 
127
+ // 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);
130
+
131
+ // Effect to set up initial messages for display
132
+ useEffect(() => {
133
+ if (options?.initialMessages && options.initialMessages.length > 0) {
134
+ console.log("AiTerminal: Loading initial messages", options.initialMessages);
135
+
136
+ // Format the initial messages for display
137
+ const formattedMessages = options.initialMessages.map((message) => {
138
+ const formattedContent = message.content
139
+ ?.trim()
140
+ ?.replaceAll("\n", "<br>")
141
+ ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
142
+
143
+ return {
144
+ ...message,
145
+ content: message.content || "",
146
+ formattedContent: formattedContent,
147
+ tool_calls: message.tool_calls || [],
148
+ };
149
+ });
150
+
151
+ console.log("AiTerminal: Formatted messages", formattedMessages);
152
+
153
+ // Update the internal message states
154
+ setMessages(formattedMessages);
155
+ setResponseMessages(formattedMessages);
156
+
157
+ // Create a response object for internal state
158
+ const initialResponse: Response = {
159
+ messages: formattedMessages,
160
+ editOperations: [],
161
+ numInputTokens: 0,
162
+ numOutputTokens: 0,
163
+ numCachedTokens: 0,
164
+ state: "loaded"
165
+ };
166
+
167
+ console.log("AiTerminal: Setting response", initialResponse);
168
+ setResponse(initialResponse);
169
+
170
+ // Create individual Terminal messages for each conversation message
171
+ const terminalMessages: TerminalMessage[] = [];
172
+
173
+ formattedMessages.forEach((message) => {
174
+ if (message.role === "user") {
175
+ // User messages appear as commands
176
+ terminalMessages.push({
177
+ type: "command",
178
+ text: message.content
179
+ });
180
+ } else if (message.role === "assistant") {
181
+ // Assistant messages appear as responses
182
+ terminalMessages.push({
183
+ type: "response",
184
+ text: (
185
+ <div
186
+ dangerouslySetInnerHTML={{
187
+ __html: message.formattedContent || message.content || "",
188
+ }}
189
+ />
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
+ });
204
+ });
205
+ }
206
+ });
207
+
208
+ setInitialTerminalMessages(terminalMessages);
209
+ }
210
+ }, [options?.initialMessages]);
211
+
123
212
  // Handle click outside for settings popover
124
213
  useEffect(() => {
125
214
  function handleClickOutside(event: MouseEvent) {
@@ -150,13 +239,13 @@ export function AiTerminal({
150
239
  if (updatedMessages && Array.isArray(updatedMessages)) {
151
240
  const formattedMessages = updatedMessages.map((message) => {
152
241
  const formattedContent = message.content
153
- .trim()
154
- .replaceAll("\n", "<br>")
155
- ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>");
242
+ ?.trim()
243
+ ?.replaceAll("\n", "<br>")
244
+ ?.replace(/\*\*(.*?)\*\*/g, "<b>$1</b>") || "";
156
245
 
157
246
  return {
158
247
  ...message,
159
- content: message.content,
248
+ content: message.content || "",
160
249
  formattedContent: formattedContent,
161
250
  tool_calls: message.tool_calls || [],
162
251
  };
@@ -192,7 +281,7 @@ export function AiTerminal({
192
281
  callback: (text: React.ReactNode, finished: boolean) => void,
193
282
  ) {
194
283
  const userMessage = {
195
- id: Date.now(), // Add unique id
284
+ id: crypto.randomUUID(), // Add unique id
196
285
  content: text,
197
286
  role: "user",
198
287
  name: "user",
@@ -214,7 +303,7 @@ export function AiTerminal({
214
303
  role: "system",
215
304
  name: "system",
216
305
  content: options.hiddenSystemPrompt,
217
- id: 0, // System message id
306
+ id: crypto.randomUUID(), // Use UUID instead of hardcoded 0
218
307
  toolCalls: [],
219
308
  },
220
309
  ]
@@ -223,72 +312,21 @@ export function AiTerminal({
223
312
  ];
224
313
 
225
314
  const response = await executePrompt(
226
- activeProfile.id,
227
315
  messages,
228
- selection,
229
- editContext!.sessionId,
230
- model,
231
- selectedText,
232
316
  context,
233
- agentId,
317
+ {
318
+ profileId: activeProfile.id,
319
+ selection,
320
+ selectedText,
321
+ model,
322
+ sessionId: editContext!.sessionId,
323
+ agentId,
324
+ addSelectedComponents: true,
325
+ },
326
+ undefined,
234
327
  (response: any) => {
235
328
  setResponse(response);
236
329
  handleResponse(response, callback, false);
237
- // if (response.editOperations.length) {
238
- // if (!editContext) return;
239
-
240
- // const newOps = response.editOperations.slice(lastOpIndex);
241
-
242
- // if (newOps.length === 0) return;
243
-
244
- // const isEditTextFieldOp = (op: EditOperation) => {
245
- // if (op.type !== "edit-field") return false;
246
- // const editFieldOp = op as EditFieldOperation;
247
- // return (
248
- // editFieldOp.fieldType &&
249
- // editFieldOp.fieldType.indexOf("text") !== -1
250
- // );
251
- // };
252
-
253
- // const isEditTextField = isEditTextFieldOp(newOps[newOps.length - 1]);
254
-
255
- // if (isEditTextField) lastOpIndex = response.editOperations.length - 1;
256
- // else lastOpIndex = response.editOperations.length;
257
-
258
- // newOps.forEach((op: EditOperation) => {
259
- // if (isEditTextFieldOp(op)) {
260
- // const editFieldOp = op as EditFieldOperation;
261
-
262
- // if (editFieldOp.itemId) {
263
- // const fieldDescriptor = {
264
- // item: {
265
- // ...editFieldOp.mainItem,
266
- // id: editFieldOp.itemId,
267
- // },
268
- // fieldId: editFieldOp.fieldId,
269
- // };
270
- // editContext.itemsRepository.updateFieldValue(
271
- // fieldDescriptor,
272
- // editFieldOp.user ?? { name: "unknown", ai: false },
273
- // false,
274
- // editFieldOp.value,
275
- // );
276
-
277
- // editContext.select([editFieldOp.itemId]);
278
- // editContext.setScrollIntoView(editFieldOp.itemId);
279
-
280
- // editContext?.setFocusedField(fieldDescriptor, false);
281
- // }
282
- // } else {
283
- // const addOp = op as AddComponentOperation;
284
- // if (op.type === "add-component" && addOp.componentId) {
285
- // const newComponentId = addOp.componentId;
286
- // editContext.select([newComponentId]);
287
- // editContext.setScrollIntoView(newComponentId);
288
- // }
289
- // }
290
- // });
291
- // }
292
330
  },
293
331
  );
294
332
 
@@ -320,7 +358,7 @@ export function AiTerminal({
320
358
 
321
359
  return (
322
360
  <div
323
- className="relative flex h-full flex-1 flex-col pl-1.5"
361
+ className="relative flex h-full flex-1 flex-col"
324
362
  data-testid="ai-terminal"
325
363
  >
326
364
  <div className="relative flex-1">
@@ -332,7 +370,9 @@ export function AiTerminal({
332
370
  setMessages([]);
333
371
  setResponseMessages([]);
334
372
  setResponse(undefined);
373
+ setInitialTerminalMessages(undefined);
335
374
  }}
375
+ initialMessages={initialTerminalMessages}
336
376
  infobar={
337
377
  response?.numInputTokens && (
338
378
  <div
@@ -448,103 +488,3 @@ export function AiTerminal({
448
488
  </div>
449
489
  );
450
490
  }
451
-
452
- async function executePrompt(
453
- profileId: string,
454
- messages: Message[],
455
- selection: string[],
456
- session: string | null,
457
- model: string | null,
458
- selectedText: string | null,
459
- context: AiContext,
460
- agentId: string,
461
- callback: (response: any) => void,
462
- ): Promise<Response | null> {
463
- const response = await fetch(context.endpoint, {
464
- method: "POST",
465
- body: JSON.stringify({
466
- ...context.promptData,
467
- profileId,
468
- messages,
469
- selection,
470
- addSelectedComponents: true,
471
- selectedText,
472
- model,
473
- sessionId: session,
474
- agentId,
475
- }),
476
- credentials: "include",
477
- headers: {
478
- "Content-Type": "application/json",
479
- Cookie: new Cookies().getAll(),
480
- },
481
- });
482
-
483
- if (!response.ok) {
484
- const text = await response.text();
485
- return {
486
- messages: [
487
- {
488
- content: "There was an error processing your request: " + text,
489
- id: 0,
490
- name: "assistant",
491
- role: "assistant",
492
- },
493
- ],
494
- editOperations: [],
495
- numInputTokens: 0,
496
- numOutputTokens: 0,
497
- numCachedTokens: 0,
498
- state: "error",
499
- };
500
- }
501
-
502
- if (!response?.body) return null;
503
-
504
- const reader = response.body.getReader();
505
- const decoder = new TextDecoder();
506
- let buffer = "";
507
-
508
- let result = null;
509
-
510
- while (true) {
511
- const { done, value } = await reader.read();
512
-
513
- if (done) {
514
- break;
515
- }
516
-
517
- buffer += decoder.decode(value, { stream: true }); // 'stream: true' ensures that any incomplete multi-byte characters aren't malformed.
518
-
519
- // Split the buffer by newline and keep the last partial line for the next iteration.
520
- const lines = buffer.split("\n");
521
-
522
- if (lines.length > 0) {
523
- buffer = lines.pop() || ""; // Incomplete line (if any) is kept for the next iteration.
524
-
525
- for (let line of lines) {
526
- if (line.trim() === "") continue; // Skip empty lines if any.
527
-
528
- try {
529
- const jsonData = JSON.parse(line);
530
- callback(jsonData);
531
- result = jsonData;
532
- } catch (e) {
533
- console.error("Error parsing line:" + line, e);
534
- }
535
- }
536
- }
537
- }
538
-
539
- // If there's any remaining content in the buffer after processing all chunks, try to process it.
540
- if (buffer.trim() !== "") {
541
- try {
542
- const jsonData = JSON.parse(buffer);
543
- result = jsonData;
544
- } catch (e) {
545
- console.error("Error parsing the final buffer content:", e);
546
- }
547
- }
548
-
549
- return result;
550
- }
@@ -267,16 +267,16 @@ export function GhostWriter() {
267
267
 
268
268
  role: "user",
269
269
  name: "user",
270
+ id: Date.now(),
270
271
  },
271
272
  ],
272
- editContext,
273
- createEditorAiContext,
273
+ { editContext, createAiContext: createEditorAiContext },
274
274
  {
275
275
  addAllContent: true,
276
276
  profile: "ghostwriter",
277
+ model: "gpt-4.1",
277
278
  },
278
279
  undefined,
279
- "gpt-4.1",
280
280
  handleAiResponse,
281
281
  );
282
282
 
@@ -61,10 +61,10 @@ export function AiImageSearch({
61
61
  "Reply with search terms only!",
62
62
  name: "user",
63
63
  role: "user",
64
+ id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
64
65
  },
65
66
  ],
66
- editContext,
67
- createEditorAiContext,
67
+ { editContext, createAiContext: createEditorAiContext },
68
68
  { allowedFunctions: ["get-content"], addContextContent: true },
69
69
  { signal: abortController.signal },
70
70
  );
@@ -44,10 +44,10 @@ export function AiImageSearchPrompt({
44
44
  "Reply with search terms only!",
45
45
  name: "user",
46
46
  role: "user",
47
+ id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
47
48
  },
48
49
  ],
49
- editContext,
50
- createEditorAiContext,
50
+ { editContext, createAiContext: createEditorAiContext },
51
51
  { allowedFunctions: ["get-content"], addContextContent: true },
52
52
  { signal: abortController.signal },
53
53
  );
@@ -350,11 +350,13 @@ ONLY provide the completion text (what comes after the user's text), never repea
350
350
  name: "system",
351
351
  role: "system",
352
352
  content: systemPrompt,
353
+ id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
353
354
  },
354
355
  {
355
356
  name: "user",
356
357
  role: "user",
357
358
  content: `Complete this text. ONLY provide the completion (do not repeat my text): ${contentUpToCursor}`,
359
+ id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
358
360
  },
359
361
  ];
360
362
 
@@ -365,8 +367,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
365
367
  try {
366
368
  const result = await executePrompt(
367
369
  messages,
368
- editContext,
369
- () => ({
370
+ {
370
371
  endpoint: "/alpaca/editor/ai/complete",
371
372
  promptData: {
372
373
  itemid: itemId,
@@ -376,10 +377,9 @@ ONLY provide the completion text (what comes after the user's text), never repea
376
377
  fieldname: fieldName,
377
378
  content: contentUpToCursor,
378
379
  },
379
- }),
380
- {},
380
+ },
381
+ { model: "gpt-4.1-nano" },
381
382
  { signal },
382
- "gpt-4.1-nano",
383
383
  );
384
384
 
385
385
  return result;
@@ -0,0 +1,83 @@
1
+ import { get } from "./serviceHelper";
2
+
3
+ export interface AgentChat {
4
+ id: string;
5
+ name: string;
6
+ sessionId: string;
7
+ userId: string;
8
+ userDisplayName: string;
9
+ itemId: string;
10
+ itemPath: string;
11
+ language: string;
12
+ version: number;
13
+ profileId?: string;
14
+ profileName: string;
15
+ model: string;
16
+ status: "active" | "completed" | "error" | "abandoned";
17
+ createdDate: string;
18
+ updatedDate: string;
19
+ lastMessageDate?: string;
20
+ totalTokensUsed: number;
21
+ totalInputTokens: number;
22
+ totalOutputTokens: number;
23
+ messageCount: number;
24
+ metadata?: string;
25
+ messages?: AgentChatMessage[];
26
+ }
27
+
28
+ export interface AgentChatMessage {
29
+ id: string;
30
+ agentId: string;
31
+ messageIndex: number;
32
+ role: string;
33
+ content: string;
34
+ name: string;
35
+ toolCallId?: string;
36
+ functionName?: string;
37
+ functionArguments?: string;
38
+ functionResult?: any;
39
+ functionError?: string;
40
+ isCompleted: boolean;
41
+ model?: string;
42
+ tokensUsed: number;
43
+ inputTokens: number;
44
+ outputTokens: number;
45
+ responseTimeMs?: number;
46
+ createdDate: string;
47
+ editOperations?: any[];
48
+ longRunningTaskIds?: string[];
49
+ metadata?: string;
50
+ }
51
+
52
+ /**
53
+ * Gets all agents for the current user
54
+ */
55
+ export async function getAgents(
56
+ status?: "active" | "completed" | "error" | "abandoned",
57
+ limit = 100
58
+ ) {
59
+ const url = `/alpaca/editor/ai/GetAgents${status ? `?status=${status}` : ""}${limit ? `${status ? "&" : "?"}limit=${limit}` : ""}`;
60
+ const response = await get<AgentChat[]>(url);
61
+ return response;
62
+ }
63
+
64
+ /**
65
+ * Gets a specific agent with its messages
66
+ */
67
+ export async function getAgent(agentId: string) {
68
+ const url = `/alpaca/editor/ai/GetAgent?agentId=${agentId}`;
69
+ const response = await get<AgentChat>(url);
70
+ return response;
71
+ }
72
+
73
+ /**
74
+ * Gets chat history for the current user
75
+ */
76
+ export async function getChatHistory(
77
+ status?: "active" | "completed" | "error" | "abandoned",
78
+ limit = 50
79
+ ) {
80
+ const url = `/alpaca/editor/ai/GetChatHistory${status ? `?status=${status}` : ""}${limit ? `${status ? "&" : "?"}limit=${limit}` : ""}`;
81
+ const response = await get<AgentChat[]>(url);
82
+ return response;
83
+ }