@blocknote/xl-ai 0.51.4 → 0.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/blocknote-xl-ai.cjs +1 -1
  2. package/dist/blocknote-xl-ai.cjs.map +1 -1
  3. package/dist/blocknote-xl-ai.js +503 -107
  4. package/dist/blocknote-xl-ai.js.map +1 -1
  5. package/dist/locales.cjs.map +1 -1
  6. package/dist/locales.js.map +1 -1
  7. package/dist/{server-JIYg7ELG.js → server-CafGbRLa.js} +35 -31
  8. package/dist/server-CafGbRLa.js.map +1 -0
  9. package/dist/server-CxZHspeS.cjs +36 -0
  10. package/dist/server-CxZHspeS.cjs.map +1 -0
  11. package/dist/server.cjs +1 -1
  12. package/dist/server.js +1 -2
  13. package/dist/style.css +1 -1
  14. package/dist/webpack-stats.json +1 -1
  15. package/package.json +12 -25
  16. package/src/AIExtension.ts +12 -7
  17. package/src/api/formats/base-tools/createAddBlocksTool.ts +4 -4
  18. package/src/api/formats/base-tools/createUpdateBlockTool.ts +4 -4
  19. package/src/api/formats/html-blocks/columnContainerDocumentState.test.ts +1 -1
  20. package/src/api/formats/html-blocks/htmlBlocks.test.ts +6 -8
  21. package/src/api/formats/html-blocks/tools/getPartialHTML.test.ts +1 -1
  22. package/src/api/formats/html-blocks/tools/index.ts +15 -21
  23. package/src/api/formats/html-blocks/tools/rebaseTool.ts +3 -3
  24. package/src/api/formats/json/errorHandling.test.ts +8 -1
  25. package/src/api/formats/json/json.test.ts +1 -1
  26. package/src/api/formats/json/tools/index.ts +4 -4
  27. package/src/api/formats/json/tools/jsontools.test.ts +1 -1
  28. package/src/api/formats/markdown-blocks/markdownBlocks.test.ts +1 -1
  29. package/src/api/formats/markdown-blocks/tools/index.ts +9 -11
  30. package/src/api/formats/markdown-blocks/tools/rebaseTool.ts +3 -3
  31. package/src/api/formats/tests/sharedTestCases.ts +2 -3
  32. package/src/api/formats/tests/snapshotPath.ts +2 -2
  33. package/src/api/formats/tests/validateTestEnvironment.test.ts +1 -1
  34. package/src/api/promptHelpers/suffixIds.ts +1 -1
  35. package/src/api/schema/__snapshots__/schemaToJSONSchema.test.ts.snap +1 -1
  36. package/src/api/schema/schemaToJSONSchema.test.ts +3 -3
  37. package/src/api/schema/schemaToJSONSchema.ts +5 -3
  38. package/src/components/AIMenu/PromptSuggestionMenu.tsx +1 -1
  39. package/src/plugins/AgentCursorPlugin.ts +8 -1
  40. package/src/prosemirror/AttributionMarks.ts +204 -0
  41. package/src/prosemirror/__snapshots__/agent.test.ts.snap +16 -265
  42. package/src/prosemirror/__snapshots__/rebaseTool.test.ts.snap +4 -4
  43. package/src/prosemirror/agent.test.ts +8 -10
  44. package/src/prosemirror/agent.ts +1 -1
  45. package/src/prosemirror/changeset.test.ts +1 -1
  46. package/src/prosemirror/fragmentUtil.test.ts +1 -1
  47. package/src/prosemirror/rebaseTool.test.ts +8 -3
  48. package/src/server.ts +0 -1
  49. package/src/streamTool/filterNewOrUpdatedOperations.test.ts +1 -1
  50. package/src/streamTool/filterValidOperations.test.ts +1 -1
  51. package/src/streamTool/preprocess.test.ts +1 -1
  52. package/src/streamTool/toValidatedOperations.test.ts +1 -1
  53. package/src/streamTool/vercelAiSdk/clientside/ClientSideTransport.ts +8 -5
  54. package/src/streamTool/vercelAiSdk/util/appendableStream.test.ts +15 -15
  55. package/src/streamTool/vercelAiSdk/util/chatHandlers.test.ts +10 -1
  56. package/src/streamTool/vercelAiSdk/util/chatHandlers.ts +7 -7
  57. package/src/style.css +0 -19
  58. package/src/testUtil/suggestChangesTestUtil.ts +1 -1
  59. package/src/util/stream.ts +1 -1
  60. package/src/vite-env.d.ts +1 -0
  61. package/types/src/AIExtension.d.ts +4 -0
  62. package/types/src/api/formats/base-tools/createAddBlocksTool.d.ts +2 -2
  63. package/types/src/api/formats/base-tools/createUpdateBlockTool.d.ts +2 -2
  64. package/types/src/api/formats/formats.d.ts +3 -3
  65. package/types/src/api/formats/html-blocks/tools/rebaseTool.d.ts +2 -2
  66. package/types/src/api/formats/json/json.d.ts +3 -3
  67. package/types/src/api/formats/markdown-blocks/tools/rebaseTool.d.ts +2 -2
  68. package/types/src/api/schema/schemaToJSONSchema.d.ts +3 -3
  69. package/types/src/prosemirror/AttributionMarks.d.ts +15 -0
  70. package/types/src/testUtil/cases/editors/blockFormatting.d.ts +17 -17
  71. package/types/src/testUtil/cases/editors/formattingAndMentions.d.ts +17 -17
  72. package/types/src/testUtil/cases/editors/simpleEditor.d.ts +51 -51
  73. package/types/src/testUtil/cases/editors/tables.d.ts +17 -17
  74. package/types/src/testUtil/cases/schemas/mention.d.ts +17 -17
  75. package/dist/server-D-Xyj9BS.cjs +0 -36
  76. package/dist/server-D-Xyj9BS.cjs.map +0 -1
  77. package/dist/server-JIYg7ELG.js.map +0 -1
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/xl-ai"
12
12
  },
