Continue

一句话定位

Continue 的 cn 是一个模型无关、单主 agent 顺序循环的开源命令行 coding agent。官方定位(docs.continue.dev/guides/cli):“cn is an open-source, modular coding agent for the command line. It provides a battle-tested agent loop so you can simply plug in your model, rules, and tools.” 它的工程重心不在编排复杂度,而在权限与命令级安全:三态权限模型 + 三种权限 mode + 一个 1241 行的 Bash 命令静态安全评估器 + human-in-the-loop 审批门,构成整个 harness 的主防线。无沙箱隔离、无跨会话长期记忆、无自进化、轨迹不反哺训练。

核心架构总览(目录结构关键路径 + 引用的 commit)

分析基于 commit d0a3c0b626b5bebc3bef4742eec05a0242be0bab(2026-06-18,--depth 1 克隆于 2026-07-11,仓库 3057 files / 34.8k★)。

Continue 是 monorepo,agent harness 本体在 extensions/cli/(npm 包 @continuedev/cli,bin=cndist/cn.js),不在 core/(那是 IDE 侧共享内核)。关键路径:

  • extensions/cli/src/ — CLI harness 全部逻辑(agent loop / tools / permissions / subagent / compaction / services)
  • extensions/cli/src/stream/streamChatResponse.ts — 主循环
  • extensions/cli/src/tools/ — 工具定义、注册、执行、子 agent、skills
  • extensions/cli/src/permissions/ — 权限模型
  • extensions/cli/src/compaction.ts — 上下文压缩
  • extensions/cli/src/systemMessage.ts — 系统提示动态组装
  • packages/terminal-security/src/evaluateTerminalCommandSecurity.ts — 独立包,Bash 命令静态安全评估器(1241 行)
  • packages/openai-adapters/ — 统一 LLM 客户端 BaseLlmApi(OpenAI 兼容层 + 各家 provider adapter)
  • extensions/vscode/extensions/intellij/ — IDE 插件,非本次重点

CLI 复用 core/ 的一部分类型(core/index.jscore/util/messageConversion.js),但 loop / 工具 / 权限逻辑均在 extensions/cli/ 自成一体。

Agent Loop(主循环 / 何时继续何时停)

主循环是 streamChatResponse()extensions/cli/src/stream/streamChatResponse.tswhile (true) 见 snapshot :443)。每轮:

  1. ChatHistoryService 刷新 history
  2. 按当前权限 mode 取 system message(每轮重取,因为 mode 可在 streaming 中途切换)
  3. 每轮重算可用工具getRequestTools
  4. pre-API 压缩检查
  5. processStreamingResponse() 拿 LLM 流式响应
  6. handleToolCalls() 执行工具、写回 history
  7. post-tool 压缩校验 + normal 压缩检查

继续/停机条件shouldContinue = validToolCalls.length > 0。即只要模型这一轮产生了 tool call 就继续循环,产生纯文本(无 tool call)就停if (!shouldContinue && !shouldAutoContinue) break)。这是经典的 “LLM 决定何时收尾”——没有硬性 max-steps 上限

一个特殊的自动续跑:若本轮发生了压缩且模型本想停,会自动注入一条 user “continue” 消息强制继续(handleAutoContinuation),跑完复位 flag 防死循环——避免”压缩刚发生就误停”。

headless 模式返回 finalResponse(仅最后答案),TUI 返回 fullResponse。循环内无独立 planner/orchestrator,是单 agent 顺序循环。

记忆与上下文管理(压缩、长期记忆、会话持久化)

自动压缩(compaction) compaction.ts

  • 触发阈值 shouldAutoCompact():266):contextLimit - maxTokens - buffer,其中 buffer = min(max(maxTokens, (1 - RATIO) * (ctx - max)), CAP)AUTO_COMPACT_BUFFER_RATIO = 0.8AUTO_COMPACT_BUFFER_CAP = 15_000compaction.ts:19-20)。即约 80% 上下文占用触发
  • compactChatHistory():给整段历史追加固定 COMPACTION_PROMPT(“provide a concise summary … so you can continue exactly where you left off”),调 LLM 生成摘要,产出 compactedHistory = [systemMessage, {role:assistant, conversationSummary}],用 conversationSummary 字段标记压缩点。
  • getHistoryForLLM():发给 LLM 时只取 system + 压缩点之后的消息。
  • 循环里三处压缩钩子:pre-API / post-tool / normal。
  • 兜底 pruneLastMessage():即便压缩后仍超长,逐条从尾部丢弃直到 fit。

