@alpaca-editor/core 1.0.4096 → 1.0.4098

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 (136) hide show
  1. package/dist/components/ui/button.d.ts +1 -1
  2. package/dist/components/ui/button.js +1 -0
  3. package/dist/components/ui/button.js.map +1 -1
  4. package/dist/components/ui/context-menu.d.ts +2 -2
  5. package/dist/components/ui/context-menu.js +16 -16
  6. package/dist/components/ui/context-menu.js.map +1 -1
  7. package/dist/editor/Editor.js +1 -1
  8. package/dist/editor/Editor.js.map +1 -1
  9. package/dist/editor/FieldActionsOverlay.js +40 -26
  10. package/dist/editor/FieldActionsOverlay.js.map +1 -1
  11. package/dist/editor/FieldListField.js +1 -1
  12. package/dist/editor/FieldListField.js.map +1 -1
  13. package/dist/editor/LinkEditorDialog.js +1 -1
  14. package/dist/editor/ai/AgentTerminal.js +56 -5
  15. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  16. package/dist/editor/ai/Agents.js +23 -9
  17. package/dist/editor/ai/Agents.js.map +1 -1
  18. package/dist/editor/ai/ContextInfoBar.js +15 -5
  19. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  20. package/dist/editor/ai/ToolCallDisplay.js +2 -0
  21. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  22. package/dist/editor/client/AboutDialog.js +7 -5
  23. package/dist/editor/client/AboutDialog.js.map +1 -1
  24. package/dist/editor/client/EditorShell.js +7 -2
  25. package/dist/editor/client/EditorShell.js.map +1 -1
  26. package/dist/editor/client/editContext.d.ts +2 -2
  27. package/dist/editor/client/hooks/useSocketMessageHandler.js +5 -0
  28. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  29. package/dist/editor/client/itemsRepository.js +1 -0
  30. package/dist/editor/client/itemsRepository.js.map +1 -1
  31. package/dist/editor/control-center/Setup.js +1 -1
  32. package/dist/editor/control-center/Setup.js.map +1 -1
  33. package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
  34. package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
  35. package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
  36. package/dist/editor/control-center/setup-steps/AiSetupStep/index.d.ts +0 -1
  37. package/dist/editor/control-center/setup-steps/AiSetupStep/index.js +3 -506
  38. package/dist/editor/control-center/setup-steps/AiSetupStep/index.js.map +1 -1
  39. package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -15
  40. package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js +226 -3
  41. package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -1
  42. package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +1 -1
  43. package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
  44. package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
  45. package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
  46. package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.d.ts +1 -7
  47. package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +323 -3
  48. package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -1
  49. package/dist/editor/control-center/setup-steps/AiSetupStep/types.d.ts +1 -0
  50. package/dist/editor/control-center/setup-steps/AiSetupStep/types.js +2 -0
  51. package/dist/editor/control-center/setup-steps/AiSetupStep/types.js.map +1 -0
  52. package/dist/editor/control-center/setup-steps/AiSetupStep/utils.d.ts +4 -0
  53. package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js +25 -0
  54. package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js.map +1 -0
  55. package/dist/editor/control-center/setup-steps/IndexSetupStep.js +2 -1
  56. package/dist/editor/control-center/setup-steps/IndexSetupStep.js.map +1 -1
  57. package/dist/editor/field-types/SingleLineText.js.map +1 -1
  58. package/dist/editor/field-types/TreeListEditor.js +102 -16
  59. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  60. package/dist/editor/field-types/richtext/components/ReactSlate.js +1 -1
  61. package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +1 -1
  62. package/dist/editor/menubar/toolbar-sections/EditControls.js +2 -2
  63. package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
  64. package/dist/editor/menubar/toolbar-sections/InsertControls.js +1 -1
  65. package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -1
  66. package/dist/editor/page-editor-chrome/FrameMenu.js +25 -12
  67. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  68. package/dist/editor/page-editor-chrome/SuggestionHighlighting.js +2 -2
  69. package/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -1
  70. package/dist/editor/page-viewer/PageViewer.js +2 -1
  71. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  72. package/dist/editor/reviews/Comments.js +4 -4
  73. package/dist/editor/reviews/Comments.js.map +1 -1
  74. package/dist/editor/services/agentService.d.ts +2 -0
  75. package/dist/editor/services/agentService.js.map +1 -1
  76. package/dist/editor/services/aiService.d.ts +1 -0
  77. package/dist/editor/services/aiService.js.map +1 -1
  78. package/dist/editor/sidebar/ComponentTree.js +18 -6
  79. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  80. package/dist/editor/sidebar/Insert.js +1 -1
  81. package/dist/editor/ui/Splitter.js +2 -1
  82. package/dist/editor/ui/Splitter.js.map +1 -1
  83. package/dist/editor/utils.js +0 -1
  84. package/dist/editor/utils.js.map +1 -1
  85. package/dist/page-wizard/steps/MetaDataStep.js +43 -41
  86. package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
  87. package/dist/page-wizard/steps/SelectStep.js +19 -4
  88. package/dist/page-wizard/steps/SelectStep.js.map +1 -1
  89. package/dist/revision.d.ts +2 -2
  90. package/dist/revision.js +2 -2
  91. package/dist/styles.css +15 -18
  92. package/package.json +1 -1
  93. package/src/components/ui/button.tsx +1 -0
  94. package/src/components/ui/context-menu.tsx +44 -20
  95. package/src/editor/Editor.tsx +1 -1
  96. package/src/editor/FieldActionsOverlay.tsx +113 -91
  97. package/src/editor/FieldListField.tsx +4 -1
  98. package/src/editor/LinkEditorDialog.tsx +1 -1
  99. package/src/editor/ai/AgentTerminal.tsx +84 -4
  100. package/src/editor/ai/Agents.tsx +18 -5
  101. package/src/editor/ai/ContextInfoBar.tsx +22 -6
  102. package/src/editor/ai/ToolCallDisplay.tsx +2 -0
  103. package/src/editor/client/AboutDialog.tsx +22 -17
  104. package/src/editor/client/EditorShell.tsx +8 -2
  105. package/src/editor/client/editContext.ts +2 -2
  106. package/src/editor/client/hooks/useSocketMessageHandler.ts +8 -0
  107. package/src/editor/client/itemsRepository.ts +1 -0
  108. package/src/editor/control-center/Setup.tsx +1 -1
  109. package/src/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.tsx +296 -0
  110. package/src/editor/control-center/setup-steps/AiSetupStep/index.tsx +7 -660
  111. package/src/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.tsx +363 -24
  112. package/src/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.tsx +1 -1
  113. package/src/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.tsx +139 -0
  114. package/src/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.tsx +385 -8
  115. package/src/editor/control-center/setup-steps/AiSetupStep/types.ts +1 -0
  116. package/src/editor/control-center/setup-steps/AiSetupStep/utils.ts +43 -0
  117. package/src/editor/control-center/setup-steps/IndexSetupStep.tsx +2 -0
  118. package/src/editor/field-types/SingleLineText.tsx +0 -9
  119. package/src/editor/field-types/TreeListEditor.tsx +115 -16
  120. package/src/editor/field-types/richtext/components/ReactSlate.tsx +1 -1
  121. package/src/editor/field-types/richtext/components/SimpleRichTextEditor.tsx +1 -1
  122. package/src/editor/menubar/toolbar-sections/EditControls.tsx +2 -2
  123. package/src/editor/menubar/toolbar-sections/InsertControls.tsx +1 -1
  124. package/src/editor/page-editor-chrome/FrameMenu.tsx +81 -68
  125. package/src/editor/page-editor-chrome/SuggestionHighlighting.tsx +5 -5
  126. package/src/editor/page-viewer/PageViewer.tsx +3 -2
  127. package/src/editor/reviews/Comments.tsx +13 -8
  128. package/src/editor/services/agentService.ts +3 -0
  129. package/src/editor/services/aiService.ts +2 -0
  130. package/src/editor/sidebar/ComponentTree.tsx +20 -6
  131. package/src/editor/sidebar/Insert.tsx +1 -1
  132. package/src/editor/ui/Splitter.tsx +2 -2
  133. package/src/editor/utils.ts +0 -1
  134. package/src/page-wizard/steps/MetaDataStep.tsx +61 -50
  135. package/src/page-wizard/steps/SelectStep.tsx +37 -4
  136. package/src/revision.ts +2 -2