13
13
  "license": "GPL-3.0 OR PROPRIETARY",
14
- "version": "0.51.4",
14
+ "version": "0.52.1",
15
15
  "files": [
16
16
  "dist",
17
17
  "types",
@@ -28,7 +28,6 @@
28
28
  "wysiwyg",
29
29
  "rich-text-editor",
30
30
  "notion",
31
- "yjs",
32
31
  "block-based",
33
32
  "tiptap"
34
33
  ],
@@ -63,9 +62,6 @@
63
62
  "dependencies": {
64
63
  "@ai-sdk/provider-utils": "^4.0.2",
65
64
  "@ai-sdk/react": "^3.0.5",
66
- "@blocknote/core": "0.51.4",
67
- "@blocknote/mantine": "0.51.4",
68
- "@blocknote/react": "0.51.4",
69
65
  "@floating-ui/react": "^0.27.18",
70
66
  "@handlewithcare/prosemirror-suggest-changes": "^0.1.8",
71
67
  "@tiptap/core": "^3.13.0",
@@ -78,30 +74,27 @@
78
74
  "prosemirror-tables": "^1.8.3",
79
75
  "prosemirror-transform": "^1.11.0",
80
76
  "prosemirror-view": "^1.41.4",
81
- "react": "^19.2.5",
82
- "react-dom": "^19.2.5",
83
- "react-icons": "^5.5.0",
84
- "y-prosemirror": "^1.3.7"
77
+ "@blocknote/core": "^0.52.1",
78
+ "@blocknote/react": "^0.52.1"
85
79
  },
86
80
  "devDependencies": {
81
+ "react-icons": "^5.5.0",
87
82
  "@ai-sdk/anthropic": "^3.0.2",
88
83
  "@ai-sdk/google": "^3.0.2",
89
84
  "@ai-sdk/groq": "^3.0.2",
90
85
  "@ai-sdk/mistral": "^3.0.2",
91
86
  "@ai-sdk/openai": "^3.0.2",
92
87
  "@ai-sdk/openai-compatible": "^2.0.2",
93
- "@blocknote/xl-multi-column": "0.51.4",
94
88
  "@mswjs/interceptors": "^0.37.6",
95
89
  "@types/diff": "^6.0.0",
96
90
  "@types/json-diff": "^1.0.3",
97
91
  "@types/json-schema": "^7.0.15",
98
92
  "@types/lodash.isequal": "^4.5.8",
99
93
  "@types/lodash.merge": "^4.6.9",
94
+ "@types/node": "22.13.13",
100
95
  "@types/react": "^19.2.3",
101
96
  "@types/react-dom": "^19.2.3",
102
97
  "@vitejs/plugin-react": "^6.0.1",
103
- "@vitest/runner": "^4.1.2",
104
- "eslint": "^8.57.1",
105
98
  "glob": "^10.5.0",
106
99
  "headers-polyfill": "^4.0.3",
107
100
  "msw": "^2.11.5",
@@ -110,27 +103,21 @@
110
103
  "rollup-plugin-webpack-stats": "^0.2.6",
111
104
  "typescript": "^5.9.3",
112
105
  "undici": "^6.22.0",
113
- "vite": "^8.0.8",
114
- "vite-plugin-eslint": "^1.8.1",
115
106
  "vite-plugin-externalize-deps": "^0.10.0",
116
- "vitest": "^4.1.2"
107
+ "vite-plus": "^0.1.24",
108
+ "@blocknote/shared": "^0.30.0",
109
+ "@blocknote/xl-multi-column": "^0.52.1"
117
110
  },
