diff --git a/packages/xl-ai/src/api/LLMRequest.ts b/packages/xl-ai/src/api/LLMRequest.ts index c11a19d62..fcd781af0 100644 --- a/packages/xl-ai/src/api/LLMRequest.ts +++ b/packages/xl-ai/src/api/LLMRequest.ts @@ -9,6 +9,7 @@ import { LLMResponse } from "./LLMResponse.js"; import type { PromptBuilder } from "./formats/PromptBuilder.js"; import { htmlBlockLLMFormat } from "./formats/html-blocks/htmlBlocks.js"; import { LLMFormat } from "./index.js"; +import { trimEmptyBlocks } from "./promptHelpers/trimEmptyBlocks.js"; export type LLMRequestOptions = { /** @@ -155,7 +156,7 @@ export async function doLLMRequest( cursorBlock && deleteEmptyCursorBlock && isEmptyParagraph(cursorBlock) && - editor.document.length > 1 + trimEmptyBlocks(editor.document).length > 0 ? cursorBlock.id : undefined; diff --git a/packages/xl-ai/src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts b/packages/xl-ai/src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts index 1df1b714d..7fe83e758 100644 --- a/packages/xl-ai/src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts +++ b/packages/xl-ai/src/api/formats/html-blocks/defaultHTMLPromptBuilder.ts @@ -1,4 +1,5 @@ import { CoreMessage } from "ai"; +import { trimEmptyBlocks } from "../../promptHelpers/trimEmptyBlocks.js"; import type { PromptBuilder } from "../PromptBuilder.js"; import { getDataForPromptNoSelection, @@ -99,6 +100,8 @@ function promptManipulateDocumentUseHTMLBlocks(opts: { } export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => { + const isEmptyDocument = trimEmptyBlocks(editor.document).length === 0; + if (opts.selectedBlocks) { const data = await getDataForPromptWithSelection(editor, { selectedBlocks: opts.selectedBlocks, @@ -141,7 +144,7 @@ export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => { return promptManipulateSelectionHTMLBlocks({ ...data, userPrompt: opts.userPrompt, - isEmptyDocument: editor.isEmpty, + isEmptyDocument, }); } else { const data = await getDataForPromptNoSelection(editor, opts); @@ -174,7 +177,7 @@ export const defaultHTMLPromptBuilder: PromptBuilder = async (editor, opts) => { return promptManipulateDocumentUseHTMLBlocks({ ...data, userPrompt: opts.userPrompt, - isEmptyDocument: editor.isEmpty, + isEmptyDocument, }); } }; diff --git a/packages/xl-ai/src/api/formats/html-blocks/htmlPromptData.ts b/packages/xl-ai/src/api/formats/html-blocks/htmlPromptData.ts index 594950970..aeceedd84 100644 --- a/packages/xl-ai/src/api/formats/html-blocks/htmlPromptData.ts +++ b/packages/xl-ai/src/api/formats/html-blocks/htmlPromptData.ts @@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection( excludeBlockIds?: string[]; }, ) { - const input = trimEmptyBlocks(editor.document); + const cursorBlockId = editor.getTextCursorPosition().block.id; + const input = trimEmptyBlocks(editor.document, { + cursorBlockId, + }); const blockArray = await convertBlocks( flattenBlocks(input), async (block) => { diff --git a/packages/xl-ai/src/api/formats/json/defaultJSONPromptBuilder.ts b/packages/xl-ai/src/api/formats/json/defaultJSONPromptBuilder.ts index 0cf00895d..0b1d7324b 100644 --- a/packages/xl-ai/src/api/formats/json/defaultJSONPromptBuilder.ts +++ b/packages/xl-ai/src/api/formats/json/defaultJSONPromptBuilder.ts @@ -1,4 +1,5 @@ import { CoreMessage } from "ai"; +import { trimEmptyBlocks } from "../../promptHelpers/trimEmptyBlocks.js"; import { PromptBuilder } from "../PromptBuilder.js"; import { getDataForPromptNoSelection, @@ -122,21 +123,24 @@ function promptManipulateDocumentUseJSONBlocks(opts: { } export const defaultJSONPromptBuilder: PromptBuilder = async (editor, opts) => { + const isEmptyDocument = trimEmptyBlocks(editor.document).length === 0; + if (opts.selectedBlocks) { const data = await getDataForPromptWithSelection(editor, { selectedBlocks: opts.selectedBlocks, }); + return promptManipulateSelectionJSONBlocks({ ...data, userPrompt: opts.userPrompt, - isEmptyDocument: editor.isEmpty, + isEmptyDocument, }); } else { const data = await getDataForPromptNoSelection(editor, opts); return promptManipulateDocumentUseJSONBlocks({ ...data, userPrompt: opts.userPrompt, - isEmptyDocument: editor.isEmpty, + isEmptyDocument, }); } }; diff --git a/packages/xl-ai/src/api/formats/json/jsonPromptData.ts b/packages/xl-ai/src/api/formats/json/jsonPromptData.ts index 72480f929..2ac81328f 100644 --- a/packages/xl-ai/src/api/formats/json/jsonPromptData.ts +++ b/packages/xl-ai/src/api/formats/json/jsonPromptData.ts @@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection( excludeBlockIds?: string[]; }, ) { - const input = trimEmptyBlocks(editor.document); + const cursorBlockId = editor.getTextCursorPosition().block.id; + const input = trimEmptyBlocks(editor.document, { + cursorBlockId, + }); const blockArray = await convertBlocks( flattenBlocks(input), async (block) => { diff --git a/packages/xl-ai/src/api/formats/markdown-blocks/markdownPromptData.ts b/packages/xl-ai/src/api/formats/markdown-blocks/markdownPromptData.ts index 5b983dc7c..91394e738 100644 --- a/packages/xl-ai/src/api/formats/markdown-blocks/markdownPromptData.ts +++ b/packages/xl-ai/src/api/formats/markdown-blocks/markdownPromptData.ts @@ -11,7 +11,10 @@ export async function getDataForPromptNoSelection( excludeBlockIds?: string[]; }, ) { - const input = trimEmptyBlocks(editor.document); + const cursorBlockId = editor.getTextCursorPosition().block.id; + const input = trimEmptyBlocks(editor.document, { + cursorBlockId, + }); const blockArray = await convertBlocks( flattenBlocks(input), async (block) => { diff --git a/packages/xl-ai/src/api/promptHelpers/trimEmptyBlocks.ts b/packages/xl-ai/src/api/promptHelpers/trimEmptyBlocks.ts index c6969ae2b..a75bec0b1 100644 --- a/packages/xl-ai/src/api/promptHelpers/trimEmptyBlocks.ts +++ b/packages/xl-ai/src/api/promptHelpers/trimEmptyBlocks.ts @@ -7,19 +7,16 @@ export function trimEmptyBlocks( opts?: { trimStart?: boolean; trimEnd?: boolean; + cursorBlockId?: string; }, ) { - if (source.length === 1) { - // don't trim empty blocks from a single block document - return source; - } // trim empty trailing blocks that don't have the cursor // if we don't do this, commands like "add some paragraphs" // would add paragraphs after the trailing blocks const trimmedSource = trimArray( source, (block) => { - return isEmptyParagraph(block); + return isEmptyParagraph(block) && opts?.cursorBlockId !== block.id; }, opts?.trimStart ?? false, opts?.trimEnd ?? true,