会话持久化 session.ts:本地落盘 ~/.continue/sessions/<sessionId>.json(dir 由 CONTINUE_GLOBAL_DIR 可覆盖)。ChatHistoryService 是单一真相源,每次改动 updateSessionHistory() 落盘,支持 undo/redo 栈(past/future)。cn --resume / /resume 加载历史 session。

长期记忆 = 未实现(CLI 层):没有跨会话 memory store、没有向量记忆库、没有自动 recall。仅 IDE core 侧有 codebase indexing(core/indexing/),CLI harness 本身不依赖。

工具体系(定义/调用协议/注册/权限)

工具定义 tools/types.tsTool 接口:{name, displayName, description, parameters(JSON-schema), readonly, isBuiltIn, run(args,ctx), preprocess?, evaluateToolCallPolicy?}

内置工具tools/index.tsx):Read / Write / List / Bash(runTerminalCommand) / Fetch / Checklist(writeChecklist) / CheckBackgroundJob / AskQuestion,加条件工具——Search(需 ripgrep)、EditMultiEdit(按模型能力二选一,见”与模型的协同”)、Exit(headless)、ReportFailure/UploadArtifact(有 --id hosted agent 时)、Subagent(beta flag)、Skills、以及所有 MCP 工具。

注册/组装 getAllAvailableTools(isHeadless)运行时动态组装,随模型/mode/flag 变化。

调用协议:走 OpenAI function-calling(convertToolToChatCompletionTool,tools 传入 chat completion 的 tools 字段)。另保留一个 <tool>{json}</tool> 文本解析兜底(extractToolCalls),供不支持原生 tool-call 的模型。

执行 executeToolCall:run 前后各打一次 telemetry + git-ai hook;用 preprocessResult.args ?? arguments

权限与并行streamChatResponse.helpers.ts executeStreamedToolCalls,snapshot 内对应逻辑):权限检查串行(保序、逐个过审批门),已批准的工具用 Promise.all 并行执行parallelToolCallCount = 批内工具数,传给各工具,Bash/Read 据此把输出上限除以并发数防上下文爆掉(runTerminalCommand.ts)。

MCP 工具 convertMcpToolToContinueTool:MCP inputSchema 直接映射成 Tool.parameters,run 转发到 services.mcp.runTool

Prompt 设计(系统提示结构、动态组装)

