@platejs/ai 49.2.15 → 50.1.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.
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,35 +15,18 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
31
21
  var index_exports = {};
32
22
  __export(index_exports, {
33
23
  BaseAIPlugin: () => BaseAIPlugin,
34
- escapeInput: () => escapeInput,
35
- getChunkTrimmed: () => getChunkTrimmed,
36
- getCurrentBlockPath: () => getCurrentBlockPath,
37
- getListNode: () => getListNode,
24
+ getEditorPrompt: () => getEditorPrompt,
25
+ getMarkdown: () => getMarkdown,
38
26
  insertAINodes: () => insertAINodes,
39
- isCompleteCodeBlock: () => isCompleteCodeBlock,
40
- isCompleteMath: () => isCompleteMath,
41
- isSameNode: () => isSameNode,
42
- nodesWithProps: () => nodesWithProps,
43
27
  removeAIMarks: () => removeAIMarks,
44
28
  removeAINodes: () => removeAINodes,
45
- streamDeserializeInlineMd: () => streamDeserializeInlineMd,
46
- streamDeserializeMd: () => streamDeserializeMd,
47
- streamInsertChunk: () => streamInsertChunk,
48
- streamSerializeMd: () => streamSerializeMd,
29
+ replacePlaceholders: () => replacePlaceholders,
49
30
  undoAI: () => undoAI,
50
31
  withAIBatch: () => withAIBatch
51
32
  });
@@ -128,298 +109,91 @@ var BaseAIPlugin = (0, import_platejs3.createTSlatePlugin)({
128
109
  undo: (0, import_platejs3.bindFirst)(undoAI, editor)
129
110
  }));
130
111
 
131
- // src/lib/streaming/streamDeserializeInlineMd.ts
132
- var import_markdown = require("@platejs/markdown");
133
- var streamDeserializeInlineMd = (editor, text, options) => {
134
- return editor.getApi(import_markdown.MarkdownPlugin).markdown.deserializeInline(text, options);
135
- };
136
-
137
- // src/lib/streaming/streamDeserializeMd.ts
138
- var import_markdown3 = require("@platejs/markdown");
139
- var import_platejs15 = require("platejs");
140
-
141
- // src/react/ai/AIPlugin.ts
142
- var import_react = require("platejs/react");
143
- var AIPlugin = (0, import_react.toPlatePlugin)(BaseAIPlugin);
144
-
145
- // src/react/ai-chat/AIChatPlugin.ts
146
- var import_react9 = require("@platejs/selection/react");
147
- var import_platejs12 = require("platejs");
148
- var import_react10 = require("platejs/react");
112
+ // src/lib/utils/getEditorPrompt.ts
113
+ var import_selection = require("@platejs/selection");
114
+ var import_platejs5 = require("platejs");
149
115
 
150
- // src/react/ai-chat/transforms/acceptAIChat.ts
116
+ // src/lib/utils/getMarkdown.ts
117
+ var import_markdown = require("@platejs/markdown");
151
118
  var import_platejs4 = require("platejs");
