Skip to content

Commit

Permalink
✨ support for all context providers in .prompt files
Browse files Browse the repository at this point in the history
  • Loading branch information
sestinj committed Jun 12, 2024
1 parent 6cf4467 commit 2ac8a46
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 29 deletions.
16 changes: 8 additions & 8 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,15 @@ async function serializedToIntermediateConfig(
const promptFolder = initial.experimental?.promptPath;

let promptFiles: { path: string; content: string }[] = [];
if (promptFolder) {
promptFiles = (
await Promise.all(
workspaceDirs.map((dir) => getPromptFiles(ide, promptFolder)),
)
promptFiles = (
await Promise.all(
workspaceDirs.map((dir) =>
getPromptFiles(ide, path.join(dir, promptFolder ?? ".prompts")),
),
)
.flat()
.filter(({ path }) => path.endsWith(".prompt"));
}
)
.flat()
.filter(({ path }) => path.endsWith(".prompt"));

// Also read from ~/.continue/.prompts
promptFiles.push(...readAllGlobalPromptFiles());
Expand Down
43 changes: 41 additions & 2 deletions core/config/promptFile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IDE, SlashCommand } from "..";
import * as YAML from "yaml";
import type { IDE, SlashCommand } from "..";
import { stripImages } from "../llm/countTokens.js";
import { renderTemplatedString } from "../llm/llms/index.js";
import { getBasename } from "../util/index.js";
Expand Down Expand Up @@ -44,7 +44,16 @@ export function slashCommandFromPromptFile(
return {
name,
description,
run: async function* ({ input, llm, history, ide }) {
run: async function* ({
input,
llm,
history,
ide,
config,
fetch,
selectedCode,
addContextItem,
}) {
// Remove slash command prefix from input
let userInput = input;
if (userInput.startsWith(`/${name}`)) {
Expand All @@ -54,6 +63,35 @@ export function slashCommandFromPromptFile(
}

// Render prompt template
const helpers: [string, Handlebars.HelperDelegate][] | undefined =
config.contextProviders?.map((provider) => {
return [
provider.description.title,
async (context: any) => {
const items = await provider.getContextItems(context, {
embeddingsProvider: config.embeddingsProvider,
fetch,
fullInput: userInput,
ide,
llm,
reranker: config.reranker,
selectedCode,
});
items.forEach((item) =>
addContextItem({
...item,
id: {
itemId: item.description,
providerTitle: provider.description.title,
},
}),
);
return items.map((item) => item.content).join("\n\n");
},
];
});

// A few context providers that don't need to be in config.json to work in .prompt files
const diff = await ide.getDiff();
const currentFilePath = await ide.getCurrentFile();
const promptUserInput = await renderTemplatedString(
Expand All @@ -66,6 +104,7 @@ export function slashCommandFromPromptFile(
? await ide.readFile(currentFilePath)
: undefined,
},
helpers,
);

const messages = [...history];
Expand Down
17 changes: 11 additions & 6 deletions core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ export class Core {
configHandler: ConfigHandler,
abortedMessageIds: Set<string>,
msg: Message<ToCoreProtocol["command/run"][0]>,
messenger: IMessenger<ToCoreProtocol, FromCoreProtocol>,
) {
const {
input,
Expand Down Expand Up @@ -404,11 +405,10 @@ export class Core {
params,
ide,
addContextItem: (item) => {
// TODO
// protocol.request("addContextItem", {
// item,
// historyIndex,
// });
messenger.request("addContextItem", {
item,
historyIndex,
});
},
selectedCode,
config,
Expand All @@ -422,7 +422,12 @@ export class Core {
yield { done: true, content: "" };
}
on("command/run", (msg) =>
runNodeJsSlashCommand(this.configHandler, this.abortedMessageIds, msg),
runNodeJsSlashCommand(
this.configHandler,
this.abortedMessageIds,
msg,
this.messenger,
),
);

// Autocomplete
Expand Down
21 changes: 20 additions & 1 deletion core/llm/llms/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Handlebars from "handlebars";
import { v4 as uuidv4 } from "uuid";
import {
BaseCompletionOptions,
ILLM,
Expand Down Expand Up @@ -67,15 +68,33 @@ export async function renderTemplatedString(
template: string,
readFile: (filepath: string) => Promise<string>,
inputData: any,
helpers?: [string, Handlebars.HelperDelegate][],
): Promise<string> {
const promises: { [key: string]: Promise<string> } = {};
if (helpers) {
for (const [name, helper] of helpers) {
Handlebars.registerHelper(name, (...args) => {
const id = uuidv4();
promises[id] = helper(...args);
return `__${id}__`;
});
}
}

const [newTemplate, vars] = getHandlebarsVars(template);
const data: any = { ...inputData };
for (const key in vars) {
const fileContents = await readFile(vars[key]);
data[key] = fileContents || (inputData[vars[key]] ?? vars[key]);
}
const templateFn = Handlebars.compile(newTemplate);
const final = templateFn(data);
let final = templateFn(data);

await Promise.all(Object.values(promises));
for (const id in promises) {
final = final.replace(`__${id}__`, await promises[id]);
}

return final;
}

Expand Down
9 changes: 1 addition & 8 deletions core/protocol/ideWebview.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ContextItemWithId, ContextSubmenuItem } from "..";
import type { ContextSubmenuItem } from "..";
import type { RangeInFileWithContents } from "../commands/util";
import { ToIdeFromWebviewOrCoreProtocol } from "./ide.js";
import { ToWebviewFromIdeOrCoreProtocol } from "./webview.js";
Expand Down Expand Up @@ -38,13 +38,6 @@ export type ToIdeFromWebviewProtocol = ToIdeFromWebviewOrCoreProtocol & {
export type ToWebviewFromIdeProtocol = ToWebviewFromIdeOrCoreProtocol & {
setInactive: [undefined, void];
submitMessage: [{ message: any }, void]; // any -> JSONContent from TipTap
addContextItem: [
{
historyIndex: number;
item: ContextItemWithId;
},
void,
];
updateSubmenuItems: [
{ provider: string; submenuItems: ContextSubmenuItem[] },
void,
Expand Down
2 changes: 1 addition & 1 deletion core/protocol/passThrough.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ export const WEBVIEW_TO_CORE_PASS_THROUGH: (keyof ToCoreFromWebviewProtocol)[] =

// Message types to pass through from core to webview
export const CORE_TO_WEBVIEW_PASS_THROUGH: (keyof ToWebviewFromCoreProtocol)[] =
["configUpdate", "getDefaultModelTitle", "indexProgress"];
["configUpdate", "getDefaultModelTitle", "indexProgress", "addContextItem"];
9 changes: 8 additions & 1 deletion core/protocol/webview.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import type { IndexingProgressUpdate } from "..";
import type { ContextItemWithId, IndexingProgressUpdate } from "..";

export type ToWebviewFromIdeOrCoreProtocol = {
configUpdate: [undefined, void];
getDefaultModelTitle: [undefined, string];
indexProgress: [IndexingProgressUpdate, void];
refreshSubmenuItems: [undefined, void];
addContextItem: [
{
historyIndex: number;
item: ContextItemWithId;
},
void,
];
};
8 changes: 6 additions & 2 deletions docs/docs/walkthroughs/prompt-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,13 @@ To add a system message, start the body with `<system></system>` tags like in th
The body also supports templating with [Handlebars syntax](https://handlebarsjs.com/guide/). The following variables are currently available:

- `input`: The full text from the input box in the sidebar that is sent along with the slash command
- `diff`: The current git diff in your workspace
- `currentFile`: The currently open file in your IDE

We plan to add support soon for templating with all [context providers](../customization/context-providers.md).
#### Context providers

The body of a .prompt file also supports any [context provider](../customization/context-providers.md) that you have added to your config by referencing the name of the context provider.

For example, if you wanted to include the contents of the terminal in your prompt, then you would use `{{{terminal}}}` in your prompt file. If you wanted to use the "url" context provider to include the contents of https://github.com/continuedev/continue, you would use `{{{url "https://github.com/continuedev/continue"}}}`, where the second part is the argument to the context provider, separated by a space.

## Feedback

Expand Down

0 comments on commit 2ac8a46

Please sign in to comment.