systemMessage.ts constructSystemMessage() 动态拼装,每轮循环重新取(因 mode 可能变):

  • basebaseSystemMessage):“You are an agent in the Continue CLI…”,含 <env>(cwd / 是否 git repo / platform / date)+ <context name="gitStatus">(启动时 git status --porcelain 快照)。
  • agent 文件:按序找 AGENTS.md / AGENT.md / CLAUDE.md / CODEX.md 第一个存在的,塞进 <context name="userRules">——兼容 Claude / Codex 的 memory 文件
  • rules--rule flag(可来自 Hub)+ config.yaml 的 rules + .continue/rules/*.md~/.continue/rules/*.mdalwaysApply 的 markdown rule(loadMarkdownRulesWithMetadata,带 frontmatter globs/regex 门控),去重后追加。
  • mode 相关:plan mode 注入只读约束 <context name="planMode">;非 plan 注入 commit 签名要求(Co-Authored-By: Continue,可用 env 关)。
  • headless / json:追加”只给最终答案” / “输出必须是可 parse 的 JSON”指令。

Router / 编排(任务分解、多 agent、子 agent)

子 agent 是唯一编排机制,且默认关闭(beta flag isBetaSubagentToolEnabledtools/index.tsx)。

  • Subagent 工具(tools/subagent.ts):参数 {subagent_name, description, prompt}。可用子 agent 来自配置里 roles"subagent" 的 modelModelService.getSubagentModelssubagent/get-agents.ts)——即子 agent = “带专属 system prompt 的另一个模型配置”,非代码硬编码角色。
  • executeSubAgentsubagent/executor.ts:58):在同进程内递归调 streamChatResponsesubagent-executor.ts:141 直接 import 并调用主循环)跑一个子 loop。子 agent system message = 主 base + 该 model 的 chatOptions.baseSystemMessage。执行期间临时把工具权限全开 {tool:"*", permission:"allow"}subagent-executor.ts:86,注释承认这是临时方案),并临时禁用 ChatHistoryService(隔离父子 session),结束后 finally 恢复。返回子 agent 最后一条消息作为结果,附 <task_metadata>status:…
  • 无自动任务分解 / 无 planner:主 agent 靠 prompt 自行决定是否 spawn 子 agent;没有 DAG、没有 supervisor 调度。属”扁平单主 agent + 可选一层子 agent”。

Skill / 插件体系

Skillstools/skills.ts):Anthropic 式 progressive disclosure。启动时 loadMarkdownSkills() 扫描 skill 目录(~/.continue/skills/<name>/SKILL.md),把每个 skill 的 name+description 列进工具描述;模型调 Skills(skill_name) 才把完整 <skill_content> + 关联 <skill_files> 注入。/import-skill <url|name> 让 agent 自己抓 GitHub repo 装 skill。

MCPservices/MCPService.ts):用官方 @modelcontextprotocol/sdkClient,三种 transport 全支持——stdio / SSE / StreamableHTTPmcpTransports.ts)。从 assistant.mcpServers 配置连接,headless/agent 模式下任一 MCP 连接失败会抛错。MCP tools/prompts 汇总进 state。

Rules(见 Prompt 设计)也是一种插件式行为注入。config / model / rule / skill 均可来自 Continue HubhubLoader.ts)。

自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)

基本未实现。没有 self-reflection loop、没有从失败中学习、没有 eval 驱动纠错回路、没有把轨迹反馈进 prompt/权重。唯一”纠错”相关:ReportFailure 工具(仅 --id hosted agent 场景)让 agent 主动上报任务失败;writeChecklistChecklist 工具)让 agent 维护任务清单做运行内自我跟踪——非跨会话进化。结论:自进化 = 未实现

可观测性(日志 / trace 格式)

  • 本地日志 util/logger.ts:winston,落盘 ~/.continue/logs/cn.log,每进程一个随机 SESSION_ID。loop 内大量 logger.debug(chunk / tool / 压缩 / token 用量含 cache_read/write)。
  • Telemetry telemetry/telemetryService.ts基于 OpenTelemetryMeterProvider + OTLP/console exporter)。默认需显式配置 OTEL_EXPORTER_OTLP_ENDPOINT 等才启用hasOtelConfig),可 CONTINUE_METRICS_ENABLED=0 关。指标:session/LOC/PR/commit/cost/token/edit-decision/active-time/mcp-connections/startup-time/response-time/slash-command 等 counter+histogram;logToolResult(含 durationMs/success/errorReason/参数)、logApiRequest
  • 注意:是 metrics 而非 tracing——无内置分布式 trace span 树、无 UI trace viewer(CLI)。

安全与权限(审批门、密钥管理)

这是 Continue harness 的核心设计

  • 三态权限模型(docs/cli/tool-permissions):allow(自动跑)/ ask(TUI 弹窗审批)/ exclude(对 agent 隐藏)。
  • 默认策略 permissions/defaultPolicies.ts:读类工具(Read/List/Search/Fetch/Diff/Status/AskQuestion/Checklist/Skills…)默认 allow;写类(Edit/MultiEdit/Write:12-14)+ Bash + * 默认 askheadless 模式把 Bash 和 * 提到 allow(因无人审批,:31-33)。
  • 权限 mode(Shift+Tab 或 flag 切换):normal / planPLAN_MODE_POLICIES:写操作全 exclude、只读 + Bash allowdefaultPolicies.ts:42-54)/ autoAUTO_MODE_POLICIES = *:allow)。
  • 优先级(docs):mode(--auto/--readonly)> CLI flags(--allow/--ask/--exclude)> ~/.continue/permissions.yaml(持久化,TUI 选 “don’t ask again” 写入)> 默认。
  • 匹配 permissionChecker.ts:first-match-wins;支持 Bash(npm install*) 命令级 glob、Write(**/*.ts) 参数级 glob(matchesToolPattern / matchesArguments)。
  • 动态策略 evaluateToolCallPolicy:工具可覆写策略,disabled 永远优先(安全兜底);Bash 用它接安全评估器(见沙箱一节)。
  • 密钥管理:LLM 凭据走 AuthService(Continue Hub OAuth / API key),env 变量 + config.yaml secrets。未见硬编码密钥扫描 / secret redaction 机制;Bash 安全评估器会拦 LD_PRELOAD/PATH 等危险 env 修改。审批门是 human-in-the-loop 主防线。

