diff --git a/core/commands/index.ts b/core/commands/index.ts index 7115d22bec..3037d7ef7c 100644 --- a/core/commands/index.ts +++ b/core/commands/index.ts @@ -1,6 +1,7 @@ import { CustomCommand, SlashCommand, SlashCommandDescription } from "../"; import { renderTemplatedString } from "../promptFiles/v1/renderTemplatedString"; import { replaceSlashCommandWithPromptInChatHistory } from "../promptFiles/v1/updateChatHistory"; +import { renderPromptFileV2 } from "../promptFiles/v2/renderPromptFile"; import { renderChatMessage } from "../util/messageContent"; import SlashCommands from "./slash"; @@ -15,7 +16,16 @@ export function slashFromCustomCommand( name: commandName, description: customCommand.description ?? "", prompt: customCommand.prompt, - run: async function* ({ input, llm, history, ide, completionOptions }) { + run: async function* ({ + input, + llm, + history, + ide, + completionOptions, + config, + selectedCode, + fetch, + }) { // Render prompt template let renderedPrompt: string; if (customCommand.prompt.includes("{{{ input }}}")) { @@ -25,7 +35,21 @@ export function slashFromCustomCommand( { input }, ); } else { - renderedPrompt = customCommand.prompt + "\n\n" + input; + const renderedPromptFile = await renderPromptFileV2( + customCommand.prompt, + { + config, + llm, + ide, + selectedCode, + fetch, + fullInput: input, + embeddingsProvider: config.modelsByRole.embed[0], + reranker: config.modelsByRole.rerank[0], + }, + ); + + renderedPrompt = renderedPromptFile[1]; } // Replaces slash command messages with the rendered prompt diff --git a/core/promptFiles/v1/slashCommandFromPromptFile.ts b/core/promptFiles/v1/slashCommandFromPromptFile.ts index 6abd4927fd..fd0b48b2c2 100644 --- a/core/promptFiles/v1/slashCommandFromPromptFile.ts +++ b/core/promptFiles/v1/slashCommandFromPromptFile.ts @@ -2,6 +2,7 @@ import { ContinueSDK, SlashCommand } from "../.."; import { renderChatMessage } from "../../util/messageContent"; import { getLastNPathParts } from "../../util/uri"; import { parsePromptFileV1V2 } from "../v2/parsePromptFileV1V2"; +import { renderPromptFileV2 } from "../v2/renderPromptFile"; import { getContextProviderHelpers } from "./getContextProviderHelpers"; import { renderTemplatedString } from "./renderTemplatedString"; @@ -67,7 +68,17 @@ export function slashCommandFromPromptFileV1( context.llm.systemMessage = systemMessage; const userInput = extractUserInput(context.input, name); - const renderedPrompt = await renderPromptV1(prompt, context, userInput); + const [_, renderedPrompt] = await renderPromptFileV2(prompt, { + config: context.config, + fullInput: userInput, + embeddingsProvider: context.config.modelsByRole.embed[0], + reranker: context.config.modelsByRole.rerank[0], + llm: context.llm, + ide: context.ide, + selectedCode: context.selectedCode, + fetch: context.fetch, + }); + const messages = replaceSlashCommandWithPromptInChatHistory( context.history, name, diff --git a/core/promptFiles/v2/renderPromptFile.ts b/core/promptFiles/v2/renderPromptFile.ts index 1f08011a8e..4d52c7ba12 100644 --- a/core/promptFiles/v2/renderPromptFile.ts +++ b/core/promptFiles/v2/renderPromptFile.ts @@ -66,7 +66,7 @@ export async function renderPromptFileV2( rawContent: string, extras: ContextProviderExtras, ): Promise<[ContextItem[], string]> { - const [preamble, body] = getPreambleAndBody(rawContent); + const [_, body] = getPreambleAndBody(rawContent); const contextItemsPromises: Promise[] = []; const renderedBody = body.replace(/@([^\s]+)/g, (match, name) => { @@ -75,6 +75,10 @@ export async function renderPromptFileV2( }); const contextItems = (await Promise.all(contextItemsPromises)).flat(); + const renderedPrompt = + contextItems.map((item) => item.content).join("\n\n") + + "\n\n" + + renderedBody; - return [contextItems, renderedBody]; + return [contextItems, renderedPrompt]; } diff --git a/docs/docs/customize/context-providers.mdx b/docs/docs/customize/context-providers.mdx index b31deedf4e..204f680f05 100644 --- a/docs/docs/customize/context-providers.mdx +++ b/docs/docs/customize/context-providers.mdx @@ -530,10 +530,6 @@ The [Model Context Protocol](https://modelcontextprotocol.io/introduction) is a You'll then be able to type "@" and see "MCP" in the context providers dropdown. -### Prompt Files - -See [Prompt Files](./deep-dives/prompt-files.md). Prompt files are not added directly to the config file; prompt files are parsed and injected into the config automatically, to be used like other context providers. - ### `@Issue` Reference the conversation in a GitHub issue. @@ -883,7 +879,6 @@ You can override this query by setting the `issueQuery` parameter. You can set the `maxResults` parameter to limit the number of results returned. The default is `50`. - ### `@Discord` Reference the messages in a Discord channel. diff --git a/docs/docs/customize/deep-dives/prompt-files.md b/docs/docs/customize/deep-dives/prompt-files.md deleted file mode 100644 index 68995746fa..0000000000 --- a/docs/docs/customize/deep-dives/prompt-files.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: Prompt files ---- - -Prompt files allow you to build and use local prompts, and provide a convenient way to test and iterate on prompts before publishing them to the Hub. - -:::info -Visit the Hub to [explore prompts](https://hub.continue.dev/explore/prompts) or [create your own](https://hub.continue.dev/new?type=block&blockType=prompts) -::: - -## Quick start - -Below is a quick example of setting up a prompt file: - -1. Create a folder called `.continue/prompts` at the top level of your workspace (or you can use the button in the UI by typing @, selecting "Prompt Files", and selecting "New Prompt File"). -2. Add a file called `rails.prompt` to this folder. -3. Write the following contents to `rails.prompt` and save. - -```.prompt -name: Rails Project -description: Information about this project ---- -Attached is a summary of the current Ruby on Rails application, including the @Gemfile and database schema in @db/schema.rb -``` - -Now to use this prompt, you can highlight code and use cmd/ctrl + L to select it in the Continue sidebar. - -Then, type / and choose the "Rails Project" prompt. You can now ask any question as usual and the LLM will have the information from your .prompt file. - -## Format - -The format is inspired by [HumanLoops's .prompt file](https://docs.humanloop.com/docs/prompt-file-format), with additional templating to reference files, URLs, and context providers. - -:::info -The current state of this format is experimental and subject to change -::: - -### Preamble - -The "preamble" is everything above the `---` separator, and lets you specify model parameters. It uses YAML syntax and currently supports the following parameters: - -- `name` - The display title -- `description` - The description you will see in the dropdown -- `version` - Can be either "1" (for legacy prompt files) or "2" (this is the default and does not need to be set) - -If you don't need any of these parameters, you can leave out the preamble and do not need to include the `---` separator. - -### Context - -Many [context provider](../context-providers.mdx) can be referenced by typing "@" followed by the name of the context provider. The currently supported list is: - -- `@terminal` - The contents of the terminal -- `@currentFile` - The currently active file -- `@open` - All open files -- `@os` - Information about the operating system -- `@problems` - Problems reported by the language server in the active file -- `@repo-map` - A map of files in the repository -- `@tree` - A tree view of the repository structure - -Or you can directly type URLs and file paths: - -- `@https://github.com/continuedev/continue` - The contents of a URL -- `@src/index.ts` - The contents of a file (VS Code only) - -All references will be attached as context items, rather than injected directly inline. - -## Feedback - -If you have ideas about how to improve the `.prompt` file format, please reach out on [Discord](https://discord.gg/NWtdYexhMs). diff --git a/docs/docs/customize/deep-dives/prompts.md b/docs/docs/customize/deep-dives/prompts.md new file mode 100644 index 0000000000..1cd1c00851 --- /dev/null +++ b/docs/docs/customize/deep-dives/prompts.md @@ -0,0 +1,97 @@ +--- +title: Prompts +--- + +Prompts are reusable instructions that can be referenced at any time during chat. They are especially useful as context for repetitive and/or complex tasks. + +:::info +Visit the Hub to [explore prompts](https://hub.continue.dev/explore/prompts) or [create your own](https://hub.continue.dev/new?type=block&blockType=prompts) +::: + +## Examples + +Below are some examples to get you started. + +### Security review + +```text title="Security best practices review" +@open - Review these files for the following security best practices: +- Does the architecture follow security-by-design principles? +- Are there potential security vulnerabilities in the system design? +- Is sensitive data handled appropriately throughout the lifecycle? +``` + +### Reference best practice guides + +```text title="Redux best practices review" +@https://redux.js.org/style-guide/ +@currentFile + +Review this code for adherence to Redux best practices. +``` + +### Pull in commonly used files for tasks + +```text title="Generate a new TypeORM entity" +@src/db/dataSource.ts @src/db/entity/SampleEntity.ts + +Use these files to generate a new TypeORM entity based on the following requirements: +``` + +## Including Context Providers in your prompts + +Many [context providers](../context-providers.mdx) can be referenced by typing "@" followed by the name of the context provider. The currently supported list is: + +- `@terminal` - The contents of the terminal +- `@currentFile` - The currently active file +- `@open` - All open files +- `@os` - Information about the operating system +- `@problems` - Problems reported by the language server in the active file +- `@repo-map` - A map of files in the repository +- `@tree` - A tree view of the repository structure + +Or you can directly type URLs and file paths: + +- `@https://github.com/continuedev/continue` - The contents of a URL +- `@src/index.ts` - The contents of a file (VS Code only) + +All references will be attached as context items, rather than injected directly inline. + +## Local `.prompt` files + +In addition to Prompt blocks on the Hub, you can also define prompts in local `.prompt` files, located in the `.continue/prompts` folder at the top level of your workspace. This is useful for quick iteration on prompts to test them out before pushing up to the Hub. + +### Quick Start + +Below is a quick example of setting up a prompt file: + +1. Create a folder called `.continue/prompts` at the top level of your workspace +2. Add a file called `test.prompt` to this folder. +3. Write the following contents to `test.prompt` and save. + +```.prompt +name: Current file prompt +description: A test prompt using the current file context provider +--- +@currentFile +``` + +Now to use this prompt, you can open Chat, type /, select the prompt, and add type out some additional text such as "Review the code for any issues". + +### Format + +The format is inspired by [HumanLoops's .prompt file](https://docs.humanloop.com/docs/prompt-file-format), with additional templating to reference files, URLs, and context providers. + +:::info +The current state of this format is experimental and subject to change +::: + +### Preamble + +The "preamble" is everything above the `---` separator, and lets you specify model parameters. It uses YAML syntax and currently supports the following parameters: + +- `name` - The display title +- `description` - The description you will see in the dropdown +- `version` - Can be either "1" (for legacy prompt files) or "2" (this is the default and does not need to be set) + +If you don't need any of these parameters, you can leave out the preamble and do not need to include the `---` separator. diff --git a/docs/docs/customize/deep-dives/slash-commands.mdx b/docs/docs/customize/deep-dives/slash-commands.mdx index 0c97967681..059cf82135 100644 --- a/docs/docs/customize/deep-dives/slash-commands.mdx +++ b/docs/docs/customize/deep-dives/slash-commands.mdx @@ -26,7 +26,7 @@ The easiest way to add a slash command is by adding [`prompt` blocks](../../hub/ It is also possible to write your own slash command by defining a “.prompt file.” Prompt files can be as simple as a text file, but also include templating so that you can refer to files, URLs, highlighted code, and more. -Learn more about prompt files [here](./prompt-files.md) +Learn more about prompt files [here](./prompts.md) ### MCP Server prompts diff --git a/docs/docs/customize/deep-dives/vscode-actions.md b/docs/docs/customize/deep-dives/vscode-actions.md index 0c0cdd1f1f..d9f1b7b66e 100644 --- a/docs/docs/customize/deep-dives/vscode-actions.md +++ b/docs/docs/customize/deep-dives/vscode-actions.md @@ -14,7 +14,7 @@ To make common use cases even more accessible, we provide a handful of other way ## Quick actions -Quick Actions are displayed as buttons above top-level classes and functions in your source code, letting you invoke actions with one click. They will edit that class or function, but nothing outside of it. They can also be customized with [.prompt files](./prompt-files.md) to perform custom actions. +Quick Actions are displayed as buttons above top-level classes and functions in your source code, letting you invoke actions with one click. They will edit that class or function, but nothing outside of it. They can also be customized with [.prompt files](./prompts.md) to perform custom actions. ![quick-actions](/img/quick-actions.png) diff --git a/docs/docs/customize/tutorials/build-your-own-context-provider.mdx b/docs/docs/customize/tutorials/build-your-own-context-provider.mdx index 7710a84c28..1494680c0f 100644 --- a/docs/docs/customize/tutorials/build-your-own-context-provider.mdx +++ b/docs/docs/customize/tutorials/build-your-own-context-provider.mdx @@ -50,7 +50,7 @@ Then, create a server that responds to requests as are made from [HttpContextPro The `"options"` property can be used to send additional parameters to your endpoint, which will be included in the request body. :::info -The following methods for creating custom context providers are deprecated. We recommend using HTTP context providers, [MCP Servers](../context-providers.mdx#model-context-protocol), and [Prompt files](../deep-dives/prompt-files.md) where possible. +The following methods for creating custom context providers are deprecated. We recommend using HTTP context providers, [MCP Servers](../context-providers.mdx#model-context-protocol), and [Prompts](../deep-dives/prompts.md) where possible. ::: ## Using CustomContextProvider diff --git a/docs/docs/customize/tutorials/build-your-own-slash-command.md b/docs/docs/customize/tutorials/build-your-own-slash-command.md index 27b0517b3a..03543a22fb 100644 --- a/docs/docs/customize/tutorials/build-your-own-slash-command.md +++ b/docs/docs/customize/tutorials/build-your-own-slash-command.md @@ -3,7 +3,7 @@ title: Build your own slash command --- :::info -Slash commands can currently only be added using [`config.json`](../../json-reference.md) or `config.ts`. The [`YAML Config Format`](../../reference.md) is the new and preferred format. We recommend looking into [Prompt Files](../deep-dives/prompt-files.md) to achieve similar functionality. +Slash commands can currently only be added using [`config.json`](../../json-reference.md) or `config.ts`. The [`YAML Config Format`](../../reference.md) is the new and preferred format. We recommend looking into [Prompt Files](../deep-dives/prompts.md) to achieve similar functionality. ::: There are two ways to add custom slash commands: diff --git a/docs/docs/hub/blocks/block-types.md b/docs/docs/hub/blocks/block-types.md index 0c2698542a..b9c5bbd130 100644 --- a/docs/docs/hub/blocks/block-types.md +++ b/docs/docs/hub/blocks/block-types.md @@ -41,12 +41,7 @@ Learn more in the [rules deep dive](../../customize/deep-dives/rules.md), and vi Prompts blocks are pre-written, reusable prompts that can be referenced at any time during chat. They are especially useful as context for repetitive and/or complex tasks. [Explore prompts](https://hub.continue.dev/explore/prompts) on the hub. -Prompt blocks have the same syntax as [prompt files](../../customize/deep-dives/prompt-files.md). There are two important differences between prompt blocks and prompt files: - -1. Currently, prompt blocks cannot use context providers -2. Prompt blocks are stored within `config.yaml` rather than `.continue/prompts` in project directory and - -The `config.yaml` spec for `prompts` can be found [here](../../reference.md#prompts). +Prompt blocks have the same syntax as [prompt files](../../customize/deep-dives/prompts.md). The `config.yaml` spec for `prompts` can be found [here](../../reference.md#prompts). ## Data diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index c74e6a71b6..06e717ad7e 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -286,7 +286,7 @@ const config = { ], }, { - to: "/customize/deep-dives/prompt-files", + to: "/customize/deep-dives/prompts", from: ["/walkthroughs/prompt-files", "/features/prompt-files"], }, // TODO - actions redirects @@ -489,6 +489,10 @@ const config = { to: "/getting-started/install", from: "/getting-started", }, + { + to: "/customize/deep-dives/prompts", + from: "/customize/deep-dives/prompt-files", + }, ], }, ], diff --git a/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-customize.md b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-customize.md index 2ffc4d0f29..d3c1097e7f 100644 --- a/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-customize.md +++ b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-customize.md @@ -13,7 +13,7 @@ Continue 有一个大的内置斜杠命令库,但是当你首次安装时, 有两种方法添加定制斜杠命令: -1. 使用 `.prompt` 文件 - 这是大多数情况下推荐的。[在这里](../customize/deep-dives/prompt-files.md) 查看完整参考。 +1. 使用 `.prompt` 文件 - 这是大多数情况下推荐的。[在这里](../customize/deep-dives/prompts.md) 查看完整参考。 2. 使用 `config.ts` - 这给你对于 LLM, IDE 和其他重要的入口可编程的访问,通过编写 JavaScript/TypeScript 函数 ### 使用 `config.ts` 定制斜杠命令 diff --git a/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-use-it.md b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-use-it.md index f265a98856..a0d4c0023d 100644 --- a/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-use-it.md +++ b/docs/i18n/zh-CN/docusaurus-plugin-content-docs/current/actions/how-to-use-it.md @@ -24,7 +24,7 @@ Actions 是常见用例的快捷方式。例如,你可能想要审查代码, 通过定义一个 ".prompt 文件" ,也可以编写你自己的斜杠命令。 prompt 文件可以是个简单的文本文件,但是也包含模板,所以你可以引用文件, URL ,高亮代码以及更多。 -完整的 .prompt 文件可以参考 [这里](../customize/deep-dives/prompt-files.md) 。 +完整的 .prompt 文件可以参考 [这里](../customize/deep-dives/prompt.md) 。 :::tip[Prompt 库] 为了帮助你开始,[我们精心编写了一个小的 `.prompt` 文件库](https://github.com/continuedev/prompt-file-examples) 。我们鼓励社区贡献到这个仓库,所以请考虑为你的 prompt 创建一个拉取请求! diff --git a/gui/src/components/mainInput/TipTapEditor/utils/editorConfig.ts b/gui/src/components/mainInput/TipTapEditor/utils/editorConfig.ts index 8addede878..e50769ac84 100644 --- a/gui/src/components/mainInput/TipTapEditor/utils/editorConfig.ts +++ b/gui/src/components/mainInput/TipTapEditor/utils/editorConfig.ts @@ -1,4 +1,4 @@ -import { Editor } from "@tiptap/core"; +import { Editor, JSONContent } from "@tiptap/core"; import Document from "@tiptap/extension-document"; import History from "@tiptap/extension-history"; import Image from "@tiptap/extension-image"; @@ -48,6 +48,28 @@ export function getPlaceholderText( : "Ask a follow-up"; } +/** + * Checks if the editor content is valid for submission. + * A valid submission can contain either text content or prompt/code blocks + * + * @param json The editor JSON content + * @returns true if the content is valid for submission, false otherwise + */ +export function hasValidEditorContent(json: JSONContent): boolean { + // Check for prompt or code blocks + const hasPromptOrCodeBlock = json.content?.some( + (c) => + c.type === ContinueExtensions.PromptBlock.name || + c.type === ContinueExtensions.CodeBlock.name, + ); + + // Check for text content + const hasTextContent = json.content?.some((c) => c.content); + + // Content is valid if it has either text or special blocks + return hasTextContent || hasPromptOrCodeBlock || false; +} + /** * This function is called only once, so we need to use refs to pass in the latest values */ @@ -367,8 +389,8 @@ export function createEditorConfig(options: { const json = editor.getJSON(); - // Don't do anything if input box is empty - if (!json.content?.some((c) => c.content)) { + // Don't do anything if input box doesn't have valid content + if (!hasValidEditorContent(json)) { return; }