@@ -1,106 +1,17 @@
1
- import React, { useCallback, useMemo, useState } from "react";
1
+ import { useState } from "react";
2
2
  import { Card } from "../../../../components/ui/card";
3
3
  import { useEditContext } from "../../../client/editContext";
4
- import { ItemDescriptor } from "../../../pageModel";
5
- import { getChildren } from "../../../services/contentService";
6
- import type { ItemTreeNodeData } from "../../../services/contentService";
7
4
  import { SparklesIcon } from "lucide-react";
8
- import { contentItemId } from "../../../../config/config";
9
- import { RequiredContainersList } from "./required-containers/RequiredContainersList";
5
+ import { RequiredContainersSection } from "./required-containers/RequiredContainersSection";
10
6
  import { ProviderSection } from "./provider/ProviderSection";
11
7
  import { GenerateToolsSection } from "./tools/GenerateToolsSection";
12
-
13
- export type StepState = "idle" | "checking" | "success" | "error";
14
-
15
- function findByName(
16
- items: ItemTreeNodeData[],
17
- name: string,
18
- ): ItemTreeNodeData | undefined {
19
- const target = name.toLowerCase();
20
- return items.find(
21
- (x) =>
22
- (((x.displayName as string) || x.name || "") as string).toLowerCase() ===
23
- target,
24
- );
25
- }
8
+ import type { StepState } from "./types";
26
9
 