沙箱与执行隔离

无 OS 级沙箱 / 无容器隔离。Bash 工具(runTerminalCommand.ts)直接 spawn 用户 login shellgetShellCommand:Unix $SHELL -l -c,Windows PowerShell,含 WSL 检测),跑在用户真实环境,能 source .zshrc/.bashrc

隔离靠命令级静态安全评估 packages/terminal-security/src/evaluateTerminalCommandSecurity.ts(1241 行):用 shell-quote tokenize,逐条命令(含多行/管道分别评估,取最严),分三级返回 disabled / allowedWithPermission / allowedWithoutPermission

  • critical → disabled(直接禁)rm -rf / 类危险路径(isCriticalCommand,抠 /etc/sudoers 等)、fork bomb。
  • high-risk → 需审批:privilege escalation(sudo/su/doas)、网络工具(curl/wget/nc/ssh/scp/rsync…)、脚本解释器执行文件(bash/python/node -c 或跑脚本)、./script.sh 直接执行、危险 env 修改、包管理 install、管道到危险命令(dangerousPipeCommands)。
  • safe → 免审批:只读信息命令(ls/pwd/cat/head/tail/grep/find(无 -exec/git status|log|diff/npm test|build…isSafeCommand)。

超时默认 180s(可传上限 600s),输出上限 50k 字符 / 1000 行(可 env 调,按并发数均分)。长命令可移到后台 jobBackgroundJobService,上限 5 并发)。

结论:沙箱 = 未实现(无隔离层);防线是”静态命令白/黑名单 + 人工审批 + 输出截断”。

与模型的协同设计

模型无关,官方卖点是 “plug in your model”。统一走 packages/openai-adaptersBaseLlmApi(OpenAI 兼容 + 各家 adapter),config.yaml 声明 provider/model/roles。协同点:

  • 能力探测选工具isModelCapable(provider,name,model)tools/index.tsx)决定给 MultiEdit(强模型)还是 Edit(弱模型),并可用 model.chatOptions.toolOverrides 覆写工具(applyChatCompletionToolOverrides)。
  • tool-call 双通道:优先原生 function calling,弱模型走 <tool> 文本解析兜底。
  • token 预算getModelContextLimit/getModelMaxTokensutil/tokenizer.ts)驱动压缩阈值与 prune;用 gpt-tokenizer 估算。
  • retrychatCompletionStreamWithBackoff + withExponentialBackoff,识别 context-length error。
  • cache 感知:读取 prompt_tokens_details.cache_read/write_tokens 记 telemetry;system message 结构相对稳定利于 prompt caching。
  • 无为特定模型定制的训练/RL 协同——纯推理侧适配层。

