Context Providers
Context Providers allow you to type '@' and see a dropdown of content that can all be fed to the LLM as context. Every context provider is a plugin, which means if you want to reference some source of information that you don't see here, you can request (or build!) a new context provider.
As an example, say you are working on solving a new GitHub Issue. You type '@issue' and select the one you are working on. Continue can now see the issue title and contents. You also know that the issue is related to the files 'readme.md' and 'helloNested.py', so you type '@readme' and '@hello' to find and select them. Now these 3 "Context Items" are displayed inline with the rest of your input.
Built-in Context Providersβ
To use any of the built-in context providers, open ~/.continue/config.json
and add it to the contextProviders
list.
Filesβ
Type '@file' to reference any file in your current workspace.
{ "name": "file" }
Codeβ
Type '@code' to reference specific functions or classes from throughout your project.
{ "name": "code" }
Git Diffβ
Type '@diff' to reference all of the changes you've made to your current branch. This is useful if you want to summarize what you've done or ask for a general review of your work before committing.
{ "name": "diff" }
Terminalβ
Type '@terminal' to reference the contents of your IDE's terminal.
{ "name": "terminal" }
Documentationβ
Type @docs
to index and retrieve snippets from any documentation site. You can add any site by selecting "Add Docs" in the dropdown, then entering the root URL of the documentation site and a title to remember it by. After the site has been indexed, you can type @docs
, select your documentation from the dropdown, and Continue will use similarity search to automatically find important sections when answering your question.
{ "name": "docs" }
Continue also pre-indexes a number of common sites, listed here. The embeddings for these sites are hosted by us, but downloaded for local use after the first time. All other indexing occurs entirely locally.
Adding a Documentation Site via Configurationβ
To add a documentation site via configuration, update the config.json
file as follows:
{
"name": "docs",
"params": {
"sites": [
{
"title": "ExampleDocs",
"startUrl": "https://exampledocs.com/docs",
"rootUrl": "https://exampledocs.com",
"maxDepth": 3 // Default
}
]
}
}
The docs are indexed when you modify the configuration file, unless indexing is disabled. If you want to manually trigger the indexing, you can use the command Continue: Docs Index
. For force indexing, you can use the command Continue: Docs Force Re-Index
. Note that these commands will work even if automatic indexing is disabled.
Open Filesβ
Type '@open' to reference the contents of all of your open files. Set onlyPinned
to true
to only reference pinned files.
{ "name": "open", "params": { "onlyPinned": true } }
Codebase Retrievalβ
Type '@codebase' to automatically retrieve the most relevant snippets from your codebase. Read more about indexing and retrieval here.
{ "name": "codebase" }
Foldersβ
Type '@folder' to use the same retrieval mechanism as '@codebase', but only on a single folder.
{ "name": "folder" }
Exact Searchβ
Type '@search' to reference the results of codebase search, just like the results you would get from VS Code search. This context provider is powered by ripgrep.
{ "name": "search" }
URLβ
Type '@url' and input a URL, then Continue will convert it to a markdown document to pass to the model.
{ "name": "url" }
File Treeβ
Type '@tree' to reference the structure of your current workspace. The LLM will be able to see the nested directory structure of your project.
{ "name": "tree" }
Googleβ
Type '@google' to reference the results of a Google search. For example, type "@google python tutorial" if you want to search and discuss ways of learning Python.
{
"name": "google",
"params": { "serperApiKey": "<your serper.dev api key>" }
}
Note: You can get an API key for free at serper.dev.
GitHub Issuesβ
Type '@issue' to reference the conversation in a GitHub issue. Make sure to include your own GitHub personal access token to avoid being rate-limited:
{
"name": "issue",
"params": {
"repos": [
{
"owner": "continuedev",
"repo": "continue"
}
],
"githubToken": "ghp_xxx"
}
}
GitLab Merge Requestβ
Type @gitlab-mr
to reference an open MR for this branch on GitLab.
Configurationβ
You will need to create a personal access token with the read_api
scope. then add the following to your configuration:
{
"name": "gitlab-mr",
"params": {
"token": "..."
}
}
Using Self-Hosted GitLabβ
You can specify the domain to communicate with by setting the domain
parameter in your configurtion. By default this is set to gitlab.com
.
{
"name": "gitlab-mr",
"params": {
"token": "...",
"domain": "gitlab.example.com"
}
}
Filtering Commentsβ
If you select some code to be edited, you can have the context provider filter out comments for other files. To enable this feature, set filterComments
to true
.
Jira Issuesβ
Type '@jira' to reference the conversation in a Jira issue. Make sure to include your own Atlassian API Token, or use your email
and token
, with token set to your password for basic authentication. If you use your own Atlassian API Token, don't configure your email.
{
"name": "jira",
"params": {
"domain": "company.atlassian.net",
"token ": "ATATT..."
}
}
Jira Datacenter Supportβ
This context provider supports both Jira API version 2 and 3. It will use version 3 by default since
that's what the cloud version uses, but if you have the datacenter version of Jira, you'll need
to set the API Version to 2 using the apiVersion
property.
"params": {
"apiVersion": "2",
...
}
Issue Queryβ
By default, the following query will be used to find issues:
assignee = currentUser() AND resolution = Unresolved order by updated DESC
You can override this query by setting the issueQuery
parameter.
PostgreSQLβ
Type @postgres
to reference the schema of a table, and some sample rows. A dropdown will appear, allowing you to select a specific table, or all tables.
The only required settings are those for creating the database connection: host
, port
, user
, password
, and database
.
By default, the schema
filter is set to public
, and the sampleRows
is set to 3. You may unset the schema if you want to include tables from all schemas.
{
"name": "postgres",
"params": {
"host": "localhost",
"port": 5436,
"user": "myuser",
"password": "catsarecool",
"database": "animals",
"schema": "public",
"sampleRows": 3
}
}
Database Tablesβ
Type @database
to reference table schemas you can use the drop-down or start typeing table names based off of your configuration. Configuration supports multiple databases, allowing you to specify various connection details for PostgreSQL, MySQL, SQLite. Each connection should include a unique name, the connection_type (e.g., postgres, sqlite), and the necessary connection parameters specific to each database type.
{
"name": "database",
"params": {
"connections": [
{
"name": "examplePostgres",
"connection_type": "postgres",
"connection": {
"user": "username",
"host": "localhost",
"database": "exampleDB",
"password": "yourPassword",
"port": 5432
}
},
{
"name": "exampleSqlite",
"connection_type": "sqlite",
"connection": {
"filename": "/path/to/your/sqlite/database.db"
}
}
]
}
}
Debugger: Local Variablesβ
Type @locals
to reference the contents of the local variables with top n level (defaulting to 3) of call stack for that thread. A dropdown will appear, allowing you to select a specific thread to see the local variables in that thread.
{
"name": "locals",
"params": {
"stackDepth": 3
}
}
Operating Systemβ
Type @os
to reference the architecture and platform of your current operating system.
{ "name": "os" }
Requesting Context Providersβ
Not seeing what you want? Create an issue here to request a new ContextProvider.
Building Your Own Context Providerβ
Introductory Exampleβ
To write your own context provider, you just have to implement the CustomContextProvider
interface:
interface CustomContextProvider {
title: string;
displayTitle?: string;
description?: string;
renderInlineAs?: string;
type?: ContextProviderType;
getContextItems(
query: string,
extras: ContextProviderExtras,
): Promise<ContextItem[]>;
loadSubmenuItems?: (
args: LoadSubmenuItemsArgs,
) => Promise<ContextSubmenuItem[]>;
}
As an example, let's say you have a set of internal documents that have been indexed in a vector database. You've set up a simple REST API that allows internal users to query and get back relevant snippets. This context provider will send the query to this server and return the results from the vector database. The return type of getContextItems
must be an array of objects that have all of the following properties:
name
: The name of the context item, which will be displayed as a titledescription
: A longer description of the context itemcontent
: The actual content of the context item, which will be fed to the LLM as context
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,
}));
},
};
It can then be added in config.ts
like so:
export function modifyConfig(config: Config): Config {
if (!config.contextProviders) {
config.contextProviders = [];
}
config.contextProviders.push(RagContextProvider);
return config;
}
No modification in config.json
is necessary.
Custom Context Providers with Submenu or Queryβ
There are 3 types of context providers: "normal", "query", and "submenu". The "normal" type is the default, and is what we've seen so far.
The "query" type is used when you want to display a text box to the user, and then use the contents of that text box to generate the context items. Built-in examples include "search" and "google". This text is what gets passed to the "query" argument in getContextItems
. To implement a "query" context provider, simply set "type": "query"
in your custom context provider object.
The "submenu" type is used when you want to display a list of searchable items in the dropdown. Built-in examples include "issue" and "folder". To implement a "submenu" context provider, set "type": "submenu"
and implement the loadSubmenuItems
and getContextItems
functions. Here is an example that shows a list of all README files in the current workspace:
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[]> => {
// Filter all workspace files for READMEs
const allFiles = await args.ide.listWorkspaceContents();
const readmes = allFiles.filter((filepath) =>
filepath.endsWith("README.md"),
);
// 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("/");
}
The flow of information in the above example is as follows:
- The user types
@readme
and selects it from the dropdown, now displaying the submenu where they can search for any item returned byloadSubmenuItems
. - The user selects one of the READMEs in the submenu, enters the rest of their input, and presses enter.
- The
id
of the chosenContextSubmenuItem
is passed togetContextItems
as thequery
argument. In this case it is the filepath of the README. - The
getContextItems
function can then use thequery
to retrieve the full contents of the README and format the content before returning the context item which will be included in the prompt.
Importing outside modulesβ
To include outside Node modules in your config.ts, run npm install <module_name>
from the ~/.continue
directory, and then import them in config.ts.
Continue will use esbuild to bundle your config.ts
and any dependencies into a single Javascript file. The exact configuration used can be found here.
CustomContextProvider
Referenceβ
title
: An identifier for the context providerdisplayTitle
(optional): The title displayed in the dropdowndescription
(optional): The longer description displayed in the dropdown when hoveredtype
(optional): The type of context provider. Options are "normal", "query", and "submenu". Defaults to "normal".renderInlineAs
(optional): The string that will be rendered inline at the top of the prompt. If no value is provided, thedisplayTitle
will be used. An empty string can be provided to prevent rendering the defaultdisplayTitle
.getContextItems
: A function that returns the documents to include in the prompt. It should return a list ofContextItem
s, and is given access to the following arguments:extras.fullInput
: A string representing the user's full input to the text box. This can be used for example to generate an embedding to compare against a set of other embedded documentsextras.embeddingsProvider
: The embeddings provider has anembed
function that will convert text (such asfullInput
) to an embeddingextras.llm
: The current default LLM, which you can use to make completion requestsextras.ide
: An instance of theIDE
class, which lets you gather various sources of information from the IDE, including the contents of the terminal, the list of open files, or any warnings in the currently open file.query
: (not currently used) A string representing the query
loadSubmenuItems
(optional): A function that returns a list ofContextSubmenuItem
s to display in a submenu. It is given access to anIDE
, the same that is passed togetContextItems
.
Writing Context Providers in Other Languagesβ
If you'd like to write a context provider in a language other than TypeScript, you can use the "http" context provider to call a server that hosts your own code. Add the context provider to config.json
like this:
{
"name": "http",
"params": {
"url": "https://myserver.com/context-provider",
"title": "http",
"description": "Custom HTTP Context Provider",
"displayTitle": "My Custom Context"
}
}
Then, create a server that responds to requests as are made from HttpContextProvider.ts. See the hello
endpoint in context_provider_server.py for an example that uses FastAPI.
Extension API for VSCodeβ
Continue exposes an API for registering context providers from a 3rd party VSCode extension. This is useful if you have a VSCode extension that provides some additional context that you would like to use in Continue. To use this API, add the following to your package.json
:
{
"extensionDependencies": ["continue.continue"]
}
Or copy ~/.continue/type/core/index.d.ts
to your extension repository.
Then, you can use the registerCustomContextProvider
function to register your context provider. Your custom context provider must implement the IContextProvider
interface.
Here is an example:
import * as vscode from "vscode";
class MyCustomProvider implements IContextProvider {
get description(): ContextProviderDescription {
return {
title: "custom",
displayTitle: "Custom",
description: "Custom description",
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);