Continue 源码分析
Continue
VS Code Extension

通过配置创建新的 Extension,用于区别于 Continue 。
{
  "name": "continue",
  "icon": "media/icon.png",
  "version": "0.9.218",
  "displayName": "LNSoft Continue",
  "description": "The leading open-source AI code assistant",
  "publisher": "LNSoft Continue"
}
入口
VS Code 扩展的起点是 activate.ts。activateExtension 这里的函数将注册所有命令,并将 Continue GUI 作为 webview 加载到 IDE 的侧边栏中。
配置
目录:extensions/vscode
package.json 由开发者手动创建和维护,主要用于定义项目的配置信息。
- configuration
 - commands
 - keybindings
 - menus
 - views
 
package-lock.json 由 npm 自动生成和更新,主要用于锁定依赖的具体版本,确保安装一致性。
国际化

可以通过使用 package.nls.json 文件来支持多语言。package.nls.json 文件包含了所有需要本地化的字符串,并且可以为不同的语言创建相应的翻译文件,如 package.nls.zh-cn.json。
- 步骤
    
- 在 package.json 中使用占位符: 在 package.json 文件中,用占位符(
%占位符%)替换需要本地化的字符串。 - 创建 package.nls.json 文件: 在扩展的根目录下创建 package.nls.json 文件,定义占位符和默认语言的映射。默认语言(通常是英文)的字符串。
 - 创建语言特定的翻译文件: 为每种语言创建一个翻译文件(
package.nls.<language>.json),如 package.nls.zh-cn.json,并提供相应的翻译。 
 - 在 package.json 中使用占位符: 在 package.json 文件中,用占位符(
 
{
  "name": "continue",
  "icon": "media/icon.png",
  "version": "0.9.191",
  "contributes": {
    "commands": [
      {
        "command": "continue.focusContinueInputWithoutClear",
        "category": "Continue",
        "title": "%focusContinueInputWithoutClear%",
        "group": "Continue"
      },
      {
        "command": "continue.toggleFullScreen",
        "category": "Continue",
        "title": "%toggleFullScreen%",
        "icon": "$(fullscreen)",
        "group": "Continue"
      },
      {
        "command": "continue.newSession",
        "category": "Continue",
        "title": "%newSession%",
        "icon": "$(add)",
        "group": "Continue"
      },
      {
        "command": "continue.viewHistory",
        "category": "Continue",
        "title": "%viewHistory%",
        "icon": "$(history)",
        "group": "Continue"
      },
      {
        "command": "continue.writeCommentsForCode",
        "category": "Continue",
        "title": "%writeCommentsForCode%",
        "group": "Continue"
      },
      {
        "command": "continue.writeDocstringForCode",
        "category": "Continue",
        "title": "%writeDocstringForCode%",
        "group": "Continue"
      },
      {
        "command": "continue.fixCode",
        "category": "Continue",
        "title": "%fixCode%",
        "group": "Continue"
      },
      {
        "command": "continue.optimizeCode",
        "category": "Continue",
        "title": "%optimizeCode%",
        "group": "Continue"
      }
    ]
}
package.nls.json
{
  "newSession": "New Session",
  "toggleFullScreen": "Toggle Full Screen",
  "viewHistory": "View History",
  "fixCode": "Fix this Code",
  "optimizeCode": "Optimize this Code",
  "writeDocstringForCode": "Write a Docstring for this Code",
  "writeCommentsForCode": "Write Comments for this Code",
  "focusContinueInputWithoutClear": "Add Highlighted Code to Context"
}
package.nls.zh-cn.json
{
  "newSession": "新会话",
  "toggleFullScreen": "切换全屏",
  "viewHistory": "查看历史记录",
  "fixCode": "修复代码",
  "optimizeCode": "优化代码",
  "writeDocstringForCode": "为此代码编写文档字符串",
  "writeCommentsForCode": "为此代码编写注释",
  "focusContinueInputWithoutClear": "将高亮显示的代码添加到上下文"
}
GUI
主界面
左边是主界面,不同的元素使用不同的颜色区分;右边是主界面中元素对应的组件或配置(颜色一致),通过 缩进 方式表示他们之间的包含关系。

路由
| 路径 | 组件 | 
|---|---|
| / | GUI | 
| /index.html | GUI | 
| /history | History | 
| /stats | Stats | 
| /help | Help | 
| /help | HelpPage | 
| /settings | SettingsPage | 
| /addModel | AddNewModel | 
| /addModel/provider/:providerName | ConfigureProvider | 
| /monaco | MonacoPage | 
| /onboarding | Onboarding | 
| /localOnboarding | LocalOnboarding | 
| /migration | MigrationPage | 
| /apiKeysOnboarding | ApiKeysOnboarding | 
| /apiKeyAutocompleteOnboarding | ApiKeyAutocompleteOnboarding | 
标题 & 图标
![]()
extensions/vscode/package.json
{
  "contributes": {
    "viewsContainers": {
      "activitybar": [
        {
          "id": "continue",
          "title": "Continue",
          "icon": "media/sidebar-icon.png"
        }
      ]
    },
    "views": {
      "continue": [
        {
          "type": "webview",
          "id": "continue.continueGUIView",
          "name": "",
          "visibility": "visible"
        }
      ]
    }
  }
}
在 Visual Studio Code 扩展中,viewsContainers 配置用于在活动栏(Activity Bar)中添加自定义视图容器。
菜单
通过编辑配置文件 package.json
WebView View/Title

{
  "contributes": {
    "menus": {
      "view/title": [
        {
          "command": "continue.newSession",
          "group": "navigation@1",
          "when": "view == continue.continueGUIView"
        },
        {
          "command": "continue.toggleFullScreen",
          "group": "navigation@1",
          "when": "view == continue.continueGUIView"
        },
        {
          "command": "continue.viewHistory",
          "group": "navigation@1",
          "when": "view == continue.continueGUIView"
        }
      ]
    }
  }
}
上下文菜单

{
  "contributes": {
    "menus": {
      "continue.continueSubMenu": [
        {
          "command": "continue.focusContinueInputWithoutClear",
          "group": "Continue",
          "when": "editorHasSelection"
        },
        {
          "command": "continue.writeCommentsForCode",
          "group": "Continue",
          "when": "editorHasSelection"
        },
        {
          "command": "continue.writeDocstringForCode",
          "group": "Continue",
          "when": "editorHasSelection"
        },
        {
          "command": "continue.fixCode",
          "group": "Continue",
          "when": "editorHasSelection"
        },
        {
          "command": "continue.optimizeCode",
          "group": "Continue",
          "when": "editorHasSelection"
        },
        {
          "command": "continue.fixGrammar",
          "group": "Continue",
          "when": "editorHasSelection && editorLangId == 'markdown'"
        }
      ]
    }
  }
}
Tab AutoComplete
getTabCompletion core/autocomplete/completionProvider.ts
使用 Ollama 设置
在 ~/.continue/config.json 文件中配置。
{
  "tabAutocompleteModel": {
    "title": "Tab Autocomplete",
    "provider": "ollama",
    "model": "codeqwen:7b",
    "apiKey": ""
  }
}
Tab AutoComplete 选项
默认 Tab AutoComplete 选项配置在代码:core/util/parameters.ts
{
  "tabAutocompleteOptions": {
    "multilineCompletions": "auto",
    "maxPromptTokens": 400
  }
}
- multilineCompletions 控制是否提供多行代码的自动补全
    
"always": 默认。总是在多行代码上提供自动补全"never": 从不在多行代码上提供自动补全"auto": 根据代码上下文自动决定是否提供多行代码的自动补全
 - maxPromptTokens 要使用的提示 Token 的最大数量。数字越小,完成速度越快,但上下文越少。
 
使用什么样的模型
建议用于自动完成的模型是使用高度特定的提示格式进行训练的,这使它们能够响应完成代码的请求。出色的自动完成不需要庞大的模型。大多数最先进的自动完成模型的参数不超过 10B,超过这个数字并不能显着提高性能。
| 模型 | 大小 | 
|---|---|
| deepseek-coder:1.3b-base | 1.3B | 
| starcoder2:3b | 3B | 
| deepseek-coder:6.7b-base | 6.7B | 
| codeqwen:7b | 7B | 
| deepseek-coder-v2:16b | 16B | 
| codestral:22b | 22B | 
支持编程语言
您需要支持编程语言,可以通过编辑代码:core/autocomplete/languages.ts
// TypeScript
export const Typescript = {
  name: "TypeScript",
  topLevelKeywords: ["function", "class", "module", "export", "import"],
  singleLineComment: "//",
  endOfLine: [";"],
};
// Python
export const Python = {
  name: "Python",
  // """"#" is for .ipynb files, where we add '"""' surrounding markdown blocks.
  // This stops the model from trying to complete the start of a new markdown block
  topLevelKeywords: ["def", "class", '"""#'],
  singleLineComment: "#",
  endOfLine: [],
};
// ...
export const LANGUAGES: { [extension: string]: AutocompleteLanguageInfo } = {
  ts: Typescript,
  js: Typescript,
  tsx: Typescript,
  jsx: Typescript,
  ipynb: Python,
  py: Python,
  pyi: Python,
  java: Java,
  cpp: Cpp,
  cxx: Cpp,
  h: Cpp,
  hpp: Cpp,
  cs: CSharp,
  c: C,
  scala: Scala,
  sc: Scala,
  go: Go,
  rs: Rust,
  hs: Haskell,
  php: PHP,
  rb: Ruby,
  rails: RubyOnRails,
  swift: Swift,
  kt: Kotlin,
  clj: Clojure,
  cljs: Clojure,
  cljc: Clojure,
  jl: Julia,
  fs: FSharp,
  fsi: FSharp,
  fsx: FSharp,
  fsscript: FSharp,
  r: R,
  R: R,
  dart: Dart,
  sol: Solidity,
  yaml: YAML,
  yml: YAML,
  md: Markdown,
};
Embedding Model
在配置文件 ~/.continue/config.json 中配置 transformers.js 模型,并不能生效,目前没有指定模型的功能。
{
  "embeddingsProvider": {
    "provider": "transformers.js",
    "model": "bge-small-zh-v1.5"  // 无效
  },
}
可以通过文件 core/indexing/embeddings/TransformersJsEmbeddingsProvider.ts 修改来指定中文模型 bge-small-zh-v1.5。
  static model: string = "bge-small-zh-v1.5";
两处都要修改
transformers.js 支持的模型
- jina-embeddings-v2-base-zh
 - bge-small-zh-v1.5
 - bge-base-zh-v1.5
 - bge-large-zh-v1.5
 - all-MiniLM-L6-v2
 - bge-base-en-v1.5
 
Slash Command
Slash 命令接口,定义在 core/index.d.ts 中,需要您定义一个 name(用于调用命令的文本),一个 description(在 slash 命令菜单中显示的文本)和一个在调用命令时将被调用的 run 函数。run 函数是一个异步生成器,它产生要在聊天中显示的内容。run 函数传递了一个 ContinueSDK 对象,可以用它与 IDE 交互,调用 LLM,并查看聊天历史,以及其他一些实用程序。
export interface SlashCommand {
  name: string;
  description: string;
  params?: { [key: string]: any };
  run: (sdk: ContinueSDK) => AsyncGenerator<string | undefined>;
}
在 core/commands/slash 中有许多示例的斜杠命令,我们建议从中借鉴。一旦您在此文件夹中创建了新的 SlashCommand,请确保完成以下操作:
- 将您的命令添加到 core/commands/slash/index.ts 中的数组中
 - 将您的命令添加到 config_schema.json 中的列表中。这样可以确保智能感知在用户编辑 
config.json时显示您的提供程序可用的命令。如果您的命令接受任何参数,您还应该按照现有示例将它们添加到 JSON 模式中。 
编写内建 Slash Command:翻译中文(/tr)
增加文件 core/commands/slash/translate.ts,并在其中添加以下内容:
import { SlashCommand } from "../../index.js";
import { stripImages } from "../../llm/countTokens.js";
const TranslateChineseCommand: SlashCommand = {
  name: "tr",
  description: "Translate to Chinese",
  run: async function* ({ ide, llm, input }) {
    if (input.trim() === "") {
      yield "Please enter the text you want to translate into Chinese.";
      return;
    }
    // input = '/tr hello world' => 'hello world'
    input = input.replace("/tr", "").trim();
    const prompt = `The text the user wants to translate is:
"${input}"
Please translate into Chinese. Your output should contain only the corresponding Chinese, without any explanation or other output.`;
    for await (const chunk of llm.streamChat([
      { role: "user", content: prompt },
    ])) {
      yield stripImages(chunk.content);
    }
  },
};
export default TranslateChineseCommand;
修改文件 core/commands/slash/index.ts,并在其中添加以下内容:
//...
import TranslateChineseCommand from "./translate.js";
export default [
  //...
  TranslateChineseCommand,
];
LLM Providers
Adding an LLM Provider
Continue 支持十几种不同的 LLM “providers”,使得在 OpenAI、Ollama、Together、LM Studio、Msty 等平台上运行模型变得容易。你可以在这里找到所有现有的 providers,如果你发现缺少某个 provider,可以按照以下步骤添加:
- 在 core/llm/llms 目录中创建一个新文件。文件名应为 provider 的名称,并且应导出一个扩展自 BaseLLM 的类。这个类应包含以下最小实现。我们建议查看现有的 providers 以获取更多详细信息。LlamaCpp Provider 是一个很好的简单示例。
    
- providerName - 你的 provider 的标识符
 - 至少一个 _streamComplete 或 _streamChat - 这是向 API 发出请求并返回流响应的函数。你只需要实现其中一个,因为 Continue 可以在 “chat” 和 “raw completion” 之间自动转换。
 
 - 将你的 provider 添加到 core/llm/llms/index.ts 中的 LLMs 数组中。
 - 如果你的 provider 支持图像,将其添加到 core/llm/index.ts 中的 PROVIDER_SUPPORTS_IMAGES 数组中。
 - 将必要的 JSON Schema 类型添加到 config_schema.json 中。这确保了当用户编辑 config.json 时,Intellisense 会显示你的 provider 可用的选项。
 - 在 docs/docs/reference/Model Providers 中为你的 provider 添加一个文档页面。这应该展示在 config.json 中配置你的 provider 的示例,并解释可用的选项。
 
Context Providers
ContextProvider 是一个 Continue 插件,可以通过输入 @ 来快速选择文档作为语言模型的上下文。 IContextProvider 接口在 core/index.d.ts 中定义,但所有内置上下文提供程序都扩展于 BaseContextProvider。
export interface IContextProvider {
  get description(): ContextProviderDescription;
  getContextItems(
    query: string,
    extras: ContextProviderExtras,
  ): Promise<ContextItem[]>;
  loadSubmenuItems(args: LoadSubmenuItemsArgs): Promise<ContextSubmenuItem[]>;
}
export abstract class BaseContextProvider implements IContextProvider {
  options: { [key: string]: any };
  constructor(options: { [key: string]: any }) {
    this.options = options;
  }
  static description: ContextProviderDescription;
  get description(): ContextProviderDescription {
    return (this.constructor as any).description;
  }
  // Maybe just include the chat message in here. Should never have to go back to the context provider once you have the information.
  abstract getContextItems(
    query: string,
    extras: ContextProviderExtras,
  ): Promise<ContextItem[]>;
  async loadSubmenuItems(
    args: LoadSubmenuItemsArgs,
  ): Promise<ContextSubmenuItem[]> {
    return [];
  }
}
在定义上下文提供程序之前,请确定要创建哪种 "type"。
"query"类型在选择时将显示一个小文本输入,使用户有机会输入类似 Google 搜索查询的 GoogleContextProvider 内容。"submenu"类型将打开一个可以搜索和选择的项目子菜单。示例包括 GitHubIssuesContextProvider 和 DocsContextProvider。"normal"类型将立即添加上下文项。示例包括 DiffContextProvider 和 OpenFilesContextProvider。
编写您的上下文提供程序,请确保完成以下操作:
- 将其添加到 core/context/providers/index.ts 中的上下文提供程序数组中
 - 将其添加到 core/index.d.ts 中的 
ContextProviderName类型 - 将其添加到 config_schema.json 中的列表中。
 
Prompt files
Prompt (.prompt) 文件是构建和与他人共享 LLM 提示的简单方法。该格式的灵感来自 HumanLoops 的 .prompt 文件。保存在目录 extensions/vscode/.prompts 里。
语法
Preamble
--- 分隔符上方的所有内容,可让您指定模型参数。它使用 YAML 语法,目前支持以下参数:
- temperature
 - topP
 - topK
 - minP
 - presencePenalty
 - frequencyPenalty
 - mirostat
 - stop
 - maxTokens
 - name
 - description
 
如果不需要任何这些参数,则可以省略 “Preamble”,并且不需要包含 --- 分隔符。
Body
--- 分隔符下方的所有内容,包含您的提示。正文可以只是文本。
要添加系统消息,以 <system></system> 标签开始正文,并将系统消息放入其中。
Body 支持使用 Handlebars 语法 进行模板化。当前可用的变量如下:
- input:侧边栏输入框中的全文,与斜杠命令一起发送
 - currentFile:IDE 中当前打开的文件(目前只支持打开一个文件时有用)
 
Context providers
.prompt 文件的 Body 还支持您通过引用上下文提供程序的名称添加到配置中的 Context providers。
如果您想要使用 url 上下文提供程序来包含 https://github.com/continuedev/continue 的内容,您将使用},其中第二部分是上下文提供程序的参数,用空格分隔。
文本生成 SQL 语句
n2sql.prompt 文件
temperature: 0.5
maxTokens: 1024
name: n2sql
description: 文本生成 SQL 语句
---
<system>
你是一名数据库专家。根据以下表结构帮助用户编写 SQL 语句。
CREATE TABLE yxdsj_wshbb_gdfw_day(
  prov_name varchar(200) DEFAULT NULL COMMENT '省公司名称',
  city_name varchar(200) DEFAULT NULL COMMENT '地市公司名称',
  county_name varchar(200) DEFAULT NULL COMMENT '区县公司名称',
  tousu int(11) DEFAULT NULL COMMENT '投诉数量',
  yijian int(11) DEFAULT NULL COMMENT '意见数量',
  acpt_time varchar(200) DEFAULT NULL COMMENT '受理时间',
  tousu_bwhl  varchar(200) DEFAULT NULL COMMENT '投诉百万户量',
  yijian_bwhl  varchar(200) DEFAULT NULL COMMENT '意见百万户量'
)
</system>
}
根据上面的输入生成 SQL 语句

起名字
name.prompt 文件
temperature: 0.5
maxTokens: 256
name: name
description: 起名字
---
<system>
你是一名起名字的专家
</system>
}
根据上面的输入起名字
- 起一个有意义的名字
- 提示至少三个名字
- 名字应该有创意