轨迹利用(session/trajectory 是否反哺训练/评测)

  • 本地轨迹:完整 session(history + tool 结果 + usage/cost)落盘 json,供 --resume不反哺训练
  • 远程上传(hosted/enterprise 场景) StorageSyncService.ts:定时(默认 30s)向后端 presigned URL 上传 session snapshot + git diff snapshotgetGitDiffSnapshot)。这是给 Continue 平台的 hosted agent(cn --id)做远程会话同步 / 可观测,非训练数据管道(无标注/reward 结构)。
  • git-ai checkpoint GitAiIntegrationService.ts:若本机装了外部 git-ai CLI,每次 Edit/MultiEdit/Write 前后调 git-ai checkpoint continue-cli 给 AI 编辑打版本 checkpoint(可回滚/审计),非训练
  • eval:repo 根 eval/ 目录 --depth 1 下为空,CLI harness 内无 eval-driven 自纠机制
  • 结论:轨迹用于恢复 + 远程同步 + 编辑审计不反哺训练/离线评测(至少源码内无此管道)。

与同类 harness 的关键差异(1-3 条)

  1. 权限是一等公民、编排是二等公民:多数 harness 把复杂度放在 planner/多 agent 编排上,Continue 反其道——编排只有一个默认关闭的单层子 agent,却把工程投入压在三态权限 + 三 mode + 1241 行 Bash 命令静态安全评估器上。安全评估器还独立成包 packages/terminal-security
  2. loop 无 max-steps:停机纯由”模型是否产生 tool call”决定(shouldContinue = validToolCalls.length > 0),没有步数上限或 supervisor 中断——依赖模型自己收尾 + 压缩自动续跑兜底。
  3. 激进兼容既有生态的 memory 文件:系统提示直接读 CLAUDE.md / CODEX.md / AGENTS.md(Claude Code / Codex 的规则文件),意图是”换 harness 不换项目配置”;子 agent 也复用为”带 subagent role 的另一模型配置”而非硬编码角色。

原始源码定位

  • repo: https://github.com/continuedev/continue
  • commit/version analyzed: d0a3c0b626b5bebc3bef4742eec05a0242be0bab(2026-06-18 17:21:52 -0700;npm 包 @continuedev/cli,bin cn
  • 关键文件列表(相对 repo 根):
    • extensions/cli/src/stream/streamChatResponse.ts — 主循环 / 停机 / 压缩钩子
    • extensions/cli/src/stream/handleToolCalls.ts — 工具调用写回 / 权限过滤
    • extensions/cli/src/stream/streamChatResponse.helpers.ts — 工具并行 dispatch / 审批门
    • extensions/cli/src/systemMessage.ts — Prompt 动态组装 / rules
    • extensions/cli/src/tools/index.tsx — 工具注册/定义/schema / MCP 转换
    • extensions/cli/src/tools/runTerminalCommand.ts — Bash 执行 / 后台 job
    • extensions/cli/src/tools/subagent.ts + subagent/executor.ts + subagent/get-agents.ts — 子 agent 编排
    • extensions/cli/src/tools/skills.ts — Skill 渐进披露
    • extensions/cli/src/compaction.ts — 上下文压缩
    • extensions/cli/src/permissions/defaultPolicies.ts + permissionChecker.ts — 权限
    • packages/terminal-security/src/evaluateTerminalCommandSecurity.ts — 命令级静态安全评估
    • extensions/cli/src/services/ChatHistoryService.ts + session.ts — 会话持久化
    • extensions/cli/src/services/GitAiIntegrationService.ts — 编辑 checkpoint
    • extensions/cli/src/services/StorageSyncService.ts — 会话 + diff 上传
    • extensions/cli/src/services/MCPService.ts + mcpTransports.ts — MCP
    • extensions/cli/src/telemetry/telemetryService.ts + util/logger.ts — 可观测性
    • extensions/cli/src/slashCommands.ts — slash 命令 / 权限 mode 切换

一手源存档(sources/)

/Users/zhao/projects/self-wiki/ai-research/sources/harness/continue-dev/

  • NOTES.md — 第一阶段源码级调研笔记(验证信息 + 12 维度 + 每条论断的文件/行号)
  • src-snapshot/(核心源文件留档,152K):
    • streamChatResponse.tsstreamChatResponse.helpers.tshandleToolCalls.ts
    • systemMessage.tstools-index.tsxrunTerminalCommand.ts
    • subagent-tool.tssubagent-executor.ts
    • skills-tool.tscompaction.ts
    • defaultPolicies.tspermissionChecker.ts
    • evaluateTerminalCommandSecurity.ts