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=cn → dist/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、skillsextensions/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.js、core/util/messageConversion.js),但 loop / 工具 / 权限逻辑均在 extensions/cli/ 自成一体。
Agent Loop(主循环 / 何时继续何时停)
主循环是 streamChatResponse()(extensions/cli/src/stream/streamChatResponse.ts,while (true) 见 snapshot :443)。每轮:
- 从
ChatHistoryService刷新 history - 按当前权限 mode 取 system message(每轮重取,因为 mode 可在 streaming 中途切换)
- 每轮重算可用工具(
getRequestTools) - pre-API 压缩检查
processStreamingResponse()拿 LLM 流式响应handleToolCalls()执行工具、写回 history- 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.8、AUTO_COMPACT_BUFFER_CAP = 15_000(compaction.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.ts 的 Tool 接口:{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)、Edit 或 MultiEdit(按模型能力二选一,见”与模型的协同”)、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 可能变):
- base(
baseSystemMessage):“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:
--ruleflag(可来自 Hub)+ config.yaml 的 rules +.continue/rules/*.md与~/.continue/rules/*.md里alwaysApply的 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 isBetaSubagentToolEnabled,tools/index.tsx)。
Subagent工具(tools/subagent.ts):参数{subagent_name, description, prompt}。可用子 agent 来自配置里roles含"subagent"的 model(ModelService.getSubagentModels;subagent/get-agents.ts)——即子 agent = “带专属 system prompt 的另一个模型配置”,非代码硬编码角色。executeSubAgent(subagent/executor.ts:58):在同进程内递归调streamChatResponse(subagent-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 / 插件体系
Skills(tools/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。
MCP(services/MCPService.ts):用官方 @modelcontextprotocol/sdk 的 Client,三种 transport 全支持——stdio / SSE / StreamableHTTP(mcpTransports.ts)。从 assistant.mcpServers 配置连接,headless/agent 模式下任一 MCP 连接失败会抛错。MCP tools/prompts 汇总进 state。
Rules(见 Prompt 设计)也是一种插件式行为注入。config / model / rule / skill 均可来自 Continue Hub(hubLoader.ts)。
自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)
基本未实现。没有 self-reflection loop、没有从失败中学习、没有 eval 驱动纠错回路、没有把轨迹反馈进 prompt/权重。唯一”纠错”相关:ReportFailure 工具(仅 --id hosted agent 场景)让 agent 主动上报任务失败;writeChecklist(Checklist 工具)让 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:基于 OpenTelemetry(MeterProvider+ 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 +*默认ask。headless 模式把 Bash 和*提到allow(因无人审批,:31-33)。 - 权限 mode(Shift+Tab 或 flag 切换):
normal/plan(PLAN_MODE_POLICIES:写操作全exclude、只读 + Bashallow,defaultPolicies.ts:42-54)/auto(AUTO_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 shell(getShellCommand: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 调,按并发数均分)。长命令可移到后台 job(BackgroundJobService,上限 5 并发)。
结论:沙箱 = 未实现(无隔离层);防线是”静态命令白/黑名单 + 人工审批 + 输出截断”。
与模型的协同设计
模型无关,官方卖点是 “plug in your model”。统一走 packages/openai-adapters 的 BaseLlmApi(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/getModelMaxTokens(util/tokenizer.ts)驱动压缩阈值与 prune;用gpt-tokenizer估算。 - retry:
chatCompletionStreamWithBackoff+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 snapshot(getGitDiffSnapshot)。这是给 Continue 平台的 hosted agent(cn --id)做远程会话同步 / 可观测,非训练数据管道(无标注/reward 结构)。 - git-ai checkpoint
GitAiIntegrationService.ts:若本机装了外部git-aiCLI,每次 Edit/MultiEdit/Write 前后调git-ai checkpoint continue-cli给 AI 编辑打版本 checkpoint(可回滚/审计),非训练。 - eval:repo 根
eval/目录--depth 1下为空,CLI harness 内无 eval-driven 自纠机制。 - 结论:轨迹用于恢复 + 远程同步 + 编辑审计,不反哺训练/离线评测(至少源码内无此管道)。
与同类 harness 的关键差异(1-3 条)
- 权限是一等公民、编排是二等公民:多数 harness 把复杂度放在 planner/多 agent 编排上,Continue 反其道——编排只有一个默认关闭的单层子 agent,却把工程投入压在三态权限 + 三 mode + 1241 行 Bash 命令静态安全评估器上。安全评估器还独立成包
packages/terminal-security。 - loop 无 max-steps:停机纯由”模型是否产生 tool call”决定(
shouldContinue = validToolCalls.length > 0),没有步数上限或 supervisor 中断——依赖模型自己收尾 + 压缩自动续跑兜底。 - 激进兼容既有生态的 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,bincn) - 关键文件列表(相对 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 动态组装 / rulesextensions/cli/src/tools/index.tsx— 工具注册/定义/schema / MCP 转换extensions/cli/src/tools/runTerminalCommand.ts— Bash 执行 / 后台 jobextensions/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— 编辑 checkpointextensions/cli/src/services/StorageSyncService.ts— 会话 + diff 上传extensions/cli/src/services/MCPService.ts+mcpTransports.ts— MCPextensions/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.ts、streamChatResponse.helpers.ts、handleToolCalls.tssystemMessage.ts、tools-index.tsx、runTerminalCommand.tssubagent-tool.ts、subagent-executor.tsskills-tool.ts、compaction.tsdefaultPolicies.ts、permissionChecker.tsevaluateTerminalCommandSecurity.ts