diff --git a/examples/09-ai/01-minimal/App.tsx b/examples/09-ai/01-minimal/App.tsx
index d1e66e91e..f0b2b20c5 100644
--- a/examples/09-ai/01-minimal/App.tsx
+++ b/examples/09-ai/01-minimal/App.tsx
@@ -99,7 +99,8 @@ export default function App() {
editor={editor}
// We're disabling some default UI elements
formattingToolbar={false}
- slashMenu={false}>
+ slashMenu={false}
+ >
{/* This has AI specific components like the AI Command menu */}
diff --git a/examples/09-ai/01-minimal/README.md b/examples/09-ai/01-minimal/README.md
index aca9d4a8f..309a6d94e 100644
--- a/examples/09-ai/01-minimal/README.md
+++ b/examples/09-ai/01-minimal/README.md
@@ -6,4 +6,7 @@ Select some text and click the AI (magic wand) button, or type `/ai` anywhere in
**Relevant Docs:**
-- TODO
+- [Editor Setup](/docs/editor-basics/setup)
+- [Changing the Formatting Toolbar](/docs/ui-components/formatting-toolbar#changing-the-formatting-toolbar)
+- [Changing Slash Menu Items](/docs/ui-components/suggestion-menus#changing-slash-menu-items)
+- [Getting Stared with BlockNote AI](/docs/ai/setup)
diff --git a/examples/09-ai/02-playground/README.md b/examples/09-ai/02-playground/README.md
index ed17108a8..9a4263119 100644
--- a/examples/09-ai/02-playground/README.md
+++ b/examples/09-ai/02-playground/README.md
@@ -6,4 +6,7 @@ Change the configuration, the highlight some text to access the AI menu, or type
**Relevant Docs:**
-- TODO
+- [Editor Setup](/docs/editor-basics/setup)
+- [Changing the Formatting Toolbar](/docs/ui-components/formatting-toolbar#changing-the-formatting-toolbar)
+- [Changing Slash Menu Items](/docs/ui-components/suggestion-menus#changing-slash-menu-items)
+- [Getting Stared with BlockNote AI](/docs/ai/setup)
diff --git a/examples/09-ai/03-ai-menu-items/.bnexample.json b/examples/09-ai/03-ai-menu-items/.bnexample.json
new file mode 100644
index 000000000..94929e4e3
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/.bnexample.json
@@ -0,0 +1,15 @@
+{
+ "playground": true,
+ "docs": true,
+ "author": "matthewlipski",
+ "tags": ["AI", "llm"],
+ "dependencies": {
+ "@blocknote/xl-ai": "latest",
+ "@mantine/core": "^7.10.1",
+ "ai": "^4.1.0",
+ "@ai-sdk/openai": "^1.1.0",
+ "@ai-sdk/groq": "^1.1.0",
+ "react-icons": "^5.2.1",
+ "zustand": "^5.0.3"
+ }
+}
diff --git a/examples/09-ai/03-ai-menu-items/App.tsx b/examples/09-ai/03-ai-menu-items/App.tsx
new file mode 100644
index 000000000..05c4411c6
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/App.tsx
@@ -0,0 +1,209 @@
+///
+
+import { createGroq } from "@ai-sdk/groq";
+import { BlockNoteEditor, filterSuggestionItems } from "@blocknote/core";
+import "@blocknote/core/fonts/inter.css";
+import { en } from "@blocknote/core/locales";
+import { BlockNoteView } from "@blocknote/mantine";
+import "@blocknote/mantine/style.css";
+import {
+ FormattingToolbar,
+ FormattingToolbarController,
+ SuggestionMenuController,
+ getDefaultReactSlashMenuItems,
+ getFormattingToolbarItems,
+ useCreateBlockNote,
+} from "@blocknote/react";
+import {
+ AIToolbarButton,
+ BlockNoteAIUI,
+ locales as aiLocales,
+ createAIExtension,
+ createBlockNoteAIClient,
+ getAISlashMenuItems,
+ AIMenu,
+ getDefaultAIMenuItemsWithSelection,
+ getDefaultAIMenuItemsWithoutSelection,
+ getDefaultAIActionMenuItems,
+ AIMenuController,
+} from "@blocknote/xl-ai";
+import "@blocknote/xl-ai/style.css";
+
+import { findRelatedTopics, makeCasual } from "./customAIMenuItems.js";
+
+// Optional: proxy requests through the `@blocknote/xl-ai-server` proxy server
+// so that we don't have to expose our API keys to the client
+const client = createBlockNoteAIClient({
+ apiKey: import.meta.env.VITE_BLOCKNOTE_AI_SERVER_API_KEY || "PLACEHOLDER",
+ baseURL:
+ import.meta.env.VITE_BLOCKNOTE_AI_SERVER_BASE_URL ||
+ "https://localhost:3000/ai",
+});
+
+// Use an "open" model such as llama, in this case via groq.com
+const model = createGroq({
+ // call via our proxy client
+ ...client.getProviderSettings("groq"),
+})("llama-3.3-70b-versatile");
+
+/*
+ALTERNATIVES:
+
+Call a model directly (without the proxy):
+
+const model = createGroq({
+ apiKey: "",
+})("llama-3.3-70b-versatile");
+
+Or, use a different provider like OpenAI:
+
+const model = createOpenAI({
+ ...client.getProviderSettings("openai"),
+})("gpt-4", {});
+*/
+
+export default function App() {
+ // Creates a new editor instance.
+ const editor = useCreateBlockNote({
+ dictionary: {
+ ...en,
+ ai: aiLocales.en, // add default translations for the AI extension
+ },
+ // Register the AI extension
+ extensions: [
+ createAIExtension({
+ model,
+ }),
+ ],
+ // We set some initial content for demo purposes
+ initialContent: [
+ {
+ type: "heading",
+ props: {
+ level: 1,
+ },
+ content: "I love cats",
+ },
+ {
+ type: "paragraph",
+ content:
+ "Cats are one of the most beloved and fascinating animals in the world. Known for their agility, independence, and charm, cats have been companions to humans for thousands of years. Domesticated cats, scientifically named Felis catus, come in various breeds, colors, and personalities, making them a popular choice for pet owners everywhere. Their mysterious behavior, sharp reflexes, and quiet affection have earned them a special place in countless households.",
+ },
+ {
+ type: "paragraph",
+ content:
+ "Beyond their role as pets, cats have a rich history and cultural significance. In ancient Egypt, they were revered and even worshipped as symbols of protection and grace. Throughout history, they’ve appeared in folklore, art, and literature, often associated with curiosity, luck, and mystery. Despite superstitions surrounding black cats in some cultures, many societies around the world admire and cherish these sleek and graceful animals.",
+ },
+ {
+ type: "paragraph",
+ content:
+ "Cats also offer emotional and physical benefits to their owners. Studies have shown that interacting with cats can reduce stress, lower blood pressure, and improve mental well-being. Their gentle purring, playful antics, and warm companionship provide comfort to people of all ages. Whether lounging in the sun, chasing a toy, or curling up on a lap, cats bring joy, peace, and a bit of magic to the lives of those who welcome them into their homes.",
+ },
+ ],
+ });
+
+ // Renders the editor instance using a React component.
+ return (
+
+
+ {/* This has AI specific components like the AI Command menu */}
+ {/* We pass `aiMenu=false` as we want to render an AIMenu with our own
+ items (defined below). */}
+
+ {/* Creates a new AIMenu with the default items, as well as our custom
+ ones. */}
+ (
+ {
+ if (aiResponseStatus === "user-input") {
+ // Returns different items based on whether the AI Menu was
+ // opened via the Formatting Toolbar or the Slash Menu.
+ return editor.getSelection()
+ ? [
+ // Gets the default AI Menu items for when it's opened via
+ // the Formatting Toolbar.
+ ...getDefaultAIMenuItemsWithSelection(editor),
+ // Adds our custom item to make the text more casual.
+ // Only appears when the AI Menu is opened via the
+ // Formatting Toolbar.
+ makeCasual(editor),
+ ]
+ : [
+ // Gets the default AI Menu items for when it's opened
+ // via the Slash Menu.
+ ...getDefaultAIMenuItemsWithoutSelection(editor),
+ // Adds our custom item to find related topics. Only
+ // appears when the AI Menu is opened via the Slash
+ // Menu.
+ findRelatedTopics(editor),
+ ];
+ }
+
+ if (aiResponseStatus === "user-reviewing") {
+ // Returns different items once the AI has finished writing,
+ // so the user can choose to accept or reject the changes.
+ return getDefaultAIActionMenuItems(editor);
+ }
+
+ // Return no items in other states, e.g. when the AI is writing
+ // or when an error occurred.
+ return [];
+ }}
+ />
+ )}
+ />
+
+ {/* We disabled the default formatting toolbar with `formattingToolbar=false`
+ and replace it for one with an "AI button" (defined below).
+ (See "Formatting Toolbar" in docs)
+ */}
+
+
+ {/* We disabled the default SlashMenu with `slashMenu=false`
+ and replace it for one with an AI option (defined below).
+ (See "Suggestion Menus" in docs)
+ */}
+
+
+
+ );
+}
+
+// Formatting toolbar with the `AIToolbarButton` added
+function FormattingToolbarWithAI() {
+ return (
+ (
+
+ {...getFormattingToolbarItems()}
+
+
+ )}
+ />
+ );
+}
+
+// Slash menu with the AI option added
+function SuggestionMenuWithAI(props: {
+ editor: BlockNoteEditor;
+}) {
+ return (
+
+ filterSuggestionItems(
+ [
+ ...getDefaultReactSlashMenuItems(props.editor),
+ ...getAISlashMenuItems(props.editor),
+ ],
+ query,
+ )
+ }
+ />
+ );
+}
diff --git a/examples/09-ai/03-ai-menu-items/README.md b/examples/09-ai/03-ai-menu-items/README.md
new file mode 100644
index 000000000..5e366da30
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/README.md
@@ -0,0 +1,13 @@
+# Adding AI Menu Items
+
+In this example, we add two items to the AI Menu. The first prompts the AI to make the selected text more casual, and can be found by selecting some text and click the AI (magic wand) button. The second prompts the AI to give ideas on related topics to extend the document with, and can be found by clicking the "Ask AI" Slash Menu item.
+
+Select some text and click the AI (magic wand) button, or type `/ai` anywhere in the editor to access AI functionality.
+
+**Relevant Docs:**
+
+- [Editor Setup](/docs/editor-basics/setup)
+- [Changing the Formatting Toolbar](/docs/ui-components/formatting-toolbar#changing-the-formatting-toolbar)
+- [Changing Slash Menu Items](/docs/ui-components/suggestion-menus#changing-slash-menu-items)
+- [Getting Stared with BlockNote AI](/docs/ai/setup)
+- [Custom AI Menu Items](/docs/ai/custom-commands)
diff --git a/examples/09-ai/03-ai-menu-items/customAIMenuItems.tsx b/examples/09-ai/03-ai-menu-items/customAIMenuItems.tsx
new file mode 100644
index 000000000..82b0ef014
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/customAIMenuItems.tsx
@@ -0,0 +1,61 @@
+import { BlockNoteEditor } from "@blocknote/core";
+import { AIMenuSuggestionItem, getAIExtension } from "@blocknote/xl-ai";
+import { RiApps2AddFill, RiEmotionHappyFill } from "react-icons/ri";
+
+// Custom item to make the text more casual.
+export const makeCasual = (editor: BlockNoteEditor): AIMenuSuggestionItem => ({
+ key: "make_casual",
+ title: "Make Casual",
+ // Aliases used when filtering AI Menu items from
+ // text in prompt input.
+ aliases: ["casual", "informal", "make informal"],
+ icon: ,
+ onItemClick: async () => {
+ await getAIExtension(editor).callLLM({
+ userPrompt: "Make casual",
+ // Set to true to tell the LLM to specifically
+ // use the selected content as context. Defaults
+ // to false.
+ useSelection: true,
+ // Sets what operations the LLM is allowed to do.
+ // In this case, we only want to allow updating
+ // the selected content, so only `update` is set
+ // to true. Defaults to `true` for all
+ // operations.
+ defaultStreamTools: {
+ add: false,
+ delete: false,
+ update: true,
+ },
+ });
+ },
+ size: "small",
+});
+
+// Custom item to find related topics.
+export const findRelatedTopics = (
+ editor: BlockNoteEditor,
+): AIMenuSuggestionItem => ({
+ key: "find_related_topics",
+ title: "Find Related Topics",
+ // Aliases used when filtering AI Menu items from
+ // text in prompt input.
+ aliases: ["related topics", "find topics"],
+ icon: ,
+ onItemClick: async () => {
+ await getAIExtension(editor).callLLM({
+ userPrompt:
+ "Find several related topics to the current text and write a sentence about each",
+ // Sets what operations the LLM is allowed to do.
+ // In this case, we only want to allow adding new
+ // content, so only `add` is set to true.
+ // Defaults to `true` for all operations.
+ defaultStreamTools: {
+ add: true,
+ delete: false,
+ update: false,
+ },
+ });
+ },
+ size: "small",
+});
diff --git a/examples/09-ai/03-ai-menu-items/index.html b/examples/09-ai/03-ai-menu-items/index.html
new file mode 100644
index 000000000..8a9ab3594
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Adding AI Menu Items
+
+
+
+
+
+
diff --git a/examples/09-ai/03-ai-menu-items/main.tsx b/examples/09-ai/03-ai-menu-items/main.tsx
new file mode 100644
index 000000000..6284417d6
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/main.tsx
@@ -0,0 +1,11 @@
+// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from "./App.jsx";
+
+const root = createRoot(document.getElementById("root")!);
+root.render(
+
+
+
+);
diff --git a/examples/09-ai/03-ai-menu-items/package.json b/examples/09-ai/03-ai-menu-items/package.json
new file mode 100644
index 000000000..6a2f4b2b7
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@blocknote/example-ai-ai-menu-items",
+ "description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
+ "private": true,
+ "version": "0.12.4",
+ "scripts": {
+ "start": "vite",
+ "dev": "vite",
+ "build:prod": "tsc && vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@blocknote/core": "latest",
+ "@blocknote/react": "latest",
+ "@blocknote/ariakit": "latest",
+ "@blocknote/mantine": "latest",
+ "@blocknote/shadcn": "latest",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "@blocknote/xl-ai": "latest",
+ "@mantine/core": "^7.10.1",
+ "ai": "^4.1.0",
+ "@ai-sdk/openai": "^1.1.0",
+ "@ai-sdk/groq": "^1.1.0",
+ "react-icons": "^5.2.1",
+ "zustand": "^5.0.3"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.25",
+ "@types/react-dom": "^18.0.9",
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.3.4"
+ }
+}
\ No newline at end of file
diff --git a/examples/09-ai/03-ai-menu-items/tsconfig.json b/examples/09-ai/03-ai-menu-items/tsconfig.json
new file mode 100644
index 000000000..dbe3e6f62
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/tsconfig.json
@@ -0,0 +1,36 @@
+{
+ "__comment": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY",
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "lib": [
+ "DOM",
+ "DOM.Iterable",
+ "ESNext"
+ ],
+ "allowJs": false,
+ "skipLibCheck": true,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "composite": true
+ },
+ "include": [
+ "."
+ ],
+ "__ADD_FOR_LOCAL_DEV_references": [
+ {
+ "path": "../../../packages/core/"
+ },
+ {
+ "path": "../../../packages/react/"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/09-ai/03-ai-menu-items/vite-env.d.ts b/examples/09-ai/03-ai-menu-items/vite-env.d.ts
new file mode 100644
index 000000000..835d74da9
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/vite-env.d.ts
@@ -0,0 +1,10 @@
+///
+
+interface ImportMetaEnv {
+ readonly VITE_BLOCKNOTE_AI_SERVER_API_KEY: string;
+ readonly VITE_BLOCKNOTE_AI_SERVER_BASE_URL: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/examples/09-ai/03-ai-menu-items/vite.config.ts b/examples/09-ai/03-ai-menu-items/vite.config.ts
new file mode 100644
index 000000000..f62ab20bc
--- /dev/null
+++ b/examples/09-ai/03-ai-menu-items/vite.config.ts
@@ -0,0 +1,32 @@
+// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY
+import react from "@vitejs/plugin-react";
+import * as fs from "fs";
+import * as path from "path";
+import { defineConfig } from "vite";
+// import eslintPlugin from "vite-plugin-eslint";
+// https://vitejs.dev/config/
+export default defineConfig((conf) => ({
+ plugins: [react()],
+ optimizeDeps: {},
+ build: {
+ sourcemap: true,
+ },
+ resolve: {
+ alias:
+ conf.command === "build" ||
+ !fs.existsSync(path.resolve(__dirname, "../../packages/core/src"))
+ ? {}
+ : ({
+ // Comment out the lines below to load a built version of blocknote
+ // or, keep as is to load live from sources with live reload working
+ "@blocknote/core": path.resolve(
+ __dirname,
+ "../../packages/core/src/"
+ ),
+ "@blocknote/react": path.resolve(
+ __dirname,
+ "../../packages/react/src/"
+ ),
+ } as any),
+ },
+}));
diff --git a/packages/xl-ai/src/components/AIMenu/AIMenu.tsx b/packages/xl-ai/src/components/AIMenu/AIMenu.tsx
index 2a071faa2..33d4e7a9a 100644
--- a/packages/xl-ai/src/components/AIMenu/AIMenu.tsx
+++ b/packages/xl-ai/src/components/AIMenu/AIMenu.tsx
@@ -14,7 +14,7 @@ import {
getDefaultAIMenuItemsWithoutSelection,
} from "./getDefaultAIMenuItems.js";
-export const AIMenu = (props: {
+export type AIMenuProps = {
items?: (
editor: BlockNoteEditor,
aiResponseStatus:
@@ -26,7 +26,9 @@ export const AIMenu = (props: {
| "closed",
) => AIMenuSuggestionItem[];
onManualPromptSubmit?: (userPrompt: string) => void;
-}) => {
+};
+
+export const AIMenu = (props: AIMenuProps) => {
const editor = useBlockNoteEditor();
const [prompt, setPrompt] = useState("");
const dict = useAIDictionary();
@@ -114,7 +116,8 @@ export const AIMenu = (props: {
height="1em"
viewBox="0 -960 960 960"
width="1em"
- fill="currentColor">
+ fill="currentColor"
+ >
diff --git a/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx b/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx
new file mode 100644
index 000000000..4e615a3d3
--- /dev/null
+++ b/packages/xl-ai/src/components/AIMenu/AIMenuController.tsx
@@ -0,0 +1,36 @@
+import { useBlockNoteEditor } from "@blocknote/react";
+import { FC } from "react";
+import { useStore } from "zustand";
+
+import { getAIExtension } from "../../AIExtension.js";
+import { AIMenuProps, AIMenu } from "./AIMenu.js";
+import { BlockPositioner } from "./BlockPositioner.js";
+
+export const AIMenuController = (props: { aiMenu?: FC }) => {
+ const editor = useBlockNoteEditor();
+ const ai = getAIExtension(editor);
+
+ const aiMenuState = useStore(ai.store, (state) => state.aiMenuState);
+
+ const blockId = aiMenuState === "closed" ? undefined : aiMenuState.blockId;
+
+ const Component = props.aiMenu || AIMenu;
+
+ return (
+ {
+ if (
+ !open &&
+ aiMenuState !== "closed" &&
+ (aiMenuState.status === "user-input" ||
+ aiMenuState.status === "error")
+ ) {
+ ai.closeAIMenu();
+ }
+ }}
+ >
+
+
+ );
+};
diff --git a/packages/xl-ai/src/components/BlockNoteAIUI.tsx b/packages/xl-ai/src/components/BlockNoteAIUI.tsx
index d83a0c725..c70171592 100644
--- a/packages/xl-ai/src/components/BlockNoteAIUI.tsx
+++ b/packages/xl-ai/src/components/BlockNoteAIUI.tsx
@@ -1,9 +1,6 @@
import { useBlockNoteEditor } from "@blocknote/react";
-import { useStore } from "zustand";
-import { getAIExtension } from "../AIExtension.js";
-import { AIMenu } from "./AIMenu/AIMenu.js";
-import { BlockPositioner } from "./AIMenu/BlockPositioner.js";
+import { AIMenuController } from "./AIMenu/AIMenuController.js";
export type BlockNoteAIUIProps = {
aiBlockToolbar?: boolean;
@@ -22,29 +19,3 @@ export function BlockNoteAIUI(props: BlockNoteAIUIProps) {
return <>{props.aiMenu !== false && }>;
}
-
-const AIMenuController = () => {
- const editor = useBlockNoteEditor();
- const ai = getAIExtension(editor);
-
- const aiMenuState = useStore(ai.store, (state) => state.aiMenuState);
-
- const blockId = aiMenuState === "closed" ? undefined : aiMenuState.blockId;
-
- return (
- {
- if (
- !open &&
- aiMenuState !== "closed" &&
- (aiMenuState.status === "user-input" ||
- aiMenuState.status === "error")
- ) {
- ai.closeAIMenu();
- }
- }}>
-
-
- );
-};
diff --git a/packages/xl-ai/src/index.ts b/packages/xl-ai/src/index.ts
index dc9cc5cda..b14e7fb76 100644
--- a/packages/xl-ai/src/index.ts
+++ b/packages/xl-ai/src/index.ts
@@ -3,6 +3,11 @@ import "./style.css";
export * from "./AIExtension.js";
export * from "./api/blocknoteAIClient/client.js";
export * from "./components/BlockNoteAIUI.js";
+export * from "./components/AIMenu/AIMenu.js";
+export * from "./components/AIMenu/AIMenuController.js";
+export * from "./components/AIMenu/BlockPositioner.js";
+export * from "./components/AIMenu/getDefaultAIMenuItems.js";
+export * from "./components/AIMenu/PromptSuggestionMenu.js";
export * from "./components/FormattingToolbar/AIToolbarButton.js";
export * from "./components/SuggestionMenu/getAISlashMenuItems.js";
diff --git a/playground/src/examples.gen.tsx b/playground/src/examples.gen.tsx
index 8ef2e5e4e..61d221427 100644
--- a/playground/src/examples.gen.tsx
+++ b/playground/src/examples.gen.tsx
@@ -1440,6 +1440,34 @@
"pathFromRoot": "examples/09-ai",
"slug": "ai"
}
+ },
+ {
+ "projectSlug": "ai-menu-items",
+ "fullSlug": "ai/ai-menu-items",
+ "pathFromRoot": "examples/09-ai/03-ai-menu-items",
+ "config": {
+ "playground": true,
+ "docs": true,
+ "author": "matthewlipski",
+ "tags": [
+ "AI",
+ "llm"
+ ],
+ "dependencies": {
+ "@blocknote/xl-ai": "latest",
+ "@mantine/core": "^7.10.1",
+ "ai": "^4.1.0",
+ "@ai-sdk/openai": "^1.1.0",
+ "@ai-sdk/groq": "^1.1.0",
+ "react-icons": "^5.2.1",
+ "zustand": "^5.0.3"
+ } as any
+ },
+ "title": "Adding AI Menu Items",
+ "group": {
+ "pathFromRoot": "examples/09-ai",
+ "slug": "ai"
+ }
}
]
},