总结网页内容
url.prompt 文件
temperature: 0.5
maxTokens: 4096
name: url
description: 总结网页信息
---
<system>
你是一名专业的文学家,你需要总结网页的信息。
</system>
}
总结:

Quick Actions
快速操作使用 CodeLens 提供程序在代码中的函数和类上方添加交互元素。代码参考:extensions/vscode/src/lang-server/codeLens/providers/QuickActionsCodeLensProvider.ts

启用/禁用快速操作
要禁用快速操作,请打开设置菜单 (⌘ + ,),搜索"continue.enableQuickActions",然后切换复选框以禁用。
自定义快速操作
通过 ~/.continue/config.json 文件配置自定义快速操作。
单元测试
在选定的代码上方生成并插入单元测试的快速操作。
{
  "experimental": {
    "quickActions": [
      {
        "title": "Unit test",
        "prompt": "Write a unit test for this code. Do not change anything about the code itself.",
      }
    ]
  }
}
详细解释
将提示和代码发送到聊天面板,以提供详细解释。
{
  "experimental": {
    "quickActions": [
      {
        "title": "Detailed explanation",
        "prompt": "Explain the following code in detail, including all methods and properties.",
        "sendToChat": true
      }
    ]
  }
}
编程语言支持
对于您打开的文件的语言,您必须安装语言服务器协议(Language Server Protocol)扩展。
| 语言 | 扩展 | 
|---|---|
| JavaScript | JavaScript and TypeScript Nightly | 
| TypeScript | JavaScript and TypeScript Nightly | 
| Python | Python | 
| Java | Language Support for Java(TM) by Red Hat | 
| C/C++ | C/C++ | 
| Rust | rust-analyzer |