构建你自己的上下文提供者
入门示例
要编写自己的上下文提供者,您只需实现 CustomContextProvider 接口:
interface CustomContextProvider {
title: string;
displayTitle?: string;
description?: string;
renderInlineAs?: string;
type?: ContextProviderType;
getContextItems(
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]>;
loadSubmenuItems?: (
args: LoadSubmenuItemsArgs,
) => Promise<ContextSubmenuItem[]>;
}
举个例子,假设你有一组内部文档已经被索引到一个向量数据库中。你已经设置了一个简单的REST API,允许内部用户查询并获取相关的片段。这个上下文提供者将把查询发送到这个服务器,并从向量数据库中返回结果。getContextItems的返回类型必须是一个对象数组,这些对象具有以下所有属性:
name: 上下文项的名称,将显示为标题description: 上下文项目的详细描述content: 上下文项的实际内容,将作为上下文输入到LLM中
const RagContextProvider: CustomContextProvider = {
title: "rag",
displayTitle: "RAG",
description:
"Retrieve snippets from our vector database of internal documents",
getContextItems: async (
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]> => {
const response = await fetch("https://internal_rag_server.com/retrieve", {
method: "POST",
body: JSON.stringify({ query }),
});
const results = await response.json();
return results.map((result) => ({
name: result.title,
description: result.title,
content: result.contents,
}));
},
};
然后可以像这样添加到 config.ts 中:
export function modifyConfig(config: Config): Config {
if (!config.contextProviders) {
config.contextProviders = [];
}
config.contextProviders.push(RagContextProvider);
return config;
}
不需要修改config.json。
带有子菜单或查询的自定义上下文提供者
有三种类型的上下文提供者:"normal"、"query"和"submenu"。"normal"类型是默认的,也是我们目前所见到的。
"query" 类型用于当您想向用户显示一个文本框,然后使用该文本框的内容生成上下文项时。内置示例包括 "search" 和 "google"。此文本将传递给 getContextItems 中的 "query" 参数。要实现一个 "query" 上下文提供者,只需在您的自定义上下文提供者对象中设置 "type": "query"。
"submenu" 类型用于在下拉菜单中显示可搜索的项目列表。内置示例包括 "issue" 和 "folder"。要实现 "submenu" 上下文提供程序,请设置 "type": "submenu" 并实现 loadSubmenuItems 和 getContextItems 函数。以下是一个显示当前工作区中所有 README 文件列表的示例:
const ReadMeContextProvider: CustomContextProvider = {
title: "readme",
displayTitle: "README",
description: "Reference README.md files in your workspace",
type: "submenu",
getContextItems: async (
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]> => {
// 'query' is the filepath of the README selected from the dropdown
const content = await extras.ide.readFile(query);
return [
{
name: getFolder(query),
description: getFolderAndBasename(query),
content,
},
];
},
loadSubmenuItems: async (
args: LoadSubmenuItemsArgs,
): Promise<ContextSubmenuItem[]> => {
const { ide } = args;
// Filter all workspace files for READMEs
const workspaceDirs = await ide.getWorkspaceDirs()
const allFiles = await Promise.all(
workspaceDirs.map(dir => ide.subprocess(`find ${dir} -name "README.md"`)),
);
// 'readmes' now contains an array of file paths for each README.md file found in the workspace,
// excluding those in 'node_modules'
const readmes = allFiles
.flatMap(mds => mds[0].split("\n"))
.filter(file => file.trim() !== '' && !file.includes("/node_modules/"))
// Return the items that will be shown in the dropdown
return readmes.map((filepath) => {
return {
id: filepath,
title: getFolder(filepath),
description: getFolderAndBasename(filepath),
};
});
},
};
export function modifyConfig(config: Config): Config {
if (!config.contextProviders) {
config.contextProviders = [];
}
config.contextProviders.push(ReadMeContextProvider);
return config;
}
function getFolder(path: string): string {
return path.split(/[\/\\]/g).slice(-2)[0];
}
function getFolderAndBasename(path: string): string {
return path
.split(/[\/\\]/g)
.slice(-2)
.join("/");
}
上述示例中的信息流如下:
- 用户输入
@readme并从下拉菜单中选择它,现在显示子菜单,他们可以在其中搜索由loadSubmenuItems返回的任何项目。 - 用户从子菜单中选择一个README,输入其余的内容,然后按下回车键。
- 所选
ContextSubmenuItem的id作为query参数传递给getContextItems。在这种情况下,它是README的文件路径。 - 然后,
getContextItems函数可以使用query来检索 README 的完整内容,并在返回将包含在提示中的上下文项之前格式化内容。
导入外部模块
要在你的config.ts中包含外部的Node模块,请从~/.continue目录运行npm install ,然后在config.ts中导入它们。
Continue 将使用 esbuild 将您的 config.ts 和任何依赖项打包成一个单一的 Javascript 文件。使用的确切配置可以在 这里 找到。
CustomContextProvider 参考
title: 上下文提供者的标识符displayTitle(可选): 下拉菜单中显示的标题description(可选):当悬停时在下拉菜单中显示的较长描述type(可选): 上下文提供者的类型。选项为 "normal"、"query" 和 "submenu"。默认为 "normal"。renderInlineAs(可选):将在提示顶部内联渲染的字符串。如果未提供值,则将使用displayTitle。可以提供空字符串以防止渲染默认的displayTitle。getContextItems: 一个返回要包含在提示中的文档的函数。它应该返回一个ContextItem的列表,并且可以访问以下参数:extras.fullInput: 一个表示用户输入到文本框中的完整内容的字符串。例如,可以用于生成嵌入以与其他嵌入文档进行比较extras.embeddingsProvider: 嵌入提供者有一个embed函数,可以将文本(如fullInput)转换为嵌入extras.llm: 当前的默认LLM,您可以使用它来发出完成请求extras.ide:IDE类的一个实例,它允许您从IDE中收集各种信息源,包括终端的内容、打开的文件列表或当前打开文件中的任何警告。query: (当前未使用)一个表示查询的字符串
loadSubmenuItems(可选):一个返回要在子菜单中显示的ContextSubmenuItem列表的函数。它可以访问传递给getContextItems的IDE。
用其他语言编写上下文提供者
如果你想用TypeScript以外的语言编写上下文提供者,你可以使用"http"上下文提供者来调用托管你自己代码的服务器。像这样将上下文提供者添加到config.json中:
{
"name": "http",
"params": {
"url": "https://myserver.com/context-provider",
"title": "http",
"description": "Custom HTTP Context Provider",
"displayTitle": "My Custom Context",
"options": {}
}
}
然后,创建一个服务器,响应从HttpContextProvider.ts发出的请求。查看context_provider_server.py中的hello端点,这是一个使用FastAPI的示例。
"options" 属性可用于向您的端点发送额外的参数,这些参数将包含在请求体中。
VSCode 扩展 API
Continue 提供了一个 API,用于从第三方 VSCode 扩展注册上下文提供者。如果你有一个 VSCode 扩展,提供了你希望在 Continue 中使用的一些额外上下文,这将非常有用。要使用此 API,请将以下内容添加到你的 package.json 中:
{
"extensionDependencies": ["continue.continue"]
}
或者从 npm 安装 Continue Core 模块:
npm i @continuedev/core
您可以在package.json中将Continue核心模块添加为开发依赖项:
{
"devDependencies": {
"@continuedev/core": "^0.0.1"
}
}
然后,你可以使用registerCustomContextProvider函数来注册你的上下文提供者。你的自定义上下文提供者必须实现IContextProvider接口。
以下是一个示例:
import * as vscode from "vscode";
import {
IContextProvider,
ContextProviderDescription,
ContextProviderExtras,
ContextItem,
LoadSubmenuItemsArgs,
ContextSubmenuItem,
} from "@continuedev/core";
class MyCustomProvider implements IContextProvider {
get description(): ContextProviderDescription {
return {
title: "Custom",
displayTitle: "Custom",
description: "my custom context provider",
type: "normal",
};
}
async getContextItems(
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]> {
return [
{
name: "Custom",
description: "Custom description",
content: "Custom content",
},
];
}
async loadSubmenuItems(
args: LoadSubmenuItemsArgs,
): Promise<ContextSubmenuItem[]> {
return [];
}
}
// create an instance of your custom provider
const customProvider = new MyCustomProvider();
// get Continue extension using vscode API
const continueExt = vscode.extensions.getExtension("Continue.continue");
// get the API from the extension
const continueApi = continueExt?.exports;
// register your custom provider
continueApi?.registerCustomContextProvider(customProvider);
这将注册MyCustomProvider到Continue!