118
111
  "peerDependencies": {
119
112
  "react": "^18.0 || ^19.0 || >= 19.0.0-rc",
120
113
  "react-dom": "^18.0 || ^19.0 || >= 19.0.0-rc"
121
114
  },
122
- "eslintConfig": {
123
- "extends": [
124
- "../../.eslintrc.json"
125
- ]
126
- },
127
115
  "scripts": {
128
- "dev": "vite",
129
- "build": "tsc && vite build",
130
- "lint": "eslint src --max-warnings 0",
131
- "test": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" vitest --run",
132
- "test-watch": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" vitest watch",
116
+ "dev": "vp dev",
117
+ "lint": "vp lint src",
118
+ "test-watch": "NODE_EXTRA_CA_CERTS=\"$(mkcert -CAROOT)/rootCA.pem\" vp test watch",
133
119
  "rename-msw-snapshots": "node scripts/rename-msw-snapshots.mjs",
120
+ "clean": "rimraf dist && rimraf types",
134
121
  "email": "email dev"
135
122
  }
136
123
  }
@@ -6,10 +6,8 @@ import {
6
6
  getNodeById,
7
7
  UnreachableCaseError,
8
8
  } from "@blocknote/core";
9
- import {
10
- ForkYDocExtension,
11
- ShowSelectionExtension,
12
- } from "@blocknote/core/extensions";
9
+ import { ShowSelectionExtension } from "@blocknote/core/extensions";
10
+ import type { ForkYDocExtension } from "@blocknote/core/yjs";
13
11
  import {
14
12
  applySuggestions,
15
13
  revertSuggestions,
@@ -22,6 +20,7 @@ import { fixTablesKey } from "prosemirror-tables";
22
20
  import { buildAIRequest, sendMessageWithAIRequest } from "./api/index.js";
23
21
  import { createAgentCursorPlugin } from "./plugins/AgentCursorPlugin.js";
24
22
  import { AIRequestHelpers, InvokeAIOptions } from "./types.js";
23
+ import { AttributionMarksExtension } from "./prosemirror/AttributionMarks.js";
25
24
 
26
25
  type AIPluginState = {
27
26
  aiMenuState:
@@ -83,6 +82,7 @@ export const AIExtension = createExtension(
83
82
  key: "ai",
84
83
  options,
85
84
  store,
85
+ blockNoteExtensions: [AttributionMarksExtension()],
86
86
  mount({ signal }: { signal: AbortSignal }) {
87
87
  let scrollInProgress = false;
88
88
  // Listens for `scroll` and `scrollend` events to see if a new scroll was
@@ -220,7 +220,9 @@ export const AIExtension = createExtension(
220
220
  });
221
221
 
222
222
  // If in collaboration mode, merge the changes back into the original yDoc
223
- editor.getExtension(ForkYDocExtension)?.merge({ keepChanges: true });
223
+ editor
224
+ .getExtension<typeof ForkYDocExtension>("yForkDoc")
225
+ ?.merge({ keepChanges: true });
224
226
 
225
227
  this.closeAIMenu();
226
228
  },
@@ -238,7 +240,9 @@ export const AIExtension = createExtension(
238
240
  });
239
241
 
240
242
  // If in collaboration mode, discard the changes and revert to the original yDoc
241
- editor.getExtension(ForkYDocExtension)?.merge({ keepChanges: false });
243
+ editor
244
+ .getExtension<typeof ForkYDocExtension>("yForkDoc")
245
+ ?.merge({ keepChanges: false });
242
246
  this.closeAIMenu();
243
247
  },
