@alpaca-editor/core 1.0.4095 → 1.0.4097
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.js +1 -0
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/context-menu.d.ts +2 -2
- package/dist/components/ui/context-menu.js +16 -16
- package/dist/components/ui/context-menu.js.map +1 -1
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FieldActionsOverlay.js +40 -26
- package/dist/editor/FieldActionsOverlay.js.map +1 -1
- package/dist/editor/FieldListField.js +1 -1
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/LinkEditorDialog.js +1 -1
- package/dist/editor/ai/AgentTerminal.js +203 -59
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +23 -9
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.d.ts +11 -0
- package/dist/editor/ai/ContextInfoBar.js +357 -0
- package/dist/editor/ai/ContextInfoBar.js.map +1 -0
- package/dist/editor/ai/DancingDots.js +1 -1
- package/dist/editor/ai/DancingDots.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.js +2 -0
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/client/AboutDialog.js +7 -5
- package/dist/editor/client/AboutDialog.js.map +1 -1
- package/dist/editor/client/EditorShell.js +7 -2
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +2 -2
- package/dist/editor/client/hooks/useSocketMessageHandler.js +3 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +6 -2
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/control-center/Setup.js +1 -1
- package/dist/editor/control-center/Setup.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.d.ts +2 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js +195 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/index.js +22 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/index.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js +233 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +15 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js +14 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.d.ts +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js +94 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.d.ts +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +328 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/types.d.ts +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/types.js +2 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/types.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.d.ts +4 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js +25 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep/utils.js.map +1 -0
- package/dist/editor/control-center/setup-steps/IndexSetupStep.js +2 -1
- package/dist/editor/control-center/setup-steps/IndexSetupStep.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +102 -16
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +1 -1
- package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +2 -2
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/InsertControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/InsertControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +25 -12
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineEditor.js +102 -7
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/SuggestionHighlighting.js +2 -2
- package/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -1
- package/dist/editor/reviews/Comments.js +4 -4
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +2 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +1 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +18 -6
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/editor/sidebar/Insert.js +1 -1
- package/dist/editor/ui/Splitter.js +2 -1
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/editor/utils.js +0 -1
- package/dist/editor/utils.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +5 -2
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +15 -18
- package/package.json +1 -1
- package/src/components/ui/button.tsx +1 -0
- package/src/components/ui/context-menu.tsx +44 -20
- package/src/editor/Editor.tsx +1 -1
- package/src/editor/FieldActionsOverlay.tsx +113 -91
- package/src/editor/FieldListField.tsx +4 -1
- package/src/editor/LinkEditorDialog.tsx +1 -1
- package/src/editor/ai/AgentTerminal.tsx +261 -157
- package/src/editor/ai/Agents.tsx +18 -5
- package/src/editor/ai/ContextInfoBar.tsx +567 -0
- package/src/editor/ai/DancingDots.tsx +1 -1
- package/src/editor/ai/ToolCallDisplay.tsx +2 -0
- package/src/editor/client/AboutDialog.tsx +22 -17
- package/src/editor/client/EditorShell.tsx +8 -2
- package/src/editor/client/editContext.ts +2 -2
- package/src/editor/client/hooks/useSocketMessageHandler.ts +3 -0
- package/src/editor/client/itemsRepository.ts +6 -5
- package/src/editor/control-center/Setup.tsx +1 -1
- package/src/editor/control-center/setup-steps/AiSetupStep/EmbeddingsModelSection.tsx +296 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/index.tsx +38 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.tsx +413 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.tsx +92 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersSection.tsx +139 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.tsx +409 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/types.ts +1 -0
- package/src/editor/control-center/setup-steps/AiSetupStep/utils.ts +43 -0
- package/src/editor/control-center/setup-steps/IndexSetupStep.tsx +2 -0
- package/src/editor/field-types/SingleLineText.tsx +0 -9
- package/src/editor/field-types/TreeListEditor.tsx +115 -16
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +1 -1
- package/src/editor/field-types/richtext/components/SimpleRichTextEditor.tsx +1 -1
- package/src/editor/menubar/toolbar-sections/EditControls.tsx +3 -2
- package/src/editor/menubar/toolbar-sections/InsertControls.tsx +1 -1
- package/src/editor/page-editor-chrome/FrameMenu.tsx +81 -68
- package/src/editor/page-editor-chrome/InlineEditor.tsx +129 -7
- package/src/editor/page-editor-chrome/SuggestionHighlighting.tsx +5 -5
- package/src/editor/reviews/Comments.tsx +13 -8
- package/src/editor/services/agentService.ts +3 -0
- package/src/editor/services/aiService.ts +2 -0
- package/src/editor/sidebar/ComponentTree.tsx +20 -6
- package/src/editor/sidebar/Insert.tsx +1 -1
- package/src/editor/ui/Splitter.tsx +2 -2
- package/src/editor/utils.ts +0 -1
- package/src/page-wizard/steps/ContentStep.tsx +46 -0
- package/src/revision.ts +2 -2
- package/dist/editor/control-center/setup-steps/AiSetupStep.js +0 -531
- package/dist/editor/control-center/setup-steps/AiSetupStep.js.map +0 -1
- package/src/editor/control-center/setup-steps/AiSetupStep.tsx +0 -784
- /package/dist/editor/control-center/setup-steps/{AiSetupStep.d.ts → AiSetupStep/index.d.ts} +0 -0
|
@@ -244,6 +244,9 @@ export function useSocketMessageHandler(deps: {
|
|
|
244
244
|
if (message.type === "edit-operation") {
|
|
245
245
|
const op = message.payload as EditOperation;
|
|
246
246
|
if (op.type === "edit-field") {
|
|
247
|
+
// Ignore our own edit-field operations to avoid redundant updates
|
|
248
|
+
if (op.sessionId && op.sessionId === sessionId) return;
|
|
249
|
+
|
|
247
250
|
const editFieldOperation = op as any;
|
|
248
251
|
const field = await itemsRepository.getField({
|
|
249
252
|
item: {
|
|
@@ -68,9 +68,7 @@ const TEMPLATE_SECTION_TEMPLATE_ID = "E269FBB5-3750-427A-9149-7AA950B49301"; //
|
|
|
68
68
|
/**
|
|
69
69
|
* Checks if an item change represents a template-related modification that should trigger cache clearing
|
|
70
70
|
*/
|
|
71
|
-
const isTemplateChange = async (
|
|
72
|
-
change: ItemChange
|
|
73
|
-
): Promise<boolean> => {
|
|
71
|
+
const isTemplateChange = async (change: ItemChange): Promise<boolean> => {
|
|
74
72
|
try {
|
|
75
73
|
// Check if the item is under the /sitecore/templates path
|
|
76
74
|
if (
|
|
@@ -483,6 +481,7 @@ export function useItemsRepository(
|
|
|
483
481
|
|
|
484
482
|
if (itemsToFetch.length !== 0) {
|
|
485
483
|
const time = Date.now();
|
|
484
|
+
const startSequence = saveSequenceCounter.current;
|
|
486
485
|
await fetchItemsFromServer(itemsToFetch);
|
|
487
486
|
|
|
488
487
|
const getFieldValue = (
|
|
@@ -515,8 +514,9 @@ export function useItemsRepository(
|
|
|
515
514
|
modifiedField.fieldId,
|
|
516
515
|
);
|
|
517
516
|
|
|
518
|
-
//
|
|
519
|
-
if (isOutdated(modifiedField)) {
|
|
517
|
+
// Avoid clobbering in-flight edits: only sync to server value if not dirty
|
|
518
|
+
if (isOutdated(modifiedField) && !modifiedField.isDirty) {
|
|
519
|
+
console.log("Syncing to server value", modifiedField.fieldId, modifiedField.item.id, modifiedField.item.language, modifiedField.item.version, serverValue);
|
|
520
520
|
return { ...modifiedField, value: serverValue };
|
|
521
521
|
}
|
|
522
522
|
|
|
@@ -532,6 +532,7 @@ export function useItemsRepository(
|
|
|
532
532
|
};
|
|
533
533
|
|
|
534
534
|
const isOutdated = (x: ModifiedField) => {
|
|
535
|
+
if (x.saveSequence > startSequence) return false;
|
|
535
536
|
if (x.timestamp > time) return false;
|
|
536
537
|
const item = itemsMap.current.get(generateKey(x.item));
|
|
537
538
|
if (!item) return true;
|
|
@@ -16,7 +16,7 @@ export function Setup() {
|
|
|
16
16
|
return (
|
|
17
17
|
<div className="h-full overflow-auto p-4">
|
|
18
18
|
<div className="mb-4 text-lg font-semibold text-gray-800">Setup</div>
|
|
19
|
-
<div className="grid grid-cols-1 gap-4">
|
|
19
|
+
<div className="grid grid-cols-1 gap-4 max-w-xl">
|
|
20
20
|
{steps.map((Step, idx) => (
|
|
21
21
|
<Step key={idx} />
|
|
22
22
|
))}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Button } from "../../../../components/ui/button";
|
|
3
|
+
import { AlertCircle, CheckCircle, RefreshCw } from "lucide-react";
|
|
4
|
+
import { useEditContext } from "../../../client/editContext";
|
|
5
|
+
import type { ItemDescriptor } from "../../../pageModel";
|
|
6
|
+
import { getChildren } from "../../../services/contentService";
|
|
7
|
+
import type { ItemTreeNodeData } from "../../../services/contentService";
|
|
8
|
+
import { findByName, resolvePathUnderContent } from "./utils";
|
|
9
|
+
import type { StepState } from "./types";
|
|
10
|
+
|
|
11
|
+
// Sitecore IDs and constants used by AI models/endpoints
|
|
12
|
+
const AI_MODELS_CONTAINER_TEMPLATE_ID = "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b";
|
|
13
|
+
const AI_MODEL_TEMPLATE_ID = "d2e3f4a5-4b5c-5c6d-bf0b-3e4f5a6b7c8e";
|
|
14
|
+
const MODEL_NAME_FIELD_ID = "f1e2d3c4-5b6a-7980-8e9f-1a2b3c4d5e6f";
|
|
15
|
+
const MODEL_ENDPOINT_FIELD_ID = "cbade708-ce95-4f54-81b7-308ea61a76a6";
|
|
16
|
+
const EDITOR_SETTINGS_EMBEDDINGS_MODEL_FIELD_ID = "08d0579d-3bf2-4777-981f-3f0856da948e"; // Embeddings Model (Droptree)
|
|
17
|
+
|
|
18
|
+
const DEFAULT_EMBEDDINGS_MODEL_NAME = "text-embedding-3-large";
|
|
19
|
+
|
|
20
|
+
export function EmbeddingsModelSection() {
|
|
21
|
+
const editContext = useEditContext();
|
|
22
|
+
const [state, setState] = React.useState<StepState>("checking");
|
|
23
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
24
|
+
const [isBusy, setIsBusy] = React.useState(false);
|
|
25
|
+
const [currentModelName, setCurrentModelName] = React.useState<string | null>(
|
|
26
|
+
null,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const userLang = editContext?.contentEditorItem?.language || "en";
|
|
30
|
+
|
|
31
|
+
const statusIcon = React.useCallback((s: StepState) => {
|
|
32
|
+
if (s === "success")
|
|
33
|
+
return <CheckCircle className="h-4 w-4 text-green-600" strokeWidth={1} />;
|
|
34
|
+
if (s === "error")
|
|
35
|
+
return <AlertCircle className="h-4 w-4 text-red-600" strokeWidth={1} />;
|
|
36
|
+
return (
|
|
37
|
+
<RefreshCw className="h-4 w-4 animate-spin text-amber-600" strokeWidth={1} />
|
|
38
|
+
);
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
const checkStatus = React.useCallback(async () => {
|
|
42
|
+
try {
|
|
43
|
+
setState("checking");
|
|
44
|
+
setError(null);
|
|
45
|
+
setCurrentModelName(null);
|
|
46
|
+
|
|
47
|
+
const settingsItem = await resolvePathUnderContent(
|
|
48
|
+
editContext?.sessionId,
|
|
49
|
+
userLang,
|
|
50
|
+
["Settings", "Editor"],
|
|
51
|
+
);
|
|
52
|
+
if (!settingsItem) {
|
|
53
|
+
setState("error");
|
|
54
|
+
setError("Editor settings item not found. Create it first.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Read the Embeddings Model droptree field
|
|
59
|
+
const field = await editContext!.itemsRepository.getField({
|
|
60
|
+
item: { id: settingsItem.id, language: userLang, version: 0 },
|
|
61
|
+
fieldId: EDITOR_SETTINGS_EMBEDDINGS_MODEL_FIELD_ID,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const raw = (field?.rawValue || "").trim();
|
|
65
|
+
if (!raw) {
|
|
66
|
+
setState("error");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Normalize ID braces and load the model item to get its display name
|
|
71
|
+
const modelId = raw.replace(/^[{(]+|[})]+$/g, "");
|
|
72
|
+
const model = await editContext!.itemsRepository.getItem({
|
|
73
|
+
id: `{${modelId}}`,
|
|
74
|
+
language: userLang,
|
|
75
|
+
version: 0,
|
|
76
|
+
});
|
|
77
|
+
if (!model) {
|
|
78
|
+
setState("error");
|
|
79
|
+
setError(
|
|
80
|
+
"Embeddings Model points to a missing item. Please fix to re-create and assign.",
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setCurrentModelName(model.name);
|
|
86
|
+
setState("success");
|
|
87
|
+
} catch (e: any) {
|
|
88
|
+
setState("error");
|
|
89
|
+
setError(e?.message || "Failed to check embeddings model");
|
|
90
|
+
}
|
|
91
|
+
}, [editContext, userLang]);
|
|
92
|
+
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
checkStatus();
|
|
95
|
+
}, [checkStatus]);
|
|
96
|
+
|
|
97
|
+
const ensureEmbeddingsModel = React.useCallback(async () => {
|
|
98
|
+
if (!editContext) return;
|
|
99
|
+
try {
|
|
100
|
+
setIsBusy(true);
|
|
101
|
+
setError(null);
|
|
102
|
+
|
|
103
|
+
const settingsItem = await resolvePathUnderContent(
|
|
104
|
+
editContext.sessionId,
|
|
105
|
+
userLang,
|
|
106
|
+
["Settings", "Editor"],
|
|
107
|
+
);
|
|
108
|
+
if (!settingsItem)
|
|
109
|
+
throw new Error("Editor settings item not found. Create it first.");
|
|
110
|
+
|
|
111
|
+
// Load children under /Settings/Editor
|
|
112
|
+
const editorChildren = (await getChildren(
|
|
113
|
+
settingsItem.id,
|
|
114
|
+
editContext.sessionId!,
|
|
115
|
+
[],
|
|
116
|
+
false,
|
|
117
|
+
userLang,
|
|
118
|
+
"path",
|
|
119
|
+
)) as unknown as ItemTreeNodeData[];
|
|
120
|
+
|
|
121
|
+
// Find endpoints container and choose OpenAI or Azure OpenAI endpoint
|
|
122
|
+
const endpointsContainer = findByName(editorChildren, "Ai Endpoints");
|
|
123
|
+
if (!endpointsContainer) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
"No AI endpoints found. Please add an OpenAI or Azure OpenAI endpoint first.",
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const endpointChildren = (await getChildren(
|
|
129
|
+
endpointsContainer.id,
|
|
130
|
+
editContext.sessionId!,
|
|
131
|
+
[],
|
|
132
|
+
false,
|
|
133
|
+
userLang,
|
|
134
|
+
"path",
|
|
135
|
+
)) as unknown as ItemTreeNodeData[];
|
|
136
|
+
const openAi = findByName(endpointChildren, "OpenAI");
|
|
137
|
+
const azureOpenAi = findByName(endpointChildren, "Azure OpenAI");
|
|
138
|
+
const selectedEndpoint = openAi || azureOpenAi;
|
|
139
|
+
if (!selectedEndpoint) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
"No OpenAI or Azure OpenAI endpoint exists. Add one in 'Provider' section.",
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Ensure Ai Models container exists
|
|
146
|
+
let modelsContainer = findByName(editorChildren, "Ai Models");
|
|
147
|
+
if (!modelsContainer) {
|
|
148
|
+
const createdModels = await editContext.operations.createItem(
|
|
149
|
+
settingsItem,
|
|
150
|
+
AI_MODELS_CONTAINER_TEMPLATE_ID,
|
|
151
|
+
"Ai Models",
|
|
152
|
+
);
|
|
153
|
+
if (!createdModels)
|
|
154
|
+
throw new Error("Failed to create 'Ai Models' container");
|
|
155
|
+
modelsContainer = {
|
|
156
|
+
id: createdModels.id,
|
|
157
|
+
name: "Ai Models",
|
|
158
|
+
displayName: "Ai Models",
|
|
159
|
+
thumbUrl: "",
|
|
160
|
+
previewUrl: "",
|
|
161
|
+
templateId: "",
|
|
162
|
+
icon: "",
|
|
163
|
+
hasChildren: false,
|
|
164
|
+
isComponent: false,
|
|
165
|
+
language: userLang,
|
|
166
|
+
version: 0,
|
|
167
|
+
hasLayout: false,
|
|
168
|
+
} as unknown as ItemTreeNodeData;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Find or create the "text-embedding-3-large" model
|
|
172
|
+
const modelChildren = (await getChildren(
|
|
173
|
+
modelsContainer.id,
|
|
174
|
+
editContext.sessionId!,
|
|
175
|
+
[],
|
|
176
|
+
false,
|
|
177
|
+
userLang,
|
|
178
|
+
"path",
|
|
179
|
+
)) as unknown as ItemTreeNodeData[];
|
|
180
|
+
|
|
181
|
+
let modelNode = findByName(modelChildren, DEFAULT_EMBEDDINGS_MODEL_NAME);
|
|
182
|
+
let modelDescriptor: ItemDescriptor | null = null;
|
|
183
|
+
|
|
184
|
+
if (modelNode) {
|
|
185
|
+
modelDescriptor = {
|
|
186
|
+
id: modelNode.id,
|
|
187
|
+
language: userLang,
|
|
188
|
+
version: 0,
|
|
189
|
+
} as ItemDescriptor;
|
|
190
|
+
} else {
|
|
191
|
+
const createdModel = await editContext.operations.createItem(
|
|
192
|
+
{
|
|
193
|
+
id: modelsContainer.id,
|
|
194
|
+
language: userLang,
|
|
195
|
+
version: 0,
|
|
196
|
+
} as ItemDescriptor,
|
|
197
|
+
AI_MODEL_TEMPLATE_ID,
|
|
198
|
+
DEFAULT_EMBEDDINGS_MODEL_NAME,
|
|
199
|
+
);
|
|
200
|
+
if (!createdModel)
|
|
201
|
+
throw new Error(
|
|
202
|
+
`Failed to create model '${DEFAULT_EMBEDDINGS_MODEL_NAME}'`,
|
|
203
|
+
);
|
|
204
|
+
modelDescriptor = createdModel;
|
|
205
|
+
|
|
206
|
+
// Set Model Name field
|
|
207
|
+
await editContext.operations.editField({
|
|
208
|
+
field: {
|
|
209
|
+
fieldId: MODEL_NAME_FIELD_ID,
|
|
210
|
+
item: {
|
|
211
|
+
id: modelDescriptor.id,
|
|
212
|
+
language: userLang,
|
|
213
|
+
version: 0,
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
value: DEFAULT_EMBEDDINGS_MODEL_NAME,
|
|
217
|
+
rawValue: DEFAULT_EMBEDDINGS_MODEL_NAME,
|
|
218
|
+
refresh: "delayed",
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Link model to the selected endpoint
|
|
223
|
+
const endpointGuid = `{${(selectedEndpoint.id as string)
|
|
224
|
+
.replace(/[{}()]/g, "")
|
|
225
|
+
.toUpperCase()}}`;
|
|
226
|
+
await editContext.operations.editField({
|
|
227
|
+
field: {
|
|
228
|
+
fieldId: MODEL_ENDPOINT_FIELD_ID,
|
|
229
|
+
item: { id: modelDescriptor!.id, language: userLang, version: 0 },
|
|
230
|
+
},
|
|
231
|
+
rawValue: endpointGuid,
|
|
232
|
+
refresh: "delayed",
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Assign model to Editor settings' Embeddings Model field
|
|
236
|
+
const modelGuid = `{${(modelDescriptor!.id as string)
|
|
237
|
+
.replace(/[{}()]/g, "")
|
|
238
|
+
.toUpperCase()}}`;
|
|
239
|
+
await editContext.operations.editField({
|
|
240
|
+
field: {
|
|
241
|
+
fieldId: EDITOR_SETTINGS_EMBEDDINGS_MODEL_FIELD_ID,
|
|
242
|
+
item: { id: settingsItem.id, language: userLang, version: 0 },
|
|
243
|
+
},
|
|
244
|
+
rawValue: modelGuid,
|
|
245
|
+
refresh: "immediate",
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
editContext.requestRefresh?.("immediate");
|
|
249
|
+
editContext.showToast?.(
|
|
250
|
+
`Embeddings model set to '${DEFAULT_EMBEDDINGS_MODEL_NAME}'`,
|
|
251
|
+
);
|
|
252
|
+
await checkStatus();
|
|
253
|
+
} catch (e: any) {
|
|
254
|
+
setError(e?.message || "Failed to ensure embeddings model");
|
|
255
|
+
setState("error");
|
|
256
|
+
} finally {
|
|
257
|
+
setIsBusy(false);
|
|
258
|
+
}
|
|
259
|
+
}, [editContext, userLang, checkStatus]);
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div className="mt-3">
|
|
263
|
+
<div className="flex items-center justify-between gap-2">
|
|
264
|
+
<div className="flex items-center gap-2">
|
|
265
|
+
{statusIcon(state)}
|
|
266
|
+
<span className="text-sm text-gray-700">
|
|
267
|
+
{state === "success"
|
|
268
|
+
? `Embeddings model: ${currentModelName}`
|
|
269
|
+
: state === "error"
|
|
270
|
+
? "Embeddings model not assigned"
|
|
271
|
+
: "Checking embeddings model..."}
|
|
272
|
+
</span>
|
|
273
|
+
</div>
|
|
274
|
+
{state !== "success" && (
|
|
275
|
+
<Button size="sm" onClick={ensureEmbeddingsModel} disabled={isBusy}>
|
|
276
|
+
{isBusy ? (
|
|
277
|
+
<RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin" />
|
|
278
|
+
) : (
|
|
279
|
+
<CheckCircle strokeWidth={1} className="h-4 w-4" />
|
|
280
|
+
)}
|
|
281
|
+
Fix
|
|
282
|
+
</Button>
|
|
283
|
+
)}
|
|
284
|
+
</div>
|
|
285
|
+
{error && (
|
|
286
|
+
<div className="mt-2 rounded border border-yellow-200 bg-yellow-50 p-2 text-xs whitespace-pre-wrap text-yellow-800">
|
|
287
|
+
{error}
|
|
288
|
+
</div>
|
|
289
|
+
)}
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export default EmbeddingsModelSection;
|
|
295
|
+
|
|
296
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Card } from "../../../../components/ui/card";
|
|
3
|
+
import { useEditContext } from "../../../client/editContext";
|
|
4
|
+
import { SparklesIcon } from "lucide-react";
|
|
5
|
+
import { RequiredContainersSection } from "./required-containers/RequiredContainersSection";
|
|
6
|
+
import { ProviderSection } from "./provider/ProviderSection";
|
|
7
|
+
import { GenerateToolsSection } from "./tools/GenerateToolsSection";
|
|
8
|
+
import type { StepState } from "./types";
|
|
9
|
+
|
|
10
|
+
export function AiSetupStep() {
|
|
11
|
+
const editContext = useEditContext();
|
|
12
|
+
const [aiState, setAiState] = useState<StepState>("idle");
|
|
13
|
+
const userLang = editContext?.contentEditorItem?.language || "en";
|
|
14
|
+
|
|
15
|
+
// IDs for tool templates/fields
|
|
16
|
+
const AI_TOOLS_TEMPLATE_ID = "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11"; // container
|
|
17
|
+
const AI_TOOL_TEMPLATE_ID = "a2e8a0d9-7b1f-4d1a-a2d8-8f3ea6d6f0b1"; // item template
|
|
18
|
+
const FIELD_FUNCTION_NAME_ID = "3d9f2b1a-9d44-4d26-8a1b-92f0fb4d3a2c";
|
|
19
|
+
const FIELD_LABEL_ID = "5a19f5a5-1d21-4b6a-9f83-6f3fc0b34b2e";
|
|
20
|
+
const FIELD_DESCRIPTION_ID = "6b2e4b8e-8a9f-4d8f-9f6e-1a2b3c4d5e6f";
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Card
|
|
24
|
+
className="w-full"
|
|
25
|
+
icon={<SparklesIcon strokeWidth={1} className="h-5 w-5" />}
|
|
26
|
+
title="AI setup"
|
|
27
|
+
description="Add an AI endpoint (OpenAI, Azure OpenAI, or OpenRouter)."
|
|
28
|
+
>
|
|
29
|
+
<RequiredContainersSection />
|
|
30
|
+
|
|
31
|
+
<ProviderSection />
|
|
32
|
+
|
|
33
|
+
<GenerateToolsSection />
|
|
34
|
+
</Card>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default AiSetupStep;
|