@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.
- 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 +56 -5
- 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.js +15 -5
- package/dist/editor/ai/ContextInfoBar.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 +5 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/itemsRepository.js +1 -0
- 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.d.ts +0 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/index.js +3 -506
- package/dist/editor/control-center/setup-steps/AiSetupStep/index.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.d.ts +1 -15
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js +226 -3
- package/dist/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.d.ts +1 -1
- 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 -7
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +323 -3
- package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -1
- 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/SuggestionHighlighting.js +2 -2
- package/dist/editor/page-editor-chrome/SuggestionHighlighting.js.map +1 -1
- package/dist/editor/page-viewer/PageViewer.js +2 -1
- package/dist/editor/page-viewer/PageViewer.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/MetaDataStep.js +43 -41
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
- package/dist/page-wizard/steps/SelectStep.js +19 -4
- package/dist/page-wizard/steps/SelectStep.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 +84 -4
- package/src/editor/ai/Agents.tsx +18 -5
- package/src/editor/ai/ContextInfoBar.tsx +22 -6
- 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 +8 -0
- package/src/editor/client/itemsRepository.ts +1 -0
- 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 +7 -660
- package/src/editor/control-center/setup-steps/AiSetupStep/provider/ProviderSection.tsx +363 -24
- package/src/editor/control-center/setup-steps/AiSetupStep/required-containers/RequiredContainersList.tsx +1 -1
- 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 +385 -8
- 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 +2 -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/SuggestionHighlighting.tsx +5 -5
- package/src/editor/page-viewer/PageViewer.tsx +3 -2
- 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/MetaDataStep.tsx +61 -50
- package/src/page-wizard/steps/SelectStep.tsx +37 -4
- package/src/revision.ts +2 -2
|
@@ -290,11 +290,19 @@ export function ContextInfoBar({
|
|
|
290
290
|
try {
|
|
291
291
|
const dragObj = editContext?.dragObject;
|
|
292
292
|
if (dragObj?.type === "component") {
|
|
293
|
-
const
|
|
293
|
+
const idsFromComponents = (dragObj.components || [])
|
|
294
|
+
.map((c) => c.id)
|
|
295
|
+
.filter((x) => !!x);
|
|
294
296
|
const idFromData = e.dataTransfer.getData("componentId");
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
297
|
+
const allIds = Array.from(
|
|
298
|
+
new Set(
|
|
299
|
+
[...(idsFromComponents as string[]), idFromData].filter(
|
|
300
|
+
(x): x is string => !!x,
|
|
301
|
+
),
|
|
302
|
+
),
|
|
303
|
+
);
|
|
304
|
+
if (allIds.length) {
|
|
305
|
+
await addComponentIdsToContext(allIds);
|
|
298
306
|
if (isCollapsed) setIsCollapsed(false);
|
|
299
307
|
return;
|
|
300
308
|
}
|
|
@@ -306,6 +314,14 @@ export function ContextInfoBar({
|
|
|
306
314
|
return;
|
|
307
315
|
}
|
|
308
316
|
|
|
317
|
+
// Fallbacks when no dragObj or different source
|
|
318
|
+
const fallbackComponentId = e.dataTransfer.getData("componentId");
|
|
319
|
+
if (fallbackComponentId) {
|
|
320
|
+
await addComponentIdsToContext([fallbackComponentId]);
|
|
321
|
+
if (isCollapsed) setIsCollapsed(false);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
309
325
|
try {
|
|
310
326
|
const textData = e.dataTransfer.getData("text/plain");
|
|
311
327
|
if (textData) {
|
|
@@ -525,14 +541,14 @@ export function ContextInfoBar({
|
|
|
525
541
|
<div className="flex flex-wrap items-center gap-2">{chips}</div>
|
|
526
542
|
<div className="ml-2 flex flex-col items-end gap-1">
|
|
527
543
|
{canAddPage && (
|
|
528
|
-
<Button size="
|
|
544
|
+
<Button size="xs" variant="outline" onClick={addPagesToContext}>
|
|
529
545
|
<Plus className="mr-1 h-3 w-3" strokeWidth={1} /> Add current
|
|
530
546
|
item
|
|
531
547
|
</Button>
|
|
532
548
|
)}
|
|
533
549
|
{canAddSelection && (
|
|
534
550
|
<Button
|
|
535
|
-
size="
|
|
551
|
+
size="xs"
|
|
536
552
|
variant="outline"
|
|
537
553
|
onClick={addSelectedComponentsToContext}
|
|
538
554
|
>
|
|
@@ -61,6 +61,8 @@ const getToolIcon = (toolName: string) => {
|
|
|
61
61
|
// Comments and suggestions
|
|
62
62
|
"add-comment": <CheckSquare strokeWidth={1} size={14} />,
|
|
63
63
|
"get-comments": <CheckSquare strokeWidth={1} size={14} />,
|
|
64
|
+
"get-reviews": <CheckSquare strokeWidth={1} size={14} />,
|
|
65
|
+
"invite-reviewer": <CheckSquare strokeWidth={1} size={14} />,
|
|
64
66
|
"get-suggestions": <Brain strokeWidth={1} size={14} />,
|
|
65
67
|
|
|
66
68
|
// Default fallback
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Dialog } from "
|
|
1
|
+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../../components/ui/dialog";
|
|
2
2
|
import { DialogProps } from "./editContext";
|
|
3
3
|
import { useImperativeHandle, useState, forwardRef, useEffect } from "react";
|
|
4
4
|
import { buildDate, version } from "../../revision";
|
|
@@ -20,25 +20,30 @@ export const AboutDialog = forwardRef<DialogProps<void>, DialogProps<void>>(
|
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
22
|
<Dialog
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
open={visible}
|
|
24
|
+
onOpenChange={(open: boolean) => {
|
|
25
|
+
if (!open) {
|
|
26
|
+
setVisible(false);
|
|
27
|
+
props.onClose(null);
|
|
28
|
+
}
|
|
27
29
|
}}
|
|
28
|
-
header="About SiteMagician"
|
|
29
|
-
style={{ width: "400px" }}
|
|
30
30
|
>
|
|
31
|
-
<
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
<DialogContent style={{ width: 400 }}>
|
|
32
|
+
<DialogHeader>
|
|
33
|
+
<DialogTitle>About parhelion</DialogTitle>
|
|
34
|
+
</DialogHeader>
|
|
35
|
+
<div className="flex flex-col gap-4 p-2">
|
|
36
|
+
<div className="bg-wizard-demo mt-3 aspect-[1.75] w-full rounded-lg"></div>
|
|
37
|
+
<div>
|
|
38
|
+
Build: <span className="font-bold"> {version}</span> from{" "}
|
|
39
|
+
<span className="font-bold">{buildDate}</span>
|
|
40
|
+
</div>
|
|
41
|
+
<div className="mt-4 text-sm text-gray-600">
|
|
42
|
+
© {new Date().getFullYear()} canvas Reply GmbH. All rights
|
|
43
|
+
reserved.
|
|
44
|
+
</div>
|
|
36
45
|
</div>
|
|
37
|
-
|
|
38
|
-
© {new Date().getFullYear()} canvas Reply GmbH. All rights
|
|
39
|
-
reserved.
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
46
|
+
</DialogContent>
|
|
42
47
|
</Dialog>
|
|
43
48
|
);
|
|
44
49
|
},
|
|
@@ -1644,6 +1644,9 @@ export function EditorShell({
|
|
|
1644
1644
|
readonly: isReadOnly,
|
|
1645
1645
|
selection,
|
|
1646
1646
|
select: (ids: string[]) => {
|
|
1647
|
+
try {
|
|
1648
|
+
console.log("[DND][EditContext] select", ids);
|
|
1649
|
+
} catch {}
|
|
1647
1650
|
setSelection(ids);
|
|
1648
1651
|
},
|
|
1649
1652
|
selectedForInsertion,
|
|
@@ -1691,6 +1694,7 @@ export function EditorShell({
|
|
|
1691
1694
|
) => {
|
|
1692
1695
|
if ((!dragObject && !insertOption) || !page) return;
|
|
1693
1696
|
setDragObject(undefined);
|
|
1697
|
+
|
|
1694
1698
|
|
|
1695
1699
|
if (spotPositionElement && spotPositionAnchor) {
|
|
1696
1700
|
setInserting({
|
|
@@ -1761,7 +1765,8 @@ export function EditorShell({
|
|
|
1761
1765
|
} as LinkComponentOperation;
|
|
1762
1766
|
console.log("op", op);
|
|
1763
1767
|
} else {
|
|
1764
|
-
|
|
1768
|
+
const componentIds = dragObject.components?.map((c) => c.id) ?? [];
|
|
1769
|
+
if (componentIds.length === 0) return;
|
|
1765
1770
|
op = {
|
|
1766
1771
|
type: "move-component",
|
|
1767
1772
|
mainItem: page!.item.descriptor,
|
|
@@ -1772,11 +1777,12 @@ export function EditorShell({
|
|
|
1772
1777
|
},
|
|
1773
1778
|
placeholderKey,
|
|
1774
1779
|
placeholderIndex: index,
|
|
1775
|
-
componentIds
|
|
1780
|
+
componentIds,
|
|
1776
1781
|
date: new Date().toISOString(),
|
|
1777
1782
|
id: uuid(),
|
|
1778
1783
|
description: "Move component",
|
|
1779
1784
|
} as MoveComponentOperation;
|
|
1785
|
+
|
|
1780
1786
|
}
|
|
1781
1787
|
}
|
|
1782
1788
|
|
|
@@ -58,7 +58,7 @@ export type DragObject = {
|
|
|
58
58
|
typeId: string;
|
|
59
59
|
templateId?: string;
|
|
60
60
|
name?: string;
|
|
61
|
-
|
|
61
|
+
components?: ItemDescriptor[];
|
|
62
62
|
items?: ItemDescriptor[];
|
|
63
63
|
};
|
|
64
64
|
|
|
@@ -176,7 +176,7 @@ export type EditContextType = {
|
|
|
176
176
|
showToast: (message: string) => void;
|
|
177
177
|
sessionId: string;
|
|
178
178
|
openSplashScreen: () => void;
|
|
179
|
-
getComponentCommands: (
|
|
179
|
+
getComponentCommands: (components: Component[]) => Promise<ComponentCommand[]>;
|
|
180
180
|
selectMedia: ({
|
|
181
181
|
selectedIdPath,
|
|
182
182
|
mode,
|
|
@@ -244,6 +244,14 @@ 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 (
|
|
249
|
+
op.sessionId &&
|
|
250
|
+
op.sessionId === sessionId &&
|
|
251
|
+
(op as any).user?.ai !== true
|
|
252
|
+
)
|
|
253
|
+
return;
|
|
254
|
+
|
|
247
255
|
const editFieldOperation = op as any;
|
|
248
256
|
const field = await itemsRepository.getField({
|
|
249
257
|
item: {
|
|
@@ -516,6 +516,7 @@ export function useItemsRepository(
|
|
|
516
516
|
|
|
517
517
|
// Avoid clobbering in-flight edits: only sync to server value if not dirty
|
|
518
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);
|
|
519
520
|
return { ...modifiedField, value: serverValue };
|
|
520
521
|
}
|
|
521
522
|
|
|
@@ -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
|
+
|