244
248
 
@@ -379,7 +383,8 @@ export const AIExtension = createExtension(
379
383
  */
380
384
  async invokeAI(opts: InvokeAIOptions) {
381
385
  this.setAIResponseStatus("thinking");
382
- editor.getExtension(ForkYDocExtension)?.fork();
386
+ // If in collaboration mode, fork the yDoc to allow modifications without affecting the remote
387
+ editor.getExtension<typeof ForkYDocExtension>("yForkDoc")?.fork();
383
388
 
384
389
  try {
385
390
  // Create a new AbortController for this request
@@ -54,7 +54,7 @@ export function createAddBlocksTool<T>(config: {
54
54
  rebaseTool: (
55
55
  id: string,
56
56
  editor: BlockNoteEditor<any, any, any>,
57
- ) => Promise<RebaseTool>;
57
+ ) => RebaseTool;
58
58
  /**
59
59
  * Converts the operation from `AddBlocksToolCall<T>` to `AddBlocksToolCall<PartialBlock<any, any, any>>`
60
60
  *
@@ -68,7 +68,7 @@ export function createAddBlocksTool<T>(config: {
68
68
  isUpdateToPreviousOperation: boolean;
69
69
  isPossiblyPartial: boolean;
70
70
  },
71
- ) => Promise<AddBlocksToolCall<PartialBlock<any, any, any>> | undefined>;
71
+ ) => AddBlocksToolCall<PartialBlock<any, any, any>> | undefined;
72
72
  }) {
73
73
  return (
74
74
  editor: BlockNoteEditor<any, any, any>,
@@ -196,7 +196,7 @@ export function createAddBlocksTool<T>(config: {
196
196
 
197
197
  const operation = chunk.operation as AddBlocksToolCall<T>;
198
198
 
199
- const jsonToolCall = await config.toJSONToolCall(editor, {
199
+ const jsonToolCall = config.toJSONToolCall(editor, {
200
200
  ...chunk,
201
201
  operation,
202
202
  });
@@ -223,7 +223,7 @@ export function createAddBlocksTool<T>(config: {
223
223
  let agentSteps: AgentStep[] = [];
224
224
  if (i < addedBlockIds.length) {
225
225
  // we have already added this block, so we need to update it
226
- const tool = await config.rebaseTool(addedBlockIds[i], editor);
226
+ const tool = config.rebaseTool(addedBlockIds[i], editor);
227
227
  const steps = updateToReplaceSteps(
228
228
  {
229
229
  id: addedBlockIds[i],
@@ -59,7 +59,7 @@ export function createUpdateBlockTool<T>(config: {
59
59
  rebaseTool: (
60
60
  id: string,
61
61
  editor: BlockNoteEditor<any, any, any>,
62
- ) => Promise<RebaseTool>;
62
+ ) => RebaseTool;
63
63
  /**
64
64
  * Converts the operation from `AddBlocksToolCall<T>` to `AddBlocksToolCall<PartialBlock<any, any, any>>`
65
65
  *
@@ -73,7 +73,7 @@ export function createUpdateBlockTool<T>(config: {
73
73
  isUpdateToPreviousOperation: boolean;
74
74
  isPossiblyPartial: boolean;
75
75
  },
76
- ) => Promise<UpdateBlockToolCall<PartialBlock<any, any, any>> | undefined>;
76
+ ) => UpdateBlockToolCall<PartialBlock<any, any, any>> | undefined;
77
77
  }) {
78
78
  return (
79
79
  editor: BlockNoteEditor<any, any, any>,
@@ -202,7 +202,7 @@ export function createUpdateBlockTool<T>(config: {
202
202
 
203
203
  // REC: we could investigate whether we can use a single rebasetool across operations instead of
204
204
  // creating a new one every time (possibly expensive)
205
- const tool = await config.rebaseTool(operation.id, editor);
205
+ const tool = config.rebaseTool(operation.id, editor);
206
206
 
207
207
  const fromPos = selectionPositions
208
208
  ? tool.invertMap.invert().map(selectionPositions.from())
@@ -212,7 +212,7 @@ export function createUpdateBlockTool<T>(config: {
212
212
  ? tool.invertMap.invert().map(selectionPositions.to())
213
213
  : undefined;
214
214
 
215
- const jsonToolCall = await config.toJSONToolCall(editor, {
215
+ const jsonToolCall = config.toJSONToolCall(editor, {
216
216
  ...chunk,
217
217
  operation,
218
218
  });
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { BlockNoteEditor, BlockNoteSchema } from "@blocknote/core";
4
4
  import { withMultiColumn } from "@blocknote/xl-multi-column";
5
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vite-plus/test";
6
6
 
7
7
  import { htmlBlockLLMFormat } from "./htmlBlocks.js";
8
8
 
@@ -1,7 +1,7 @@
1
1
  import { snapshot } from "msw-snapshot";
2
2
  import { setupServer } from "msw/node";
3
3
  import path from "path";
4
- import { afterAll, afterEach, beforeAll, describe, it } from "vitest";
4
+ import { afterAll, afterEach, beforeAll, describe, it } from "vite-plus/test";
5
5
  import { testAIModels } from "../../../testUtil/testAIModels.js";
6
6
 
7
7
  import { BlockNoteEditor } from "@blocknote/core";
@@ -102,11 +102,8 @@ describe("Models", () => {
102
102
  });
103
103
 
104
104
  describe("streamToolsProvider", () => {
105
- it("should return the correct stream tools", () => {
105
+ it.skip("should return the correct stream tools", () => {
106
106
  // test skipped, this is only to validate type inference
107
- return;
108
-
109
- // eslint-disable-next-line no-unreachable
110
107
  const editor = BlockNoteEditor.create();
111
108
  const streamTools = htmlBlockLLMFormat
112
109
  .getStreamToolsProvider({
@@ -118,14 +115,14 @@ describe("streamToolsProvider", () => {
118
115
 
119
116
  const executor = new StreamToolExecutor(streamTools);
120
117
 
121
- executor.executeOne({
118
+ void executor.executeOne({
122
119
  type: "add",
123
120
  blocks: ["<p>test</p>"],
124
121
  referenceId: "1",
125
122
  position: "after",
126
123
  });
127
124
 
128
- executor.executeOne({
125
+ void executor.executeOne({
129
126
  // @ts-expect-error
130
127
  type: "update",
131
128
  blocks: ["<p>test</p>"],
@@ -133,12 +130,13 @@ describe("streamToolsProvider", () => {
133
130
  position: "after",
134
131
  });
135
132
 
136
- executor.executeOne({
133
+ void executor.executeOne({
137
134
  type: "add",
138
135
  // @ts-expect-error
139
136
  blocks: [{ type: "paragraph", content: "test" }],
140
137
  referenceId: "1",
141
138
  position: "after",
142
139
  });
140
+ /* eslint-enable no-unreachable */
143
141
  });
144
142
  });
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { describe, expect, it } from "vite-plus/test";
2
2
  import { getPartialHTML } from "./getPartialHTML.js";