152
- var import_react2 = require("platejs/react");
153
- var acceptAIChat = (editor) => {
154
- const { tf } = (0, import_react2.getEditorPlugin)(editor, AIPlugin);
155
- const api = editor.getApi({ key: import_platejs4.KEYS.ai });
156
- const lastAINodePath = api.aiChat.node({ at: [], reverse: true })[1];
157
- withAIBatch(editor, () => {
158
- tf.ai.removeMarks();
159
- editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();
160
- });
161
- api.aiChat.hide();
162
- editor.tf.focus();
163
- const focusPoint = editor.api.end(lastAINodePath);
164
- editor.tf.setSelection({
165
- anchor: focusPoint,
166
- focus: focusPoint
167
- });
168
- };
169
-
170
- // src/react/ai-chat/transforms/insertBelowAIChat.ts
171
- var import_react4 = require("@platejs/selection/react");
172
- var import_cloneDeep2 = __toESM(require("lodash/cloneDeep.js"));
173
- var import_platejs6 = require("platejs");
174
-
175
- // src/react/ai-chat/transforms/replaceSelectionAIChat.ts
176
- var import_react3 = require("@platejs/selection/react");
177
- var import_cloneDeep = __toESM(require("lodash/cloneDeep.js"));
178
- var import_platejs5 = require("platejs");
179
- var createFormattedBlocks = ({
180
- blocks,
181
- format,
182
- sourceBlock
119
+ var getMarkdown = (editor, {
120
+ type
183
121
  }) => {
184
- if (format === "none") return (0, import_cloneDeep.default)(blocks);
185
- const [sourceNode] = sourceBlock;
186
- const firstTextEntry = import_platejs5.NodeApi.firstText(sourceNode);
187
- if (!firstTextEntry) return null;
188
- const blockProps = import_platejs5.NodeApi.extractProps(sourceNode);
189
- const textProps = import_platejs5.NodeApi.extractProps(firstTextEntry[0]);
190
- const applyTextFormatting = (node) => {
191
- if (import_platejs5.TextApi.isText(node)) {
192
- return { ...textProps, ...node };
193
- }
194
- if (node.children) {
195
- return {
196
- ...node,
197
- children: node.children.map(applyTextFormatting)
198
- };
199
- }
200
- return node;
201
- };
202
- return blocks.map((block, index) => {
203
- if (format === "single" && index > 0) {
204
- return block;
205
- }
206
- return applyTextFormatting({
207
- ...block,
208
- ...blockProps
209
- });
210
- });
211
- };
212
- var replaceSelectionAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
213
- if (!sourceEditor || sourceEditor.api.isEmpty()) return;
214
- const isBlockSelecting = editor.getOption(
215
- import_react3.BlockSelectionPlugin,
216
- "isSelectingSome"
217
- );
218
- editor.getApi({ key: import_platejs5.KEYS.ai }).aiChat.hide();
219
- if (!isBlockSelecting) {
220
- const firstBlock = editor.api.node({
221
- block: true,
222
- mode: "lowest"
122
+ if (type === "editor" || type === "editorWithBlockId") {
123
+ return (0, import_markdown.serializeMd)(editor, {
124
+ withBlockId: type === "editorWithBlockId"
223
125
  });
224
- if (firstBlock && editor.api.isSelected(firstBlock[1], { contains: true }) && format !== "none") {
225
- const formattedBlocks2 = createFormattedBlocks({
226
- blocks: (0, import_cloneDeep.default)(sourceEditor.children),
227
- format,
228
- sourceBlock: firstBlock
229
- });
230
- if (!formattedBlocks2) return;
231
- if (firstBlock[0].type === import_platejs5.KEYS.codeLine && sourceEditor.children[0].type === import_platejs5.KEYS.codeBlock && sourceEditor.children.length === 1) {
232
- editor.tf.insertFragment(formattedBlocks2[0].children);
233
- } else {
234
- editor.tf.insertFragment(formattedBlocks2);
235
- }
236
- editor.tf.focus();
237
- return;
238
- }
239
- editor.tf.insertFragment(sourceEditor.children);
240
- editor.tf.focus();
241
- return;
242
- }
243
- const blockSelectionApi = editor.getApi(import_react3.BlockSelectionPlugin).blockSelection;
244
- const selectedBlocks = blockSelectionApi.getNodes();
245
- if (selectedBlocks.length === 0) return;
246
- if (format === "none" || format === "single" && selectedBlocks.length > 1) {
247
- editor.tf.withoutNormalizing(() => {
248
- (0, import_react3.removeBlockSelectionNodes)(editor);
249
- editor.tf.withNewBatch(() => {
250
- editor.getTransforms(import_react3.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(
251
- (0, import_cloneDeep.default)(sourceEditor.children),
252
- {
253
- at: selectedBlocks[0][1]
254
- }
255
- );
256
- });
257
- });
258
- editor.getApi(import_react3.BlockSelectionPlugin).blockSelection.focus();
259
- return;
260
126
  }
261
- const [, firstBlockPath] = selectedBlocks[0];
262
- const formattedBlocks = createFormattedBlocks({
263
- blocks: (0, import_cloneDeep.default)(sourceEditor.children),
264
- format,
265
- sourceBlock: selectedBlocks[0]
266
- });
267
- if (!formattedBlocks) return;
268
- editor.tf.withoutNormalizing(() => {
269
- (0, import_react3.removeBlockSelectionNodes)(editor);
270
- editor.tf.withNewBatch(() => {
271
- editor.getTransforms(import_react3.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect(formattedBlocks, {
272
- at: firstBlockPath
273
- });
274
- });
275
- });
276
- editor.getApi(import_react3.BlockSelectionPlugin).blockSelection.focus();
277
- };
278
-
279
- // src/react/ai-chat/transforms/insertBelowAIChat.ts
280
- var insertBelowAIChat = (editor, sourceEditor, { format = "single" } = {}) => {
281
- if (!sourceEditor || sourceEditor.api.isEmpty()) return;
282
- const isBlockSelecting = editor.getOption(
283
- import_react4.BlockSelectionPlugin,
284
- "isSelectingSome"
285
- );
286
- editor.getApi({ key: import_platejs6.KEYS.ai }).aiChat.hide();
287
- const insertBlocksAndSelect = editor.getTransforms(import_react4.BlockSelectionPlugin).blockSelection.insertBlocksAndSelect;
288
- if (isBlockSelecting) {
289
- const selectedBlocks = editor.getApi(import_react4.BlockSelectionPlugin).blockSelection.getNodes();
290
- const selectedIds = editor.getOptions(import_react4.BlockSelectionPlugin).selectedIds;
291
- if (!selectedIds || selectedIds.size === 0) return;
292
- const lastBlock = selectedBlocks.at(-1);
293
- if (!lastBlock) return;
294
- const nextPath = import_platejs6.PathApi.next(lastBlock[1]);
295
- if (format === "none") {
296
- insertBlocksAndSelect((0, import_cloneDeep2.default)(sourceEditor.children), {
297
- at: nextPath
298
- });
299
- return;
300
- }
301
- const formattedBlocks = createFormattedBlocks({
302
- blocks: (0, import_cloneDeep2.default)(sourceEditor.children),
303
- format,
304
- sourceBlock: lastBlock
305
- });
306
- if (!formattedBlocks) return;
307
- insertBlocksAndSelect(formattedBlocks, {
308
- at: nextPath
309
- });
310
- } else {
311
- const [, end] = import_platejs6.RangeApi.edges(editor.selection);
312
- const endPath = [end.path[0]];
313
- const currentBlock = editor.api.node({
314
- at: endPath,
315
- block: true,
316
- mode: "lowest"
317
- });
318
- if (!currentBlock) return;
319
- if (format === "none") {
320
- insertBlocksAndSelect((0, import_cloneDeep2.default)(sourceEditor.children), {
321
- at: import_platejs6.PathApi.next(endPath)
322
- });
323
- return;
324
- }
325
- const formattedBlocks = createFormattedBlocks({
326
- blocks: (0, import_cloneDeep2.default)(sourceEditor.children),
327
- format,
328
- sourceBlock: currentBlock
329
- });
330
- if (!formattedBlocks) return;
331
- insertBlocksAndSelect(formattedBlocks, {
332
- at: import_platejs6.PathApi.next(endPath)
127
+ if (type === "block" || type === "blockWithBlockId") {
128
+ const blocks = editor.api.blocks({ mode: "highest" }).map(([node]) => node);
129
+ return (0, import_markdown.serializeMd)(editor, {
130
+ value: blocks,
131
+ withBlockId: type === "blockWithBlockId"
333
132
  });
334
133
  }
335
- };
336
-
337
- // src/react/ai-chat/transforms/removeAnchorAIChat.ts
338
- var import_platejs7 = require("platejs");
339
- var removeAnchorAIChat = (editor, options) => {
340
- editor.tf.withoutSaving(() => {
341
- editor.tf.removeNodes({
342
- at: [],
343
- match: (n) => import_platejs7.ElementApi.isElement(n) && n.type === (0, import_platejs7.getPluginType)(editor, import_platejs7.KEYS.aiChat),
344
- ...options
345
- });
346
- });
347
- };
348
-
349
- // src/react/ai-chat/utils/getEditorPrompt.ts
350
- var import_selection = require("@platejs/selection");
351
- var import_react6 = require("@platejs/selection/react");
352
-
353
- // src/react/ai-chat/utils/getMarkdown.ts
354
- var import_markdown2 = require("@platejs/markdown");
355
- var import_react5 = require("@platejs/selection/react");
356
- var import_platejs8 = require("platejs");
357
- var getMarkdown = (editor, type) => {
358
- if (type === "editor") {
359
- return (0, import_markdown2.serializeMd)(editor);
360
- }
361
- if (type === "block") {
362
- const blocks = editor.getOption(import_react5.BlockSelectionPlugin, "isSelectingSome") ? editor.getApi(import_react5.BlockSelectionPlugin).blockSelection.getNodes() : editor.api.nodes({
363
- mode: "highest",
364
- match: (n) => editor.api.isBlock(n)
365
- });
366
- const nodes = Array.from(blocks, (entry) => entry[0]);
367
- return (0, import_markdown2.serializeMd)(editor, { value: nodes });
368
- }
369
- if (type === "selection") {
134
+ if (type === "blockSelection" || type === "blockSelectionWithBlockId") {
370
135
  const fragment = editor.api.fragment();
371
136
  if (fragment.length === 1) {
372
137
  const modifiedFragment = [
373
138
  {
374
139
  children: fragment[0].children,
375
- type: import_platejs8.KEYS.p
140
+ type: import_platejs4.KEYS.p
376
141
  }
377
142
  ];
378
- return (0, import_markdown2.serializeMd)(editor, { value: modifiedFragment });
143
+ return (0, import_markdown.serializeMd)(editor, {
144
+ value: modifiedFragment,
145
+ withBlockId: type === "blockSelectionWithBlockId"
146
+ });
379
147
  }
380
- return (0, import_markdown2.serializeMd)(editor, { value: fragment });
148
+ return (0, import_markdown.serializeMd)(editor, {
149
+ value: fragment,
150
+ withBlockId: type === "blockSelectionWithBlockId"
151
+ });
381
152
  }
382
153
  return "";
383
154
  };
384
155
 
385
- // src/react/ai-chat/utils/getEditorPrompt.ts
156
+ // src/lib/utils/getEditorPrompt.ts
386
157
  var replacePlaceholders = (editor, text, {
387
158
  prompt
388
- }) => {
159
+ } = {}) => {
389
160
  let result = text.replace("{prompt}", prompt || "");
390
161
  const placeholders = {
162
+ "{blockSelectionWithBlockId}": "blockSelectionWithBlockId",
163
+ "{blockSelection}": "blockSelection",
164
+ "{blockWithBlockId}": "blockWithBlockId",
391
165
  "{block}": "block",
392
- "{editor}": "editor",
393
- "{selection}": "selection"
166
+ "{editorWithBlockId}": "editorWithBlockId",
167
+ "{editor}": "editor"
394
168
  };
395
169
  Object.entries(placeholders).forEach(([placeholder, type]) => {
396
170
  if (result.includes(placeholder)) {
397
- result = result.replace(placeholder, getMarkdown(editor, type));
171
+ result = result.replace(placeholder, getMarkdown(editor, { type }));
398
172
  }
399
173
  });
400
174
  return result;
401
175
  };
402
176
  var createPromptFromConfig = (config, params) => {
403
- const { isBlockSelecting, isSelecting: isSelecting3 } = params;
177
+ const { isBlockSelecting, isSelecting: isSelecting2 } = params;
404
178
  if (isBlockSelecting && config.blockSelecting) {
405
179
  return config.blockSelecting ?? config.default;
406
- } else if (isSelecting3 && config.selecting) {
180
+ } else if (isSelecting2 && config.selecting) {
407
181
  return config.selecting ?? config.default;
408
182
  } else {
409
183
  return config.default;
410
184
  }
411
185
  };
412
186
  var getEditorPrompt = (editor, {
413
- prompt = "",
414
- promptTemplate = () => "{prompt}"
415
- } = {}) => {
187
+ prompt = ""
188
+ }) => {
416
189
  const params = {
417
190
  editor,
418
- isBlockSelecting: editor.getOption(import_react6.BlockSelectionPlugin, "isSelectingSome"),
191
+ isBlockSelecting: editor.getOption(
192
+ { key: import_platejs5.KEYS.blockSelection },
193
+ "isSelectingSome"
194
+ ),
419
195
  isSelecting: (0, import_selection.isSelecting)(editor)
420
196
  };
421
- const template = promptTemplate(params);
422
- if (!template) return;
423
197
  let promptText = "";
424
198
  if (typeof prompt === "function") {
425
199
  promptText = prompt(params);
@@ -428,641 +202,17 @@ var getEditorPrompt = (editor, {
428
202
  } else {
429
203
  promptText = prompt;
430
204
  }
431
- return replacePlaceholders(editor, template, {
432
- prompt: promptText
433
- });
434
- };
435
-
436
- // src/react/ai-chat/utils/resetAIChat.ts
437
- var import_platejs9 = require("platejs");
438
- var import_react7 = require("platejs/react");
439
- var resetAIChat = (editor) => {
440
- const { api, getOptions } = (0, import_react7.getEditorPlugin)(editor, {
441
- key: import_platejs9.KEYS.aiChat
442
- });
443
- api.aiChat.stop();
444
- const chat = getOptions().chat;
445
- if (chat.messages && chat.messages.length > 0) {
446
- chat.setMessages?.([]);
447
- }
448
- editor.getTransforms(AIPlugin).ai.undo();
449
- };
450
-
451
- // src/react/ai-chat/utils/submitAIChat.ts
452
- var import_selection2 = require("@platejs/selection");
453
- var import_platejs10 = require("platejs");
454
- var import_react8 = require("platejs/react");
455
- var submitAIChat = (editor, {
456
- mode,
457
- options,
458
- prompt,
459
- system
460
- } = {}) => {
461
- const { getOptions, setOption } = (0, import_react8.getEditorPlugin)(
462
- editor,
463
- {
464
- key: import_platejs10.KEYS.aiChat
465
- }
466
- );
467
- const { chat, promptTemplate, systemTemplate } = getOptions();
468
- if (!prompt && chat.input?.length === 0) {
469
- return;
470
- }
471
- if (!prompt) {
472
- prompt = chat.input;
473
- }
474
- if (!mode) {
475
- mode = (0, import_selection2.isSelecting)(editor) ? "chat" : "insert";
476
- }
477
- if (mode === "insert") {
478
- editor.getTransforms(AIPlugin).ai.undo();
479
- }
480
- setOption("mode", mode);
481
- chat.setInput?.("");
482
- void chat.append?.(
483
- {
484
- content: getEditorPrompt(editor, {
485
- prompt,
486
- promptTemplate
487
- }) ?? "",
488
- role: "user"
489
- },
490
- {
491
- body: {
492
- system: getEditorPrompt(editor, {
493
- prompt: system,
494
- promptTemplate: systemTemplate
495
- })
496
- },
497
- ...options
498
- }
499
- );
500
- };
501
-
502
- // src/react/ai-chat/withAIChat.ts
503
- var import_platejs11 = require("platejs");
504
- var withAIChat = ({
505
- api,
506
- editor,
507
- getOptions,
508
- tf: { insertText, normalizeNode, setSelection },
509
- type
510
- }) => {
511
- const tf = editor.getTransforms(AIPlugin);
512
- const matchesTrigger = (text) => {
513
- const { trigger } = getOptions();
514
- if (trigger instanceof RegExp) {
515
- return trigger.test(text);
516
- }
517
- if (Array.isArray(trigger)) {
518
- return trigger.includes(text);
519
- }
520
- return text === trigger;
521
- };
522
- return {
523
- transforms: {
524
- insertText(text, options) {
525
- const { triggerPreviousCharPattern, triggerQuery } = getOptions();
526
- const fn = () => {
527
- if (!editor.selection || !matchesTrigger(text) || triggerQuery && !triggerQuery(editor)) {
528
- return;
529
- }
530
- const previousChar = editor.api.string(
531
- editor.api.range("before", editor.selection)
532
- );
533
- const matchesPreviousCharPattern = triggerPreviousCharPattern?.test(previousChar);
534
- if (!matchesPreviousCharPattern) return;
535
- const nodeEntry = editor.api.block({ highest: true });
536
- if (!nodeEntry || !editor.api.isEmpty(nodeEntry[0])) return;
537
- api.aiChat.show();
538
- return true;
539
- };
540
- if (fn()) return;
541
- return insertText(text, options);
542
- },
543
- normalizeNode(entry) {
544
- const [node, path] = entry;
545
- if (node[import_platejs11.KEYS.ai] && !getOptions().open) {
546
- tf.ai.removeMarks({ at: path });
547
- return;
548
- }
549
- if (import_platejs11.ElementApi.isElement(node) && node.type === type && !getOptions().open) {
550
- editor.getTransforms(AIChatPlugin).aiChat.removeAnchor({ at: path });
551
- return;
552
- }
553
- return normalizeNode(entry);
554
- }
555
- }
556
- };
557
- };
558
-
559
- // src/react/ai-chat/AIChatPlugin.ts
560
- var AIChatPlugin = (0, import_react10.createTPlatePlugin)({
561
- key: import_platejs12.KEYS.aiChat,
562
- dependencies: ["ai"],
563
- node: {
564
- isElement: true
565
- },
566
- options: {
567
- _blockChunks: "",
568
- _blockPath: null,
569
- _mdxName: null,
570
- aiEditor: null,
571
- chat: { messages: [] },
572
- experimental_lastTextId: null,
573
- mode: "chat",
574
- open: false,
575
- streaming: false,
576
- trigger: " ",
577
- triggerPreviousCharPattern: /^\s?$/,
578
- promptTemplate: () => "{prompt}",
579
- systemTemplate: () => {
580
- }
581
- }
582
- }).overrideEditor(withAIChat).extendApi(({ editor, getOption, getOptions, setOption, type }) => {
583
- return {
584
- reset: (0, import_platejs12.bindFirst)(resetAIChat, editor),
585
- submit: (0, import_platejs12.bindFirst)(submitAIChat, editor),
586
- node: (options = {}) => {
587
- const { anchor = false, streaming = false, ...rest } = options;
588
- if (anchor) {
589
- return editor.api.node({
590
- at: [],
591
- match: (n) => import_platejs12.ElementApi.isElement(n) && n.type === type,
592
- ...rest
593
- });
594
- }
595
- if (streaming) {
596
- if (!getOption("streaming")) return;
597
- const path = getOption("_blockPath");
598
- if (!path) return;
599
- return editor.api.node({
600
- at: path,
601
- mode: "lowest",
602
- reverse: true,
603
- match: (t) => !!t[(0, import_platejs12.getPluginType)(editor, import_platejs12.KEYS.ai)],
604
- ...rest
605
- });
606
- }
607
- return editor.api.node({
608
- match: (n) => n[(0, import_platejs12.getPluginType)(editor, import_platejs12.KEYS.ai)],
609
- ...rest
610
- });
611
- },
612
- reload: () => {
613
- const { chat, mode } = getOptions();
614
- if (mode === "insert") {
615
- editor.getTransforms(AIPlugin).ai.undo();
616
- }
617
- void chat.reload?.({
618
- body: {
619
- system: getEditorPrompt(editor, {
620
- promptTemplate: getOptions().systemTemplate
621
- })
622
- }
623
- });
624
- },
625
- stop: () => {
626
- setOption("streaming", false);
627
- getOptions().chat.stop?.();
628
- }
629
- };
630
- }).extendApi(({ api, editor, getOptions, setOption, tf, type }) => ({
631
- hide: () => {
632
- api.aiChat.reset();
633
- setOption("open", false);
634
- if (editor.getOption(import_react9.BlockSelectionPlugin, "isSelectingSome")) {
635
- } else {
636
- editor.tf.focus();
637
- }
638
- const lastBatch = editor.history.undos.at(-1);
639
- if (lastBatch?.ai) {
640
- delete lastBatch.ai;
641
- }
642
- tf.aiChat.removeAnchor();
643
- },
644
- show: () => {
645
- api.aiChat.reset();
646
- getOptions().chat.setMessages?.([]);
647
- setOption("open", true);
648
- }
649
- })).extendTransforms(({ editor }) => ({
650
- accept: (0, import_platejs12.bindFirst)(acceptAIChat, editor),
651
- insertBelow: (0, import_platejs12.bindFirst)(insertBelowAIChat, editor),
652
- removeAnchor: (0, import_platejs12.bindFirst)(removeAnchorAIChat, editor),
653
- replaceSelection: (0, import_platejs12.bindFirst)(replaceSelectionAIChat, editor)
654
- }));
655
-
656
- // src/lib/streaming/utils/escapeInput.ts
657
- var escapeInput = (data) => {
658
- let res = data;
659
- if (data.startsWith("$$") && !data.startsWith("$$\n") && !isCompleteMath(data)) {
660
- res = data.replace("$$", String.raw`\$\$`);
661
- }
662
- return res;
663
- };
664
-
665
- // src/lib/streaming/utils/getListNode.ts
666
- var getListNode = (editor, node) => {
667
- if (node.listStyleType && node.listStart) {
668
- const previousNode = editor.api.previous({
669
- at: editor.selection?.focus
670
- })?.[0];
671
- if (previousNode?.listStyleType && previousNode?.listStart) {
672
- return node;
673
- } else {
674
- if (node.listStart === 1) return node;
675
- return {
676
- ...node,
677
- listRestartPolite: node.listStart
678
- };
679
- }
680
- }
681
- return node;
682
- };
683
-
684
- // src/lib/streaming/utils/isSameNode.ts
685
- var import_platejs13 = require("platejs");
686
- var LIST_STYLE_TYPE = "listStyleType";
687
- var isSameNode = (editor, node1, node2) => {
688
- if (node1.type !== editor.getType(import_platejs13.KEYS.p) || node2.type !== editor.getType(import_platejs13.KEYS.p))
689
- return node1.type === node2.type;
690
- if ((0, import_platejs13.isDefined)(node1[LIST_STYLE_TYPE]) || (0, import_platejs13.isDefined)(node2[LIST_STYLE_TYPE])) {
691
- return node1[LIST_STYLE_TYPE] === node2[LIST_STYLE_TYPE];
692
- }
693
- return node1.type === node2.type;
694
- };
695
-
696
- // src/lib/streaming/utils/nodesWithProps.ts
697
- var import_platejs14 = require("platejs");
698
- var nodesWithProps = (editor, nodes, options) => {
699
- return nodes.map((node) => {
700
- if (import_platejs14.ElementApi.isElement(node)) {
701
- return {
702
- ...getListNode(editor, node),
703
- ...options.elementProps,
704
- children: nodesWithProps(editor, node.children, options)
705
- };
706
- } else {
707
- return {
708
- ...options.textProps,
709
- ...node,
710
- text: node.text
711
- };
712
- }
713
- });
714
- };
715
-
716
- // src/lib/streaming/utils/utils.ts
717
- var getChunkTrimmed = (chunk, {
718
- direction = "right"
719
- } = {}) => {
720
- const str = direction === "right" ? chunk.trimEnd() : chunk.trimStart();
721
- if (direction === "right") {
722
- return chunk.slice(str.length);
723
- } else {
724
- return chunk.slice(0, chunk.length - str.length);
725
- }
726
- };
727
- function isCompleteCodeBlock(str) {
728
- const trimmed = str.trim();
729
- const startsWithCodeBlock = trimmed.startsWith("```");
730
- const endsWithCodeBlock = trimmed.endsWith("```");
731
- return startsWithCodeBlock && endsWithCodeBlock;
732
- }
733
- function isCompleteMath(str) {
734
- const trimmed = str.trim();
735
- const startsWithMath = trimmed.startsWith("$$");
736
- const endsWithMath = trimmed.endsWith("$$");
737
- return startsWithMath && endsWithMath;
738
- }
739
-
740
- // src/lib/streaming/streamDeserializeMd.ts
741
- var statMdxTagRegex = /<([A-Za-z][A-Za-z0-9._:-]*)(?:\s[^>]*)?>/;
742
- var streamDeserializeMd = (editor, data, options) => {
743
- const input = escapeInput(data);
744
- const value = withoutDeserializeInMdx(editor, input);
745
- if (Array.isArray(value)) return value;
746
- let blocks = [];
747
- blocks = editor.getApi(import_markdown3.MarkdownPlugin).markdown.deserialize(input, {
748
- ...options,
749
- preserveEmptyParagraphs: false
750
- });
751
- const trimmedData = getChunkTrimmed(data);
752
- const lastBlock = blocks.at(-1);
753
- const addNewLine = trimmedData === "\n\n";
754
- const unshiftNewLine = getChunkTrimmed(data, { direction: "left" }) === "\n\n";
755
- const isCodeBlockOrTable = lastBlock?.type === "code_block" || lastBlock?.type === "table";
756
- let result = blocks;
757
- if (lastBlock && !isCodeBlockOrTable && trimmedData.length > 0 && !addNewLine) {
758
- const textNode = [
759
- {
760
- text: trimmedData
761
- }
762
- ];
763
- const lastChild = lastBlock.children.at(-1);
764
- if (lastChild && import_platejs15.TextApi.isText(lastChild) && Object.keys(lastChild).length === 1) {
765
- lastBlock.children.pop();
766
- const textNode2 = [
767
- {
768
- text: lastChild.text + trimmedData
769
- }
770
- ];
771
- lastBlock.children.push(...textNode2);
772
- } else {
773
- lastBlock.children.push(...textNode);
774
- }
775
- result = [...blocks.slice(0, -1), lastBlock];
776
- }
777
- if (addNewLine && !isCodeBlockOrTable) {
778
- result.push({
779
- children: [{ text: "" }],
780
- type: import_platejs15.KEYS.p
781
- });
782
- }
783
- if (unshiftNewLine && !isCodeBlockOrTable) {
784
- result.unshift({
785
- children: [{ text: "" }],
786
- type: import_platejs15.KEYS.p
787
- });
788
- }
789
- return result;
790
- };
791
- var withoutDeserializeInMdx = (editor, input) => {
792
- const mdxName = editor.getOption(AIChatPlugin, "_mdxName");
793
- if (mdxName) {
794
- const isMdxEnd = input.includes(`</${mdxName}>`);
795
- if (isMdxEnd) {
796
- editor.setOption(AIChatPlugin, "_mdxName", null);
797
- return false;
798
- } else {
799
- return [
800
- {
801
- children: [
802
- {
803
- text: input
804
- }
805
- ],
806
- type: (0, import_platejs15.getPluginType)(editor, import_platejs15.KEYS.p)
807
- }
808
- ];
809
- }
810
- } else {
811
- const newMdxName = statMdxTagRegex.exec(input)?.[1];
812
- if (input.startsWith(`<${newMdxName}`)) {
813
- editor.setOption(AIChatPlugin, "_mdxName", newMdxName ?? null);
814
- }
815
- }
816
- };
817
-
818
- // src/lib/streaming/streamInsertChunk.ts
819
- var import_platejs17 = require("platejs");
820
-
821
- // src/lib/streaming/streamSerializeMd.ts
822
- var import_markdown4 = require("@platejs/markdown");
823
- var import_platejs16 = require("platejs");
824
- var trimEndHeading = (editor, value) => {
825
- const headingKeys = /* @__PURE__ */ new Set([
826
- import_platejs16.KEYS.h1,
827
- import_platejs16.KEYS.h2,
828
- import_platejs16.KEYS.h3,
829
- import_platejs16.KEYS.h4,
830
- import_platejs16.KEYS.h5,
831
- import_platejs16.KEYS.h6
832
- ]);
833
- const lastBlock = value.at(-1);
834
- if (lastBlock && headingKeys.has(
835
- (0, import_platejs16.getPluginKey)(editor, lastBlock.type) ?? lastBlock.type
836
- ) && import_platejs16.ElementApi.isElement(lastBlock)) {
837
- const lastTextNode = lastBlock.children.at(-1);
838
- if (import_platejs16.TextApi.isText(lastTextNode)) {
839
- const trimmedText = getChunkTrimmed(lastTextNode?.text);
840
- const newChildren = [
841
- ...lastBlock.children.slice(0, -1),
842
- { text: lastTextNode.text.trimEnd() }
843
- ];
844
- const newLastBlock = {
845
- ...lastBlock,
846
- children: newChildren
847
- };
848
- return {
849
- trimmedText,
850
- value: [...value.slice(0, -1), newLastBlock]
851
- };
852
- }
853
- }
854
- return { trimmedText: "", value };
855
- };
856
- var streamSerializeMd = (editor, options, chunk) => {
857
- const { value: optionsValue, ...restOptions } = options;
858
- const { value } = trimEndHeading(editor, optionsValue ?? editor.children);
859
- let result = "";
860
- result = editor.getApi(import_markdown4.MarkdownPlugin).markdown.serialize({
861
- preserveEmptyParagraphs: false,
862
- value,
863
- ...restOptions
864
- });
865
- const trimmedChunk = getChunkTrimmed(chunk);
866
- if (isCompleteCodeBlock(result) && !chunk.endsWith("```")) {
867
- result = result.trimEnd().slice(0, -3) + trimmedChunk;
868
- }
869
- if (isCompleteMath(result) && !chunk.endsWith("$$")) {
870
- result = result.trimEnd().slice(0, -3) + trimmedChunk;
871
- }
872
- result = result.replace(/&#x20;/g, " ");
873
- result = result.replace(/&#x200B;/g, " ");
874
- result = result.replace(/\u200B/g, "");
875
- if (trimmedChunk !== "\n\n") {
876
- result = result.trimEnd() + trimmedChunk;
877
- }
878
- if (chunk.endsWith("\n\n")) {
879
- if (result === "\n") {
880
- result = "";
881
- } else if (result.endsWith("\n\n")) {
882
- result = result.slice(0, -1);
883
- }
884
- }
885
- result = result.replace(/\\([\\`*_{}\\[\]()#+\-\\.!~<>|$])/g, "$1");
886
- return result;
887
- };
888
-
889
- // src/lib/streaming/streamInsertChunk.ts
890
- var getNextPath = (path, length) => {
891
- let result = path;
892
- for (let i = 0; i < length; i++) {
893
- result = import_platejs17.PathApi.next(result);
894
- }
895
- return result;
896
- };
897
- function streamInsertChunk(editor, chunk, options = {}) {
898
- const { _blockChunks, _blockPath } = editor.getOptions(AIChatPlugin);
899
- if (_blockPath === null) {
900
- const blocks = streamDeserializeMd(editor, chunk);
901
- const path = getCurrentBlockPath(editor);
902
- const startBlock = editor.api.node(path)[0];
903
- const startInEmptyParagraph = import_platejs17.NodeApi.string(startBlock).length === 0 && startBlock.type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.p);
904
- if (startInEmptyParagraph) {
905
- editor.tf.removeNodes({ at: path });
906
- }
907
- if (blocks.length > 0) {
908
- editor.tf.insertNodes(nodesWithProps(editor, [blocks[0]], options), {
909
- at: path,
910
- nextBlock: !startInEmptyParagraph,
911
- select: true
912
- });
913
- editor.setOption(AIChatPlugin, "_blockPath", getCurrentBlockPath(editor));
914
- editor.setOption(AIChatPlugin, "_blockChunks", chunk);
915
- if (blocks.length > 1) {
916
- const nextBlocks = blocks.slice(1);
917
- const nextPath = getCurrentBlockPath(editor);
918
- editor.tf.insertNodes(nodesWithProps(editor, nextBlocks, options), {
919
- at: nextPath,
920
- nextBlock: true,
921
- select: true
922
- });
923
- const lastBlock = editor.api.node(
924
- getNextPath(nextPath, nextBlocks.length)
925
- );
926
- editor.setOption(AIChatPlugin, "_blockPath", lastBlock[1]);
927
- const lastBlockChunks = streamSerializeMd(
928
- editor,
929
- {
930
- value: [lastBlock[0]]
931
- },
932
- chunk
933
- );
934
- editor.setOption(AIChatPlugin, "_blockChunks", lastBlockChunks);
935
- }
936
- }
937
- } else {
938
- const tempBlockChunks = _blockChunks + chunk;
939
- const tempBlocks = streamDeserializeMd(editor, tempBlockChunks);
940
- if (tempBlocks.length === 0) {
941
- return console.warn(
942
- `unsupport md nodes: ${JSON.stringify(tempBlockChunks)}`
943
- );
944
- }
945
- if (tempBlocks.length === 1) {
946
- const currentBlock = editor.api.node(_blockPath)[0];
947
- if (isSameNode(editor, currentBlock, tempBlocks[0])) {
948
- const chunkNodes = streamDeserializeInlineMd(editor, chunk);
949
- editor.tf.insertNodes(nodesWithProps(editor, chunkNodes, options), {
950
- at: editor.api.end(_blockPath),
951
- select: true
952
- });
953
- const updatedBlock = editor.api.node(_blockPath);
954
- const serializedBlock = streamSerializeMd(
955
- editor,
956
- {
957
- value: [updatedBlock[0]]
958
- },
959
- tempBlockChunks
960
- );
961
- const blockText = import_platejs17.NodeApi.string(tempBlocks[0]);
962
- if (serializedBlock === tempBlockChunks && blockText === serializedBlock) {
963
- editor.setOption(AIChatPlugin, "_blockChunks", tempBlockChunks);
964
- } else {
965
- editor.tf.replaceNodes(
966
- nodesWithProps(editor, [tempBlocks[0]], options),
967
- {
968
- at: _blockPath,
969
- select: true
970
- }
971
- );
972
- const serializedBlock2 = streamSerializeMd(
973
- editor,
974
- {
975
- value: [tempBlocks[0]]
976
- },
977
- tempBlockChunks
978
- );
979
- editor.setOption(
980
- AIChatPlugin,
981
- "_blockChunks",
982
- // one block includes multiple children
983
- tempBlocks[0].type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.codeBlock) || tempBlocks[0].type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.table) || tempBlocks[0].type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.equation) ? tempBlockChunks : serializedBlock2
984
- );
985
- }
986
- } else {
987
- const serializedBlock = streamSerializeMd(
988
- editor,
989
- {
990
- value: [tempBlocks[0]]
991
- },
992
- tempBlockChunks
993
- );
994
- editor.tf.replaceNodes(
995
- nodesWithProps(editor, [tempBlocks[0]], options),
996
- {
997
- at: _blockPath,
998
- select: true
999
- }
1000
- );
1001
- editor.setOption(AIChatPlugin, "_blockChunks", serializedBlock);
1002
- }
1003
- } else {
1004
- editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]], options), {
1005
- at: _blockPath,
1006
- select: true
1007
- });
1008
- if (tempBlocks.length > 1) {
1009
- const newEndBlockPath = getNextPath(_blockPath, tempBlocks.length - 1);
1010
- editor.tf.insertNodes(
1011
- nodesWithProps(editor, tempBlocks.slice(1), options),
1012
- {
1013
- at: import_platejs17.PathApi.next(_blockPath),
1014
- select: true
1015
- }
1016
- );
1017
- editor.setOption(AIChatPlugin, "_blockPath", newEndBlockPath);
1018
- const endBlock = editor.api.node(newEndBlockPath)[0];
1019
- const serializedBlock = streamSerializeMd(
1020
- editor,
1021
- {
1022
- value: [endBlock]
1023
- },
1024
- tempBlockChunks
1025
- );
1026
- editor.setOption(AIChatPlugin, "_blockChunks", serializedBlock);
1027
- }
1028
- }
1029
- }
1030
- }
1031
- var getCurrentBlockPath = (editor) => {
1032
- const getAnchorPreviousPath = (editor2) => {
1033
- const anchorNode = editor2.getApi(AIChatPlugin).aiChat.node({ anchor: true });
1034
- if (anchorNode) {
1035
- return import_platejs17.PathApi.previous(anchorNode[1]);
1036
- }
1037
- };
1038
- const getFocusPath = (editor2) => {
1039
- return editor2.selection?.focus.path.slice(0, 1);
1040
- };
1041
- const path = getAnchorPreviousPath(editor) ?? getFocusPath(editor) ?? [0];
1042
- const entry = editor.api.node(path);
1043
- if (entry && (entry[0].type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.columnGroup) || entry[0].type === (0, import_platejs17.getPluginType)(editor, import_platejs17.KEYS.table))) {
1044
- return editor.api.above()?.[1] ?? path;
1045
- }
1046
- return path;
205
+ return promptText;
1047
206
  };
1048
207
  // Annotate the CommonJS export names for ESM import in node:
1049
208
  0 && (module.exports = {
1050
209
  BaseAIPlugin,
1051
- escapeInput,
1052
- getChunkTrimmed,
1053
- getCurrentBlockPath,
1054
- getListNode,
210
+ getEditorPrompt,
211
+ getMarkdown,
1055
212
  insertAINodes,
1056
- isCompleteCodeBlock,
1057
- isCompleteMath,
1058
- isSameNode,
1059
- nodesWithProps,
1060
213
  removeAIMarks,
1061
214
  removeAINodes,
1062
- streamDeserializeInlineMd,
1063
- streamDeserializeMd,
1064
- streamInsertChunk,
1065
- streamSerializeMd,
215
+ replacePlaceholders,
1066
216
  undoAI,
1067
217
  withAIBatch
1068
218
  });