@blocknote/xl-ai 0.32.0 → 0.33.0

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.
@@ -1 +1 @@
1
- {"builtAt":1750769797305,"assets":[{"name":"blocknote-xl-ai.cjs","size":59918},{"name":"locales.cjs","size":23791},{"name":"locales.cjs.map","size":55283},{"name":"blocknote-xl-ai.cjs.map","size":2395292}],"chunks":[{"id":"a1ee98a","entry":true,"initial":true,"files":["blocknote-xl-ai.cjs"],"names":["blocknote-xl-ai"]},{"id":"842df4c","entry":true,"initial":true,"files":["locales.cjs"],"names":["locales"]}],"modules":[{"name":"./src/style.css","size":0,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/zustand@5.0.3_@types+react@18.3.20_immer@10.1.1_react@18.3.1_use-sync-external-store@1.4.0_react@18.3.1_/node_modules/zustand/esm/vanilla.mjs","size":973,"chunks":["a1ee98a"]},{"name":"./src/streamTool/jsonSchema.ts","size":1194,"chunks":["a1ee98a"]},{"name":"./src/util/stream.ts","size":1069,"chunks":["a1ee98a"]},{"name":"./src/streamTool/filterNewOrUpdatedOperations.ts","size":891,"chunks":["a1ee98a"]},{"name":"./src/streamTool/filterValidOperations.ts","size":647,"chunks":["a1ee98a"]},{"name":"./src/streamTool/toValidatedOperations.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/streamTool/preprocess.ts","size":848,"chunks":["a1ee98a"]},{"name":"./src/streamTool/callLLMWithStreamTools.ts","size":5771,"chunks":["a1ee98a"]},{"name":"./src/util/emptyBlock.ts","size":170,"chunks":["a1ee98a"]},{"name":"./src/api/LLMResponse.ts","size":1039,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/addCursorPosition.ts","size":390,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/convertBlocks.ts","size":183,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/flattenBlocks.ts","size":162,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/suffixIds.ts","size":204,"chunks":["a1ee98a"]},{"name":"./src/util/trimArray.ts","size":327,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/trimEmptyBlocks.ts","size":288,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/htmlPromptData.ts","size":1099,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts","size":5288,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/fragmentUtil.ts","size":262,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/agent.ts","size":6220,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/changeset.ts","size":6000,"chunks":["a1ee98a"]},{"name":"./src/streamTool/streamTool.ts","size":48,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/util/validateBlockArray.ts","size":574,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/createAddBlocksTool.ts","size":5316,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/createUpdateBlockTool.ts","size":4078,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/delete.ts","size":1766,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/getPartialHTML.ts","size":699,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/rebaseTool.ts","size":1508,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/rebaseTool.ts","size":829,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/validate.ts","size":204,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/index.ts","size":2049,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/htmlBlocks.ts","size":1283,"chunks":["a1ee98a"]},{"name":"./src/api/LLMRequest.ts","size":2350,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/jsonPromptData.ts","size":1208,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/defaultJSONPromptBuilder.ts","size":3681,"chunks":["a1ee98a"]},{"name":"./src/api/schema/mergeSchema.ts","size":829,"chunks":["a1ee98a"]},{"name":"./src/api/schema/schemaToJSONSchema.ts","size":4849,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/tools/validate.ts","size":1603,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/tools/index.ts","size":1324,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/json.ts","size":1220,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/markdownPromptData.ts","size":1119,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/defaultMarkdownPromptBuilder.ts","size":2744,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/rebaseTool.ts","size":633,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/validate.ts","size":202,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/index.ts","size":1505,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/markdownBlocks.ts","size":1148,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/index.ts","size":112,"chunks":["a1ee98a"]},{"name":"./src/api/index.ts","size":138,"chunks":["a1ee98a"]},{"name":"./src/plugins/AgentCursorPlugin.ts","size":2444,"chunks":["a1ee98a"]},{"name":"./src/AIExtension.ts","size":6605,"chunks":["a1ee98a"]},{"name":"./src/blocknoteAIClient/client.ts","size":1601,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconContext.mjs","size":251,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconBase.mjs","size":4003,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/ri/index.mjs","size":6747,"chunks":["a1ee98a"]},{"name":"./src/i18n/dictionary.ts","size":150,"chunks":["a1ee98a"]},{"name":"./src/i18n/useAIDictionary.ts","size":111,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/PromptSuggestionMenu.tsx","size":2901,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/getDefaultAIMenuItems.tsx","size":6883,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenu.tsx","size":3523,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/BlockPositioner.tsx","size":1392,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenuController.tsx","size":916,"chunks":["a1ee98a"]},{"name":"./src/components/FormattingToolbar/AIToolbarButton.tsx","size":853,"chunks":["a1ee98a"]},{"name":"./src/components/SuggestionMenu/getAISlashMenuItems.tsx","size":679,"chunks":["a1ee98a"]},{"name":"./src/index.ts","size":0,"chunks":["a1ee98a"]},{"name":"./src/i18n/locales/ar.ts","size":1531,"chunks":["842df4c"]},{"name":"./src/i18n/locales/de.ts","size":1585,"chunks":["842df4c"]},{"name":"./src/i18n/locales/en.ts","size":1483,"chunks":["842df4c"]},{"name":"./src/i18n/locales/es.ts","size":1553,"chunks":["842df4c"]},{"name":"./src/i18n/locales/fr.ts","size":1569,"chunks":["842df4c"]},{"name":"./src/i18n/locales/he.ts","size":1401,"chunks":["842df4c"]},{"name":"./src/i18n/locales/hr.ts","size":1494,"chunks":["842df4c"]},{"name":"./src/i18n/locales/is.ts","size":1562,"chunks":["842df4c"]},{"name":"./src/i18n/locales/it.ts","size":1555,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ja.ts","size":1372,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ko.ts","size":1394,"chunks":["842df4c"]},{"name":"./src/i18n/locales/nl.ts","size":1536,"chunks":["842df4c"]},{"name":"./src/i18n/locales/no.ts","size":1509,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pl.ts","size":1510,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pt.ts","size":1548,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ru.ts","size":1549,"chunks":["842df4c"]},{"name":"./src/i18n/locales/sk.ts","size":1511,"chunks":["842df4c"]},{"name":"./src/i18n/locales/uk.ts","size":1556,"chunks":["842df4c"]},{"name":"./src/i18n/locales/vi.ts","size":1506,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh-tw.ts","size":1345,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh.ts","size":1340,"chunks":["842df4c"]},{"name":"./src/i18n/locales/index.ts","size":0,"chunks":["842df4c"]}]}
1
+ {"builtAt":1751535645110,"assets":[{"name":"blocknote-xl-ai.cjs","size":60340},{"name":"locales.cjs","size":23791},{"name":"locales.cjs.map","size":55283},{"name":"blocknote-xl-ai.cjs.map","size":2396958}],"chunks":[{"id":"a1ee98a","entry":true,"initial":true,"files":["blocknote-xl-ai.cjs"],"names":["blocknote-xl-ai"]},{"id":"842df4c","entry":true,"initial":true,"files":["locales.cjs"],"names":["locales"]}],"modules":[{"name":"./src/style.css","size":0,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/zustand@5.0.3_@types+react@18.3.20_immer@10.1.1_react@18.3.1_use-sync-external-store@1.4.0_react@18.3.1_/node_modules/zustand/esm/vanilla.mjs","size":973,"chunks":["a1ee98a"]},{"name":"./src/streamTool/jsonSchema.ts","size":1194,"chunks":["a1ee98a"]},{"name":"./src/util/stream.ts","size":1069,"chunks":["a1ee98a"]},{"name":"./src/streamTool/filterNewOrUpdatedOperations.ts","size":891,"chunks":["a1ee98a"]},{"name":"./src/streamTool/filterValidOperations.ts","size":647,"chunks":["a1ee98a"]},{"name":"./src/streamTool/toValidatedOperations.ts","size":753,"chunks":["a1ee98a"]},{"name":"./src/streamTool/preprocess.ts","size":848,"chunks":["a1ee98a"]},{"name":"./src/streamTool/callLLMWithStreamTools.ts","size":6023,"chunks":["a1ee98a"]},{"name":"./src/util/emptyBlock.ts","size":170,"chunks":["a1ee98a"]},{"name":"./src/api/LLMResponse.ts","size":1039,"chunks":["a1ee98a"]},{"name":"./src/util/trimArray.ts","size":327,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/trimEmptyBlocks.ts","size":272,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/addCursorPosition.ts","size":390,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/convertBlocks.ts","size":183,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/flattenBlocks.ts","size":162,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/suffixIds.ts","size":204,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/htmlPromptData.ts","size":1189,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts","size":5301,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/fragmentUtil.ts","size":262,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/agent.ts","size":6220,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/changeset.ts","size":6000,"chunks":["a1ee98a"]},{"name":"./src/streamTool/streamTool.ts","size":48,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/util/validateBlockArray.ts","size":574,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/createAddBlocksTool.ts","size":5316,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/createUpdateBlockTool.ts","size":4078,"chunks":["a1ee98a"]},{"name":"./src/api/formats/base-tools/delete.ts","size":1766,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/getPartialHTML.ts","size":699,"chunks":["a1ee98a"]},{"name":"./src/prosemirror/rebaseTool.ts","size":1508,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/rebaseTool.ts","size":829,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/validate.ts","size":204,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/tools/index.ts","size":2049,"chunks":["a1ee98a"]},{"name":"./src/api/formats/html-blocks/htmlBlocks.ts","size":1283,"chunks":["a1ee98a"]},{"name":"./src/api/LLMRequest.ts","size":2489,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/jsonPromptData.ts","size":1298,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/defaultJSONPromptBuilder.ts","size":3694,"chunks":["a1ee98a"]},{"name":"./src/api/schema/mergeSchema.ts","size":829,"chunks":["a1ee98a"]},{"name":"./src/api/schema/schemaToJSONSchema.ts","size":4849,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/tools/validate.ts","size":1603,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/tools/index.ts","size":1324,"chunks":["a1ee98a"]},{"name":"./src/api/formats/json/json.ts","size":1220,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/markdownPromptData.ts","size":1209,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/defaultMarkdownPromptBuilder.ts","size":2744,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/rebaseTool.ts","size":633,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/validate.ts","size":202,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/tools/index.ts","size":1505,"chunks":["a1ee98a"]},{"name":"./src/api/formats/markdown-blocks/markdownBlocks.ts","size":1148,"chunks":["a1ee98a"]},{"name":"./src/api/promptHelpers/index.ts","size":112,"chunks":["a1ee98a"]},{"name":"./src/api/index.ts","size":138,"chunks":["a1ee98a"]},{"name":"./src/plugins/AgentCursorPlugin.ts","size":2444,"chunks":["a1ee98a"]},{"name":"./src/AIExtension.ts","size":6605,"chunks":["a1ee98a"]},{"name":"./src/blocknoteAIClient/client.ts","size":1601,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconContext.mjs","size":251,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/lib/iconBase.mjs","size":4003,"chunks":["a1ee98a"]},{"name":"../../node_modules/.pnpm/react-icons@5.5.0_react@18.3.1/node_modules/react-icons/ri/index.mjs","size":6747,"chunks":["a1ee98a"]},{"name":"./src/i18n/dictionary.ts","size":150,"chunks":["a1ee98a"]},{"name":"./src/i18n/useAIDictionary.ts","size":111,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/PromptSuggestionMenu.tsx","size":2901,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/getDefaultAIMenuItems.tsx","size":6990,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenu.tsx","size":3523,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/BlockPositioner.tsx","size":1422,"chunks":["a1ee98a"]},{"name":"./src/components/AIMenu/AIMenuController.tsx","size":916,"chunks":["a1ee98a"]},{"name":"./src/components/FormattingToolbar/AIToolbarButton.tsx","size":853,"chunks":["a1ee98a"]},{"name":"./src/components/SuggestionMenu/getAISlashMenuItems.tsx","size":679,"chunks":["a1ee98a"]},{"name":"./src/index.ts","size":0,"chunks":["a1ee98a"]},{"name":"./src/i18n/locales/ar.ts","size":1531,"chunks":["842df4c"]},{"name":"./src/i18n/locales/de.ts","size":1585,"chunks":["842df4c"]},{"name":"./src/i18n/locales/en.ts","size":1483,"chunks":["842df4c"]},{"name":"./src/i18n/locales/es.ts","size":1553,"chunks":["842df4c"]},{"name":"./src/i18n/locales/fr.ts","size":1569,"chunks":["842df4c"]},{"name":"./src/i18n/locales/he.ts","size":1401,"chunks":["842df4c"]},{"name":"./src/i18n/locales/hr.ts","size":1494,"chunks":["842df4c"]},{"name":"./src/i18n/locales/is.ts","size":1562,"chunks":["842df4c"]},{"name":"./src/i18n/locales/it.ts","size":1555,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ja.ts","size":1372,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ko.ts","size":1394,"chunks":["842df4c"]},{"name":"./src/i18n/locales/nl.ts","size":1536,"chunks":["842df4c"]},{"name":"./src/i18n/locales/no.ts","size":1509,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pl.ts","size":1510,"chunks":["842df4c"]},{"name":"./src/i18n/locales/pt.ts","size":1548,"chunks":["842df4c"]},{"name":"./src/i18n/locales/ru.ts","size":1549,"chunks":["842df4c"]},{"name":"./src/i18n/locales/sk.ts","size":1511,"chunks":["842df4c"]},{"name":"./src/i18n/locales/uk.ts","size":1556,"chunks":["842df4c"]},{"name":"./src/i18n/locales/vi.ts","size":1506,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh-tw.ts","size":1345,"chunks":["842df4c"]},{"name":"./src/i18n/locales/zh.ts","size":1340,"chunks":["842df4c"]},{"name":"./src/i18n/locales/index.ts","size":0,"chunks":["842df4c"]}]}
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/xl-ai"
12
12
  },
13
13
  "license": "AGPL-3.0 OR PROPRIETARY",
14
- "version": "0.32.0",
14
+ "version": "0.33.0",
15
15
  "files": [
16
16
  "dist",
17
17
  "types",
@@ -56,10 +56,10 @@
56
56
  }
57
57
  },
58
58
  "dependencies": {
59
- "@blocknote/core": "0.32.0",
60
- "@blocknote/mantine": "0.32.0",
59
+ "@blocknote/core": "0.33.0",
60
+ "@blocknote/mantine": "0.33.0",
61
61
  "@blocknote/prosemirror-suggest-changes": "^0.1.3",
62
- "@blocknote/react": "0.32.0",
62
+ "@blocknote/react": "0.33.0",
63
63
  "@floating-ui/react": "^0.26.4",
64
64
  "@tiptap/core": "^2.12.0",
65
65
  "ai": "^4.3.15",
@@ -85,6 +85,7 @@
85
85
  "@ai-sdk/openai": "^1.3.22",
86
86
  "@ai-sdk/openai-compatible": "^0.2.14",
87
87
  "@ai-sdk/anthropic": "^1.2.12",
88
+ "@ai-sdk/google": "^1.2.20",
88
89
  "@mswjs/interceptors": "^0.37.5",
89
90
  "@types/diff": "^6.0.0",
90
91
  "@types/json-diff": "^1.0.3",
@@ -9,6 +9,7 @@ import { LLMResponse } from "./LLMResponse.js";
9
9
  import type { PromptBuilder } from "./formats/PromptBuilder.js";
10
10
  import { htmlBlockLLMFormat } from "./formats/html-blocks/htmlBlocks.js";
11
11
  import { LLMFormat } from "./index.js";
12
+ import { trimEmptyBlocks } from "./promptHelpers/trimEmptyBlocks.js";
12
13
 
13
14
  export type LLMRequestOptions = {
14
15
  /**
@@ -155,7 +156,7 @@ export async function doLLMRequest(
155
156
  cursorBlock &&
156
157
  deleteEmptyCursorBlock &&
157
158
  isEmptyParagraph(cursorBlock) &&
158
- editor.document.length > 1
159
+ trimEmptyBlocks(editor.document).length > 0
159
160
  ? cursorBlock.id
160
161
  : undefined;
161
162
 
@@ -176,6 +177,7 @@ export async function doLLMRequest(
176
177
  content: `USER_MESSAGE: ${m.content}`,
177
178
  };
178
179
  }
180
+
179
181
  return m;
180
182
  });
181
183
  /*
@@ -191,9 +193,9 @@ export async function doLLMRequest(
191
193
  For now, this approach works ok.
192
194
  */
193
195
  previousMessages.push({
194
- role: "assistant",
196
+ role: "system", // using "assistant" here doesn't work with gemini because we can't mix system / assistant messages
195
197
  content:
196
- "These are the operations returned by a previous LLM call: \n" +
198
+ "ASSISTANT_MESSAGE: These are the operations returned by a previous LLM call: \n" +
197
199
  JSON.stringify(
198
200
  await previousResponse.llmResult.getGeneratedOperations(),
199
201
  ),
@@ -1,4 +1,5 @@
1
1
  import { CoreMessage } from "ai";
2
+ import { trimEmptyBlocks } from "../../promptHelpers/trimEmptyBlocks.js";
2
3
  import type { PromptBuilder } from "../PromptBuilder.js";
3
4
  import {
4
5
  getDataForPromptNoSelection,
@@ -99,6 +100,8 @@ function promptManipulateDocumentUseHTMLBlocks(opts: {
99
100
  }
100
101
 
101
102
  export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => {
103
+ const isEmptyDocument = trimEmptyBlocks(editor.document).length === 0;
104
+
102
105
  if (opts.selectedBlocks) {
103
106
  const data = await getDataForPromptWithSelection(editor, {
104
107
  selectedBlocks: opts.selectedBlocks,
@@ -141,7 +144,7 @@ export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => {
141
144
  return promptManipulateSelectionHTMLBlocks({
142
145
  ...data,
143
146
  userPrompt: opts.userPrompt,
144
- isEmptyDocument: editor.isEmpty,
147
+ isEmptyDocument,
145
148
  });
146
149
  } else {
147
150
  const data = await getDataForPromptNoSelection(editor, opts);
@@ -174,7 +177,7 @@ export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => {
174
177
  return promptManipulateDocumentUseHTMLBlocks({
175
178
  ...data,
176
179
  userPrompt: opts.userPrompt,
177
- isEmptyDocument: editor.isEmpty,
180
+ isEmptyDocument,
178
181
  });
179
182
  }
180
183
  };
@@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection(
11
11
  excludeBlockIds?: string[];
12
12
  },
13
13
  ) {
14
- const input = trimEmptyBlocks(editor.document);
14
+ const cursorBlockId = editor.getTextCursorPosition().block.id;
15
+ const input = trimEmptyBlocks(editor.document, {
16
+ cursorBlockId,
17
+ });
15
18
  const blockArray = await convertBlocks(
16
19
  flattenBlocks(input),
17
20
  async (block) => {
@@ -1,4 +1,5 @@
1
1
  import { CoreMessage } from "ai";
2
+ import { trimEmptyBlocks } from "../../promptHelpers/trimEmptyBlocks.js";
2
3
  import { PromptBuilder } from "../PromptBuilder.js";
3
4
  import {
4
5
  getDataForPromptNoSelection,
@@ -122,21 +123,24 @@ function promptManipulateDocumentUseJSONBlocks(opts: {
122
123
  }
123
124
 
124
125
  export const defaultJSONPromptBuilder: PromptBuilder = async (editor, opts) => {
126
+ const isEmptyDocument = trimEmptyBlocks(editor.document).length === 0;
127
+
125
128
  if (opts.selectedBlocks) {
126
129
  const data = await getDataForPromptWithSelection(editor, {
127
130
  selectedBlocks: opts.selectedBlocks,
128
131
  });
132
+
129
133
  return promptManipulateSelectionJSONBlocks({
130
134
  ...data,
131
135
  userPrompt: opts.userPrompt,
132
- isEmptyDocument: editor.isEmpty,
136
+ isEmptyDocument,
133
137
  });
134
138
  } else {
135
139
  const data = await getDataForPromptNoSelection(editor, opts);
136
140
  return promptManipulateDocumentUseJSONBlocks({
137
141
  ...data,
138
142
  userPrompt: opts.userPrompt,
139
- isEmptyDocument: editor.isEmpty,
143
+ isEmptyDocument,
140
144
  });
141
145
  }
142
146
  };
@@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection(
11
11
  excludeBlockIds?: string[];
12
12
  },
13
13
  ) {
14
- const input = trimEmptyBlocks(editor.document);
14
+ const cursorBlockId = editor.getTextCursorPosition().block.id;
15
+ const input = trimEmptyBlocks(editor.document, {
16
+ cursorBlockId,
17
+ });
15
18
  const blockArray = await convertBlocks(
16
19
  flattenBlocks(input),
17
20
  async (block) => {
@@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection(
11
11
  excludeBlockIds?: string[];
12
12
  },
13
13
  ) {
14
- const input = trimEmptyBlocks(editor.document);
14
+ const cursorBlockId = editor.getTextCursorPosition().block.id;
15
+ const input = trimEmptyBlocks(editor.document, {
16
+ cursorBlockId,
17
+ });
15
18
  const blockArray = await convertBlocks(
16
19
  flattenBlocks(input),
17
20
  async (block) => {
@@ -7,19 +7,16 @@ export function trimEmptyBlocks(
7
7
  opts?: {
8
8
  trimStart?: boolean;
9
9
  trimEnd?: boolean;
10
+ cursorBlockId?: string;
10
11
  },
11
12
  ) {
12
- if (source.length === 1) {
13
- // don't trim empty blocks from a single block document
14
- return source;
15
- }
16
13
  // trim empty trailing blocks that don't have the cursor
17
14
  // if we don't do this, commands like "add some paragraphs"
18
15
  // would add paragraphs after the trailing blocks
19
16
  const trimmedSource = trimArray(
20
17
  source,
21
18
  (block) => {
22
- return isEmptyParagraph(block);
19
+ return isEmptyParagraph(block) && opts?.cursorBlockId !== block.id;
23
20
  },
24
21
  opts?.trimStart ?? false,
25
22
  opts?.trimEnd ?? true,
@@ -1,5 +1,12 @@
1
1
  import { useUIElementPositioning } from "@blocknote/react";
2
- import { OpenChangeReason, autoUpdate, offset, size } from "@floating-ui/react";
2
+ import {
3
+ OpenChangeReason,
4
+ UseDismissProps,
5
+ UseFloatingOptions,
6
+ autoUpdate,
7
+ offset,
8
+ size,
9
+ } from "@floating-ui/react";
3
10
  import { useMemo } from "react";
4
11
  // The block positioner automattically positions it's children below the block with `blockID`
5
12
  export const BlockPositioner = (props: {
@@ -11,6 +18,9 @@ export const BlockPositioner = (props: {
11
18
  reason: OpenChangeReason,
12
19
  ) => void;
13
20
  canDismissViaOutsidePress?: boolean;
21
+ floatingOptions?: Partial<
22
+ UseFloatingOptions & { canDismiss: boolean | UseDismissProps }
23
+ >;
14
24
  }) => {
15
25
  const element = props.blockID
16
26
  ? document.querySelector(`[data-id="${props.blockID}"]`)
@@ -55,6 +65,7 @@ export const BlockPositioner = (props: {
55
65
  });
56
66
  return cleanup;
57
67
  },
68
+ ...props.floatingOptions,
58
69
  });
59
70
 
60
71
  if (!isMounted) {
@@ -49,7 +49,7 @@ function getDefaultAIMenuItemsWithoutSelection<
49
49
  onItemClick: async () => {
50
50
  await ai.callLLM({
51
51
  userPrompt:
52
- "Continue writing: write more text at the current cursor position related to the previous text",
52
+ "Continue writing at the current cursor position related to the previous text. Add multiple blocks if needed. If the document looks like a template / draft, follow the template. Be extensive if needed.",
53
53
  // By default, LLM will be able to add / update / delete blocks. For "continue writing", we only want to allow adding new blocks.
54
54
  defaultStreamTools: {
55
55
  add: true,
@@ -105,9 +105,14 @@ export async function generateOperations<T extends StreamTool<any>[]>(
105
105
  // - optional, with defaults
106
106
 
107
107
  // mistral somehow needs "auto", while groq/llama needs "tool"
108
+ // google needs "auto" because https://github.com/vercel/ai/issues/6959
108
109
  // TODO: further research this and / or make configurable
109
110
  // for now stick to "tool" by default as this has been tested mostly
110
- mode: rest.model.provider === "mistral.chat" ? "auto" : "tool",
111
+ mode:
112
+ rest.model.provider === "mistral.chat" ||
113
+ rest.model.provider === "google.generative-ai"
114
+ ? "auto"
115
+ : "tool",
111
116
  // - mandatory ones:
112
117
  ...rest,
113
118
 
@@ -215,9 +220,14 @@ export async function streamOperations<T extends StreamTool<any>[]>(
215
220
 
216
221
  // - optional, with defaults
217
222
  // mistral somehow needs "auto", while groq/llama needs "tool"
223
+ // google needs "auto" because https://github.com/vercel/ai/issues/6959
218
224
  // TODO: further research this and / or make configurable
219
225
  // for now stick to "tool" by default as this has been tested mostly
220
- mode: rest.model.provider === "mistral.chat" ? "auto" : "tool",
226
+ mode:
227
+ rest.model.provider === "mistral.chat" ||
228
+ rest.model.provider === "google.generative-ai"
229
+ ? "auto"
230
+ : "tool",
221
231
  // - mandatory ones:
222
232
  ...rest,
223
233
 
@@ -2,4 +2,5 @@ import { Block } from "@blocknote/core";
2
2
  export declare function trimEmptyBlocks(source: Block<any, any, any>[], opts?: {
3
3
  trimStart?: boolean;
4
4
  trimEnd?: boolean;
5
+ cursorBlockId?: string;
5
6
  }): Block<any, any, any>[];
@@ -1,7 +1,10 @@
1
- import { OpenChangeReason } from "@floating-ui/react";
1
+ import { OpenChangeReason, UseDismissProps, UseFloatingOptions } from "@floating-ui/react";
2
2
  export declare const BlockPositioner: (props: {
3
3
  blockID?: string;
4
4
  children: React.ReactNode;
5
5
  onOpenChange?: (open: boolean, event: Event, reason: OpenChangeReason) => void;
6
6
  canDismissViaOutsidePress?: boolean;
7
+ floatingOptions?: Partial<UseFloatingOptions & {
8
+ canDismiss: boolean | UseDismissProps;
9
+ }>;
7
10
  }) => import("react/jsx-runtime").JSX.Element | null;