3
3
 
4
4
  describe("getPartialHTML", () => {
@@ -23,27 +23,21 @@ export const tools = {
23
23
  },
24
24
  validateBlock: validateBlockFunction,
25
25
  rebaseTool: createHTMLRebaseTool,
26
- toJSONToolCall: async (editor, chunk) => {
26
+ toJSONToolCall: (editor, chunk) => {
27
27
  const initialMockID = (window as any).__TEST_OPTIONS?.mockID;
28
28
 
29
- const blocks = (
30
- await Promise.all(
31
- chunk.operation.blocks.map(async (html) => {
32
- const parsedHtml = chunk.isPossiblyPartial
33
- ? getPartialHTML(html)
34
- : html;
35
- if (!parsedHtml) {
36
- return [];
37
- }
38
- return (await editor.tryParseHTMLToBlocks(parsedHtml)).map(
39
- (block) => {
40
- delete (block as any).id;
41
- return block;
42
- },
43
- );
44
- }),
45
- )
46
- ).flat();
29
+ const blocks = chunk.operation.blocks.flatMap((html) => {
30
+ const parsedHtml = chunk.isPossiblyPartial
31
+ ? getPartialHTML(html)
32
+ : html;
33
+ if (!parsedHtml) {
34
+ return [];
35
+ }
36
+ return editor.tryParseHTMLToBlocks(parsedHtml).map((block) => {
37
+ delete (block as any).id;
38
+ return block;
39
+ });
40
+ });
47
41
 
48
42
  // hacky
49
43
  if ((window as any).__TEST_OPTIONS) {
@@ -71,7 +65,7 @@ export const tools = {
71
65
  },
72
66
  validateBlock: validateBlockFunction,
73
67
  rebaseTool: createHTMLRebaseTool,
74
- toJSONToolCall: async (editor, chunk) => {
68
+ toJSONToolCall: (editor, chunk) => {
75
69
  const html = chunk.isPossiblyPartial
76
70
  ? getPartialHTML(chunk.operation.block)
77
71
  : chunk.operation.block;
@@ -80,7 +74,7 @@ export const tools = {
80
74
  return undefined;
81
75
  }
82
76
 
83
- const block = (await editor.tryParseHTMLToBlocks(html))[0];
77
+ const block = editor.tryParseHTMLToBlocks(html)[0];
84
78
 
85
79
  // console.log("update", operation.block);
86
80
  // console.log("html", html);
@@ -5,7 +5,7 @@ import {
5
5
  rebaseTool,
6
6
  } from "../../../../prosemirror/rebaseTool.js";
7
7
 
8
- export async function createHTMLRebaseTool(
8
+ export function createHTMLRebaseTool(
9
9
  id: string,
10
10
  editor: BlockNoteEditor<any, any, any>,
11
11
  ) {
@@ -15,7 +15,7 @@ export async function createHTMLRebaseTool(
15
15
  throw new Error("block not found");
16
16
  }
17
17
 
18
- const html = await editor.blocksToHTMLLossy([
18
+ const html = editor.blocksToHTMLLossy([
19
19
  {
20
20
  ...block,
21
21
  children: [],
@@ -24,7 +24,7 @@ export async function createHTMLRebaseTool(
24
24
 
25
25
  const initialMockID = (window as any).__TEST_OPTIONS?.mockID;
26
26
 
27
- const blocks = await editor.tryParseHTMLToBlocks(html);
27
+ const blocks = editor.tryParseHTMLToBlocks(html);
28
28
 
29
29
  // hacky
30
30
  if ((window as any).__TEST_OPTIONS) {
@@ -1,4 +1,11 @@
1
- import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest";
1
+ import {
2
+ afterAll,
3
+ afterEach,
4
+ beforeAll,
5
+ describe,
6
+ expect,
7
+ it,
8
+ } from "vite-plus/test";
2
9
 
3
10
  import { BlockNoteEditor } from "@blocknote/core";
4
11
  import { HttpResponse, http } from "msw";
@@ -1,4 +1,4 @@
1
- import { afterAll, afterEach, beforeAll, describe } from "vitest";
1
+ import { afterAll, afterEach, beforeAll, describe } from "vite-plus/test";
2
2
 
3
3
  import { snapshot } from "msw-snapshot";
4
4
  import { setupServer } from "msw/node";
@@ -19,9 +19,9 @@ export const tools = {
19
19
  ...(blockNoteSchemaToJSONSchema(editor.schema) as any),
20
20
  }),
21
21
  validateBlock: validateBlockFunction,
22
- rebaseTool: async (_id, editor) =>
22
+ rebaseTool: (_id, editor) =>
23
23
  rebaseTool(editor, getApplySuggestionsTr(editor)),
24
- toJSONToolCall: async (_editor, chunk) => {
24
+ toJSONToolCall: (_editor, chunk) => {
25
25
  return chunk.operation;
26
26
  },
27
27
  }),
@@ -35,9 +35,9 @@ export const tools = {
35
35
  ...(blockNoteSchemaToJSONSchema(editor.schema) as any),
36
36
  }),
37
37
  validateBlock: validateBlockFunction,
38
- rebaseTool: async (_id, editor) =>
38
+ rebaseTool: (_id, editor) =>
39
39
  rebaseTool(editor, getApplySuggestionsTr(editor)),
40
- toJSONToolCall: async (_editor, chunk) => {
40
+ toJSONToolCall: (_editor, chunk) => {
41
41
  const defaultPropsVals = Object.fromEntries(
42
42
  Object.entries(defaultProps).map(([key, val]) => {
43
43
  return [key, val.default];
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable jest/valid-title */
2
2
  import { BlockNoteEditor, expandPMRangeToWords } from "@blocknote/core";
3
- import { describe, expect, it } from "vitest";
3
+ import { describe, expect, it } from "vite-plus/test";
4
4
  import { addOperationTestCases } from "../../../../testUtil/cases/addOperationTestCases.js";
5
5
  import { combinedOperationsTestCases } from "../../../../testUtil/cases/combinedOperationsTestCases.js";
6
6
  import { deleteOperationTestCases } from "../../../../testUtil/cases/deleteOperationTestCases.js";
@@ -1,4 +1,4 @@
1
- import { afterAll, afterEach, beforeAll, describe } from "vitest";
1
+ import { afterAll, afterEach, beforeAll, describe } from "vite-plus/test";
2
2
 
3
3
  import { snapshot } from "msw-snapshot";
4
4
  import { setupServer } from "msw/node";
@@ -24,14 +24,12 @@ export const tools = {
24
24
  },
25
25
  validateBlock: validateBlockFunction,
26
26
  rebaseTool: createMDRebaseTool,
27
- toJSONToolCall: async (editor, chunk) => {
28
- const blocks = await Promise.all(
29
- chunk.operation.blocks.map(async (md) => {
30
- const block = (await editor.tryParseMarkdownToBlocks(md.trim()))[0]; // TODO: trim
31
- delete (block as any).id;
32
- return block;
33
- }),
34
- );
27
+ toJSONToolCall: (editor, chunk) => {
28
+ const blocks = chunk.operation.blocks.map((md) => {
29
+ const block = editor.tryParseMarkdownToBlocks(md.trim())[0]; // TODO: trim
30
+ delete (block as any).id;
31
+ return block;
32
+ });
35
33
 
36
34
  // hacky
37
35
  if ((window as any).__TEST_OPTIONS) {
@@ -58,9 +56,9 @@ export const tools = {
58
56
  },
59
57
  validateBlock: validateBlockFunction,
60
58
  rebaseTool: createMDRebaseTool,
61
- toJSONToolCall: async (editor, chunk) => {
62
- const block = (
63
- await editor.tryParseMarkdownToBlocks(chunk.operation.block.trim())
59
+ toJSONToolCall: (editor, chunk) => {
60
+ const block = editor.tryParseMarkdownToBlocks(
61
+ chunk.operation.block.trim(),
64
62
  )[0];
65
63
 
66
64
  delete (block as any).id;
@@ -6,13 +6,13 @@ import {
6
6
  rebaseTool,
7
7
  } from "../../../../prosemirror/rebaseTool.js";
8
8
 
9
- export async function createMDRebaseTool(
9
+ export function createMDRebaseTool(
10
10
  id: string,
11
11
  editor: BlockNoteEditor<any, any, any>,
12
12
  ) {
13
13
  const tr = getApplySuggestionsTr(editor);
14
- const md = await editor.blocksToMarkdownLossy([getBlock(tr.doc, id)!]);
15
- const blocks = await editor.tryParseMarkdownToBlocks(md);
14
+ const md = editor.blocksToMarkdownLossy([getBlock(tr.doc, id)!]);
15
+ const blocks = editor.tryParseMarkdownToBlocks(md);
16
16
 
17
17
  const steps = updateToReplaceSteps(
18
18
  {
@@ -1,9 +1,8 @@
1
1
  import { Chat, UIMessage } from "@ai-sdk/react";
2
2
  import { BlockNoteEditor } from "@blocknote/core";
3
- import { getCurrentTest, TestContext } from "@vitest/runner";
4
3
  import path from "path";
5
4
  import { TextSelection } from "prosemirror-state";
6
- import { describe, expect, it } from "vitest";
5
+ import { describe, expect, it, TestContext, TestRunner } from "vite-plus/test";
7
6
  import { AIExtension } from "../../../AIExtension.js";
8
7
  import { sendMessageWithAIRequest } from "../../../index.js";
9
8
  import { addOperationTestCases } from "../../../testUtil/cases/addOperationTestCases.js";
@@ -23,7 +22,7 @@ const BASE_FILE_PATH = path.resolve(__dirname, "__snapshots__");
23
22
  // @ts-expect-error - unused helper kept for debugging snapshots
24
23
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
25
24
  async function matchFileSnapshot(data: any, postFix = "") {
26
- const t = getCurrentTest()!;
25
+ const t = TestRunner.getCurrentTest()!;
27
26
  // this uses the same snapshot path, regardless of the model / streaming params
28
27
  await expect(data).toMatchFileSnapshot(
29
28
  path.resolve(
@@ -1,6 +1,6 @@
1
- import { getCurrentTest } from "@vitest/runner";
2
1
  import { getSortedEntries, toHashString } from "msw-snapshot";
3
2
  import path from "node:path";
3
+ import { TestRunner } from "vite-plus/test";
4
4
 
5
5
  async function createRequestHash(req: Request): Promise<string> {
6
6
  const url = new URL(req.url);
@@ -18,7 +18,7 @@ export function createSnapshotPathFn(_basePath: string) {
18
18
  const fetchCountMap: Record<string, number> = {};
19
19
 
20
20
  return async (info: { request: Request }): Promise<string> => {
21
- const t = getCurrentTest()!;
21
+ const t = TestRunner.getCurrentTest()!;
22
22
  const mswPath = path.join(
23
23
  t.suite!.name,
24
24
  "__msw_snapshots__",
@@ -1,6 +1,6 @@
1
1
  import * as glob from "glob";
2
2
  import path from "path";
3
- import { describe, expect, it } from "vitest";
3
+ import { describe, expect, it } from "vite-plus/test";
4
4
 
5
5
  /**
6
6
  * We should only have one snapshot file per test, this test ensures that
@@ -3,7 +3,7 @@ export function suffixIDs<T>(source: Array<T>): Array<T> {
3
3
  if (typeof el === "object" && el && "id" in el) {
4
4
  return {
5
5
  ...el,
6
- id: `${el.id}$`,
6
+ id: `${String(el.id)}$`,
7
7
  };
8
8
  }
9
9
  return el;
@@ -64,7 +64,7 @@ exports[`creates json schema 1`] = `
64
64
  "additionalProperties": false,
65
65
  "properties": {
66
66
  "content": {
67
- "$ref": "#/$defs/inlinecontent",
67
+ "type": "string",
68
68
  },
69
69
  "props": {
70
70
  "additionalProperties": false,
@@ -1,12 +1,12 @@
1
1
  import { BlockNoteEditor } from "@blocknote/core";
2
- import { expect, it } from "vitest";
2
+ import { expect, it } from "vite-plus/test";
3
3
  import { blockNoteSchemaToJSONSchema } from "./schemaToJSONSchema.js";
4
4
 
5
- it("creates json schema", async () => {
5
+ it("creates json schema", () => {
6
6
  // eslint-disable-next-line no-console
7
7
  const editor = BlockNoteEditor.create();
8
8
 
9
9
  const jsonSchema = blockNoteSchemaToJSONSchema(editor.schema);
10
- await expect(jsonSchema).toMatchSnapshot();
10
+ expect(jsonSchema).toMatchSnapshot();
11
11
  // console.log(JSON.stringify(blockNoteSchemaToJSONSchema(editor.schema), undefined, 2));
12
12
  });
@@ -217,9 +217,11 @@ function blockSchemaToJSONSchema(schema: BlockSchema) {
217
217
  content:
218
218
  val.content === "inline"
219
219
  ? { $ref: "#/$defs/inlinecontent" }
220
- : val.content === "table"
221
- ? { type: "object", properties: {} } // TODO
222
- : undefined,
220
+ : val.content === "plain"
221
+ ? { type: "string" }
222
+ : val.content === "table"
223
+ ? { type: "object", properties: {} } // TODO
224
+ : undefined,
223
225
  // filter out default props (TODO: make option)
224
226
  props: propSchemaToJSONSchema(val.propSchema),
225
227
  // Object.fromEntries(
@@ -83,7 +83,7 @@ export const PromptSuggestionMenu = (props: PromptSuggestionMenuProps) => {
83
83
  handler(event);
84
84
  } else {
85
85
  // TODO: check focus?
86
- handleEnter(event);
86
+ void handleEnter(event);
87
87
  }
88
88
  } else {
89
89
  handler(event);
@@ -1,6 +1,13 @@
1
1
  import { Plugin, PluginKey } from "prosemirror-state";
2
2
  import { Decoration, DecorationSet } from "prosemirror-view";
3
- import { defaultSelectionBuilder } from "y-prosemirror";
3
+
4
+ // Pulled from `y-prosemirror`https://github.com/yjs/y-prosemirror/blob/v1.3.7/src/plugins/cursor-plugin.js
5
+ const defaultSelectionBuilder = (user: { name: string; color: string }) => {
6
+ return {
7
+ style: `background-color: ${user.color}70`,
8
+ class: "ProseMirror-yjs-selection",
9
+ };
10
+ };
4
11
 
5
12
  type AgentCursorState = {
6
13
  selection: { anchor: number; head: number } | undefined;