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