diff --git a/packages/backend/server/src/plugins/copilot/providers/provider.ts b/packages/backend/server/src/plugins/copilot/providers/provider.ts index 889a06ab4d..54605efaa6 100644 --- a/packages/backend/server/src/plugins/copilot/providers/provider.ts +++ b/packages/backend/server/src/plugins/copilot/providers/provider.ts @@ -14,6 +14,7 @@ import { AccessController } from '../../../core/permission'; import { Models } from '../../../models'; import { IndexerService } from '../../indexer'; import { CopilotContextService } from '../context'; +import { PromptService } from '../prompt'; import { buildContentGetter, buildDocContentGetter, @@ -201,11 +202,23 @@ export abstract class CopilotProvider { break; } case 'docCompose': { - tools.doc_compose = createDocComposeTool(); + const promptService = this.moduleRef.get(PromptService, { + strict: false, + }); + tools.doc_compose = createDocComposeTool( + promptService, + this.factory + ); break; } case 'codeArtifact': { - tools.code_artifact = createCodeArtifactTool(); + const promptService = this.moduleRef.get(PromptService, { + strict: false, + }); + tools.code_artifact = createCodeArtifactTool( + promptService, + this.factory + ); break; } } diff --git a/packages/backend/server/src/plugins/copilot/tools/code-artifact.ts b/packages/backend/server/src/plugins/copilot/tools/code-artifact.ts index 8039a475ad..b29df25140 100644 --- a/packages/backend/server/src/plugins/copilot/tools/code-artifact.ts +++ b/packages/backend/server/src/plugins/copilot/tools/code-artifact.ts @@ -2,6 +2,8 @@ import { Logger } from '@nestjs/common'; import { tool } from 'ai'; import { z } from 'zod'; +import type { PromptService } from '../prompt'; +import type { CopilotProviderFactory } from '../providers'; import { toolError } from './error'; const logger = new Logger('CodeArtifactTool'); @@ -12,7 +14,10 @@ const logger = new Logger('CodeArtifactTool'); * it can be saved as a single .html file and opened in any browser with no * external dependencies. */ -export const createCodeArtifactTool = () => { +export const createCodeArtifactTool = ( + promptService: PromptService, + factory: CopilotProviderFactory +) => { return tool({ description: 'Generate a single-file HTML snippet (with inline '); + const prompt = await promptService.get('Make it real with text'); + if (!prompt) { + throw new Error('Prompt not found'); } - parts.push(''); - parts.push(''); - parts.push(body); - if (js.trim().length) { - parts.push(''); - } - parts.push(''); - parts.push(''); - const html = parts.join('\n'); + const provider = await factory.getProviderByModel(prompt.model); + if (!provider) { + throw new Error('Provider not found'); + } + + const content = await provider.text( + { + modelId: prompt.model, + }, + [...prompt.finish({}), { role: 'user', content: userPrompt }] + ); + + // Remove surrounding ``` or ```html fences if present + let stripped = content.trim(); + if (stripped.startsWith('```')) { + const firstNewline = stripped.indexOf('\n'); + if (firstNewline !== -1) { + stripped = stripped.slice(firstNewline + 1); + } + if (stripped.endsWith('```')) { + stripped = stripped.slice(0, -3); + } + } return { title, - html, - size: html.length, + html: stripped, + size: stripped.length, }; } catch (err: any) { logger.error(`Failed to compose code artifact (${title})`, err); diff --git a/packages/backend/server/src/plugins/copilot/tools/doc-compose.ts b/packages/backend/server/src/plugins/copilot/tools/doc-compose.ts index 0df7a4c876..d18b516336 100644 --- a/packages/backend/server/src/plugins/copilot/tools/doc-compose.ts +++ b/packages/backend/server/src/plugins/copilot/tools/doc-compose.ts @@ -2,64 +2,51 @@ import { Logger } from '@nestjs/common'; import { tool } from 'ai'; import { z } from 'zod'; +import type { PromptService } from '../prompt'; +import type { CopilotProviderFactory } from '../providers'; import { toolError } from './error'; const logger = new Logger('DocComposeTool'); -export const createDocComposeTool = () => { +export const createDocComposeTool = ( + promptService: PromptService, + factory: CopilotProviderFactory +) => { return tool({ description: 'Write a new document with markdown content. This tool creates structured markdown content for documents including titles, sections, and formatting.', parameters: z.object({ title: z.string().describe('The title of the document'), - content: z + userPrompt: z .string() .describe( - 'The main content to write in markdown format. Include proper markdown formatting like headers (# ## ###), lists (- * 1.), links [text](url), code blocks ```code```, and other markdown elements as needed.' + 'The user description of the document, will be used to generate the document' ), - sections: z - .array( - z.object({ - heading: z.string().describe('Section heading'), - content: z.string().describe('Section content in markdown'), - }) - ) - .optional() - .describe('Optional structured sections for the document'), - metadata: z - .object({ - tags: z - .array(z.string()) - .optional() - .describe('Optional tags for the document'), - description: z - .string() - .optional() - .describe('Optional brief description of the document'), - }) - .optional() - .describe('Optional metadata for the document'), }), - execute: async ({ title, content, sections, metadata }) => { + execute: async ({ title, userPrompt }) => { try { - let markdownContent = ''; - - markdownContent += `${content}\n\n`; - - if (sections && sections.length > 0) { - for (const section of sections) { - markdownContent += `## ${section.heading}\n\n`; - markdownContent += `${section.content}\n\n`; - } + const prompt = await promptService.get('Write an article about this'); + if (!prompt) { + throw new Error('Prompt not found'); } + const provider = await factory.getProviderByModel(prompt.model); + + if (!provider) { + throw new Error('Provider not found'); + } + + const content = await provider.text( + { + modelId: prompt.model, + }, + [...prompt.finish({}), { role: 'user', content: userPrompt }] + ); + return { title, - markdown: markdownContent.trim(), + markdown: content, wordCount: content.split(/\s+/).length, - metadata: metadata || {}, - tags: metadata?.tags || [], - description: metadata?.description || '', }; } catch (err: any) { logger.error(`Failed to write document: ${title}`, err); diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/doc-compose.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/doc-compose.ts index 52d112e6da..959831fc40 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/doc-compose.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/doc-compose.ts @@ -39,7 +39,6 @@ interface DocComposeToolResult { title: string; markdown: string; wordCount: number; - metadata: Record; } | ToolError | null;