27
10
  export function AiSetupStep() {
28
11
  const editContext = useEditContext();
29
12
  const [aiState, setAiState] = useState<StepState>("idle");
30
- const [aiProvider, setAiProvider] = useState<string>("");
31
- const [aiBusy, setAiBusy] = useState(false);
32
- const [aiError, setAiError] = useState<string | null>(null);
33
- const [apiKey, setApiKey] = useState<string>("");
34
-
35
- const [editorSettingsItem, setEditorSettingsItem] =
36
- useState<ItemDescriptor | null>(null);
37
- const [containersError, setContainersError] = useState<string | null>(null);
38
- const requiredContainers = useMemo(
39
- () => [
40
- { name: "Ai Models", templateId: "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b" },
41
- {
42
- name: "Ai Endpoints",
43
- templateId: "4592f2e0-06e4-470e-9820-7fd4ea148e00",
44
- },
45
- {
46
- name: "Ai Profiles",
47
- templateId: "4298ab78-2aaa-4d5f-bb3a-0bd321b86063",
48
- },
49
- {
50
- name: "Ai Schemas",
51
- templateId: "5214a52b-6c45-4671-97f2-703fe24e3d09",
52
- },
53
- { name: "Ai Quotas", templateId: "7a08ff28-70ed-459b-a7f2-db2a78d88f46" },
54
- {
55
- name: "AI Generators",
56
- templateId: "9430a3e9-7397-4598-9a55-2b263c927497",
57
- },
58
- { name: "AI Tools", templateId: "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11" },
59
- ],
60
- [],
61
- );
62
- const [containerStates, setContainerStates] = useState<
63
- Record<string, StepState>
64
- >({});
65
- const [busyMap, setBusyMap] = useState<Record<string, boolean>>({});
66
-
67
13
  const userLang = editContext?.contentEditorItem?.language || "en";
68
14
 
69
- const aiOptions = useMemo(
70
- () => [
71
- { value: "openai", label: "OpenAI" },
72
- { value: "azure-openai", label: "Azure OpenAI" },
73
- { value: "openrouter", label: "OpenRouter" },
74
- ],
75
- [],
76
- );
77
-
78
- const resolvePathUnderContent = React.useCallback(
79
- async (names: string[]): Promise<ItemDescriptor | null> => {
80
- if (!editContext?.sessionId) return null;
81
- let currentId = contentItemId;
82
- for (const segment of names) {
83
- const children = (await getChildren(
84
- currentId,
85
- editContext.sessionId,
86
- [],
87
- false,
88
- userLang,
89
- "path",
90
- )) as unknown as ItemTreeNodeData[];
91
- const next = findByName(children, segment);
92
- if (!next) return null;
93
- currentId = next.id;
94
- }
95
- return {
96
- id: currentId,
97
- language: userLang,
98
- version: 0,
99
- } as ItemDescriptor;
100
- },
101
- [editContext?.sessionId, userLang],
102
- );
103
-
104
15
  // IDs for tool templates/fields
105
16
  const AI_TOOLS_TEMPLATE_ID = "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11"; // container
106
17
  const AI_TOOL_TEMPLATE_ID = "a2e8a0d9-7b1f-4d1a-a2d8-8f3ea6d6f0b1"; // item template
@@ -108,582 +19,18 @@ export function AiSetupStep() {
108
19
  const FIELD_LABEL_ID = "5a19f5a5-1d21-4b6a-9f83-6f3fc0b34b2e";
109
20
  const FIELD_DESCRIPTION_ID = "6b2e4b8e-8a9f-4d8f-9f6e-1a2b3c4d5e6f";
110
21
 
111
- const [toolsBusy, setToolsBusy] = useState(false);
112
- const [toolsError, setToolsError] = useState<string | null>(null);
113
-
114
- const ensureAiToolsAndGenerate = useCallback(async () => {
115
- if (!editContext) return;
116
- try {
117
- setToolsBusy(true);
118
- setToolsError(null);
119
-
120
- // Resolve /Settings/Editor
121
- const settingsItem = await resolvePathUnderContent([
122
- "Settings",
123
- "Editor",
124
- ]);
125
- if (!settingsItem)
126
- throw new Error("Editor settings item not found. Create it first.");
127
-
128
- // Ensure AI Tools container exists
129
- const editorChildren = (await getChildren(
130
- settingsItem.id,
131
- editContext.sessionId!,
132
- [],
133
- false,
134
- userLang,
135
- "path",
136
- )) as unknown as ItemTreeNodeData[];
137
-
138
- let aiToolsParent = findByName(editorChildren, "AI Tools");
139
- if (!aiToolsParent) {
140
- const created = await editContext.operations.createItem(
141
- settingsItem,
142
- AI_TOOLS_TEMPLATE_ID,
143
- "AI Tools",
144
- );
145
- if (!created) throw new Error("Failed to create 'AI Tools' container");
146
- aiToolsParent = {
147
- id: created.id,
148
- name: "AI Tools",
149
- displayName: "AI Tools",
150
- thumbUrl: "",
151
- previewUrl: "",
152
- templateId: "",
153
- icon: "",
154
- hasChildren: false,
155
- isComponent: false,
156
- language: userLang,
157
- version: 0,
158
- hasLayout: false,
159
- } as unknown as ItemTreeNodeData;
160
- }
161
-
162
- // Get existing tool items under AI Tools
163
- const toolChildren = (await getChildren(
164
- aiToolsParent.id,
165
- editContext.sessionId!,
166
- [],
167
- false,
168
- userLang,
169
- "path",
170
- )) as unknown as ItemTreeNodeData[];
171
-
172
- const findChildByLabel = (label: string) =>
173
- findByName(toolChildren, label);
174
-
175
- // Known tool functions (aligned with backend function names)
176
- const tools: {
177
- functionName: string;
178
- label: string;
179
- description?: string;
180
- }[] = [
181
- {
182
- functionName: "get-content",
183
- label: "Get Content",
184
- description: "Returns page content or selected components",
185
- },
186
- {
187
- functionName: "edit-field",
188
- label: "Edit Field",
189
- description: "Edits a field on the page or datasource",
190
- },
191
- {
192
- functionName: "suggest-field-edit",
193
- label: "Suggest Field Edit",
194
- description: "Suggests changes to a field's content",
195
- },
196
- {
197
- functionName: "create-item",
198
- label: "Create Item",
199
- description: "Creates a new item using a template",
200
- },
201
- {
202
- functionName: "load-item",
203
- label: "Load Item",
204
- description: "Loads an item for context",
205
- },
206
- {
207
- functionName: "get-items",
208
- label: "Get Items",
209
- description: "Finds items by criteria",
210
- },
211
- {
212
- functionName: "get-children",
213
- label: "Get Children",
214
- description: "Lists child items under a parent",
215
- },
216
- {
217
- functionName: "get-insertoptions",
218
- label: "Get Insert Options",
219
- description: "Lists available insert templates for an item",
220
- },
221
- {
222
- functionName: "add-component",
223
- label: "Add Component",
224
- description: "Adds a component to a placeholder",
225
- },
226
- {
227
- functionName: "remove-component",
228
- label: "Remove Component",
229
- description: "Removes a component from the page",
230
- },
231
- {
232
- functionName: "move-components",
233
- label: "Move Components",
234
- description: "Moves components between placeholders",
235
- },
236
- {
237
- functionName: "get-placeholders",
238
- label: "Get Placeholders",
239
- description: "Lists placeholders for a component",
240
- },
241
- {
242
- functionName: "get-component-props-and-placeholders",
243
- label: "Get Component Props and Placeholders",
244
- description: "Returns component prop schema and placeholders",
245
- },
246
- {
247
- functionName: "search-content",
248
- label: "Search Content",
249
- description: "Searches content across the index",
250
- },
251
- {
252
- functionName: "search-images",
253
- label: "Search Images",
254
- description: "Searches images for use in content",
255
- },
256
- {
257
- functionName: "google-search",
258
- label: "Google Search",
259
- description: "Performs a web search",
260
- },
261
- {
262
- functionName: "scrape-webpage",
263
- label: "Scrape Webpage",
264
- description: "Fetches a webpage and extracts content",
265
- },
266
- {
267
- functionName: "edit-image",
268
- label: "Edit Image",
269
- description: "Uses AI to modify an image",
270
- },
271
- {
272
- functionName: "get-picture-description",
273
- label: "Get Picture Description",
274
- description: "Describes an image",
275
- },
276
- {
277
- functionName: "add-comment",
278
- label: "Add Comment",
279
- description: "Adds a comment to the page",
280
- },
281
- {
282
- functionName: "get-comments",
283
- label: "Get Comments",
284
- description: "Lists comments on the page",
285
- },
286
- {
287
- functionName: "get-suggestions",
288
- label: "Get Suggestions",
289
- description: "Provides AI suggestions",
290
- },
291
- ];
292
-
293
- // Create or update tool items
294
- for (const t of tools) {
295
- let node = findChildByLabel(t.label);
296
- if (!node) {
297
- const created = await editContext.operations.createItem(
298
- {
299
- id: aiToolsParent.id,
300
- language: userLang,
301
- version: 0,
302
- } as ItemDescriptor,
303
- AI_TOOL_TEMPLATE_ID,
304
- t.label,
305
- );
306
- if (!created) throw new Error(`Failed to create tool '${t.label}'`);
307
- node = {
308
- id: created.id,
309
- name: t.label,
310
- displayName: t.label,
311
- thumbUrl: "",
312
- previewUrl: "",
313
- templateId: "",
314
- icon: "",
315
- hasChildren: false,
316
- isComponent: false,
317
- language: userLang,
318
- version: 0,
319
- hasLayout: false,
320
- } as unknown as ItemTreeNodeData;
321
- }
322
-
323
- // Set Function Name
324
- await editContext.operations.editField({
325
- field: {
326
- fieldId: FIELD_FUNCTION_NAME_ID,
327
- item: { id: node.id, language: userLang, version: 0 },
328
- },
329
- value: t.functionName,
330
- rawValue: t.functionName,
331
- refresh: "delayed",
332
- });
333
-
334
- // Set Label
335
- await editContext.operations.editField({
336
- field: {
337
- fieldId: FIELD_LABEL_ID,
338
- item: { id: node.id, language: userLang, version: 0 },
339
- },
340
- value: t.label,
341
- rawValue: t.label,
342
- refresh: "delayed",
343
- });
344
-
345
- // Set Description
346
- if (t.description) {
347
- await editContext.operations.editField({
348
- field: {
349
- fieldId: FIELD_DESCRIPTION_ID,
350
- item: { id: node.id, language: userLang, version: 0 },
351
- },
352
- value: t.description,
353
- rawValue: t.description,
354
- refresh: "delayed",
355
- });
356
- }
357
- }
358
-
359
- setAiState("success");
360
- editContext.requestRefresh?.("immediate");
361
- } catch (e: any) {
362
- setToolsError(e?.message || "Failed to generate AI tools");
363
- } finally {
364
- setToolsBusy(false);
365
- }
366
- }, [editContext, resolvePathUnderContent, userLang]);
367
-
368
- const createAiEndpoint = useCallback(async () => {
369
- if (!aiProvider || !editContext) return;
370
- try {
371
- setAiBusy(true);
372
- setAiError(null);
373
-
374
- const settingsItem = await resolvePathUnderContent([
375
- "Settings",
376
- "Editor",
377
- ]);
378
- if (!settingsItem)
379
- throw new Error("Editor settings item not found. Create it first.");
380
-
381
- const children = (await getChildren(
382
- settingsItem.id,
383
- editContext.sessionId!,
384
- [],
385
- false,
386
- userLang,
387
- "path",
388
- )) as unknown as ItemTreeNodeData[];
389
- let aiEndpointsParent = findByName(children, "Ai Endpoints");
390
- if (!aiEndpointsParent) {
391
- const aiEndpointsTemplateId = "4592f2e0-06e4-470e-9820-7fd4ea148e00";
392
- const createdContainer = await editContext.operations.createItem(
393
- settingsItem,
394
- aiEndpointsTemplateId,
395
- "Ai Endpoints",
396
- );
397
- if (!createdContainer)
398
- throw new Error("Failed to create 'Ai Endpoints' container");
399
- aiEndpointsParent = {
400
- id: createdContainer.id,
401
- name: "Ai Endpoints",
402
- thumbUrl: "",
403
- previewUrl: "",
404
- templateId: "",
405
- icon: "",
406
- hasChildren: false,
407
- isComponent: false,
408
- displayName: "Ai Endpoints",
409
- language: userLang,
410
- version: 0,
411
- hasLayout: false,
412
- } as unknown as ItemTreeNodeData;
413
- }
414
-
415
- const endpointTemplateId = "a6358b92-a9ea-4dd8-b4e1-7d6d3a3b9c40";
416
- const endpointName =
417
- aiProvider === "openai"
418
- ? "OpenAI"
419
- : aiProvider === "azure-openai"
420
- ? "Azure OpenAI"
421
- : "Open Router";
422
-
423
- // Find or create endpoint
424
- let endpointItem: ItemDescriptor | null = null;
425
- const epChildren = (await getChildren(
426
- aiEndpointsParent!.id,
427
- editContext.sessionId!,
428
- [],
429
- false,
430
- userLang,
431
- "path",
432
- )) as unknown as ItemTreeNodeData[];
433
- const existingEndpoint = findByName(epChildren, endpointName);
434
- if (existingEndpoint) {
435
- endpointItem = {
436
- id: existingEndpoint.id,
437
- language: userLang,
438
- version: 0,
439
- } as ItemDescriptor;
440
- } else {
441
- const created = await editContext.operations.createItem(
442
- {
443
- id: aiEndpointsParent!.id,
444
- language: userLang,
445
- version: 0,
446
- } as ItemDescriptor,
447
- endpointTemplateId,
448
- endpointName,
449
- );
450
- if (!created) throw new Error("Failed to create AI endpoint");
451
- endpointItem = created;
452
- }
453
-
454
- // Set API key if provided
455
- if (apiKey && endpointItem) {
456
- const apiKeyFieldId = "db07ae53-459a-4314-89b3-ab2721df2b4f";
457
- await editContext.operations.editField({
458
- field: {
459
- fieldId: apiKeyFieldId,
460
- item: {
461
- id: endpointItem.id,
462
- language: userLang,
463
- version: 0,
464
- },
465
- },
466
- value: apiKey,
467
- rawValue: apiKey,
468
- refresh: "delayed",
469
- });
470
- }
471
-
472
- // Ensure Ai Models container exists
473
- let aiModelsParent = findByName(children, "Ai Models");
474
- if (!aiModelsParent) {
475
- const aiModelsTemplateId = "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b";
476
- const createdModels = await editContext.operations.createItem(
477
- settingsItem,
478
- aiModelsTemplateId,
479
- "Ai Models",
480
- );
481
- if (!createdModels)
482
- throw new Error("Failed to create 'Ai Models' container");
483
- aiModelsParent = {
484
- id: createdModels.id,
485
- name: "Ai Models",
486
- thumbUrl: "",
487
- previewUrl: "",
488
- templateId: "",
489
- icon: "",
490
- hasChildren: false,
491
- isComponent: false,
492
- displayName: "Ai Models",
493
- language: userLang,
494
- version: 0,
495
- hasLayout: false,
496
- } as unknown as ItemTreeNodeData;
497
- }
498
-
499
- // Create default models if missing and link to endpoint
500
- const modelsToEnsure = ["gpt-5", "gpt5-high", "image-1"];
501
- const modelTemplateId = "d2e3f4a5-4b5c-5c6d-bf0b-3e4f5a6b7c8e";
502
- const modelNameFieldId = "f1e2d3c4-5b6a-7980-8e9f-1a2b3c4d5e6f";
503
- const modelEndpointFieldId = "cbade708-ce95-4f54-81b7-308ea61a76a6";
504
-
505
- const modelChildren = (await getChildren(
506
- aiModelsParent.id,
507
- editContext.sessionId!,
508
- [],
509
- false,
510
- userLang,
511
- "path",
512
- )) as unknown as ItemTreeNodeData[];
513
-
514
- for (const modelName of modelsToEnsure) {
515
- let modelNode = findByName(modelChildren, modelName);
516
- if (!modelNode) {
517
- const createdModel = await editContext.operations.createItem(
518
- {
519
- id: aiModelsParent.id,
520
- language: userLang,
521
- version: 0,
522
- } as ItemDescriptor,
523
- modelTemplateId,
524
- modelName,
525
- );
526
- if (!createdModel)
527
- throw new Error(`Failed to create model '${modelName}'`);
528
- modelNode = {
529
- id: createdModel.id,
530
- name: modelName,
531
- displayName: modelName,
532
- thumbUrl: "",
533
- previewUrl: "",
534
- templateId: "",
535
- icon: "",
536
- hasChildren: false,
537
- isComponent: false,
538
- language: userLang,
539
- version: 0,
540
- hasLayout: false,
541
- } as unknown as ItemTreeNodeData;
542
-
543
- await editContext.operations.editField({
544
- field: {
545
- fieldId: modelNameFieldId,
546
- item: { id: modelNode.id, language: userLang, version: 0 },
547
- },
548
- value: modelName,
549
- rawValue: modelName,
550
- refresh: "delayed",
551
- });
552
-
553
- const endpointGuid = `{${(endpointItem!.id as string)
554
- .replace(/[{}()]/g, "")
555
- .toUpperCase()}}`;
556
- await editContext.operations.editField({
557
- field: {
558
- fieldId: modelEndpointFieldId,
559
- item: { id: modelNode.id, language: userLang, version: 0 },
560
- },
561
- rawValue: endpointGuid,
562
- refresh: "delayed",
563
- });
564
- }
565
- }
566
-
567
- setAiState("success");
568
- editContext.requestRefresh?.("immediate");
569
- } catch (e: any) {
570
- setAiState("error");
571
- setAiError(e?.message || "Failed to add AI endpoint");
572
- } finally {
573
- setAiBusy(false);
574
- }
575
- }, [aiProvider, editContext, userLang, resolvePathUnderContent, apiKey]);
576
-
577
- const checkRequiredContainers = useCallback(async () => {
578
- try {
579
- setContainersError(null);
580
- const initialStates: Record<string, StepState> = {};
581
- for (const rc of requiredContainers) initialStates[rc.name] = "checking";
582
- setContainerStates(initialStates);
583
-
584
- const settingsItem = await resolvePathUnderContent([
585
- "Settings",
586
- "Editor",
587
- ]);
588
- if (!settingsItem) {
589
- setEditorSettingsItem(null);
590
- const errorMsg = "Editor settings item not found. Create it first.";
591
- setContainersError(errorMsg);
592
- const errorStates: Record<string, StepState> = {};
593
- for (const rc of requiredContainers) errorStates[rc.name] = "error";
594
- setContainerStates(errorStates);
595
- return;
596
- }
597
-
598
- setEditorSettingsItem(settingsItem);
599
- const children = (await getChildren(
600
- settingsItem.id,
601
- editContext!.sessionId!,
602
- [],
603
- false,
604
- userLang,
605
- "path",
606
- )) as unknown as ItemTreeNodeData[];
607
-
608
- const states: Record<string, StepState> = {};
609
- for (const rc of requiredContainers) {
610
- const exists = !!findByName(children, rc.name);
611
- states[rc.name] = exists ? "success" : "error";
612
- }
613
- setContainerStates(states);
614
- } catch (e: any) {
615
- setContainersError(e?.message || "Failed to check AI containers");
616
- const errorStates: Record<string, StepState> = {};
617
- for (const rc of requiredContainers) errorStates[rc.name] = "error";
618
- setContainerStates(errorStates);
619
- }
620
- }, [editContext, requiredContainers, resolvePathUnderContent, userLang]);
621
-
622
- React.useEffect(() => {
623
- checkRequiredContainers();
624
- }, [checkRequiredContainers]);
625
-
626
- const createContainer = useCallback(
627
- async (name: string, templateId: string) => {
628
- if (!editorSettingsItem || !editContext) return;
629
- try {
630
- setBusyMap((s) => ({ ...s, [name]: true }));
631
- setContainersError(null);
632
-
633
- const created = await editContext.operations.createItem(
634
- editorSettingsItem,
635
- templateId,
636
- name,
637
- );
638
-
639
- if (!created) throw new Error(`Failed to create '${name}'`);
640
- setContainerStates((s) => ({ ...s, [name]: "success" }));
641
- } catch (e: any) {
642
- setContainersError(e?.message || `Failed to create '${name}'`);
643
- setContainerStates((s) => ({ ...s, [name]: "error" }));
644
- } finally {
645
- setBusyMap((s) => ({ ...s, [name]: false }));
646
- }
647
- },
648
- [editorSettingsItem, editContext],
649
- );
650
-
651
22
  return (
652
23
  <Card
24
+ className="w-full"
653
25
  icon={<SparklesIcon strokeWidth={1} className="h-5 w-5" />}
654
26
  title="AI setup"
655
27
  description="Add an AI endpoint (OpenAI, Azure OpenAI, or OpenRouter)."
656
28
  >
657
- <RequiredContainersList
658
- requiredContainers={requiredContainers}
659
- containerStates={containerStates}
660
- busyMap={busyMap}
661
- canFix={!!editorSettingsItem}
662
- containersError={containersError}
663
- onFixContainer={createContainer}
664
- />
665
-
666
- <ProviderSection
667
- aiProvider={aiProvider}
668
- aiOptions={aiOptions}
669
- onProviderChange={setAiProvider}
670
- apiKey={apiKey}
671
- onApiKeyChange={setApiKey}
672
- aiBusy={aiBusy}
673
- onAddEndpoint={createAiEndpoint}
674
- />
29
+ <RequiredContainersSection />
675
30
 
676
- <GenerateToolsSection
677
- toolsBusy={toolsBusy}
678
- toolsError={toolsError}
679
- onGenerateTools={ensureAiToolsAndGenerate}
680
- />
31
+ <ProviderSection />
681
32
 
682
- {aiError && (
683
- <div className="mt-2 rounded border border-red-200 bg-red-50 p-2 text-xs whitespace-pre-wrap text-red-700">
684
- {aiError}
685
- </div>
686
- )}
33
+ <GenerateToolsSection />
687
34
  </Card>
688
35
  );
689
36
  }