Compare commits
10 Commits
1d4ffa964d
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53faa8b216 | ||
|
|
da51538b92 | ||
|
|
ed870e0ece | ||
|
|
ab169fda98 | ||
|
|
ab515aedd6 | ||
|
|
49234517b8 | ||
|
|
7f33e40f22 | ||
|
|
23ae8ec64b | ||
|
|
a8bcdfbe2e | ||
|
|
fa8e3d407d |
240
README-CN.md
240
README-CN.md
@@ -1,23 +1,96 @@
|
||||
# claude-code-source-code
|
||||
# Claude Code 开源代码合集
|
||||
|
||||
> Claude Code 源码档案与 Python 重写的研究仓库
|
||||
|
||||
本仓库包含两个子项目,从不同角度对 Claude Code(Anthropic 官方 CLI 工具)进行深度研究:
|
||||
## 🔥🔥🔥 最新动态(太平洋时间)
|
||||
|
||||
| 子项目 | 语言 | 性质 | 文件数 |
|
||||
|--------|------|------|--------|
|
||||
| [claude-code-source-code](#一-claude-code-source-code) | TypeScript | 反编译源码档案(v2.1.88) | 1,884 个 |
|
||||
| [claw-code](#二-claw-code) | Python | 清室架构重写 | 66 个 |
|
||||
- 2026年4月2日 12:20:[Nano Claude Code v3.0:多智能体包(multi_agent/)、记忆包(memory/)、技能包(skill/),内置技能、参数替换、fork/inline 执行、AI 记忆搜索、git worktree 隔离、代理类型定义(~5000 行 Python)](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
- 2026年4月2日 07:40:[Nano Claude Code v2.0:最小 Python 重实现(~3400 行),支持开源与闭源模型、技能与记忆](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
- 2026年4月1日 08:36:[Nano Claude Code v1.0:最小 Python 重实现(~1300 行)](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
- 2026年4月1日 00:20:[Claude Code 源码解析(视频:中文)](https://www.youtube.com/watch?v=xsg6_Gvr2J0&t=10s)
|
||||
- 2026年3月31日 19:45:[Claude Code 研究报告(中文)](https://github.com/chauncygu/collection-claude-code-source-code/blob/main/docs/claude-code-deep-dive-xelatex.pdf)
|
||||
- 2026年3月31日 17:13:[Claude Code 架构分析(中文)](https://mp.weixin.qq.com/s?__biz=MzI0ODk2NDIyMQ==&mid=2247502519&idx=1&sn=1072dd7a822a78709bc7cc3bf0e1dcc2&chksm=e8de6705e2bacc854211663aa02903738560f9e858eb6ce72b94c32fdbf67917badfab2d6536&mpshare=1&scene=1&srcid=0401KpkqfaXFBReRof6AwJ74&sharer_shareinfo=30fa54f1602d1d8bb1a65e7008074e08&sharer_shareinfo_first=30fa54f1602d1d8bb1a65e7008074e08#rd)
|
||||
- 2026年3月31日 16:43:[Claude Code 功能全览(中文)](https://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666572944&idx=1&sn=c54e34711e67a2e961acb341f51d2190&chksm=81ca164af949bdfe90a616c8ef8d7e729116a4a12a480cd9d012f42f5b8d7ecd6d05e284db09&mpshare=1&scene=1&srcid=04017JkKs9qrCh4AHcfZq7qL&sharer_shareinfo=95eb268167dd1b3d98271b8b26e7553e&sharer_shareinfo_first=95eb268167dd1b3d98271b8b26e7553e#rd)
|
||||
- 2026年3月31日 15:00:[Hacker News 社区关于 Claude Code 泄露的讨论](https://news.ycombinator.com/item?id=47586778)
|
||||
- 2026年3月31日 11:48:[Anthropic 如何为 Claude Code 构建 7 层记忆与梦境系统](https://x.com/troyhua/status/2039052328070734102)
|
||||
- 2026年3月31日 09:50:[Claude Code 记忆系统解析](https://x.com/henryl_ai/status/2039022608310808965)
|
||||
- 2026年3月31日 09:48:[Claude Code 源代码疑似泄露:我们目前所知道的](https://venturebeat.com/technology/claude-codes-source-code-appears-to-have-leaked-heres-what-we-know)
|
||||
- 2026年3月31日 09:04:[拆解 Claude Code 架构(中文)](https://mp.weixin.qq.com/s?__biz=MzA3NzUxMzM5MQ==&mid=2453898430&idx=1&sn=1c4051fb17a15b17e449b7eb85d3e1c5&chksm=897cc501d472cdd6916679a0766ab146b5347bc78e48171d9da97de282a05c10eea8d22c3605&mpshare=1&scene=1&srcid=0401oXuLa2VmhvrcRZk7VHfH&sharer_shareinfo=e7ff02258e887208db510104bc343079&sharer_shareinfo_first=6c39c564855be1e2372289b5c09b6247#rd)
|
||||
- 2026年3月31日 07:07:[逐步解读 Claude Code 源码(中文)](https://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655937729&idx=1&sn=0afb97062ef5f229910e3e54dd36abb6&chksm=bc66bca5b0f4171b56075506f208efea18381031c5ffa33070701ee1200bef7e411ea10188e9&mpshare=1&scene=1&srcid=0331PBEUSD8CVryQYEluyZbc&sharer_shareinfo=c5a329d2cc3ec432238f5fc1d9d70723&sharer_shareinfo_first=c5a329d2cc3ec432238f5fc1d9d70723#rd)
|
||||
- 2026年3月31日 05:41:[Claude Code 为何优于其他工具:深度分析](https://x.com/YukerX/status/2038959908968919297)
|
||||
- 2026年3月31日 05:03:[Anthropic AI 编程工具再次泄露自身源代码](https://www.ndtv.com/science/anthropics-ai-coding-tool-leaks-its-own-source-code-for-the-second-time-in-a-year-11291517)
|
||||
- 2026年3月31日 03:28:[Claude Code 源码曝光:提示词、自愈机制与多代理架构(中文)](https://mp.weixin.qq.com/s?__biz=MzI3ODY3ODg2Nw==&mid=2247484425&idx=1&sn=f77d3b97e88cb8019f014ca2eb95db65&chksm=ea98ee5bb2249e1c637520cf02b525b98b434671f2cc23ec554e5faa868e890deeead939c578&mpshare=1&scene=1&srcid=0401kVgDQ41tx7AECPzvch3W&sharer_shareinfo=5d97c04d957d52383c9b59245e421c5a&sharer_shareinfo_first=5d97c04d957d52383c9b59245e421c5a#rd)
|
||||
- 2026年3月31日 03:02:[社区对 Claude Code 源码曝光的反应](https://x.com/hank_aibtc/status/2038919948370616330)
|
||||
- 2026年3月31日 02:57:[Claude Code 背后的代码](https://x.com/mal_shaik/status/2038918662489510273)
|
||||
- 2026年3月31日 01:23:[关于 Claude Code 源码泄露的病毒式传播帖子](https://x.com/Fried_rice/status/2038894956459290963?s=20)
|
||||
|
||||
---
|
||||
|
||||
## 一、claude-code-source-code
|
||||
## 目录
|
||||
|
||||
Claude Code v2.1.88 的反编译/解包源码,从 npm 包 `@anthropic-ai/claude-code@2.1.88` 还原,约 163,318 行 TypeScript 代码。
|
||||
- [一、original-source-code](#一original-source-code)
|
||||
- [二、claude-code-source-code](#二claude-code-source-code)
|
||||
- [整体架构](#整体架构)
|
||||
- [核心执行流程](#核心执行流程)
|
||||
- [技术栈](#技术栈)
|
||||
- [主要模块说明](#主要模块说明)
|
||||
- [工具系统(40+ 工具)](#工具系统40-工具)
|
||||
- [斜杠命令(~87 个)](#斜杠命令87-个)
|
||||
- [权限系统](#权限系统)
|
||||
- [上下文管理](#上下文管理)
|
||||
- [分析文档(docs/)](#分析文档docs)
|
||||
- [三、claw-code](#三claw-code)
|
||||
- [整体架构](#整体架构-1)
|
||||
- [核心类](#核心类)
|
||||
- [CLI 命令](#cli-命令)
|
||||
- [设计特点](#设计特点)
|
||||
- [四、nano-claude-code](#四nano-claude-code)
|
||||
- [功能特性](#功能特性)
|
||||
- [支持的模型](#支持的模型)
|
||||
- [项目结构](#项目结构)
|
||||
- [四个项目对比](#四个项目对比)
|
||||
- [许可与声明](#许可与声明)
|
||||
|
||||
---
|
||||
|
||||
本仓库包含四个子项目,从不同角度对 Claude Code(Anthropic 官方 CLI 工具)进行深度研究:
|
||||
|
||||
| 子项目 | 语言 | 性质 | 文件数 |
|
||||
|--------|------|------|--------|
|
||||
| [original-source-code](#一original-source-code) | TypeScript | 原始泄露源码档案 | 1,884 个 |
|
||||
| [claude-code-source-code](#二claude-code-source-code) | TypeScript | 反编译源码档案(v2.1.88)+ 文档 | 1,940 个 |
|
||||
| [claw-code](#三claw-code) | Python | 清室架构重写 | 109 个 |
|
||||
| [nano-claude-code](#四nano-claude-code) | Python | 最小化多模型提供商重实现 | ~30 个 |
|
||||
|
||||
---
|
||||
|
||||
## 一、original-source-code
|
||||
|
||||
2026 年 3 月 31 日原始泄露的 Claude Code TypeScript 源码,按原始状态完整保存。包含 1,884 个 TypeScript/TSX 文件(打包为 `src.zip`,约 9.5MB),覆盖完整的 `src/` 目录树——正是这批文件引发了社区讨论和后续研究。
|
||||
|
||||
```text
|
||||
original-source-code/
|
||||
├── src/ # 完整 TypeScript 源码树(1,884 个 .ts/.tsx 文件)
|
||||
│ ├── main.tsx # CLI 入口
|
||||
│ ├── query.ts # 核心代理循环
|
||||
│ ├── commands.ts # 斜杠命令定义
|
||||
│ ├── tools.ts # 工具注册
|
||||
│ └── ... # 其余所有源码目录(与 claude-code-source-code/src 结构相同)
|
||||
├── src.zip # 压缩档案(~9.5MB)
|
||||
└── readme.md
|
||||
```
|
||||
|
||||
此目录作为未修改的原始参考快照保存,未添加任何注释、文档或构建工具。如需研究注解版本,请使用 `claude-code-source-code`。
|
||||
|
||||
---
|
||||
|
||||
## 二、claude-code-source-code
|
||||
|
||||
Claude Code v2.1.88 的反编译/解包源码,从 npm 包 `@anthropic-ai/claude-code@2.1.88` 还原,约 163,318 行 TypeScript 代码,并附有深度分析文档。
|
||||
|
||||
### 整体架构
|
||||
|
||||
```
|
||||
```text
|
||||
claude-code-source-code/
|
||||
├── src/
|
||||
│ ├── main.tsx # CLI 入口与 REPL 引导(4,683 行)
|
||||
@@ -63,7 +136,7 @@ claude-code-source-code/
|
||||
|
||||
### 核心执行流程
|
||||
|
||||
```
|
||||
```text
|
||||
用户输入
|
||||
↓
|
||||
processUserInput() # 解析 /slash 命令
|
||||
@@ -138,13 +211,13 @@ yield SDKMessage # 流式返回给消费者
|
||||
|
||||
---
|
||||
|
||||
## 二、claw-code
|
||||
## 三、claw-code
|
||||
|
||||
对 Claude Code 的 Python 清室重写(不包含原始代码副本),专注于架构镜像与研究。由 [@instructkr](https://github.com/instructkr)(Sigrid Jin)完成,成为全球最快达到 30K stars 的 GitHub 仓库之一。
|
||||
|
||||
### 整体架构
|
||||
|
||||
```
|
||||
```text
|
||||
claw-code/
|
||||
├── src/
|
||||
│ ├── __init__.py # 包导出接口
|
||||
@@ -244,25 +317,142 @@ tool-pool # 工具池组装视图
|
||||
- **快照驱动**:通过 JSON 快照文件加载命令/工具元数据,无需完整实现逻辑
|
||||
- **清室重写**:不包含原始 TypeScript 代码,独立实现
|
||||
- **奇偶审计**:内置 `parity_audit.py` 追踪与原实现的差距
|
||||
- **轻量架构**:66 个文件实现核心框架,适合学习与扩展
|
||||
- **轻量架构**:109 个文件实现核心框架,适合学习与扩展
|
||||
|
||||
---
|
||||
|
||||
## 两个项目对比
|
||||
## 四、nano-claude-code
|
||||
|
||||
| 维度 | claude-code-source-code | claw-code |
|
||||
|------|------------------------|-----------|
|
||||
| 语言 | TypeScript | Python |
|
||||
| 代码量 | ~163,000 行 | ~5,000 行 |
|
||||
| 性质 | 反编译源码档案 | 清室架构重写 |
|
||||
| 功能完整度 | 完整(100%) | 架构框架(~20%) |
|
||||
| 核心循环 | `query.ts`(785KB) | `QueryEnginePort`(~200 行) |
|
||||
| 工具系统 | 40+ 完整实现 | 快照元数据 + 执行框架 |
|
||||
| 命令系统 | ~87 个完整实现 | 快照元数据 + 执行框架 |
|
||||
| 主要用途 | 深度学习完整实现细节 | 架构理解、移植研究 |
|
||||
Claude Code 的最小化可运行 Python 重实现(~5,000 行)。与专注架构映射的 `claw-code` 不同,nano-claude-code 是一个真正可立即使用的编程助手。支持 20+ 闭源模型和本地开源模型,已从 ~900 行原型成长为具备多智能体编排、持久记忆和技能系统的 v3.0 版本。
|
||||
|
||||
### 功能特性
|
||||
|
||||
| 功能 | 详情 |
|
||||
|------|------|
|
||||
| 多模型提供商 | Anthropic · OpenAI · Gemini · Kimi · Qwen · Zhipu · DeepSeek · Ollama · LM Studio · 自定义端点 |
|
||||
| 交互式 REPL | readline 历史、Tab 补全斜杠命令 |
|
||||
| 代理循环 | 流式 API + 自动工具调用循环 |
|
||||
| 18 个内置工具 | Read · Write · Edit · Bash · Glob · Grep · WebFetch · WebSearch · MemorySave · MemoryDelete · MemorySearch · MemoryList · Agent · SendMessage · CheckAgentResult · ListAgentTasks · ListAgentTypes · Skill · SkillList |
|
||||
| Diff 视图 | Edit 和 Write 操作的 Git 风格红绿差异显示 |
|
||||
| 上下文压缩 | 自动压缩长对话,保持在模型上下文限制内 |
|
||||
| 持久记忆 | 双作用域记忆(用户 + 项目),4 种类型,AI 搜索,过期警告 |
|
||||
| 多智能体 | 生成类型化子代理(coder/reviewer/researcher/…),git worktree 隔离,后台模式 |
|
||||
| 技能系统 | 内置 `/commit` · `/review` + 支持参数替换和 fork/inline 执行的自定义 Markdown 技能 |
|
||||
| 插件工具 | 通过 `tool_registry.py` 注册自定义工具 |
|
||||
| 权限系统 | `auto` / `accept-all` / `manual` 三种模式 |
|
||||
| 17 个斜杠命令 | `/model` · `/config` · `/save` · `/cost` · `/memory` · `/skills` · `/agents` · … |
|
||||
| 上下文注入 | 自动加载 `CLAUDE.md`、git 状态、当前目录、持久记忆 |
|
||||
| 会话持久化 | 保存/加载对话至 `~/.nano_claude/sessions/` |
|
||||
| 扩展思考 | 开启/关闭(仅限 Claude 模型) |
|
||||
| 成本追踪 | Token 用量 + 估算 USD 费用 |
|
||||
| 非交互模式 | `--print` 参数用于脚本/CI 场景 |
|
||||
|
||||
### 支持的模型
|
||||
|
||||
**闭源(API):** Claude(Anthropic)、GPT / o 系列(OpenAI)、Gemini(Google)、Kimi(Moonshot AI)、Qwen(阿里云百炼)、GLM(智谱)、DeepSeek
|
||||
|
||||
**开源(本地,通过 Ollama):** llama3.3/3.2、qwen2.5-coder、deepseek-r1、phi4、mistral、mixtral、gemma3、codellama 及 `ollama list` 中的任意模型
|
||||
|
||||
**自托管:** vLLM、LM Studio 或任何通过 `CUSTOM_BASE_URL` 配置的 OpenAI 兼容端点
|
||||
|
||||
### 项目结构
|
||||
|
||||
```text
|
||||
nano-claude-code/
|
||||
├── nano_claude.py # 入口:REPL + 斜杠命令 + 渲染 (~748 行)
|
||||
├── agent.py # 代理循环:消息格式 + 工具分发 (~174 行)
|
||||
├── providers.py # 多提供商适配器 + 消息格式转换 (~507 行)
|
||||
├── tools.py # 工具分发 + 所有包的自动注册 (~467 行)
|
||||
├── tool_registry.py # 中央工具注册表 + 插件入口 (~98 行)
|
||||
├── context.py # 系统提示构建:CLAUDE.md + git + 记忆 (~135 行)
|
||||
├── compaction.py # 上下文压缩(auto-compact) (~196 行)
|
||||
├── config.py # 配置加载/保存/默认值 (~72 行)
|
||||
├── memory.py # 向后兼容 shim → memory/
|
||||
├── skills.py # 向后兼容 shim → skill/
|
||||
├── subagent.py # 向后兼容 shim → multi_agent/
|
||||
│
|
||||
├── memory/ # 持久记忆包
|
||||
│ ├── store.py # 记忆条目的保存/加载/删除/搜索
|
||||
│ ├── scan.py # 索引扫描、新鲜度助手
|
||||
│ ├── context.py # 系统提示注入 + AI 排名搜索
|
||||
│ ├── types.py # MEMORY_TYPES 定义
|
||||
│ └── tools.py # MemorySave · MemoryDelete · MemorySearch · MemoryList
|
||||
│
|
||||
├── skill/ # 技能系统包
|
||||
│ ├── loader.py # SkillDef、文件解析、参数替换
|
||||
│ ├── builtin.py # 内置技能:/commit、/review
|
||||
│ ├── executor.py # inline + fork 执行模式
|
||||
│ └── tools.py # Skill · SkillList
|
||||
│
|
||||
├── multi_agent/ # 多智能体编排包
|
||||
│ ├── subagent.py # AgentDefinition、SubAgentTask、SubAgentManager、worktree 工具
|
||||
│ └── tools.py # Agent · SendMessage · CheckAgentResult · ListAgentTasks · ListAgentTypes
|
||||
│
|
||||
├── tests/ # 101 个测试(monkeypatch,不触碰真实 ~/.nano_claude/)
|
||||
├── docs/ # 文档与演示素材
|
||||
└── requirements.txt
|
||||
```
|
||||
|
||||
**快速开始:**
|
||||
|
||||
```bash
|
||||
pip install anthropic openai httpx rich
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
python nano_claude.py
|
||||
|
||||
# 启动时切换模型
|
||||
python nano_claude.py --model gpt-4o
|
||||
python nano_claude.py --model ollama/qwen2.5-coder
|
||||
|
||||
# 非交互 / CI 场景
|
||||
python nano_claude.py --print "写一个 Python 斐波那契函数" --accept-all
|
||||
```
|
||||
|
||||
**记忆**——跨会话持久化,双作用域(用户 `~/.nano_claude/memory/` 和项目 `.nano_claude/memory/`):
|
||||
|
||||
```
|
||||
/memory # 列出所有记忆(含新鲜度信息)
|
||||
MemorySave(name="...", type="feedback", content="...", scope="user")
|
||||
MemorySearch(query="...", use_ai=True)
|
||||
```
|
||||
|
||||
**技能**——可复用提示模板,在 REPL 中直接调用:
|
||||
|
||||
```
|
||||
/commit # 内置:审查暂存变更并创建 git commit
|
||||
/review 123 # 内置:审查 PR #123
|
||||
/skills # 列出所有可用技能及触发词和参数提示
|
||||
```
|
||||
|
||||
**多智能体**——生成类型化子代理,支持可选的 git worktree 隔离:
|
||||
|
||||
```
|
||||
Agent(prompt="...", subagent_type="coder", isolation="worktree", wait=False)
|
||||
SendMessage(agent_name="my-agent", message="...")
|
||||
/agents # 显示所有活跃和已完成的子代理任务
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四个项目对比
|
||||
|
||||
| 维度 | original-source-code | claude-code-source-code | claw-code | nano-claude-code |
|
||||
|------|---------------------|------------------------|-----------|-----------------|
|
||||
| 语言 | TypeScript | TypeScript | Python | Python |
|
||||
| 代码量 | ~163,000 行 | ~163,000 行 + 文档 | ~5,000 行 | ~5,000 行 |
|
||||
| 性质 | 原始泄露源码档案 | 反编译源码档案 + 分析 | 清室架构重写 | 最小化功能重实现 |
|
||||
| 功能完整度 | 完整(100%) | 完整(100%) | 架构框架(~20%) | 核心循环 + 记忆 + 多智能体 + 技能 |
|
||||
| 核心循环 | `query.ts`(785KB) | `query.ts`(785KB) | `QueryEnginePort`(~200 行) | `agent.py`(~174 行) |
|
||||
| 工具系统 | 40+ 完整实现 | 40+ 完整实现 | 快照元数据 + 执行框架 | 18 个完整实现 + 插件注册表 |
|
||||
| 记忆系统 | 是(7 层,复杂) | 是(7 层,复杂) | 否 | 是(双作用域,4 类型,AI 搜索) |
|
||||
| 多智能体 | 是(完整协调器) | 是(完整协调器) | 否 | 是(类型化代理,worktree 隔离) |
|
||||
| 技能系统 | 是(~87 个命令) | 是(~87 个命令) | 仅快照元数据 | 是(内置 + 自定义 Markdown 技能) |
|
||||
| 多模型提供商 | 否(仅 Anthropic) | 否(仅 Anthropic) | 否 | 是(10+ 提供商) |
|
||||
| 可立即运行 | 否 | 否 | 有限(仅 CLI 元数据) | 是 |
|
||||
| 主要用途 | 原始参考快照 | 深度学习完整实现细节 | 架构理解、移植研究 | 轻量级全功能编程助手 |
|
||||
|
||||
---
|
||||
|
||||
## 许可与声明
|
||||
|
||||
本仓库仅供学术研究与教育目的使用。两个子项目均基于公开可获取的信息构建。使用者应自行遵守相关法律法规及服务条款。
|
||||
本仓库仅供学术研究与教育目的使用。所有子项目均基于公开可获取的信息构建。使用者应自行遵守相关法律法规及服务条款。
|
||||
|
||||
12
README.MD
12
README.MD
@@ -1,9 +1,10 @@
|
||||
|
||||
# A collection of the newest Claude Code open source
|
||||
|
||||
> Source archive of Claude Code and a clean-room Python rewrite research repository
|
||||
> Source archive of Claude Code and different versions of the clean-room Python rewrite research repository
|
||||
|
||||
## 🔥🔥🔥 News (Pacific Time)
|
||||
- 9:50 AM · Apr 04, 2026: [Deep-dive analysis docs added (In Chinese): context compression, multi-agent architecture, memory system, hidden features, model-switching, rollback mechanism, effort level, and tracking-data cleanup guide](#5-docscc_analysis)
|
||||
- 12:20 PM · Apr 02, 2026: [Nano Claude Code v3.0: Multi-agent packages, memory package, skill package with built-in skills, argument substitution, fork/inline execution, AI memory search, git worktree isolation, agent type definitions (~5000 Lines)](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
- 7:40 AM · Apr 02, 2026: [Nano Claude Code v2.0: A Minimal Python Reimplementation (~3400 Lines), support open and closed source models, skill and memory](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
- 8:36 AM · Apr 01, 2026: [Nano Claude Code v1.0: A Minimal Python Reimplementation (~1300 Lines)](https://github.com/SafeRL-Lab/nano-claude-code)
|
||||
@@ -48,6 +49,7 @@
|
||||
+ [Features](#features)
|
||||
+ [Supported Models](#supported-models)
|
||||
+ [Project Structure](#project-structure)
|
||||
* [5. docs/cc\_analysis](#5-docscc_analysis)
|
||||
* [Comparison of the Projects](#comparison-of-the-projects)
|
||||
* [License and Disclaimer](#license-and-disclaimer)
|
||||
|
||||
@@ -437,6 +439,14 @@ SendMessage(agent_name="my-agent", message="...")
|
||||
/agents # show all active and finished sub-agent tasks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. docs/cc\_analysis
|
||||
|
||||
Analysis documents produced from the leaked Claude Code source snapshot (2026-03-31). All documents are based on the TypeScript source and are primarily written in Chinese, see [here](https://github.com/chauncygu/collection-claude-code-source-code/tree/main/docs/cc_analysis/analysis_20260401).
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Comparison of the Projects
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Claude Code 默认 Effort Level 设置为 Max
|
||||
|
||||
## 问题
|
||||
|
||||
`/effort max` 命令只对当前会话生效,重启 Claude Code 后会恢复为默认的 `medium`。
|
||||
|
||||
## 解决方案
|
||||
|
||||
在 `~/.zshrc` 中添加环境变量:
|
||||
|
||||
```bash
|
||||
export CLAUDE_CODE_EFFORT_LEVEL=max
|
||||
```
|
||||
|
||||
新开终端窗口后自动生效。
|
||||
|
||||
## 为什么不能用 settings.json
|
||||
|
||||
Claude Code 的 `~/.claude/settings.json` 支持 `effortLevel` 字段,但只接受 `low`、`medium`、`high` 三个值。`max` 是 Opus 4.6 专属的深度推理模式,只能通过环境变量持久化。
|
||||
|
||||
## Effort Level 一览
|
||||
|
||||
| 级别 | 说明 |
|
||||
|------|------|
|
||||
| `low` | 快速响应,适合简单问答 |
|
||||
| `medium` | 默认级别 |
|
||||
| `high` | 更深入的推理 |
|
||||
| `max` | 最深度推理,无 token 限制(仅 Opus 4.6) |
|
||||
|
||||
## 其他设置方式
|
||||
|
||||
- **启动参数**(单次):`claude --effort max`
|
||||
- **会话内**(单次):`/effort max`
|
||||
- **环境变量**(永久):`export CLAUDE_CODE_EFFORT_LEVEL=max` ← 推荐
|
||||
|
||||
---
|
||||
|
||||
*记录于 2026-03-30*
|
||||
@@ -0,0 +1,150 @@
|
||||
# Claude Code 自动回滚机制解析与版本切换指南
|
||||
|
||||
> 日期:2026-03-31
|
||||
|
||||
## 背景
|
||||
|
||||
Claude Code 从 v2.1.88 自动回滚到 v2.1.87,本文记录了完整的排查过程和解决方案。
|
||||
|
||||
## 回滚原因
|
||||
|
||||
**Anthropic 在 npm 做了服务端回滚**,不是本地触发的。
|
||||
|
||||
### npm Registry 状态
|
||||
|
||||
| dist-tag | 版本 |
|
||||
|----------|------|
|
||||
| `stable` | 2.1.81 |
|
||||
| `latest` | 2.1.87 |
|
||||
| `next` | 2.1.89 |
|
||||
|
||||
- v2.1.88 **已被完全从 npm 删除**(registry 中不存在)
|
||||
- `latest` tag 从 2.1.88 退回到 2.1.87
|
||||
|
||||
### 时间线
|
||||
|
||||
| 时间 | 事件 |
|
||||
|------|------|
|
||||
| Mar 28 19:25 | 自动更新下载 v2.1.87 |
|
||||
| Mar 30 18:31 | 自动更新下载 v2.1.88 |
|
||||
| Mar 30 ~ Mar 31 | Anthropic 从 npm 撤掉 v2.1.88,将 `latest` tag 退回 v2.1.87 |
|
||||
| Mar 31 05:59 | 自动更新器检查 npm registry,发现 `latest` 是 2.1.87,将 symlink 切回 |
|
||||
|
||||
## 自动更新机制
|
||||
|
||||
### 核心架构
|
||||
|
||||
```
|
||||
~/.local/bin/claude → symlink → ~/.local/share/claude/versions/{version}
|
||||
```
|
||||
|
||||
- 包名:`@anthropic-ai/claude-code`
|
||||
- 版本二进制存储:`~/.local/share/claude/versions/`
|
||||
- 入口 symlink:`~/.local/bin/claude`
|
||||
|
||||
### AutoUpdater 工作流程
|
||||
|
||||
1. 每次 Claude Code 启动时,AutoUpdater 检查 npm registry 的 `latest` dist-tag
|
||||
2. 如果本地版本与 `latest` 不匹配,下载目标版本二进制到 `versions/` 目录
|
||||
3. 更新 symlink 指向新版本
|
||||
4. 逻辑是**跟随 `latest` tag**,不是单调递增 — 所以 Anthropic 退 tag 就等于回滚
|
||||
|
||||
### 关键发现
|
||||
|
||||
- 二进制是 Bun 编译的 Mach-O arm64 可执行文件
|
||||
- 内部包含 `auto_updater_disabled`、`AutoUpdater`、`autoUpdaterStatus` 等标识
|
||||
- 启动遥测会上报 `auto_updater_disabled` 状态
|
||||
- 并发更新有互斥锁保护("Another instance is currently performing an update")
|
||||
|
||||
## 禁用自动更新的正确方式
|
||||
|
||||
通过逆向二进制中的 `h1H()` / `isAutoUpdaterDisabled` 函数,确认自动更新器的检查逻辑:
|
||||
|
||||
```javascript
|
||||
// 反编译后的禁用检查逻辑(简化)
|
||||
function getAutoUpdaterDisabledReason() {
|
||||
if (process.env.DISABLE_AUTOUPDATER) return { type: "env" };
|
||||
if (config.autoUpdates === false) return { type: "config" };
|
||||
return null; // 未禁用,自动更新正常运行
|
||||
}
|
||||
```
|
||||
|
||||
### 踩坑记录
|
||||
|
||||
`autoUpdaterDisabled: true` 是**错误的 key**,写了不生效,自动更新器仍会在启动时抢先将 symlink 切回 `latest` 指向的版本。
|
||||
|
||||
### 方法 A:环境变量(推荐,最可靠)
|
||||
|
||||
```bash
|
||||
# 加到 ~/.zshrc,每次 shell 启动自动生效
|
||||
echo 'export DISABLE_AUTOUPDATER=1' >> ~/.zshrc
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
### 方法 B:settings.json
|
||||
|
||||
编辑 `~/.claude/settings.json`,注意 key 是 `autoUpdates`:
|
||||
|
||||
```json
|
||||
"autoUpdates": false
|
||||
```
|
||||
|
||||
> 注意:对于 native 安装方式,如果同时设置了 `autoUpdatesProtectedForNative: true`,则 `autoUpdates: false` 会被覆盖,此时只能用环境变量方式。
|
||||
|
||||
## 解决方案:切回 v2.1.88
|
||||
|
||||
### 步骤 1:禁用自动更新
|
||||
|
||||
```bash
|
||||
# 确保环境变量已生效
|
||||
export DISABLE_AUTOUPDATER=1
|
||||
```
|
||||
|
||||
### 步骤 2:切换 symlink
|
||||
|
||||
```bash
|
||||
ln -sf ~/.local/share/claude/versions/2.1.88 ~/.local/bin/claude
|
||||
```
|
||||
|
||||
### 步骤 3:验证
|
||||
|
||||
```bash
|
||||
claude --version
|
||||
# 输出:2.1.88 (Claude Code)
|
||||
```
|
||||
|
||||
### 步骤 4:使用
|
||||
|
||||
```bash
|
||||
claude --dangerously-skip-permissions
|
||||
```
|
||||
|
||||
## 恢复自动更新
|
||||
|
||||
```bash
|
||||
# 1. 从 ~/.zshrc 删掉 export DISABLE_AUTOUPDATER=1
|
||||
# 2. 如果用了方法 B,从 settings.json 删掉 "autoUpdates": false
|
||||
# 3. 重启终端,自动更新器会在下次启动时恢复工作
|
||||
```
|
||||
|
||||
## 其他版本切换方式
|
||||
|
||||
```bash
|
||||
# 切到 next channel (v2.1.89)
|
||||
claude update --channel next
|
||||
|
||||
# 切到 stable channel (v2.1.81)
|
||||
claude update --channel stable
|
||||
|
||||
# 查看本地已有的版本
|
||||
ls ~/.local/share/claude/versions/
|
||||
|
||||
# 手动切换到任意本地版本
|
||||
ln -sf ~/.local/share/claude/versions/<版本号> ~/.local/bin/claude
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- v2.1.88 被 Anthropic 从 npm 删除,可能存在已知问题
|
||||
- 禁用自动更新后不会收到安全修复,需定期手动检查
|
||||
- 本地残留的 v2.1.88 二进制不会被自动清理
|
||||
@@ -0,0 +1,297 @@
|
||||
# Claude Code 上下文管理算法学习笔记
|
||||
|
||||
> 来源:Claude Code 源码快照(2026-03-31)
|
||||
> 核心文件:`src/query.ts`, `src/services/compact/`, `src/utils/toolResultStorage.ts`
|
||||
|
||||
---
|
||||
|
||||
## 架构总览:7 层递进式防御
|
||||
|
||||
每轮 query loop 按以下顺序执行,从便宜到昂贵,每一层减轻压力,可能阻止下一层触发:
|
||||
|
||||
```
|
||||
1. Tool Result Budget ← 单轮预算(同步,零 API 调用)
|
||||
2. Snip Compact ← 历史裁剪(零 API 调用)
|
||||
3. Microcompact ← 工具结果精细清理(零或极低 API 成本)
|
||||
4. Context Collapse ← 增量投影摘要(零 API 调用)
|
||||
5. Auto-Compact ← LLM 全量摘要(昂贵)
|
||||
6. Blocking Limit ← 硬停(所有自动措施关闭时)
|
||||
7. Reactive Compact ← 413 错误后紧急摘要(最后手段)
|
||||
```
|
||||
|
||||
互斥门控防止昂贵操作竞争:Context Collapse 启用时抑制 Auto-Compact,Reactive Compact 实验模式抑制主动 Auto-Compact。
|
||||
|
||||
---
|
||||
|
||||
## 第 1 层:Tool Result Budget — 单轮聚合预算
|
||||
|
||||
**问题**:N 个并行工具可能在一轮中集体产生超大上下文。
|
||||
|
||||
**三分区算法**:
|
||||
|
||||
| 分区 | 含义 | 处理 |
|
||||
|------|------|------|
|
||||
| mustReapply | 之前已替换过的结果 | 直接重用缓存的替换字符串(零 I/O,字节级一致) |
|
||||
| frozen | 之前见过但没替换 | 永不替换(保护 prompt cache) |
|
||||
| fresh | 新结果 | 参与预算分配 |
|
||||
|
||||
**阈值**:
|
||||
- 总预算:200K 字符/消息(远程可配置)
|
||||
- 单工具上限:50K 字符(默认)
|
||||
- 超出时:保留前 ~2KB 预览 + 持久化到磁盘,模型可用 Read 按需读取
|
||||
|
||||
**核心洞察**:frozen 分区 — 宁可浪费空间也不破坏缓存命中率。**Prompt cache 稳定性优先于空间效率**。
|
||||
|
||||
---
|
||||
|
||||
## 第 2 层:Snip Compact — 历史裁剪
|
||||
|
||||
**特点**:零 API 调用,直接删除旧消息。
|
||||
|
||||
**协调机制**:snipTokensFreed 传递给下游层,因为 tokenCountWithEstimation 读的是上一轮 API 返回的 input_tokens(反映 snip 前的数值),需要手动减去 snip 释放的量。
|
||||
|
||||
**双视图**:REPL 保留被 snip 的消息用于 UI 回滚,但投影层在发送 API 前过滤掉它们。
|
||||
|
||||
---
|
||||
|
||||
## 第 3 层:Microcompact — 三种精细清理路径
|
||||
|
||||
### 3a. 基于时间的清理
|
||||
|
||||
```
|
||||
触发条件:距上次助手消息 > 60 分钟(= 服务端 cache TTL)
|
||||
逻辑:cache 已过期 → 全量前缀会被重写 → 趁机清理旧工具结果
|
||||
行为:替换为 "[Old tool result content cleared]"
|
||||
保留:最近 5 个结果
|
||||
```
|
||||
|
||||
**洞察**:利用缓存 TTL 过期的"免费窗口"搭车做清理。
|
||||
|
||||
### 3b. 缓存编辑(Cache Editing)— 最精妙的设计
|
||||
|
||||
```
|
||||
触发条件:可压缩工具结果数超过阈值
|
||||
关键创新:不修改本地消息!使用 API 的 cache_edits / cache_reference 机制
|
||||
效果:服务端缓存被精确编辑,本地保持不变
|
||||
确认:用 API 返回的 cache_deleted_input_tokens(非客户端估算)
|
||||
范围:仅主线程,仅特定工具(FileRead, Bash, Grep, Glob 等)
|
||||
```
|
||||
|
||||
**洞察**:读写分离 — 本地消息不变(保证重放一致性),服务端缓存被精确编辑(节省空间)。
|
||||
|
||||
### 3c. API 原生上下文管理
|
||||
|
||||
```
|
||||
策略:clear_tool_uses + clear_thinking
|
||||
触发:输入超 180K tokens
|
||||
目标:保留最后 40K tokens
|
||||
思考块:cache 冷(>1h)时仅保留最后一轮思考
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第 4 层:Context Collapse — 增量投影式摘要(CQRS 思想)
|
||||
|
||||
**核心思想**:不破坏性替换消息,而是维护一个 commit log,每轮查询时 project 出压缩视图。
|
||||
|
||||
**阈值**:
|
||||
- 90% 上下文窗口 → 开始提交 collapse
|
||||
- 95% 上下文窗口 → 阻塞新 spawn
|
||||
- ~93%(auto-compact 位置)→ 被抑制避免竞争
|
||||
|
||||
**关键 API**:
|
||||
- `applyCollapsesIfNeeded()` — 投影压缩视图 + 可选提交新 collapse
|
||||
- `recoverFromOverflow()` — 413 时排空所有暂存 collapse(第一道防线)
|
||||
- `projectView()` — 每轮重放提交日志
|
||||
|
||||
**设计亮点**:
|
||||
- Collapse 摘要存在 commit store 中,而非 REPL 消息数组 → 跨轮持久化
|
||||
- REPL 保留完整历史(UI 回滚),API 调用看到投影视图(节省 tokens)
|
||||
- 会话恢复时从 commits + snapshot 重建
|
||||
|
||||
---
|
||||
|
||||
## 第 5 层:Auto-Compact — 带熔断的 LLM 摘要
|
||||
|
||||
**触发**:`tokenCount > contextWindow - 13,000`
|
||||
|
||||
### 摘要 prompt 结构
|
||||
|
||||
```xml
|
||||
<analysis>(内部草稿,生成后丢弃)</analysis>
|
||||
<summary>
|
||||
1. Primary Request / Intent
|
||||
2. Key Technical Concepts
|
||||
3. Files / Code
|
||||
4. Errors / Fixes
|
||||
5. Problem Solving
|
||||
6. All User Messages(用户说过的每句话都保留)
|
||||
7. Pending Tasks
|
||||
8. Current Work
|
||||
9. Optional Next Step
|
||||
</summary>
|
||||
```
|
||||
|
||||
### Prompt Cache 共享优化
|
||||
|
||||
摘要子 agent 复用主对话的缓存前缀(通过 runForkedAgent)。
|
||||
没有此优化:cache miss 率 98%,浪费全局 ~38B tok/天的 cache_creation。
|
||||
|
||||
### PTL(Prompt-Too-Long)重试
|
||||
|
||||
```
|
||||
最多重试 3 次:
|
||||
→ 按 API 轮次分组(groupMessagesByApiRound)
|
||||
→ 丢弃最老的组以覆盖 token 缺口
|
||||
→ 无法精确计算时 fallback 丢弃 20% 的组
|
||||
图片:所有图片/文档块替换为 [image]/[document] 标记后再发送
|
||||
```
|
||||
|
||||
### 熔断器
|
||||
|
||||
```
|
||||
MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
|
||||
触发后:本会话剩余时间停止尝试
|
||||
背景数据:~1,279 个会话曾出现 50+ 次连续失败(最高 3,272 次),
|
||||
每天浪费 ~250K API 调用
|
||||
```
|
||||
|
||||
### Post-Compact 恢复清单
|
||||
|
||||
| 恢复项 | 预算 |
|
||||
|--------|------|
|
||||
| 最近读取的文件 | 最多 5 个,每个 5K tokens,总计 50K |
|
||||
| Skill 附件 | 每个 5K,总计 25K |
|
||||
| Plan 状态 | 完整恢复 |
|
||||
| Deferred tools | 完整恢复 |
|
||||
| Agent 列表 | 完整恢复 |
|
||||
| MCP 指令 | 完整恢复 |
|
||||
|
||||
### Session Memory Compact(替代路径)
|
||||
|
||||
在 auto-compact 中**优先尝试**,失败回退到完整 LLM 摘要:
|
||||
```
|
||||
用预提取的 session memory 替代 LLM 摘要
|
||||
保留范围:从最后摘要消息向后扩展
|
||||
满足 minTokens(10K) 且 minMessages(5)
|
||||
不超过 maxTokens(40K)
|
||||
不变量:tool_use / tool_result 对永不拆分
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第 6-7 层:Reactive Compact + 错误恢复级联
|
||||
|
||||
### 5 层错误恢复(从便宜到昂贵)
|
||||
|
||||
```
|
||||
API 返回 prompt_too_long 或媒体尺寸被拒
|
||||
|
|
||||
v
|
||||
Layer 1: Context Collapse drain(排空所有暂存 collapse,最便宜)
|
||||
| 失败
|
||||
v
|
||||
Layer 2: Reactive Compact(完整 LLM 摘要)
|
||||
| 失败
|
||||
v
|
||||
Layer 3: Max Output 升级(8K → 64K tokens)
|
||||
| 失败
|
||||
v
|
||||
Layer 4: Multi-turn Recovery(注入 nudge 消息,最多 3 次)
|
||||
| 失败
|
||||
v
|
||||
Layer 5: Model Fallback(切换到备用模型)
|
||||
```
|
||||
|
||||
### 错误扣留(Error Withholding)模式
|
||||
|
||||
```
|
||||
流式传输期间,可恢复错误不 yield 给调用者
|
||||
→ 推入 assistantMessages 供恢复检查
|
||||
→ 防止 SDK 消费者终止会话
|
||||
→ 所有恢复手段都失败后才暴露给用户
|
||||
```
|
||||
|
||||
防循环守卫:`hasAttemptedReactiveCompact` 防止同一轮无限重试。
|
||||
|
||||
---
|
||||
|
||||
## Token Budget Continuation — 输出预算跟踪(附加机制)
|
||||
|
||||
```
|
||||
用途:长任务自动续跑(不是上下文管理,是输出预算控制)
|
||||
完成阈值:输出 < 预算 90% → 继续
|
||||
递减检测:连续 3+ 次续跑 且 最近两次增量 < 500 tokens → 停止
|
||||
每次续跑注入 nudge 消息告知进度百分比
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 值得借鉴的设计原则
|
||||
|
||||
### 1. Prompt Cache 稳定性高于空间效率
|
||||
|
||||
- frozen 分区:进入 cache 的内容永不修改
|
||||
- 字节级替换一致性:mustReapply 重用完全相同的替换字符串
|
||||
- Tool pool 排序稳定:`assembleToolPool()` 排序防止 MCP 变化破坏缓存
|
||||
- 缓存编辑不改本地消息:读写分离保证重放一致性
|
||||
|
||||
### 2. 分层防御,从便宜到昂贵
|
||||
|
||||
7 层递进,每层有可能阻止下一层触发。互斥门控防止昂贵操作竞争(collapse 抑制 autocompact)。snipTokensFreed 显式传递确保下游层看到真实 token 数。
|
||||
|
||||
### 3. 错误扣留 + 延迟恢复
|
||||
|
||||
流式传输中不立即暴露可恢复错误。给恢复机制留出空间后再决定是否暴露。这个模式可以推广到任何有多层 fallback 的系统。
|
||||
|
||||
### 4. CQRS 式双视图
|
||||
|
||||
REPL 保留完整历史(UI 回滚 + 会话恢复),API 看到投影视图(节省 tokens)。Context Collapse 的 commit log 和 projectView 就是这个思想的实现。
|
||||
|
||||
### 5. 熔断器模式
|
||||
|
||||
连续失败 3 次后停止重试。用真实数据驱动:1,279 个会话的失控循环 → 250K API 调用/天的浪费。
|
||||
|
||||
### 6. 利用缓存 TTL 做"免费清理"
|
||||
|
||||
cache 自然过期(60min)时搭车执行清理。既然前缀要重建,就把脏活一起干了。
|
||||
|
||||
### 7. Post-Compact 不从零开始
|
||||
|
||||
摘要后精心恢复关键上下文(最近文件、plan、skills)。有明确的 token 预算分配,不是全量恢复也不是什么都不恢复。
|
||||
|
||||
### 8. 不变量保护无处不在
|
||||
|
||||
- tool_use / tool_result 对永不拆分
|
||||
- Compact 边界消息记录 pre-compact 状态供恢复重链
|
||||
- Partial compact 的 "up_to" 变体清除旧边界防止级联剪枝 bug
|
||||
- 子 agent compact 不重置主线程的模块级状态
|
||||
|
||||
---
|
||||
|
||||
## Query Loop 状态机一览
|
||||
|
||||
```typescript
|
||||
State = {
|
||||
messages,
|
||||
toolUseContext,
|
||||
autoCompactTracking, // 熔断计数
|
||||
maxOutputTokensRecoveryCount, // 输出恢复计数
|
||||
hasAttemptedReactiveCompact, // 防循环守卫
|
||||
maxOutputTokensOverride, // 8K → 64K 升级
|
||||
pendingToolUseSummary,
|
||||
stopHookActive,
|
||||
turnCount,
|
||||
transition // 状态转移原因
|
||||
}
|
||||
|
||||
transition 类型:
|
||||
collapse_drain_retry
|
||||
reactive_compact_retry
|
||||
max_output_tokens_escalate
|
||||
max_output_tokens_recovery
|
||||
stop_hook_blocking
|
||||
token_budget_continuation
|
||||
```
|
||||
|
||||
每轮不是递归而是 `while(true)` + 显式状态转移,避免长会话栈溢出。
|
||||
Binary file not shown.
@@ -0,0 +1,710 @@
|
||||
# Claude Code 值得借鉴的算法与设计模式
|
||||
|
||||
> 来源:Claude Code 源码快照(2026-03-31)
|
||||
> 上下文管理部分见另一份笔记 `Claude_Code_Context_Management_Notes.md`
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [权限系统:多层安全级联](#1-权限系统多层安全级联)
|
||||
2. [流式工具执行:模型推理与工具执行重叠](#2-流式工具执行模型推理与工具执行重叠)
|
||||
3. [并发控制与重试策略](#3-并发控制与重试策略)
|
||||
4. [终端渲染引擎:双缓冲 + Diff 写入](#4-终端渲染引擎双缓冲--diff-写入)
|
||||
5. [纯 TypeScript 原生模块移植](#5-纯-typescript-原生模块移植)
|
||||
6. [FileEditTool:12 步验证链](#6-filedittool12-步验证链)
|
||||
7. [记忆系统:提取与召回](#7-记忆系统提取与召回)
|
||||
8. [多 Agent 协调:Swarm 架构](#8-多-agent-协调swarm-架构)
|
||||
9. [启动优化:并行预取](#9-启动优化并行预取)
|
||||
10. [其他精巧设计](#10-其他精巧设计)
|
||||
|
||||
---
|
||||
|
||||
## 1. 权限系统:多层安全级联
|
||||
|
||||
### 1.1 Bash 命令权限解析(8 步级联)
|
||||
|
||||
文件:`src/tools/BashTool/bashPermissions.ts`
|
||||
|
||||
```
|
||||
Step 0: Tree-sitter AST 解析
|
||||
→ simple(干净命令)/ too-complex(无法静态分析)/ parse-unavailable(降级正则)
|
||||
+ Shadow 模式:Tree-sitter 观察性运行,记录与 legacy 路径的分歧
|
||||
|
||||
Step 1: 沙盒自动放行
|
||||
→ sandboxing 启用 + autoAllowBashIfSandboxed → 允许
|
||||
→ 复合命令拆分,逐子命令检查 deny 规则
|
||||
|
||||
Step 2: 精确匹配权限检查
|
||||
→ 优先级:deny > ask > allow > passthrough
|
||||
|
||||
Step 3: LLM 分类器 deny/ask 规则
|
||||
→ Haiku 模型并行分类 deny 和 ask 描述列表
|
||||
→ 仅高置信度结果触发
|
||||
|
||||
Step 4: 命令操作符拆分
|
||||
→ 对 |, &&, ||, ; 递归调用权限检查
|
||||
→ 即使管道段被允许,原始命令仍重新验证
|
||||
|
||||
Step 5: Legacy 误解析门控
|
||||
→ 仅当 Tree-sitter 不可用时运行
|
||||
|
||||
Step 6: 逐子命令检查
|
||||
→ splitCommand → 过滤 cd ${cwd} → checkCommandAndSuggestRules
|
||||
|
||||
Step 7: 8 步子级联
|
||||
→ 精确匹配 → 前缀 deny → ask 规则 → 路径约束
|
||||
→ 精确 allow → 前缀/通配符 allow → sed 约束
|
||||
→ 模式权限 → 只读检查 → passthrough
|
||||
```
|
||||
|
||||
### 1.2 规则匹配中的安全技巧
|
||||
|
||||
**复合命令防护**:前缀和通配符规则拒绝匹配复合命令。防止 `cd /path && python3 evil.py` 被 `cd:*` 规则放行。
|
||||
|
||||
**环境变量剥离的不对称设计**:
|
||||
- Deny 规则:使用激进的 `stripAllLeadingEnvVars`(固定点循环剥离所有环境变量),防止 `FOO=bar denied_cmd` 绕过
|
||||
- Allow 规则:使用保守的 `stripSafeWrappers`,只接受白名单中的 ~60 个安全环境变量
|
||||
|
||||
**安全环境变量白名单**(SAFE_ENV_VARS):
|
||||
- 包含:`NODE_ENV`, `RUST_LOG`, `CGO_ENABLED` 等
|
||||
- 排除:`PATH`, `LD_PRELOAD`, `LD_LIBRARY_PATH`, `DYLD_*`, `PYTHONPATH`, `NODE_OPTIONS`, `BASH_ENV`
|
||||
|
||||
### 1.3 Shell 安全分析(23 个验证器)
|
||||
|
||||
文件:`src/tools/BashTool/bashSecurity.ts`
|
||||
|
||||
按安全优先级排序的验证链:
|
||||
|
||||
| 验证器 | 检测内容 |
|
||||
|--------|---------|
|
||||
| `validateJqCommand` | `system()`, `-f`, `--from-file`, `-L` |
|
||||
| `validateObfuscatedFlags` | 引号内隐藏的标志(如 `"-rf"`) |
|
||||
| `validateShellMetacharacters` | 参数中的 `;`, `\|`, `&` |
|
||||
| `validateDangerousVariables` | `BASH_ENV`, `PROMPT_COMMAND`, `PS1`, `BASH_FUNC_*` |
|
||||
| `validateCommentQuoteDesync` | 引号内的 `#`(注释跟踪混淆) |
|
||||
| `validateCarriageReturn` | CR 字符(shell-quote/bash 分词差异) |
|
||||
| `validateIFSInjection` | `IFS=` 赋值 |
|
||||
| `validateDangerousPatterns` | 反引号, `$()`, `${}`, zsh 扩展 (`=cmd`, `~[`, `(e:`) |
|
||||
| `validateUnicodeWhitespace` | 非 ASCII 空白字符 |
|
||||
| `validateBraceExpansion` | `{...,...}` 模式 |
|
||||
| `validateZshDangerousCommands` | 20+ 个 zsh 内建命令(`zmodload`, `syswrite`, `ztcp` 等) |
|
||||
|
||||
**关键排序技巧**:非误解析验证器的 `ask` 结果被延迟返回。循环继续运行误解析验证器;只有没有误解析验证器触发时,延迟的非误解析结果才被返回。防止非误解析的 `ask` 掩盖应该设置 `isBashSecurityCheckForMisparsing` 的误解析 `ask`。
|
||||
|
||||
### 1.4 只读命令分类(双层判定)
|
||||
|
||||
文件:`src/tools/BashTool/readOnlyValidation.ts`
|
||||
|
||||
**Tier 1 — Flag 级别白名单**:每个命令的每个 flag 都有类型标注(`none`, `number`, `string`, 特定字面量)。特例:
|
||||
- `xargs` 的 `-i`/`-e` 被移除(GNU `getopt_long` 可选参数语义漏洞)
|
||||
- `tree` 的 `-R` 被移除(它会写文件)
|
||||
- `fd`/`fdfind` 的 `-x`/`--exec` 被排除
|
||||
|
||||
**Tier 2 — 正则匹配**:`cat`, `head`, `tail`, `wc`, `jq`, `echo`, `pwd` 等简单命令。
|
||||
|
||||
**复合命令安全**:`cd && git` 组合被阻止(沙盒逃逸 — 通过恶意 git hooks)。检测写入 `.git/hooks/`、`objects/`、`refs/` 后运行 git 的命令链。
|
||||
|
||||
### 1.5 Auto-Mode (YOLO) 分类器
|
||||
|
||||
文件:`src/utils/permissions/yoloClassifier.ts`
|
||||
|
||||
**不是传统 ML — 是 LLM 即分类器**。
|
||||
|
||||
**两阶段 XML 分类**:
|
||||
```
|
||||
Stage 1(快速判定):
|
||||
max_tokens=64, stop_sequences=['</block>']
|
||||
→ "no"(允许):立即返回
|
||||
→ "yes" 或无法解析:升级到 Stage 2
|
||||
|
||||
Stage 2(深度推理):
|
||||
max_tokens=4096, 启用 chain-of-thought
|
||||
→ 用 <thinking> 标签推理后再决定
|
||||
→ 解析时先剥离 <thinking> 块再匹配 <block> 标签
|
||||
```
|
||||
|
||||
**200ms 竞赛模式**(interactiveHandler.ts):
|
||||
```
|
||||
5 个参赛者同时启动:
|
||||
1. 用户权限对话框
|
||||
2. Hooks 异步执行
|
||||
3. Bash 分类器异步执行
|
||||
4. Bridge 权限响应(claude.ai)
|
||||
5. Channel 权限中继(Telegram 等)
|
||||
|
||||
createResolveOnce 原子 claim() — 第一个到达的赢,其他 no-op
|
||||
|
||||
200ms 宽限期:
|
||||
前 200ms 内忽略用户交互(防止意外按键取消分类器)
|
||||
200ms 后任何用户交互都会杀死分类器的自动批准机会
|
||||
```
|
||||
|
||||
**投机性分类器检查**:在权限对话框出现之前就启动分类器(`startSpeculativeClassifierCheck`),与 deny/ask 分类器、hooks、对话框设置并行运行。
|
||||
|
||||
---
|
||||
|
||||
## 2. 流式工具执行:模型推理与工具执行重叠
|
||||
|
||||
文件:`src/services/tools/StreamingToolExecutor.ts`
|
||||
|
||||
### 核心思想
|
||||
|
||||
工具在模型**还在生成 token 时就开始执行**,而非等完整响应结束。
|
||||
|
||||
### 并发控制算法
|
||||
|
||||
```typescript
|
||||
canExecuteTool(isConcurrencySafe: boolean): boolean {
|
||||
const executing = this.tools.filter(t => t.status === 'executing')
|
||||
return (
|
||||
executing.length === 0 ||
|
||||
(isConcurrencySafe && executing.every(t => t.isConcurrencySafe))
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- 没有正在执行的工具 → 可以执行
|
||||
- 自身并发安全 且 所有正在执行的也并发安全 → 可以执行
|
||||
- 否则 → 等待
|
||||
|
||||
### 工具状态机
|
||||
|
||||
```
|
||||
queued → executing → completed → yielded
|
||||
```
|
||||
|
||||
队列有序处理。非并发工具遇到无法执行时直接 break(保持严格顺序);并发工具可跳过。
|
||||
|
||||
### 错误级联
|
||||
|
||||
**只有 Bash 错误才取消兄弟工具**。原因:Bash 命令有隐式依赖链(mkdir 失败 → 后续命令无意义)。Read/WebFetch 等独立工具不取消。
|
||||
|
||||
`siblingAbortController` 是 parent 的子控制器 — 兄弟子进程立即死亡,但父 query loop 不中断。
|
||||
|
||||
### 进度流式传输
|
||||
|
||||
使用 Promise 信号机制(`progressAvailableResolve`)。`getRemainingResults()` async generator 用 `Promise.race` 在工具完成和新进度到达之间等待,确保进度消息实时传递而非缓冲。
|
||||
|
||||
### 与 query.ts 的集成
|
||||
|
||||
```
|
||||
流式循环中:
|
||||
API content_block_stop 事件
|
||||
→ 立即 yield AssistantMessage
|
||||
→ query.ts 喂给 StreamingToolExecutor.addTool()
|
||||
|
||||
事件间隙:
|
||||
→ getCompletedResults() 收割已完成的工具
|
||||
|
||||
流式结束后:
|
||||
→ getRemainingResults() 排空所有待处理工具
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 并发控制与重试策略
|
||||
|
||||
### 3.1 并发 Generator 合并(all 函数)
|
||||
|
||||
文件:`src/utils/generators.ts`
|
||||
|
||||
```
|
||||
维护 waiting 队列 + active Promise 集合
|
||||
1. 初始填充 concurrencyCap 个 generator
|
||||
2. Promise.race 所有活跃 generator
|
||||
3. 某个 yield → 立即 .next() 推进它
|
||||
4. 某个完成 → waiting 中取一个填补
|
||||
5. 公平交错 + 有界并行(默认上限 10)
|
||||
```
|
||||
|
||||
### 3.2 工具并发安全分类
|
||||
|
||||
| 分类 | 工具 | 依据 |
|
||||
|------|------|------|
|
||||
| 始终安全 | FileRead, LSP, TaskCreate, TaskGet, Brief | 返回 `true` |
|
||||
| 输入依赖 | BashTool | 委托给 `isReadOnly(input)`,只读命令并发,写命令独占 |
|
||||
| 默认不安全 | FileEdit, FileWrite 等 | 使用默认 `false`(fail-closed) |
|
||||
|
||||
### 3.3 指数退避 + 抖动重试
|
||||
|
||||
文件:`src/services/api/withRetry.ts`
|
||||
|
||||
```
|
||||
baseDelay = min(500ms * 2^(attempt-1), 32s)
|
||||
jitter = random(0, 25% * baseDelay) // 加性抖动,非乘性
|
||||
finalDelay = baseDelay + jitter
|
||||
// server retry-after header 存在时覆盖
|
||||
```
|
||||
|
||||
**529(过载)处理 — 级联放大防护**:
|
||||
```
|
||||
非前台查询(摘要、标题、分类器)→ 收到 529 立即放弃(不重试)
|
||||
前台查询 → 重试最多 3 次
|
||||
3 次 529 后 → FallbackTriggeredError → 切换备用模型
|
||||
```
|
||||
|
||||
**Fast Mode 降级**:
|
||||
```
|
||||
429/529 + fast mode 激活:
|
||||
retry-after < 20s → 继续 fast mode 重试(保持 prompt cache)
|
||||
retry-after ≥ 20s → 冷却(最少 10min)切换标准速度
|
||||
```
|
||||
|
||||
**无人值守模式**(`CLAUDE_CODE_UNATTENDED_RETRY`):
|
||||
```
|
||||
429/529 无限重试,最大退避 5 分钟
|
||||
长休眠拆为 30s 心跳间隔(防止主机标记会话空闲)
|
||||
6 小时硬上限重置
|
||||
```
|
||||
|
||||
### 3.4 流式看门狗
|
||||
|
||||
文件:`src/services/api/claude.ts`
|
||||
|
||||
```
|
||||
空闲超时默认 90s(可配置)
|
||||
50% 时间 → 警告
|
||||
100% 时间 → 硬中止挂起的流
|
||||
每个 chunk 重置计时器
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 终端渲染引擎:双缓冲 + Diff 写入
|
||||
|
||||
### 4.1 双缓冲帧交换
|
||||
|
||||
文件:`src/ink/ink.tsx`, `src/ink/output.ts`, `src/ink/screen.ts`
|
||||
|
||||
```
|
||||
每次渲染后:
|
||||
backFrame = frontFrame
|
||||
frontFrame = newFrame
|
||||
```
|
||||
|
||||
**Screen 缓冲区**:packed `Int32Array`,每个单元格 2 个 word(8 bytes)。
|
||||
- Word 0: char pool ID
|
||||
- Word 1: style ID + hyperlink ID + cell width(位打包)
|
||||
- `resetScreen()` 复用同一 buffer(只增不缩),用 `BigInt64Array` 视图批量清零
|
||||
|
||||
**charCache**(16384 上限):跨帧缓存 grapheme 聚类结果,大多数行不变时直接命中。
|
||||
|
||||
### 4.2 Diff 算法
|
||||
|
||||
文件:`src/ink/screen.ts` (diffEach), `src/ink/log-update.ts`
|
||||
|
||||
```
|
||||
1. 计算两帧 damage rectangle 的并集
|
||||
2. 仅在 damage 区域内逐 word 比较 Int32Array
|
||||
3. findNextDiff() 是纯函数,设计为 JIT 内联
|
||||
4. VirtualScreen 跟踪光标位置,只在目标不一致时发移动指令
|
||||
```
|
||||
|
||||
**关键优化**:
|
||||
- **DECSTBM 硬件滚动**:ScrollBox 的 scrollTop 变化时用终端硬件滚动(`CSI top;bot r + CSI n S/T`),而非重写整个区域。先对 prev.screen 执行 `shiftRows()` 模拟硬件位移,后续 diff 自然只找到新滚入的行。
|
||||
- **StylePool.transition()**:按 (fromId, toId) 对缓存 ANSI 样式转换字符串 — 预热后零分配
|
||||
- **fg-only 空格跳过**:只有前景色的空格单元格视为不可见,跳过写入
|
||||
|
||||
### 4.3 Blit 优化
|
||||
|
||||
文件:`src/ink/render-node-to-output.ts`
|
||||
|
||||
```
|
||||
节点干净(not dirty)且布局位置不变
|
||||
→ 直接从 prevScreen 复制单元格(blit)
|
||||
→ blitRegion() 使用 TypedArray.set() 批量内存拷贝
|
||||
→ 每行一次调用,连续全宽区域只需一次
|
||||
→ 跳过整个子树的重新渲染
|
||||
```
|
||||
|
||||
### 4.4 渲染器 Peephole 优化
|
||||
|
||||
文件:`src/ink/optimizer.ts`
|
||||
|
||||
单趟扫描 Diff 数组:
|
||||
- 合并连续 `cursorMove`(加 dx/dy)
|
||||
- 折叠连续 `cursorTo`(只保留最后一个)
|
||||
- 拼接相邻 `styleStr`
|
||||
- 取消 cursor hide/show 对
|
||||
- 去重相同 URI 的 hyperlink patch
|
||||
- 移除 count=0 的 clear patch
|
||||
|
||||
---
|
||||
|
||||
## 5. 纯 TypeScript 原生模块移植
|
||||
|
||||
### 5.1 Yoga 布局引擎(C++ → TypeScript)
|
||||
|
||||
文件:`src/native-ts/yoga-layout/index.ts`(~2400 行)
|
||||
|
||||
完整的 Flexbox 布局实现,消除了 native binary 依赖。
|
||||
|
||||
**多层缓存策略**:
|
||||
| 缓存 | 机制 | 效果 |
|
||||
|------|------|------|
|
||||
| Dirty-flag | 干净子树 + 匹配输入 → 跳过 | 最基本的剪枝 |
|
||||
| 双槽缓存 | 分别缓存 layout 和 measure 结果 | 同一节点两种调用模式 |
|
||||
| 4 槽环形缓存 | packed Float64Array | 500 消息 scrollbox: 76k→4k layoutNode 调用 |
|
||||
| flex-basis 缓存 | generation-stamped | 短路递归 computeFlexBasis |
|
||||
| 快速路径标志 | `_hasAutoMargin` 等 | 全零情况单分支跳过 |
|
||||
|
||||
**`resolveEdges4Into()`**:一次遍历解析全部 4 条物理边到预分配元组,提升共享 fallback 查找。
|
||||
|
||||
### 5.2 模糊搜索(Rust nucleo/fzf → TypeScript)
|
||||
|
||||
文件:`src/native-ts/file-index/index.ts`
|
||||
|
||||
**逐步过滤架构**:
|
||||
```
|
||||
Step 1: 字符位图过滤(O(1) 拒绝)
|
||||
→ 每个路径一个 26-bit charBits 掩码
|
||||
→ (charBits & needleBitmap) !== needleBitmap → 跳过
|
||||
|
||||
Step 2: 融合 indexOf 扫描
|
||||
→ String.indexOf()(V8/JSC 中 SIMD 加速)
|
||||
→ 同时找到匹配位置 + 累积 gap/consecutive 分数
|
||||
→ 无需第二次评分遍历
|
||||
|
||||
Step 3: Gap-bound 拒绝
|
||||
→ 计算分数上限(所有边界奖励)减去已知 gap 惩罚
|
||||
→ 无法超过当前 top-k 阈值 → 跳过昂贵的边界评分
|
||||
|
||||
Step 4: 边界/驼峰评分
|
||||
→ 路径分隔符 (/\-_.) 匹配奖励
|
||||
→ 驼峰转换匹配奖励
|
||||
→ 首字符匹配奖励
|
||||
→ 常数近似 nucleo/fzf-v2 权重
|
||||
|
||||
Top-k 维护:升序数组 + 二分插入(避免全量 O(n log n) 排序)
|
||||
```
|
||||
|
||||
**其他特性**:
|
||||
- 异步构建:每 ~4ms yield 事件循环,`readyCount` 支持构建中的部分索引搜索
|
||||
- 智能大小写:全小写查询 = 大小写不敏感;有大写 = 敏感
|
||||
- 测试文件惩罚:路径包含 "test" → 1.05x 分数惩罚
|
||||
|
||||
### 5.3 语法高亮 + Word-Level Diff(Rust syntect/bat → TypeScript)
|
||||
|
||||
文件:`src/native-ts/color-diff/index.ts`
|
||||
|
||||
- highlight.js 延迟加载(避免 ~200ms 的 190+ 语法注册启动成本)
|
||||
- `diff` npm 包的 `diffArrays` 做词级 diff
|
||||
- RGB → ANSI-256 颜色近似:移植 `ansi_colours` Rust crate 的立方体 vs 灰阶感知最近索引算法
|
||||
- Monokai Extended / GitHub-light 作用域到颜色映射
|
||||
- Storage 关键字重分割(highlight.js 把 `const`/`function`/`class` 归为 "keyword";端口重分割以匹配 syntect 的 cyan storage 颜色)
|
||||
|
||||
---
|
||||
|
||||
## 6. FileEditTool:12 步验证链
|
||||
|
||||
文件:`src/tools/FileEditTool/FileEditTool.ts`
|
||||
|
||||
```
|
||||
1. 密钥检测 → 阻止向 team memory 文件写入密钥
|
||||
2. 空操作检测 → old_string === new_string 直接拒绝
|
||||
3. Deny 规则检查 → 文件路径匹配 deny 权限规则
|
||||
4. UNC 路径安全 → 跳过 \\server\share(防止 NTLM 凭证泄露)
|
||||
5. 文件大小守卫 → > 1 GiB 拒绝
|
||||
6. 编码检测 → UTF-16LE BOM (0xFF 0xFE) / UTF-8, \r\n → \n
|
||||
7. 文件存在检查 → 不存在时建议相似文件(findSimilarFile)
|
||||
8. 空 old_string → 仅在文件为空时允许(创建文件场景)
|
||||
9. Notebook 重定向 → .ipynb 必须使用 NotebookEditTool
|
||||
10. 陈旧性检测 → mtime 比较,失败时回退到内容比较(避免云同步/杀毒软件时间戳干扰的误报)
|
||||
11. 引号规范化 → 弯引号→直引号搜索;写入时用启发式恢复弯引号样式
|
||||
12. 歧义匹配 → 多处匹配 + 非 replace_all → 拒绝并要求更多上下文
|
||||
```
|
||||
|
||||
### 引号规范化算法(utils.ts)
|
||||
|
||||
```
|
||||
搜索阶段:
|
||||
1. 精确匹配 old_string → 找到则使用
|
||||
2. normalizeQuotes(old_string) → 弯引号转直引号
|
||||
3. 在 normalizeQuotes(fileContent) 中搜索
|
||||
4. 返回 fileContent 中的原始子串(保留弯引号)
|
||||
|
||||
写入阶段(preserveQuoteStyle):
|
||||
检测到规范化被应用时:
|
||||
→ 将 new_string 中的直引号转回弯引号
|
||||
→ 启发式:空白/行首/开括号后 = 开引号;字母间 = 撇号
|
||||
```
|
||||
|
||||
### 反序列化映射(desanitizeMatchString)
|
||||
|
||||
模型不会看到某些 XML 标签(发送给 API 前被清理)。当模型在编辑中输出清理后的形式时,反向映射:
|
||||
- `<fnr>` → `<function_results>`
|
||||
- `\n\nH:` → `\n\nHuman:`
|
||||
|
||||
### call() 写入路径中的双重陈旧性检查
|
||||
|
||||
```
|
||||
validateInput 时检查一次陈旧性
|
||||
→ 通过
|
||||
→ call() 中重新同步读取文件,再次检查
|
||||
→ 防止 validate 和 call 之间的 TOCTOU 竞态
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 记忆系统:提取与召回
|
||||
|
||||
### 7.1 记忆提取(extractMemories)
|
||||
|
||||
文件:`src/services/extractMemories/`
|
||||
|
||||
**架构**:每个完整 query loop 结束时,fork 一个子 agent(共享父级 prompt cache)执行提取。
|
||||
|
||||
```
|
||||
提取流程:
|
||||
1. 门控:仅主 agent,非子 agent,非远程模式
|
||||
2. 重叠守卫:已有提取在运行 → 暂存当前上下文(最新覆盖旧的)
|
||||
3. 轮次节流:合格轮次未达阈值 → 跳过
|
||||
4. 互斥:主 agent 已手动写入记忆 → 跳过并推进游标
|
||||
5. 注入记忆清单:扫描目录 + 读 frontmatter → 预格式化
|
||||
6. Fork agent 执行:最多 5 轮,受限工具访问
|
||||
7. 游标推进:仅在成功后;失败时留在原位以重新考虑
|
||||
8. 尾随运行:完成后检查暂存的待处理上下文
|
||||
```
|
||||
|
||||
**工具限制**:Read/Grep/Glob 无限制;只读 Bash;Edit/Write 仅限记忆目录内。
|
||||
|
||||
### 7.2 记忆召回(findRelevantMemories)
|
||||
|
||||
文件:`src/memdir/findRelevantMemories.ts`
|
||||
|
||||
**不是启发式评分 — 是 LLM 评分**:
|
||||
|
||||
```
|
||||
Phase 1: 扫描
|
||||
→ 读取记忆目录所有 .md 文件(排除 MEMORY.md)
|
||||
→ 每个文件读前 30 行提取 frontmatter(name, description, type)
|
||||
→ 按 mtime 降序排列,上限 200 个文件
|
||||
→ 单遍设计:读取后排序(而非 stat-排序-读取),syscall 减半
|
||||
|
||||
Phase 2: LLM 选择
|
||||
→ 发送查询 + 格式化清单 + 最近使用工具列表给 Sonnet
|
||||
→ 结构化 JSON 输出
|
||||
→ "只包含你确定有帮助的记忆。不确定就不包含。最多 5 个。"
|
||||
→ 最近使用工具列表防止为已活跃使用的工具推荐 API 文档
|
||||
→ 但关于这些工具的警告/陷阱仍然会被选中
|
||||
|
||||
Phase 3: 新鲜度处理
|
||||
→ 超过 1 天的记忆注入 <system-reminder> 告警
|
||||
→ "此记忆已 N 天。关于代码行为的声明可能过时。"
|
||||
```
|
||||
|
||||
**already-surfaced 过滤**:过滤掉之前轮次已展示的路径,5 个名额全部花在新候选上。
|
||||
|
||||
---
|
||||
|
||||
## 8. 多 Agent 协调:Swarm 架构
|
||||
|
||||
### 8.1 协调者模式(Coordinator)
|
||||
|
||||
文件:`src/coordinator/coordinatorMode.ts`
|
||||
|
||||
```
|
||||
任务工作流阶段:
|
||||
Research(并行 workers)→ Synthesis(协调者)→ Implementation(workers)→ Verification(workers)
|
||||
|
||||
并发规则:
|
||||
只读任务 → 自由并行
|
||||
写密集任务 → 按文件区域串行
|
||||
验证可与不同文件的实现重叠
|
||||
|
||||
Worker prompt 必须自包含:
|
||||
Worker 看不到协调者对话 → 每个 prompt 需要完整上下文(文件路径、行号等)
|
||||
|
||||
Continue vs Spawn 决策:
|
||||
高上下文重叠 → continue(复用已加载上下文)
|
||||
低上下文重叠 → spawn 新 worker
|
||||
```
|
||||
|
||||
### 8.2 两种后端策略
|
||||
|
||||
| 后端 | 隔离方式 | 通信 | 特点 |
|
||||
|------|---------|------|------|
|
||||
| In-Process | `AsyncLocalStorage` 上下文隔离 | 基于文件的 mailbox | 共享 API client + MCP 连接;独立 AbortController(leader 中断不杀 worker) |
|
||||
| Pane-Based (tmux/iTerm2) | 独立 OS 进程 | 基于文件的 mailbox | CLI flag 传播(`--agent-id`, `--agent-name`, `--team-name`, `--agent-color`);leader 的模型/权限/环境变量全部传播 |
|
||||
|
||||
### 8.3 权限桥接
|
||||
|
||||
In-process teammate 通过 `leaderPermissionBridge` 路由权限提示到 leader 的 UI(复用 BashPermissionRequest、FileEditToolDiff 等对话框)。Bridge 不可用时回退到 mailbox 权限同步。
|
||||
|
||||
### 8.4 Fork Subagent
|
||||
|
||||
文件:`src/tools/AgentTool/forkSubagent.ts`
|
||||
|
||||
```
|
||||
子进程继承父级完整对话上下文 + system prompt
|
||||
|
||||
递归 fork 防护:
|
||||
isInForkChild() 检查对话历史中的 <fork_boilerplate> 标签
|
||||
|
||||
Cache 共享设计:
|
||||
保留完整父级 assistant 消息(所有 tool_use 块)
|
||||
构建 tool_result 块(占位文本:"Fork started -- processing in background")
|
||||
只有最后的 text 块不同 → 最大化 prompt cache 命中
|
||||
|
||||
子进程 10 条严格规则:
|
||||
不生成子 agent、不评论、只用工具、提交变更、
|
||||
结构化输出(Scope/Result/Key files/Files changed/Issues)、最多 500 字
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 启动优化:并行预取
|
||||
|
||||
文件:`src/main.tsx` 前 20 行
|
||||
|
||||
```typescript
|
||||
// 这些副作用必须在所有其他 import 之前运行:
|
||||
profileCheckpoint('main_tsx_entry') // 标记入口(在 ~135ms import 之前)
|
||||
startMdmRawRead() // 并行:MDM 子进程读取(plutil/reg query)
|
||||
startKeychainPrefetch() // 并行:macOS 钥匙串双读取
|
||||
// 无此优化:~65ms 同步阻塞(每次 macOS 启动)
|
||||
```
|
||||
|
||||
**启动分析器**(`startupProfiler.ts`):
|
||||
- 采样日志:内部 100%,外部 0.5%。记录 import_time, init_time, settings_time, total_time
|
||||
- 详细分析:`CLAUDE_CODE_PROFILE_STARTUP=1`,带 `process.memoryUsage()` 快照的完整时间线
|
||||
- 非采样用户零开销(`profileCheckpoint` 立即返回)
|
||||
|
||||
---
|
||||
|
||||
## 10. 其他精巧设计
|
||||
|
||||
### 10.1 35 行状态管理
|
||||
|
||||
文件:`src/state/store.ts`
|
||||
|
||||
```typescript
|
||||
createStore<T>(initialState, onChange?) => {
|
||||
getState() // 返回当前状态
|
||||
setState(updater) // updater: (prev) => next
|
||||
// Object.is() 相等检查(引用相同则跳过)
|
||||
// 触发 onChange + 通知 Set<Listener>
|
||||
subscribe(listener) // 返回 unsubscribe
|
||||
}
|
||||
```
|
||||
|
||||
无中间件,无选择器,无 devtools。配合 `useSyncExternalStore` 实现最小化重渲染。
|
||||
|
||||
### 10.2 ToolSearchTool — 延迟工具发现
|
||||
|
||||
文件:`src/tools/ToolSearchTool/ToolSearchTool.ts`
|
||||
|
||||
**两种查询模式**:
|
||||
|
||||
直接选择(`select:ToolA,ToolB`):精确查找,返回 `tool_reference` 块。
|
||||
|
||||
关键词搜索评分:
|
||||
| 匹配类型 | 分数 |
|
||||
|---------|------|
|
||||
| 名称部分精确匹配 | +10(MCP: +12) |
|
||||
| 名称部分子串匹配 | +5(MCP: +6) |
|
||||
| 全名回退 | +3 |
|
||||
| searchHint 词边界匹配 | +4 |
|
||||
| 描述词边界匹配 | +2 |
|
||||
|
||||
`+` 前缀标记必需词(全部必须匹配才入围)。
|
||||
|
||||
工具名解析:MCP 工具去 `mcp__` 前缀后按 `__` 和 `_` 分割;普通工具按驼峰转换和 `_` 分割。
|
||||
|
||||
### 10.3 Token 估算(无 API 调用)
|
||||
|
||||
文件:`src/utils/tokens.ts`
|
||||
|
||||
```
|
||||
粗略估算:content.length / bytesPerToken
|
||||
|
||||
文件类型感知:
|
||||
JSON/JSONL/JSONC: 2 bytes/token(密集单字符 token)
|
||||
其他: 4 bytes/token
|
||||
|
||||
区块级估算:
|
||||
text/thinking: length / 4
|
||||
image/document: 固定 2000 tokens
|
||||
tool_use: (name + JSON.stringify(input)).length / 4
|
||||
|
||||
上下文窗口估算(tokenCountWithEstimation):
|
||||
1. 从后向前找到最后一条有 API usage 数据的消息
|
||||
2. 处理并行工具调用:跨越共享 message.id 的兄弟记录
|
||||
3. 返回 usage.input_tokens + 粗略估算(后续消息)
|
||||
4. 无 usage 数据时全量粗略估算
|
||||
```
|
||||
|
||||
### 10.4 错误扣留模式(Error Withholding)
|
||||
|
||||
```
|
||||
流式传输中可恢复错误不暴露给调用者:
|
||||
→ prompt_too_long, media_size, max_output_tokens
|
||||
→ 推入 assistantMessages 供恢复检查
|
||||
→ 所有恢复失败后才 yield 给用户
|
||||
→ 防止 SDK 消费者在中间错误时终止会话
|
||||
```
|
||||
|
||||
### 10.5 Prompt Cache 稳定性设计集锦
|
||||
|
||||
| 技术 | 位置 | 效果 |
|
||||
|------|------|------|
|
||||
| 工具池排序 | `assembleToolPool()` | 防止 MCP 变更破坏缓存前缀 |
|
||||
| 系统 prompt 分界标记 | `SYSTEM_PROMPT_DYNAMIC_BOUNDARY` | 静态部分 `scope: global` 跨组织缓存 |
|
||||
| Agent 列表附件注入 | AgentTool prompt.ts | 从工具描述中移出动态列表(减少 10.2% cache_creation) |
|
||||
| Fork 消息构造 | forkSubagent.ts | 所有子进程共享相同 tool_result 占位符,仅最后文本块不同 |
|
||||
| Tool result 替换一致性 | toolResultStorage.ts | mustReapply 重用完全相同的替换字符串(字节级一致) |
|
||||
| frozen 分区 | toolResultStorage.ts | 进入 cache 的内容永不修改 |
|
||||
|
||||
### 10.6 文本选择算法
|
||||
|
||||
文件:`src/ink/selection.ts`
|
||||
|
||||
- anchor + focus 点用屏幕缓冲区坐标(col, row)
|
||||
- 双击/三击选词/行模式:`anchorSpan` 启用拖拽时按词/行扩展
|
||||
- 滚动捕获:`scrolledOffAbove`/`scrolledOffBelow` 累加器捕获拖拽滚动时离开视口的行
|
||||
- 词边界检测匹配 iTerm2 默认行为(路径字符 `/-+\~_.` 视为词字符)
|
||||
- `getSelectedText()` 合并离屏和在屏行,尊重软换行标记重建逻辑行
|
||||
|
||||
### 10.7 鼠标 Hit Testing
|
||||
|
||||
文件:`src/ink/hit-test.ts`
|
||||
|
||||
递归深度优先遍历 DOM 树。**子节点逆序遍历**(后绘制的在上层),确保正确 z-order。
|
||||
- `dispatchClick()`:从最深命中节点沿 parentNode 冒泡
|
||||
- `dispatchHover()`:类 DOM mouseEnter/mouseLeave(非冒泡),diff hovered-node 集合
|
||||
|
||||
### 10.8 GrepTool 分页
|
||||
|
||||
```
|
||||
默认限制:250 条(未指定时)
|
||||
head_limit=0:无限制(谨慎使用)
|
||||
offset 参数:跳过前 N 条
|
||||
分页在 ripgrep 返回后、路径相对化之前应用(节省 CPU)
|
||||
appliedLimit 仅在实际截断时报告(让模型知道有更多结果)
|
||||
```
|
||||
|
||||
### 10.9 Partial Compact 方向性
|
||||
|
||||
```
|
||||
from(默认):
|
||||
摘要 pivot 之后的消息,保留之前的
|
||||
→ prompt cache 保留(保留的消息在前)
|
||||
|
||||
up_to:
|
||||
摘要 pivot 之前的消息,保留之后的
|
||||
→ prompt cache 失效(摘要在保留消息之前)
|
||||
→ 剥离旧 compact 边界和摘要(防止陈旧边界混淆扫描器)
|
||||
```
|
||||
|
||||
### 10.10 API 消息轮次分组
|
||||
|
||||
文件:`src/services/compact/grouping.ts`
|
||||
|
||||
```
|
||||
groupMessagesByApiRound:
|
||||
按 API 轮次边界分组(不同 message.id 标记新轮次)
|
||||
比之前的 human-turn 分组更细粒度
|
||||
→ 支持单 human turn 的 SDK/CCR/eval 会话中的精确 compact
|
||||
流式 chunk 共享 id → 同一响应内的交错 tool_result 保持正确分组
|
||||
```
|
||||
BIN
docs/cc_analysis/analysis_20260401/Claude_Code_深度分析报告.pdf
Normal file
BIN
docs/cc_analysis/analysis_20260401/Claude_Code_深度分析报告.pdf
Normal file
Binary file not shown.
871
docs/cc_analysis/analysis_20260401/Claude_Code上下文压缩算法深度分析.md
Normal file
871
docs/cc_analysis/analysis_20260401/Claude_Code上下文压缩算法深度分析.md
Normal file
@@ -0,0 +1,871 @@
|
||||
# Claude Code 上下文压缩算法深度分析
|
||||
|
||||
> 基于 Claude Code 源码(2026-03-31 快照,512K 行 TypeScript)逆向分析
|
||||
> 核心文件:`src/services/compact/` 目录下 11 个文件
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [架构总览](#1-架构总览)
|
||||
2. [第1层:微压缩(Microcompact)](#2-第1层微压缩microcompact)
|
||||
3. [第2层:自动压缩(Auto-Compact)](#3-第2层自动压缩auto-compact)
|
||||
4. [第3层:传统压缩(Full Compact)](#4-第3层传统压缩full-compact)
|
||||
5. [第4层:Session Memory 压缩](#5-第4层session-memory-压缩)
|
||||
6. [消息分组算法](#6-消息分组算法)
|
||||
7. [Token 估算算法](#7-token-估算算法)
|
||||
8. [压缩提示词工程](#8-压缩提示词工程)
|
||||
9. [5层错误恢复中的压缩角色](#9-5层错误恢复中的压缩角色)
|
||||
10. [各层对比与设计哲学](#10-各层对比与设计哲学)
|
||||
|
||||
---
|
||||
|
||||
## 1. 架构总览
|
||||
|
||||
Claude Code 的上下文压缩不是单一算法,而是一个 **4层递进的压缩体系**,每层解决不同层面的问题:
|
||||
|
||||
```
|
||||
用户消息 → [第1层:微压缩] → [第2层:自动压缩] → API 调用
|
||||
↓ ↓
|
||||
细粒度清理旧工具输出 上下文即将超限时触发
|
||||
(不丢语义,<1ms) (调用 LLM 或 Session Memory)
|
||||
↓
|
||||
┌──────────────┴──────────────┐
|
||||
[第4层:SM压缩] [第3层:传统压缩]
|
||||
(用已有摘要,<10ms) (Fork Agent 生成摘要,5-30s)
|
||||
```
|
||||
|
||||
**核心原则:** 尽可能用廉价的规则操作延迟昂贵的 LLM 调用,只在不得已时丢弃信息。
|
||||
|
||||
### 涉及的源文件
|
||||
|
||||
| 文件 | 行数 | 职责 |
|
||||
|------|------|------|
|
||||
| `microCompact.ts` | ~400 | 微压缩:规则清理旧工具结果 |
|
||||
| `apiMicrocompact.ts` | — | API 层缓存编辑集成 |
|
||||
| `timeBasedMCConfig.ts` | — | 时间触发微压缩配置 |
|
||||
| `autoCompact.ts` | ~350 | 自动压缩:阈值判断 + 断路器 |
|
||||
| `compact.ts` | ~600+ | 传统压缩:Fork Agent 摘要 |
|
||||
| `prompt.ts` | ~375 | 压缩提示词模板 |
|
||||
| `sessionMemoryCompact.ts` | ~630 | Session Memory 压缩路径 |
|
||||
| `grouping.ts` | ~63 | 消息按 API 轮次分组 |
|
||||
| `postCompactCleanup.ts` | — | 压缩后清理 |
|
||||
| `compactWarningHook.ts` | — | 压缩警告钩子 |
|
||||
| `compactWarningState.ts` | — | 压缩警告状态 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 第1层:微压缩(Microcompact)
|
||||
|
||||
**源文件:** `microCompact.ts`
|
||||
|
||||
### 核心思想
|
||||
|
||||
不调用 LLM,纯规则操作——清理旧的、大块的工具输出结果,保留语义信息。这是每轮查询前都会执行的最轻量操作。
|
||||
|
||||
### 可压缩工具白名单
|
||||
|
||||
```typescript
|
||||
const COMPACTABLE_TOOLS = new Set([
|
||||
'Read', // 文件读取结果可能很大
|
||||
'Bash', // Shell 输出可能很长
|
||||
'Grep', // 搜索结果
|
||||
'Glob', // 文件列表
|
||||
'WebSearch', // 网页搜索结果
|
||||
'WebFetch', // 网页抓取结果
|
||||
'Edit', // 文件编辑的 diff
|
||||
'Write', // 文件写入确认
|
||||
])
|
||||
```
|
||||
|
||||
不在白名单中的工具(如 Agent、Skill、MCP 等)的结果不会被微压缩。
|
||||
|
||||
### 两个子路径
|
||||
|
||||
#### 子路径 A:时间触发微压缩
|
||||
|
||||
```
|
||||
触发条件:距上次助手消息的时间间隔超过阈值(API 缓存已过期)
|
||||
|
||||
执行逻辑:
|
||||
1. 收集所有可压缩工具的 tool_use ID
|
||||
2. 保留最近 N 个工具结果
|
||||
3. 将更早的 tool_result 内容替换为:
|
||||
"[Old tool result content cleared]"
|
||||
4. 不修改 tool_use 块(保持 API 配对完整性)
|
||||
|
||||
特点:
|
||||
- 缓存已过期,所以无需保护缓存
|
||||
- 直接修改本地消息内容
|
||||
- 减少重传时的 token 消耗
|
||||
```
|
||||
|
||||
#### 子路径 B:缓存编辑微压缩(Cached MC)
|
||||
|
||||
这是更精巧的路径——在缓存仍然有效时工作:
|
||||
|
||||
```
|
||||
触发条件:
|
||||
- 特性开关 CACHED_MICROCOMPACT 开启
|
||||
- 模型支持缓存编辑 API
|
||||
- 当前是主线程查询(非 fork agent)
|
||||
|
||||
执行逻辑:
|
||||
1. collectCompactableToolIds(): 收集所有可压缩的 tool_use ID
|
||||
2. registerToolResult(): 注册每个工具结果(按用户消息分组)
|
||||
3. registerToolMessage(): 记录工具消息组
|
||||
4. getToolResultsToDelete(): 根据 count/keep 阈值决定删除哪些
|
||||
5. createCacheEditsBlock(): 生成 cache_edits API 块
|
||||
|
||||
关键区别:
|
||||
- 不修改本地消息内容!
|
||||
- 通过 API 的 cache_edits 字段告诉服务端删除特定工具结果的缓存
|
||||
- 保持 prompt cache 命中率
|
||||
- 状态通过 pendingCacheEdits / pinnedCacheEdits 管理
|
||||
```
|
||||
|
||||
**缓存编辑的状态管理:**
|
||||
|
||||
```typescript
|
||||
// 全局状态
|
||||
let cachedMCState: CachedMCState | null = null
|
||||
let pendingCacheEdits: CacheEditsBlock | null = null
|
||||
|
||||
// consumePendingCacheEdits():
|
||||
// 返回待插入的缓存编辑块,然后清空 pending 状态
|
||||
// 调用者在 API 请求后必须调用 pinCacheEdits() 固定它们
|
||||
|
||||
// getPinnedCacheEdits():
|
||||
// 返回之前已固定的缓存编辑,需要在后续请求中重新发送
|
||||
|
||||
// markToolsSentToAPIState():
|
||||
// 标记工具已发送给 API(成功响应后调用)
|
||||
```
|
||||
|
||||
### Token 估算辅助
|
||||
|
||||
```typescript
|
||||
function calculateToolResultTokens(block: ToolResultBlockParam): number {
|
||||
if (typeof block.content === 'string') {
|
||||
return roughTokenCountEstimation(block.content) // 字符数 / 4
|
||||
}
|
||||
// 数组:逐项计算
|
||||
return block.content.reduce((sum, item) => {
|
||||
if (item.type === 'text') return sum + roughTokenCountEstimation(item.text)
|
||||
if (item.type === 'image' || item.type === 'document') return sum + 2000
|
||||
return sum
|
||||
}, 0)
|
||||
}
|
||||
|
||||
function estimateMessageTokens(messages: Message[]): number {
|
||||
let totalTokens = 0
|
||||
for (const message of messages) {
|
||||
for (const block of message.message.content) {
|
||||
switch (block.type) {
|
||||
case 'text': totalTokens += roughTokenCountEstimation(block.text); break
|
||||
case 'tool_result': totalTokens += calculateToolResultTokens(block); break
|
||||
case 'image':
|
||||
case 'document': totalTokens += 2000; break // 固定估算
|
||||
case 'thinking': totalTokens += roughTokenCountEstimation(block.thinking); break
|
||||
case 'redacted_thinking': totalTokens += roughTokenCountEstimation(block.data); break
|
||||
case 'tool_use': totalTokens += roughTokenCountEstimation(block.name + JSON.stringify(block.input ?? {})); break
|
||||
default: totalTokens += roughTokenCountEstimation(JSON.stringify(block)); break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.ceil(totalTokens * (4 / 3)) // × 4/3 保守填充
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 第2层:自动压缩(Auto-Compact)
|
||||
|
||||
**源文件:** `autoCompact.ts`
|
||||
|
||||
### 阈值计算
|
||||
|
||||
```typescript
|
||||
// 有效上下文窗口 = 模型上下文窗口 - 摘要输出预留
|
||||
const MAX_OUTPUT_TOKENS_FOR_SUMMARY = 20_000 // p99.99 的摘要输出是 17,387 tokens
|
||||
|
||||
function getEffectiveContextWindowSize(model: string): number {
|
||||
const reservedTokensForSummary = Math.min(
|
||||
getMaxOutputTokensForModel(model),
|
||||
MAX_OUTPUT_TOKENS_FOR_SUMMARY,
|
||||
)
|
||||
let contextWindow = getContextWindowForModel(model)
|
||||
// 支持环境变量覆盖(用于测试)
|
||||
if (process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW) {
|
||||
contextWindow = Math.min(contextWindow, parsed)
|
||||
}
|
||||
return contextWindow - reservedTokensForSummary
|
||||
}
|
||||
|
||||
// 自动压缩阈值 = 有效上下文窗口 - 13K 缓冲
|
||||
const AUTOCOMPACT_BUFFER_TOKENS = 13_000
|
||||
|
||||
function getAutoCompactThreshold(model: string): number {
|
||||
return getEffectiveContextWindowSize(model) - AUTOCOMPACT_BUFFER_TOKENS
|
||||
}
|
||||
|
||||
// 举例(Opus 200K 上下文):
|
||||
// 有效窗口 = 200,000 - 20,000 = 180,000
|
||||
// 自动压缩阈值 = 180,000 - 13,000 = 167,000 tokens
|
||||
```
|
||||
|
||||
### 其他阈值
|
||||
|
||||
```typescript
|
||||
const WARNING_THRESHOLD_BUFFER_TOKENS = 20_000 // 警告阈值
|
||||
const ERROR_THRESHOLD_BUFFER_TOKENS = 20_000 // 错误阈值
|
||||
const MANUAL_COMPACT_BUFFER_TOKENS = 3_000 // 手动 /compact 的阻塞限制
|
||||
```
|
||||
|
||||
### 断路器机制
|
||||
|
||||
```typescript
|
||||
const MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES = 3
|
||||
|
||||
// BQ 数据分析发现:1,279 个会话连续失败 50+ 次(最多 3,272 次),
|
||||
// 每天浪费约 250K 次 API 调用。所以加了断路器。
|
||||
|
||||
if (tracking.consecutiveFailures >= MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES) {
|
||||
return { wasCompacted: false } // 直接跳过,不再尝试
|
||||
}
|
||||
```
|
||||
|
||||
### shouldAutoCompact 决策树
|
||||
|
||||
```
|
||||
shouldAutoCompact(messages, model, querySource):
|
||||
|
||||
1. querySource 是 'session_memory' 或 'compact'?
|
||||
→ 返回 false(防止递归死锁——压缩代理自己不能触发压缩)
|
||||
|
||||
2. querySource 是 'marble_origami'(上下文折叠代理)?
|
||||
→ 返回 false(防止破坏主线程的已提交日志)
|
||||
|
||||
3. isAutoCompactEnabled() 返回 false?
|
||||
→ 返回 false
|
||||
(检查 DISABLE_COMPACT、DISABLE_AUTO_COMPACT 环境变量和用户配置)
|
||||
|
||||
4. 响应式压缩模式开启?(tengu_cobalt_raccoon gate)
|
||||
→ 返回 false(让 API 的 prompt-too-long 错误触发响应式压缩)
|
||||
|
||||
5. 上下文折叠模式开启?
|
||||
→ 返回 false(上下文折叠是 90%/95% 流程,自动压缩在 93% 会干扰它)
|
||||
|
||||
6. tokenCountWithEstimation(messages) - snipTokensFreed >= threshold?
|
||||
→ 返回 true
|
||||
```
|
||||
|
||||
### autoCompactIfNeeded 执行流程
|
||||
|
||||
```
|
||||
autoCompactIfNeeded(messages, context, ...):
|
||||
|
||||
1. DISABLE_COMPACT 环境变量?→ 跳过
|
||||
|
||||
2. 断路器检查:consecutiveFailures >= 3?→ 跳过
|
||||
|
||||
3. shouldAutoCompact() 返回 true?
|
||||
↓ 是
|
||||
4. 优先尝试 Session Memory 压缩
|
||||
↓ 成功 → 返回结果
|
||||
↓ 失败
|
||||
|
||||
5. 回退到传统压缩(compactConversation)
|
||||
↓ 成功 → 重置 consecutiveFailures = 0,返回结果
|
||||
↓ 失败
|
||||
|
||||
6. consecutiveFailures++
|
||||
↓ 达到 3 次
|
||||
7. 日志:断路器触发,本次会话不再尝试自动压缩
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 第3层:传统压缩(Full Compact)
|
||||
|
||||
**源文件:** `compact.ts` + `prompt.ts`
|
||||
|
||||
### 核心机制:Fork Agent
|
||||
|
||||
传统压缩使用一个 **Fork Agent**——创建当前会话的一个分支,让它生成摘要。关键优势是**共享主会话的 prompt cache**。
|
||||
|
||||
```
|
||||
主会话消息: [user1, assistant1, user2, assistant2, ...]
|
||||
↓ 全部传入
|
||||
Fork Agent(共享 prompt cache)
|
||||
↓ 单轮回复
|
||||
生成结构化摘要(<analysis> + <summary>)
|
||||
↓
|
||||
后处理 → 替换原消息
|
||||
```
|
||||
|
||||
### 预处理管线
|
||||
|
||||
```
|
||||
原始消息
|
||||
↓
|
||||
stripImagesFromMessages() ← 图片 → "[image]",文档 → "[document]"
|
||||
↓ (防止压缩请求自身超过上下文限制)
|
||||
stripReinjectedAttachments() ← 删除技能发现/列表附件
|
||||
↓ (压缩后会自动重新注入)
|
||||
normalizeMessagesForAPI() ← 规范化消息格式
|
||||
↓
|
||||
发送给 Fork Agent
|
||||
```
|
||||
|
||||
### 摘要输出格式
|
||||
|
||||
Fork Agent 被要求生成两个 XML 块:
|
||||
|
||||
```xml
|
||||
<analysis>
|
||||
[思考草稿——用于提高摘要质量的中间推理过程]
|
||||
[这部分最终会被删除,不会进入压缩后的上下文]
|
||||
</analysis>
|
||||
|
||||
<summary>
|
||||
1. Primary Request and Intent:
|
||||
[详细描述用户的所有请求和意图]
|
||||
|
||||
2. Key Technical Concepts:
|
||||
- [概念1]
|
||||
- [概念2]
|
||||
|
||||
3. Files and Code Sections:
|
||||
- [文件名1]
|
||||
- [为什么这个文件重要]
|
||||
- [代码片段]
|
||||
- [文件名2]
|
||||
- [代码片段]
|
||||
|
||||
4. Errors and fixes:
|
||||
- [错误描述]:
|
||||
- [修复方式]
|
||||
- [用户反馈]
|
||||
|
||||
5. Problem Solving:
|
||||
[问题解决过程]
|
||||
|
||||
6. All user messages:
|
||||
- [逐条列出所有非工具结果的用户消息]
|
||||
|
||||
7. Pending Tasks:
|
||||
- [待办事项1]
|
||||
- [待办事项2]
|
||||
|
||||
8. Current Work:
|
||||
[精确描述当前工作内容,包含文件名和代码片段]
|
||||
|
||||
9. Optional Next Step:
|
||||
[下一步计划,包含最近对话的直接引用]
|
||||
</summary>
|
||||
```
|
||||
|
||||
### 防止工具调用的强力前导词
|
||||
|
||||
```typescript
|
||||
const NO_TOOLS_PREAMBLE = `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.
|
||||
|
||||
- Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.
|
||||
- You already have all the context you need in the conversation above.
|
||||
- Tool calls will be REJECTED and will waste your only turn — you will fail the task.
|
||||
- Your entire response must be plain text: an <analysis> block followed by a <summary> block.
|
||||
`
|
||||
```
|
||||
|
||||
为什么需要这么强力?注释解释了:
|
||||
|
||||
```
|
||||
// Sonnet 4.6+ 自适应思考模型有时会忽略较弱的尾部指令并尝试调用工具。
|
||||
// 在 maxTurns: 1 的情况下,被拒绝的工具调用意味着没有文本输出
|
||||
// → 回退到流式备用路径(4.6 上 2.79% vs 4.5 上 0.01%)。
|
||||
// 把这个放在最前面并明确说明拒绝后果,可以防止浪费轮次。
|
||||
```
|
||||
|
||||
### 后处理(formatCompactSummary)
|
||||
|
||||
```typescript
|
||||
function formatCompactSummary(summary: string): string {
|
||||
// 1. 删除 <analysis> 块(草稿,已无价值)
|
||||
summary = summary.replace(/<analysis>[\s\S]*?<\/analysis>/, '')
|
||||
|
||||
// 2. 提取 <summary> 内容,替换为可读标题
|
||||
const match = summary.match(/<summary>([\s\S]*?)<\/summary>/)
|
||||
if (match) {
|
||||
summary = summary.replace(/<summary>[\s\S]*?<\/summary>/,
|
||||
`Summary:\n${match[1].trim()}`)
|
||||
}
|
||||
|
||||
// 3. 清理多余空行
|
||||
summary = summary.replace(/\n\n+/g, '\n\n')
|
||||
return summary.trim()
|
||||
}
|
||||
```
|
||||
|
||||
### 压缩后消息序列
|
||||
|
||||
```
|
||||
[CompactBoundaryMessage] ← 标记压缩边界(含 token 统计、trigger 类型)
|
||||
[SummaryUserMessage] ← 格式化后的摘要
|
||||
[messagesToKeep] ← 保留的最近消息(如果有)
|
||||
[Attachments] ← 重新注入的附件
|
||||
- 最近读取的文件(前 5 个,每个 ≤ 5K tokens,总预算 50K)
|
||||
- Plan 文件(如果有活跃计划)
|
||||
- MCP 指令增量
|
||||
- 技能发现增量
|
||||
- 代理列表增量
|
||||
[HookResults] ← PreCompact/PostCompact 钩子结果
|
||||
```
|
||||
|
||||
### Prompt-Too-Long 重试机制
|
||||
|
||||
当压缩请求本身超过上下文限制时:
|
||||
|
||||
```typescript
|
||||
const MAX_PTL_RETRIES = 3
|
||||
|
||||
function truncateHeadForPTLRetry(messages, ptlResponse): Message[] | null {
|
||||
// 1. 移除上一次重试的标记消息(防止重试停滞)
|
||||
// 2. 按 API 轮次分组
|
||||
const groups = groupMessagesByApiRound(messages)
|
||||
if (groups.length < 2) return null // 无法再裁剪
|
||||
|
||||
// 3. 决定删除多少组
|
||||
const tokenGap = getPromptTooLongTokenGap(ptlResponse)
|
||||
if (tokenGap !== undefined) {
|
||||
// 能解析出 token 缺口 → 精确删除
|
||||
let acc = 0, dropCount = 0
|
||||
for (const g of groups) {
|
||||
acc += roughTokenCountEstimationForMessages(g)
|
||||
dropCount++
|
||||
if (acc >= tokenGap) break
|
||||
}
|
||||
} else {
|
||||
// 不能解析 → 删除 20% 最旧的组
|
||||
dropCount = Math.max(1, Math.floor(groups.length * 0.2))
|
||||
}
|
||||
|
||||
// 4. 保证至少保留 1 组
|
||||
dropCount = Math.min(dropCount, groups.length - 1)
|
||||
|
||||
// 5. 如果裁剪后第一条是 assistant 消息,补一个 user marker
|
||||
// (API 要求第一条消息必须是 user)
|
||||
const sliced = groups.slice(dropCount).flat()
|
||||
if (sliced[0]?.type === 'assistant') {
|
||||
return [createUserMessage({ content: PTL_RETRY_MARKER, isMeta: true }), ...sliced]
|
||||
}
|
||||
return sliced
|
||||
}
|
||||
```
|
||||
|
||||
### 部分压缩(Partial Compact)
|
||||
|
||||
支持两个方向:
|
||||
|
||||
| 方向 | 提示词 | 用途 |
|
||||
|------|--------|------|
|
||||
| `from`(默认) | `PARTIAL_COMPACT_PROMPT` | 保留旧消息,仅摘要"最近的消息" |
|
||||
| `up_to` | `PARTIAL_COMPACT_UP_TO_PROMPT` | 摘要旧消息,保留新消息。摘要会放在开头,后续消息跟在后面 |
|
||||
|
||||
`up_to` 模式的摘要包含一个特殊的第 9 章节 "Context for Continuing Work",专门为后续消息提供上下文。
|
||||
|
||||
---
|
||||
|
||||
## 5. 第4层:Session Memory 压缩
|
||||
|
||||
**源文件:** `sessionMemoryCompact.ts`
|
||||
|
||||
### 核心思想
|
||||
|
||||
不调用 LLM 生成新摘要,而是直接使用已经通过后台记忆提取(`extractMemories`)积累的 Session Memory 作为"摘要"。
|
||||
|
||||
### 优势
|
||||
|
||||
- **速度快**:不需要 API 调用,<10ms
|
||||
- **质量可预测**:Session Memory 是在每轮查询后渐进更新的,不是一次性压缩
|
||||
- **保留近期消息**:不像传统压缩那样替换所有消息
|
||||
|
||||
### 配置参数
|
||||
|
||||
```typescript
|
||||
const DEFAULT_SM_COMPACT_CONFIG = {
|
||||
minTokens: 10_000, // 至少保留 10K tokens 的最近消息
|
||||
minTextBlockMessages: 5, // 至少保留 5 条含文本的消息
|
||||
maxTokens: 40_000, // 最多保留 40K tokens(硬上限)
|
||||
}
|
||||
// 这些值通过 GrowthBook 远程配置,可动态调整
|
||||
```
|
||||
|
||||
### calculateMessagesToKeepIndex 算法
|
||||
|
||||
这是 Session Memory 压缩的核心算法——决定保留哪些最近的消息:
|
||||
|
||||
```
|
||||
输入:messages[], lastSummarizedIndex(Session Memory 已覆盖到哪条消息)
|
||||
|
||||
算法:
|
||||
1. startIndex = lastSummarizedIndex + 1
|
||||
(即:从 Session Memory 尚未覆盖的消息开始)
|
||||
|
||||
2. 计算当前 [startIndex, end] 范围的 token 总量和含文本消息数
|
||||
|
||||
3. 如果已经超过 maxTokens (40K) → 直接返回(不再扩展)
|
||||
|
||||
4. 如果同时满足 ≥ minTokens (10K) AND ≥ minTextBlockMessages (5)
|
||||
→ 直接返回(已足够)
|
||||
|
||||
5. 否则,从 startIndex 往前逐条扩展:
|
||||
- 每加入一条消息,更新 token 和消息计数
|
||||
- 停止条件:
|
||||
a. 达到 maxTokens (40K)
|
||||
b. 同时满足 minTokens 和 minTextBlockMessages
|
||||
c. 到达上一个 CompactBoundary(不跨越旧的压缩边界)
|
||||
|
||||
6. adjustIndexToPreserveAPIInvariants(messages, startIndex)
|
||||
→ 确保不切断 tool_use/tool_result 配对
|
||||
→ 确保不分离共享 message.id 的 thinking 块
|
||||
```
|
||||
|
||||
### adjustIndexToPreserveAPIInvariants 算法
|
||||
|
||||
这个算法解决一个棘手的问题——流式传输时,一个 API 响应会产生多条消息(thinking、tool_use 等),它们共享同一个 `message.id`。如果在中间切断,`normalizeMessagesForAPI` 合并时会丢失 thinking 块。
|
||||
|
||||
```
|
||||
输入:messages[], startIndex
|
||||
|
||||
步骤 1:修复 tool_use/tool_result 配对
|
||||
1a. 收集 [startIndex, end] 范围内所有 tool_result 的 tool_use_id
|
||||
1b. 收集范围内已有的 tool_use_id
|
||||
1c. 找出缺失的 tool_use_id(在范围外)
|
||||
1d. 向前搜索,把包含缺失 tool_use 的 assistant 消息纳入范围
|
||||
|
||||
步骤 2:修复 thinking 块分离
|
||||
2a. 收集范围内所有 assistant 消息的 message.id
|
||||
2b. 向前搜索,把共享同一 message.id 的 assistant 消息纳入范围
|
||||
|
||||
返回:调整后的 startIndex
|
||||
```
|
||||
|
||||
**源码注释中的真实 bug 场景:**
|
||||
|
||||
```
|
||||
Session 存储(压缩前):
|
||||
Index N: assistant, message.id: X, content: [thinking]
|
||||
Index N+1: assistant, message.id: X, content: [tool_use: ORPHAN_ID]
|
||||
Index N+2: assistant, message.id: X, content: [tool_use: VALID_ID]
|
||||
Index N+3: user, content: [tool_result: ORPHAN_ID, tool_result: VALID_ID]
|
||||
|
||||
如果 startIndex = N+2:
|
||||
旧代码:只检查 N+2 的 tool_results,找不到,返回 N+2
|
||||
normalizeMessagesForAPI 合并后:
|
||||
msg[1]: assistant with [tool_use: VALID_ID] ← ORPHAN tool_use 被排除!
|
||||
msg[2]: user with [tool_result: ORPHAN_ID, tool_result: VALID_ID]
|
||||
API 报错:孤立的 tool_result 引用了不存在的 tool_use
|
||||
```
|
||||
|
||||
### trySessionMemoryCompaction 完整流程
|
||||
|
||||
```
|
||||
trySessionMemoryCompaction(messages, agentId, autoCompactThreshold):
|
||||
|
||||
1. shouldUseSessionMemoryCompaction()?
|
||||
→ 检查 tengu_session_memory AND tengu_sm_compact 特性开关
|
||||
→ 支持 ENABLE_CLAUDE_CODE_SM_COMPACT / DISABLE_CLAUDE_CODE_SM_COMPACT 环境变量
|
||||
|
||||
2. 初始化远程配置(仅首次)
|
||||
|
||||
3. 等待正在进行的 Session Memory 提取完成(带超时)
|
||||
|
||||
4. 获取 lastSummarizedMessageId 和 sessionMemory 内容
|
||||
|
||||
5. Session Memory 文件不存在?→ 返回 null
|
||||
6. Session Memory 是空模板?→ 返回 null
|
||||
|
||||
7. 确定 lastSummarizedIndex:
|
||||
a. 正常情况:在 messages 中查找 lastSummarizedMessageId 的索引
|
||||
b. 恢复的会话:设为 messages.length - 1(从末尾开始)
|
||||
|
||||
8. calculateMessagesToKeepIndex() → startIndex
|
||||
9. 过滤掉 messagesToKeep 中的旧 CompactBoundary
|
||||
|
||||
10. 执行 SessionStart 钩子(恢复 CLAUDE.md 等上下文)
|
||||
|
||||
11. 创建压缩结果:
|
||||
- 截断过大的 Session Memory 章节
|
||||
- 生成摘要用户消息
|
||||
- 附加 Plan 文件(如果有)
|
||||
|
||||
12. 检查压缩后 token 是否仍超过阈值
|
||||
→ 是:返回 null(回退到传统压缩)
|
||||
→ 否:返回 CompactionResult
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 消息分组算法
|
||||
|
||||
**源文件:** `grouping.ts`
|
||||
|
||||
```typescript
|
||||
function groupMessagesByApiRound(messages: Message[]): Message[][] {
|
||||
const groups: Message[][] = []
|
||||
let current: Message[] = []
|
||||
let lastAssistantId: string | undefined
|
||||
|
||||
for (const msg of messages) {
|
||||
// 当出现新的 assistant message.id 时,开始新的一组
|
||||
if (
|
||||
msg.type === 'assistant' &&
|
||||
msg.message.id !== lastAssistantId &&
|
||||
current.length > 0
|
||||
) {
|
||||
groups.push(current)
|
||||
current = [msg]
|
||||
} else {
|
||||
current.push(msg)
|
||||
}
|
||||
if (msg.type === 'assistant') {
|
||||
lastAssistantId = msg.message.id
|
||||
}
|
||||
}
|
||||
|
||||
if (current.length > 0) {
|
||||
groups.push(current)
|
||||
}
|
||||
return groups
|
||||
}
|
||||
```
|
||||
|
||||
**设计细节:**
|
||||
|
||||
- 同一 API 请求的流式块共享同一个 `message.id`
|
||||
- `StreamingToolExecutor` 在流式输出期间交错插入 `tool_result`,但它们属于同一轮次
|
||||
- 只要 `message.id` 不变,所有消息都在同一组内
|
||||
- 不跟踪未解决的 `tool_use` ID——让分组边界自然形成,由 `ensureToolResultPairing` 在 API 层修复残留的配对问题
|
||||
|
||||
---
|
||||
|
||||
## 7. Token 估算算法
|
||||
|
||||
贯穿所有压缩路径的核心辅助:
|
||||
|
||||
### 粗略估算
|
||||
|
||||
```typescript
|
||||
function roughTokenCountEstimation(text: string): number {
|
||||
return text.length / 4 // 经验法则:4 字符 ≈ 1 token
|
||||
}
|
||||
```
|
||||
|
||||
### 消息级估算
|
||||
|
||||
```typescript
|
||||
function estimateMessageTokens(messages: Message[]): number {
|
||||
let totalTokens = 0
|
||||
for (const message of messages) {
|
||||
if (message.type !== 'user' && message.type !== 'assistant') continue
|
||||
for (const block of message.message.content) {
|
||||
switch (block.type) {
|
||||
case 'text':
|
||||
totalTokens += roughTokenCountEstimation(block.text)
|
||||
break
|
||||
case 'tool_result':
|
||||
totalTokens += calculateToolResultTokens(block)
|
||||
break
|
||||
case 'image':
|
||||
case 'document':
|
||||
totalTokens += 2000 // 固定值,不论实际大小
|
||||
break
|
||||
case 'thinking':
|
||||
totalTokens += roughTokenCountEstimation(block.thinking)
|
||||
// 注意:不计算签名(signature 是元数据,不被模型 tokenize)
|
||||
break
|
||||
case 'redacted_thinking':
|
||||
totalTokens += roughTokenCountEstimation(block.data)
|
||||
break
|
||||
case 'tool_use':
|
||||
totalTokens += roughTokenCountEstimation(
|
||||
block.name + JSON.stringify(block.input ?? {})
|
||||
)
|
||||
// 不计算 JSON wrapper 和 id 字段
|
||||
break
|
||||
default:
|
||||
totalTokens += roughTokenCountEstimation(JSON.stringify(block))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Math.ceil(totalTokens * (4 / 3)) // 保守填充 33%
|
||||
}
|
||||
```
|
||||
|
||||
### 精确计算
|
||||
|
||||
```typescript
|
||||
// 当有 API 响应的 usage 数据时,使用精确值
|
||||
function tokenCountFromLastAPIResponse(messages: Message[]): number | undefined {
|
||||
// 从最后一条 assistant 消息的 usage 字段读取
|
||||
// usage.input_tokens 包含了 API 看到的实际 token 数
|
||||
}
|
||||
|
||||
// 混合策略
|
||||
function tokenCountWithEstimation(messages: Message[]): number {
|
||||
// 优先使用 API 返回的精确值
|
||||
// 不可用时回退到估算
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 压缩提示词工程
|
||||
|
||||
**源文件:** `prompt.ts`
|
||||
|
||||
### 三种提示词模板
|
||||
|
||||
| 模板 | 变量名 | 用途 |
|
||||
|------|--------|------|
|
||||
| 完整压缩 | `BASE_COMPACT_PROMPT` | 摘要整个对话 |
|
||||
| 部分压缩(from) | `PARTIAL_COMPACT_PROMPT` | 只摘要最近的消息 |
|
||||
| 部分压缩(up_to) | `PARTIAL_COMPACT_UP_TO_PROMPT` | 摘要旧消息,作为后续消息的前导 |
|
||||
|
||||
### 提示词结构
|
||||
|
||||
```
|
||||
[NO_TOOLS_PREAMBLE] ← 强力禁止工具调用
|
||||
[DETAILED_ANALYSIS_INSTRUCTION] ← 要求 <analysis> 思考草稿
|
||||
[MAIN_PROMPT] ← 9 章节结构化摘要要求 + 示例
|
||||
[Custom Instructions] ← 用户自定义指令(如果有)
|
||||
[NO_TOOLS_TRAILER] ← 再次强调不要调用工具
|
||||
```
|
||||
|
||||
### <analysis> 块的作用
|
||||
|
||||
```
|
||||
提示词要求模型先在 <analysis> 中"打草稿":
|
||||
1. 按时间顺序分析每条消息
|
||||
2. 识别用户意图、技术决策、代码模式
|
||||
3. 特别关注用户反馈("用户让你做不同的事情")
|
||||
4. 双重检查技术准确性和完整性
|
||||
|
||||
这类似于 Chain-of-Thought,但最终会被 formatCompactSummary() 删除,
|
||||
只保留 <summary> 部分进入压缩后的上下文。
|
||||
```
|
||||
|
||||
### 压缩后的摘要消息
|
||||
|
||||
```typescript
|
||||
function getCompactUserSummaryMessage(summary, suppressFollowUp, transcriptPath, recentPreserved): string {
|
||||
let msg = `This session is being continued from a previous conversation that ran out of context.
|
||||
The summary below covers the earlier portion of the conversation.
|
||||
|
||||
${formatCompactSummary(summary)}`
|
||||
|
||||
// 如果有 transcript 路径,提供回溯指引
|
||||
if (transcriptPath) {
|
||||
msg += `\n\nIf you need specific details from before compaction
|
||||
(like exact code snippets, error messages, or content you generated),
|
||||
read the full transcript at: ${transcriptPath}`
|
||||
}
|
||||
|
||||
// 如果保留了最近消息
|
||||
if (recentMessagesPreserved) {
|
||||
msg += `\n\nRecent messages are preserved verbatim.`
|
||||
}
|
||||
|
||||
// 如果是自动压缩(suppressFollowUp = true)
|
||||
if (suppressFollowUpQuestions) {
|
||||
msg += `\nContinue the conversation from where it left off
|
||||
without asking the user any further questions.
|
||||
Resume directly — do not acknowledge the summary,
|
||||
do not recap what was happening,
|
||||
do not preface with "I'll continue" or similar.
|
||||
Pick up the last task as if the break never happened.`
|
||||
}
|
||||
|
||||
// 如果是 Proactive/KAIROS 模式
|
||||
if (proactiveModule?.isProactiveActive()) {
|
||||
msg += `\n\nYou are running in autonomous/proactive mode.
|
||||
This is NOT a first wake-up — you were already working autonomously before compaction.
|
||||
Continue your work loop: pick up where you left off based on the summary above.
|
||||
Do not greet the user or ask what to work on.`
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 5层错误恢复中的压缩角色
|
||||
|
||||
在 `query.ts` 的 5 层错误恢复机制中,压缩系统承担了前 2 层:
|
||||
|
||||
```
|
||||
API 调用失败
|
||||
↓
|
||||
第1层:上下文折叠排水(Context Collapse Drain)
|
||||
↓ 失败
|
||||
第2层:响应式压缩(Reactive Compact) ← 使用 compact.ts
|
||||
↓ 失败
|
||||
第3层:最大输出升级(8K → 64K tokens)
|
||||
↓ 失败
|
||||
第4层:多轮恢复(注入"请继续"消息,最多 3 次)
|
||||
↓ 失败
|
||||
第5层:模型回退(切换到备用模型,剥离 thinking 签名块)
|
||||
↓ 失败
|
||||
暴露错误给用户
|
||||
```
|
||||
|
||||
**响应式压缩** vs **主动压缩**:
|
||||
|
||||
| 属性 | 主动压缩(Auto-Compact) | 响应式压缩(Reactive Compact) |
|
||||
|------|--------------------------|-------------------------------|
|
||||
| 触发 | token 数超过阈值 | API 返回 prompt-too-long 错误 |
|
||||
| 时机 | API 调用前 | API 调用失败后 |
|
||||
| 路径 | `autoCompact.ts` → `compact.ts` | `query.ts` 错误恢复层 |
|
||||
| 回退 | SM → 传统压缩 → 放弃 | 传统压缩 → 裁剪最旧消息 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 各层对比与设计哲学
|
||||
|
||||
### 横向对比
|
||||
|
||||
| 属性 | 微压缩 | Session Memory | 传统压缩 | PTL Recovery |
|
||||
|------|--------|---------------|----------|-------------|
|
||||
| **调用 LLM** | 否 | 否 | 是(Fork Agent) | 否 |
|
||||
| **信息损失** | 最小(仅删工具输出) | 中等(靠已有摘要) | 中等(9章摘要) | 高(丢弃最旧消息) |
|
||||
| **延迟** | <1ms | <10ms | 5-30s | ~0 |
|
||||
| **触发** | 每轮自动 | 自动压缩优先路径 | 自动/手动 | 压缩自身超限 |
|
||||
| **prompt cache** | 保留(缓存编辑) | 破坏 | 共享(Fork) | 破坏 |
|
||||
| **最大输出** | — | — | 20K tokens | — |
|
||||
| **断路器** | 无 | 无 | 有(3次) | 有(3次) |
|
||||
| **token 预算** | — | 40K 最大保留 | 50K 文件重注入 | 按组裁剪 |
|
||||
|
||||
### 设计哲学总结
|
||||
|
||||
1. **渐进式降级**:从无损操作(微压缩)到有损操作(传统压缩)到丢弃操作(PTL Recovery),每一层都比上一层代价更高
|
||||
|
||||
2. **缓存优先**:微压缩的缓存编辑路径专门设计为不破坏 prompt cache,传统压缩通过 Fork Agent 共享 cache
|
||||
|
||||
3. **安全性保证**:
|
||||
- 永远不切断 tool_use/tool_result 配对
|
||||
- 永远不分离共享 message.id 的消息块
|
||||
- 断路器防止失败时无限重试
|
||||
- 递归保护防止压缩代理触发自身压缩
|
||||
|
||||
4. **可观测性**:每个压缩操作都记录 `logEvent`(如 `tengu_compact`, `tengu_cached_microcompact`),包含压缩前后的 token 数、触发原因、重试次数等
|
||||
|
||||
5. **可配置性**:几乎所有阈值都支持环境变量覆盖(用于测试)或 GrowthBook 远程配置(用于动态调整)
|
||||
|
||||
---
|
||||
|
||||
*来自:AI超元域 | B站频道:https://space.bilibili.com/3493277319825652*
|
||||
|
||||
*基于 Claude Code 源码逆向分析,2026-03-31*
|
||||
441
docs/cc_analysis/analysis_20260401/Claude_Code模型切换机制深度分析.md
Normal file
441
docs/cc_analysis/analysis_20260401/Claude_Code模型切换机制深度分析.md
Normal file
@@ -0,0 +1,441 @@
|
||||
# Claude Code 是否偷换模型?源码级逆向分析
|
||||
|
||||
> 基于 Claude Code 源码(2026-03-31 快照,512K 行 TypeScript)逆向分析
|
||||
> 核心文件:`src/utils/model/model.ts`、`src/services/api/withRetry.ts`、`src/query.ts`、`src/services/api/claude.ts`
|
||||
|
||||
---
|
||||
|
||||
## 结论先行
|
||||
|
||||
**不存在"偷换模型"。你的主对话模型完全由你控制,不会被偷偷降级。**
|
||||
|
||||
但 Claude Code 确实在后台使用 Haiku(弱模型)执行辅助任务(配额检查、摘要生成等),这些 Haiku 调用不会出现在你的对话中,也不会替代你与 Opus 的交互。
|
||||
|
||||
唯一可能改变主对话模型的场景是 **529 连续过载回退**(Opus → Sonnet),此时会显示明确的系统消息通知用户。
|
||||
|
||||
---
|
||||
|
||||
## 1. 主对话模型选择:完全由用户控制
|
||||
|
||||
### 模型选择优先级(源码确认)
|
||||
|
||||
```typescript
|
||||
// src/utils/model/model.ts:92
|
||||
function getMainLoopModel(): ModelName {
|
||||
const model = getUserSpecifiedModelSetting()
|
||||
if (model !== undefined && model !== null) {
|
||||
return parseUserSpecifiedModel(model)
|
||||
}
|
||||
return getDefaultMainLoopModel()
|
||||
}
|
||||
|
||||
// src/utils/model/model.ts:61
|
||||
function getUserSpecifiedModelSetting(): ModelSetting | undefined {
|
||||
// 优先级从高到低:
|
||||
// 1. /model 命令(会话内切换)— 最高优先级
|
||||
const modelOverride = getMainLoopModelOverride()
|
||||
if (modelOverride !== undefined) return modelOverride
|
||||
|
||||
// 2. --model 启动参数 / ANTHROPIC_MODEL 环境变量 / settings.json
|
||||
return process.env.ANTHROPIC_MODEL || settings.model || undefined
|
||||
}
|
||||
```
|
||||
|
||||
**你设了 Opus,主对话就用 Opus。没有任何代码在你不知情的情况下把它换掉。**
|
||||
|
||||
### 默认模型
|
||||
|
||||
```typescript
|
||||
// src/utils/model/model.ts:105
|
||||
function getDefaultOpusModel(): ModelName {
|
||||
// 支持环境变量覆盖
|
||||
if (process.env.ANTHROPIC_DEFAULT_OPUS_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
|
||||
}
|
||||
return getModelStrings().opus46 // 默认 Opus 4.6
|
||||
}
|
||||
|
||||
function getDefaultSonnetModel(): ModelName {
|
||||
if (process.env.ANTHROPIC_DEFAULT_SONNET_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
|
||||
}
|
||||
// 3P 提供商默认 Sonnet 4.5(可能尚未支持 4.6)
|
||||
if (getAPIProvider() !== 'firstParty') return getModelStrings().sonnet45
|
||||
return getModelStrings().sonnet46
|
||||
}
|
||||
|
||||
function getDefaultHaikuModel(): ModelName {
|
||||
if (process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
|
||||
return process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
|
||||
}
|
||||
return getModelStrings().haiku45 // Haiku 4.5(所有平台通用)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 唯一会改变主对话模型的场景:529 过载回退
|
||||
|
||||
### 触发条件(极其严格)
|
||||
|
||||
```typescript
|
||||
// src/services/api/withRetry.ts:326-350
|
||||
|
||||
// 必须同时满足以下所有条件:
|
||||
// 1. 收到 529 错误(服务器过载)
|
||||
// 2. 连续 529 次数 >= MAX_529_RETRIES
|
||||
// 3. 配置了 fallbackModel
|
||||
// 4. 以下二选一:
|
||||
// a. 设置了 FALLBACK_FOR_ALL_PRIMARY_MODELS 环境变量
|
||||
// b. 非 Claude.ai 订阅用户 且 使用非自定义 Opus 模型
|
||||
|
||||
if (is529Error(error) &&
|
||||
(process.env.FALLBACK_FOR_ALL_PRIMARY_MODELS ||
|
||||
(!isClaudeAISubscriber() && isNonCustomOpusModel(options.model)))) {
|
||||
consecutive529Errors++
|
||||
if (consecutive529Errors >= MAX_529_RETRIES) {
|
||||
if (options.fallbackModel) {
|
||||
// 触发回退
|
||||
throw new FallbackTriggeredError(options.model, options.fallbackModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**关键限制:**
|
||||
|
||||
| 条件 | 说明 |
|
||||
|------|------|
|
||||
| `!isClaudeAISubscriber()` | **Claude.ai 订阅用户默认不触发回退** |
|
||||
| `isNonCustomOpusModel()` | 仅对标准 Opus 模型生效(自定义模型 ID 不触发) |
|
||||
| `MAX_529_RETRIES` | 需要连续多次 529 才触发 |
|
||||
|
||||
### 回退执行过程(透明可见)
|
||||
|
||||
```typescript
|
||||
// src/query.ts:894-946
|
||||
|
||||
if (innerError instanceof FallbackTriggeredError && fallbackModel) {
|
||||
// 1. 切换模型
|
||||
currentModel = fallbackModel // Opus → Sonnet(不是 Haiku)
|
||||
|
||||
// 2. 清理孤立的 assistant 消息
|
||||
yield* yieldMissingToolResultBlocks(assistantMessages, 'Model fallback triggered')
|
||||
assistantMessages.length = 0
|
||||
|
||||
// 3. 剥离 thinking 签名块(签名绑定原模型,发给回退模型会导致 400)
|
||||
// 源码注释:
|
||||
// "Strip before retry so the fallback model gets clean history."
|
||||
|
||||
// 4. 更新工具上下文中的模型引用
|
||||
toolUseContext.options.mainLoopModel = fallbackModel
|
||||
|
||||
// 5. 记录分析事件
|
||||
logEvent('tengu_api_opus_fallback_triggered', {
|
||||
original_model: options.model,
|
||||
fallback_model: options.fallbackModel,
|
||||
})
|
||||
|
||||
// 6. 显示系统消息通知用户(在 UI 中可见)
|
||||
`Switched to ${renderModelName(fallbackModel)} due to high demand
|
||||
for ${renderModelName(originalModel)}`
|
||||
}
|
||||
```
|
||||
|
||||
### 回退目标
|
||||
|
||||
```typescript
|
||||
// src/main.tsx:1336-1337
|
||||
// 回退模型必须与主模型不同
|
||||
if (fallbackModel && options.model && fallbackModel === options.model) {
|
||||
// 验证失败,不设置回退
|
||||
}
|
||||
|
||||
// 回退目标是 Sonnet(不是 Haiku)
|
||||
// 通过 getDefaultSonnetModel() 获取
|
||||
```
|
||||
|
||||
### 用户如何知道发生了回退
|
||||
|
||||
回退时,UI 中会显示一条系统消息:
|
||||
|
||||
```
|
||||
Switched to Claude Sonnet 4.6 due to high demand for Claude Opus 4.6
|
||||
```
|
||||
|
||||
同时在 `AssistantTextMessage.tsx:178` 中提供操作建议:
|
||||
|
||||
```
|
||||
To continue immediately, use /model to switch to Sonnet and continue coding.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 后台辅助任务使用 Haiku — 不影响主对话
|
||||
|
||||
Claude Code 在后台使用 Haiku(`getSmallFastModel()`)执行多种轻量辅助任务。这些调用**完全独立于你的对话**,不会出现在消息流中。
|
||||
|
||||
### 所有 Haiku 使用场景(逐一列出)
|
||||
|
||||
#### 3.1 配额检查
|
||||
|
||||
```typescript
|
||||
// src/services/claudeAiLimits.ts:199-218
|
||||
async function makeTestQuery() {
|
||||
const model = getSmallFastModel() // → Haiku
|
||||
const anthropic = await getAnthropicClient({ maxRetries: 0, model, source: 'quota_check' })
|
||||
// 发送 max_tokens: 1 的最小请求,仅读取响应头的配额信息
|
||||
return anthropic.beta.messages.create({
|
||||
model,
|
||||
max_tokens: 1,
|
||||
messages: [{ role: 'user', content: 'quota' }],
|
||||
}).asResponse()
|
||||
}
|
||||
```
|
||||
|
||||
**用途:** 检测用户是否已达配额限制。只读取 HTTP 响应头,不使用模型输出。
|
||||
|
||||
#### 3.2 离开摘要(Away Summary)
|
||||
|
||||
```typescript
|
||||
// src/services/awaySummary.ts:44-52
|
||||
// 当用户长时间离开后返回时,生成一个简短摘要
|
||||
{
|
||||
thinkingConfig: { type: 'disabled' }, // 关闭思考
|
||||
tools: [], // 不给工具
|
||||
model: getSmallFastModel(), // → Haiku
|
||||
}
|
||||
```
|
||||
|
||||
**用途:** 用户长时间不操作后返回时,快速生成"你离开期间发生了什么"的简要摘要。
|
||||
|
||||
#### 3.3 Token 计数
|
||||
|
||||
```typescript
|
||||
// src/services/api/claude.ts:540-543
|
||||
// WARNING: if you change this to use a non-Haiku model,
|
||||
// this request will fail in 1P unless it uses getCLISyspromptPrefix.
|
||||
const model = getSmallFastModel() // → Haiku
|
||||
// 调用 countTokens API 获取精确 token 数
|
||||
```
|
||||
|
||||
**用途:** 调用 Anthropic 的 `countTokens` 端点获取精确 token 计数,用于自动压缩阈值判断。
|
||||
|
||||
#### 3.4 工具使用摘要
|
||||
|
||||
```typescript
|
||||
// src/services/api/claude.ts:3273-3280
|
||||
// 在主模型流式输出期间,并行用 Haiku 生成工具调用的简短描述
|
||||
{
|
||||
model: getSmallFastModel(), // → Haiku
|
||||
enablePromptCaching: false,
|
||||
}
|
||||
```
|
||||
|
||||
**用途:** 当模型连续调用多个工具时,生成简短的工具使用描述(如"读取了 config.ts 并修改了第 42 行")。
|
||||
|
||||
源码注释明确说明了并行关系:
|
||||
```typescript
|
||||
// src/query.ts:1054
|
||||
// Yield tool use summary from previous turn —
|
||||
// haiku (~1s) resolved during model streaming (5-30s)
|
||||
```
|
||||
Haiku 在后台 1 秒内完成摘要,同时 Opus 还在处理你的主对话。
|
||||
|
||||
#### 3.5 记忆相关性评分
|
||||
|
||||
```typescript
|
||||
// src/memdir/findRelevantMemories.ts
|
||||
// 用 Sonnet(非 Haiku)评估记忆文件的相关性
|
||||
// 从标题中选择最多 5 条与当前查询相关的记忆
|
||||
```
|
||||
|
||||
#### 3.6 Web 搜索预处理
|
||||
|
||||
```typescript
|
||||
// src/tools/WebSearchTool/WebSearchTool.ts:280
|
||||
model: useHaiku ? getSmallFastModel() : context.options.mainLoopModel,
|
||||
toolChoice: useHaiku ? { type: 'tool', name: 'web_search' } : undefined,
|
||||
```
|
||||
|
||||
**用途:** 当条件满足时(`useHaiku` 标志),用 Haiku 预处理搜索查询。
|
||||
|
||||
#### 3.7 其他辅助调用
|
||||
|
||||
| 调用者 | 模型 | 用途 |
|
||||
|--------|------|------|
|
||||
| `tokenEstimation.ts` | Haiku | Vertex 全局区域 token 计数回退 |
|
||||
| `analyzeContext.ts` | Haiku | 上下文分析的 countTokens 回退 |
|
||||
| `claudeAiLimits.ts` | Haiku | 配额状态检查 |
|
||||
| Bedrock `client.ts` | Haiku | 小模型可指定不同 AWS 区域 |
|
||||
|
||||
### 辅助任务 vs 主对话的隔离
|
||||
|
||||
```
|
||||
你的对话:
|
||||
用户 → [Opus 4.6] → 助手响应 → [Opus 4.6] → 助手响应 → ...
|
||||
|
||||
后台并行:
|
||||
[Haiku] → 配额检查(1 token)
|
||||
[Haiku] → 工具使用摘要(~1s)
|
||||
[Haiku] → token 计数
|
||||
|
||||
两条线完全隔离,Haiku 的输出不进入你的对话消息流。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Fast Mode:同模型加速,不换模型
|
||||
|
||||
这是一个常见误解,源码中有明确声明:
|
||||
|
||||
```typescript
|
||||
// src/constants/prompts.ts:702
|
||||
`Fast mode for Claude Code uses the same ${FRONTIER_MODEL_NAME} model
|
||||
with faster output. It does NOT switch to a different model.
|
||||
It can be toggled with /fast.`
|
||||
```
|
||||
|
||||
Fast Mode 通过 API 的 speed 参数请求更快的输出,模型不变。如果 API 拒绝 fast mode(如组织未启用),会自动降回标准速度:
|
||||
|
||||
```typescript
|
||||
// src/services/api/withRetry.ts:310-313
|
||||
if (wasFastModeActive && isFastModeNotEnabledError(error)) {
|
||||
handleFastModeRejectedByAPI()
|
||||
retryContext.fastMode = false
|
||||
continue // 重试,同一模型,标准速度
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Plan Mode 临时模型切换 — 透明可见
|
||||
|
||||
```typescript
|
||||
// src/commands/model/model.tsx:214
|
||||
// Do not update fast mode in settings since this is an automatic downgrade
|
||||
|
||||
// src/commands/model/model.tsx:256
|
||||
onDone(`Current model: ${chalk.bold(renderModelLabel(mainLoopModelForSession))}
|
||||
(session override from plan mode)\nBase model: ${displayModel}`)
|
||||
```
|
||||
|
||||
Plan Mode 可能临时使用 Sonnet 执行实现步骤,但:
|
||||
- UI 显示 "session override from plan mode"
|
||||
- 显示 Base model 让你知道原始模型
|
||||
- 不修改 settings 中的模型设置
|
||||
|
||||
---
|
||||
|
||||
## 6. Effort 降级 — 不换模型,换参数
|
||||
|
||||
```typescript
|
||||
// src/utils/effort.ts:162
|
||||
// API rejects 'max' on non-Opus-4.6 models — downgrade to 'high'.
|
||||
```
|
||||
|
||||
如果设置了 `effort: max` 但模型不支持,会降级 effort 参数(max → high),不换模型。
|
||||
|
||||
---
|
||||
|
||||
## 7. 全局搜索:不存在的场景
|
||||
|
||||
通过对 512K 行源码的全局搜索,以下场景**被确认不存在**:
|
||||
|
||||
| 假设的偷换场景 | 搜索结果 | 证据 |
|
||||
|----------------|----------|------|
|
||||
| 根据订阅层级偷换弱模型 | **不存在** | `getMainLoopModel()` 不检查订阅类型 |
|
||||
| 根据额度用量偷换弱模型 | **不存在** | 额度用完返回 429 错误,不换模型 |
|
||||
| 随机/概率性降级到弱模型 | **不存在** | 无 `Math.random()` 与模型选择相关的代码 |
|
||||
| A/B 测试使用弱模型回答 | **不存在** | GrowthBook 控制功能开关,不控制模型 |
|
||||
| 静默替换后不通知用户 | **不存在** | 529 回退有系统消息,其他场景不换主模型 |
|
||||
| 把 Opus 对话路由到 Haiku | **不存在** | Haiku 仅用于辅助任务 |
|
||||
| 根据问题复杂度选择弱模型 | **不存在** | 主循环始终使用用户指定的模型 |
|
||||
| 根据时间段降级(如高峰期) | **不存在** | 无时间相关的模型选择逻辑 |
|
||||
| 首次用户用弱模型 | **不存在** | 默认模型是 Opus 4.6 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 模型使用全景图
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 你的主对话 │
|
||||
│ │
|
||||
│ 模型:你指定的(默认 Opus 4.6) │
|
||||
│ 控制:/model 命令 > --model 参数 > 环境变量 > 设置 │
|
||||
│ 唯一例外:529 连续过载 → Sonnet 回退(有通知) │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ 后台辅助任务(Haiku) │
|
||||
│ │
|
||||
│ 配额检查 → 1 token 请求,只读响应头 │
|
||||
│ Token 计数 → countTokens API 调用 │
|
||||
│ 工具摘要 → 并行于主对话,~1s 完成 │
|
||||
│ 离开摘要 → 用户回来时显示简要信息 │
|
||||
│ Web 搜索 → 搜索查询预处理(条件触发) │
|
||||
│ │
|
||||
│ 这些不进入你的对话消息流 │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Fork Agent 任务 │
|
||||
│ │
|
||||
│ 上下文压缩 → 使用你的主模型(共享 prompt cache) │
|
||||
│ 记忆提取 → 使用你的主模型 │
|
||||
│ 权限分类器 → Haiku(auto 模式下的命令安全分类) │
|
||||
│ │
|
||||
│ 压缩结果进入上下文,但不替代你的对话 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 如何验证你正在使用的模型
|
||||
|
||||
### 方法 1:查看 API 响应
|
||||
|
||||
每条助手消息的内部结构中包含模型信息:
|
||||
|
||||
```typescript
|
||||
// AssistantMessage.message.model 字段包含实际使用的模型 ID
|
||||
// 例如:"claude-opus-4-6-20260301"
|
||||
```
|
||||
|
||||
### 方法 2:使用 /cost 命令
|
||||
|
||||
`/cost` 命令显示按模型分类的 token 使用量,你可以看到每个模型消耗了多少 token。
|
||||
|
||||
### 方法 3:检查 status line
|
||||
|
||||
状态栏显示当前模型名称。如果发生回退,会更新为回退后的模型。
|
||||
|
||||
### 方法 4:环境变量调试
|
||||
|
||||
```bash
|
||||
# 查看所有 API 调用的模型信息
|
||||
export CLAUDE_CODE_DEBUG=1
|
||||
|
||||
# 强制禁用回退
|
||||
unset FALLBACK_FOR_ALL_PRIMARY_MODELS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 总结
|
||||
|
||||
| 问题 | 答案 | 依据 |
|
||||
|------|------|------|
|
||||
| Opus 会被偷偷换成 Haiku 吗? | **不会** | Haiku 仅用于辅助任务,不进入主对话 |
|
||||
| Opus 会被偷偷换成 Sonnet 吗? | **仅在 529 连续过载时,且会通知** | `withRetry.ts:347` + `query.ts:946` |
|
||||
| Claude.ai 订阅用户会被降级吗? | **默认不会** | `!isClaudeAISubscriber()` 条件排除 |
|
||||
| 后台有 Haiku 调用吗? | **有,但不影响你的对话** | 6 种辅助任务,全部隔离 |
|
||||
| Fast Mode 换模型吗? | **不换** | 源码明确声明 "does NOT switch to a different model" |
|
||||
| 有没有根据问题难度选模型? | **没有** | 主循环始终使用用户指定模型 |
|
||||
|
||||
**一句话:你付费用 Opus,对话就用 Opus。Haiku 只在幕后干杂活。**
|
||||
|
||||
---
|
||||
|
||||
*来自:AI超元域 | B站频道:https://space.bilibili.com/3493277319825652*
|
||||
|
||||
*基于 Claude Code 源码逆向分析,2026-03-31*
|
||||
764
docs/cc_analysis/analysis_20260401/Claude_Code记忆系统深度分析.md
Normal file
764
docs/cc_analysis/analysis_20260401/Claude_Code记忆系统深度分析.md
Normal file
@@ -0,0 +1,764 @@
|
||||
# Claude Code Memory 记忆系统深度分析
|
||||
|
||||
> 基于 Claude Code 源码(2026-03-31 快照,512K 行 TypeScript)逆向分析
|
||||
> 核心文件:`src/memdir/`(8个文件)、`src/services/extractMemories/`(2个)、`src/services/SessionMemory/`(3个)、`src/services/teamMemorySync/`(5个)
|
||||
|
||||
---
|
||||
|
||||
## 1. 三层记忆架构总览
|
||||
|
||||
Claude Code 的记忆系统不是一个简单的文件存储,而是一个**三层递进的知识管理体系**:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 第3层:团队记忆(Team Memory) │
|
||||
│ 跨用户、按仓库 │ 服务端同步 │ REST API + 乐观锁 │
|
||||
│ 秘密扫描保护 │ 文件监听器 │ 30种凭证检测规则 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 第2层:持久记忆(Persistent Memory / extractMemories) │
|
||||
│ 跨会话、按项目 │ 本地文件 │ 后台 Fork Agent 自动提取 │
|
||||
│ 4种类型分类 │ MEMORY.md 索引 │ AI 相关性召回 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ 第1层:会话记忆(Session Memory) │
|
||||
│ 仅当前会话 │ 单个文件 │ 10个固定章节 │ 服务于压缩 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
| 层级 | 范围 | 持久性 | 触发方式 | 存储位置 |
|
||||
|------|------|--------|----------|----------|
|
||||
| 会话记忆 | 当前会话 | 临时(会话结束即停用) | 后采样钩子(token+工具调用阈值) | 会话目录下单文件 |
|
||||
| 持久记忆 | 跨会话、按项目 | 永久(直到手动删除) | 每轮查询结束时(Stop Hook) | `~/.claude/projects/<项目>/memory/` |
|
||||
| 团队记忆 | 跨用户、按仓库 | 远程服务器 + 本地镜像 | 文件监听器(2秒去抖) | `memory/team/` + Anthropic API |
|
||||
|
||||
---
|
||||
|
||||
## 2. 持久记忆系统(核心)
|
||||
|
||||
### 2.1 记忆文件格式
|
||||
|
||||
每条记忆是一个独立的 Markdown 文件,带 YAML frontmatter:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: 用户偏好-简洁回复
|
||||
description: 用户不希望在每次回复末尾加总结
|
||||
type: feedback
|
||||
---
|
||||
|
||||
不要在回复末尾总结刚做了什么,用户能看到 diff。
|
||||
|
||||
**Why:** 用户明确要求过"stop summarizing what you just did"
|
||||
**How to apply:** 所有回复结束时,直接结束,不加回顾性总结。
|
||||
```
|
||||
|
||||
### 2.2 四种记忆类型
|
||||
|
||||
```typescript
|
||||
const MEMORY_TYPES = ['user', 'feedback', 'project', 'reference'] as const
|
||||
```
|
||||
|
||||
| 类型 | 用途 | 保存时机 | 作用域(团队模式) |
|
||||
|------|------|----------|:------------------:|
|
||||
| **user** | 用户角色、目标、知识背景 | 了解到用户的身份信息时 | 始终私有 |
|
||||
| **feedback** | 用户对工作方式的指导 | 用户纠正或确认做法时 | 默认私有 |
|
||||
| **project** | 项目进展、目标、事件 | 了解到工作计划、截止日期时 | 偏向团队 |
|
||||
| **reference** | 外部系统指针 | 了解到 Linear/Grafana/Slack 等资源时 | 通常团队 |
|
||||
|
||||
**每种类型要求的结构:**
|
||||
- feedback 和 project 类型必须包含 `**Why:**` 和 `**How to apply:**` 行
|
||||
- 相对日期必须转换为绝对日期(如"周四"→"2026-03-05")
|
||||
- user 类型的示例:"深度 Go 经验,React 新手——用后端类比解释前端概念"
|
||||
|
||||
### 2.3 明确不保存的内容
|
||||
|
||||
源码中硬编码了 6 类排除项(即使用户明确要求也不保存):
|
||||
|
||||
1. 代码模式、架构、文件路径、项目结构——可从代码推导
|
||||
2. Git 历史、最近变更——`git log`/`git blame` 是权威来源
|
||||
3. 调试方案或修复步骤——修复在代码中,commit message 有上下文
|
||||
4. CLAUDE.md 中已有的内容——不重复
|
||||
5. 临时任务细节:进行中的工作、当前对话上下文
|
||||
6. 如果用户要求保存 PR 列表或活动摘要,要追问"什么是令人意外的或不明显的?"——只保存那部分
|
||||
|
||||
### 2.4 MEMORY.md 索引机制
|
||||
|
||||
```
|
||||
MEMORY.md 是索引,不是记忆本身
|
||||
```
|
||||
|
||||
**格式:** 纯 Markdown,无 frontmatter。每条一行,约 150 字符以内:
|
||||
```markdown
|
||||
- [用户偏好-简洁回复](feedback_concise.md) — 不在回复末尾加总结
|
||||
- [项目-合并冻结](project_freeze.md) — 3月5日起移动端发布冻结
|
||||
```
|
||||
|
||||
**限制:**
|
||||
- 最大 200 行(`MAX_ENTRYPOINT_LINES`)
|
||||
- 最大 25,000 字节(`MAX_ENTRYPOINT_BYTES`)
|
||||
- 超出时在末尾追加截断警告
|
||||
- 截断按行边界执行(不会切断一行的中间)
|
||||
|
||||
**两步保存流程:**
|
||||
1. 写入记忆文件(如 `feedback_concise.md`)
|
||||
2. 在 MEMORY.md 中添加索引行
|
||||
|
||||
可选的 `skipIndex` 模式(通过 `tengu_moth_copse` 特性开关)可跳过第2步。
|
||||
|
||||
### 2.5 存储目录结构
|
||||
|
||||
```
|
||||
~/.claude/
|
||||
projects/
|
||||
-Users-charlesqin-Desktop-myproject/ ← sanitizePath(项目根目录)
|
||||
memory/ ← AUTO_MEM_DIRNAME
|
||||
MEMORY.md ← 索引文件
|
||||
user_role.md ← 私有记忆文件
|
||||
feedback_testing.md
|
||||
project_deadline.md
|
||||
reference_linear.md
|
||||
team/ ← 团队记忆子目录
|
||||
MEMORY.md ← 团队索引
|
||||
project_api_migration.md
|
||||
reference_oncall_board.md
|
||||
logs/ ← KAIROS 每日日志
|
||||
2026/
|
||||
03/
|
||||
2026-03-31.md
|
||||
```
|
||||
|
||||
### 2.6 路径安全机制
|
||||
|
||||
`paths.ts` 包含多层安全验证:
|
||||
|
||||
| 安全层 | 检查内容 | 防御目标 |
|
||||
|--------|----------|----------|
|
||||
| 绝对路径检查 | 拒绝相对路径 | 路径遍历 |
|
||||
| 根路径检查 | 拒绝长度 < 3 的路径 | 写入系统根目录 |
|
||||
| UNC 路径检查 | 拒绝 `\\server\share` 和 `//server/share` | NTLM 凭证泄露 |
|
||||
| Null 字节检查 | 拒绝包含 `\0` 的路径 | 路径截断攻击 |
|
||||
| Tilde 展开限制 | 拒绝 `~`、`~/`、`~/.`、`~/..` | 匹配整个 HOME |
|
||||
| **项目设置排除** | `.claude/settings.json` 不能设 `autoMemoryDirectory` | **恶意仓库重定向写入到 `~/.ssh`** |
|
||||
| NFC 规范化 | Unicode NFC 标准化 | macOS 路径不一致 |
|
||||
| Git 根规范化 | worktree 共享主仓库的记忆 | 避免重复记忆目录 |
|
||||
|
||||
**关键安全设计:** `projectSettings`(提交到仓库的 `.claude/settings.json`)被有意排除在 `autoMemoryDirectory` 的信任来源之外。源码注释明确说明原因:
|
||||
|
||||
```typescript
|
||||
// SECURITY: projectSettings is intentionally excluded —
|
||||
// a malicious repo could set autoMemoryDirectory: "~/.ssh"
|
||||
// and gain write access to sensitive directories
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 自动记忆提取(extractMemories)
|
||||
|
||||
### 3.1 触发时机
|
||||
|
||||
```
|
||||
用户输入 → 模型响应 → 工具执行 → 循环... → 模型最终响应(无工具调用)
|
||||
↓
|
||||
Stop Hooks 执行
|
||||
↓
|
||||
executeExtractMemories() ← 即发即忘
|
||||
```
|
||||
|
||||
**前置条件(全部满足才执行):**
|
||||
1. `EXTRACT_MEMORIES` 编译时特性开关开启
|
||||
2. `isExtractModeActive()` = true(`tengu_passport_quail` GrowthBook 开关)
|
||||
3. `isAutoMemoryEnabled()` = true
|
||||
4. 非子代理(`!toolUseContext.agentId`)
|
||||
5. 非 bare 模式
|
||||
6. 自上次提取以来有新的模型可见消息
|
||||
|
||||
### 3.2 互斥机制
|
||||
|
||||
```typescript
|
||||
// 如果主代理在对话中已经直接写了记忆文件,跳过自动提取
|
||||
if (hasMemoryWritesSince(lastMemoryMessageUuid)) {
|
||||
// 推进游标但不执行提取——避免覆盖用户显式保存的记忆
|
||||
lastMemoryMessageUuid = messages[messages.length - 1].uuid
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
这防止了自动提取和用户手动保存之间的冲突。
|
||||
|
||||
### 3.3 Fork Agent 执行
|
||||
|
||||
```typescript
|
||||
const result = await runForkedAgent({
|
||||
messages: conversationMessages,
|
||||
system: extractionPrompt,
|
||||
maxTurns: 5, // 硬上限:5轮(读1轮 + 写1-4轮)
|
||||
canUseTool: createAutoMemCanUseTool(autoMemPath),
|
||||
// ... 共享主会话的 prompt cache
|
||||
})
|
||||
```
|
||||
|
||||
**工具权限白名单:**
|
||||
|
||||
| 工具 | 权限 |
|
||||
|------|------|
|
||||
| FileRead | 允许(无限制) |
|
||||
| Grep | 允许(无限制) |
|
||||
| Glob | 允许(无限制) |
|
||||
| Bash | 仅只读命令(ls, find, grep, cat, stat, wc, head, tail) |
|
||||
| FileEdit | 仅限 `autoMemPath` 内 |
|
||||
| FileWrite | 仅限 `autoMemPath` 内 |
|
||||
| MCP / Agent / 写入型 Bash | **全部禁止** |
|
||||
|
||||
### 3.4 提取节流
|
||||
|
||||
```typescript
|
||||
let turnsSinceLastExtraction = 0
|
||||
const turnsBeforeExtraction = getFeatureValue('tengu_bramble_lintel', 1)
|
||||
|
||||
// 每 N 轮查询才执行一次提取(默认每轮都执行)
|
||||
if (turnsSinceLastExtraction < turnsBeforeExtraction) {
|
||||
turnsSinceLastExtraction++
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 提取后通知
|
||||
|
||||
成功提取后,将写入的文件路径列表作为 `SystemMemorySavedMessage` 追加到主对话中,这样主代理知道记忆已更新。
|
||||
|
||||
---
|
||||
|
||||
## 4. AI 驱动的记忆召回(findRelevantMemories)
|
||||
|
||||
### 4.1 召回流程
|
||||
|
||||
```
|
||||
用户发送消息
|
||||
↓
|
||||
scanMemoryFiles(memoryDir)
|
||||
↓ 递归读取所有 .md 文件(排除 MEMORY.md)
|
||||
↓ 解析前 30 行 frontmatter(description + type)
|
||||
↓ 按 mtime 降序排序,上限 200 个文件
|
||||
↓
|
||||
过滤掉 alreadySurfaced(之前轮次已展示的路径)
|
||||
↓
|
||||
selectRelevantMemories(query, memories, signal, recentTools)
|
||||
↓ 构建文本清单:每行 "- [type] filename (timestamp): description"
|
||||
↓ 附加 "Recently used tools: ..." 部分
|
||||
↓
|
||||
sideQuery → Sonnet 模型
|
||||
↓ 系统提示:SELECT_MEMORIES_SYSTEM_PROMPT
|
||||
↓ 用户消息:Query + Available memories
|
||||
↓ 结构化输出:{ selected_memories: string[] }
|
||||
↓ max_tokens: 256
|
||||
↓
|
||||
返回最多 5 条 RelevantMemory(路径 + mtime)
|
||||
```
|
||||
|
||||
### 4.2 选择提示词的关键规则
|
||||
|
||||
```
|
||||
- 返回最多 5 个文件名
|
||||
- 要有选择性和辨别力;如果不确定,不要包含
|
||||
- 如果提供了最近使用的工具列表:
|
||||
✗ 不要选择这些工具的使用参考/API 文档(已经在用了)
|
||||
✓ 仍然选择这些工具的警告/陷阱/已知问题
|
||||
```
|
||||
|
||||
### 4.3 记忆新鲜度标注
|
||||
|
||||
```typescript
|
||||
function memoryAge(mtimeMs: number): string {
|
||||
const days = memoryAgeDays(mtimeMs)
|
||||
if (days === 0) return 'today'
|
||||
if (days === 1) return 'yesterday'
|
||||
return `${days} days ago`
|
||||
}
|
||||
|
||||
function memoryFreshnessText(mtimeMs: number): string {
|
||||
if (memoryAgeDays(mtimeMs) <= 1) return '' // 新鲜记忆不加警告
|
||||
return `This memory is ${days} days old.
|
||||
Memories are point-in-time observations, not live state —
|
||||
claims about code behavior or file:line citations may be outdated.
|
||||
Verify against current code before asserting as fact.`
|
||||
}
|
||||
```
|
||||
|
||||
**设计动机(源码注释):** 用户报告过过期的记忆被模型当作事实断言。"47 days ago" 比 ISO 时间戳更能触发模型的过期推理。
|
||||
|
||||
### 4.4 召回前的验证要求
|
||||
|
||||
源码中注入的系统提示明确要求模型在使用记忆前验证:
|
||||
|
||||
```
|
||||
- 如果记忆提到一个文件路径 → 检查文件是否存在
|
||||
- 如果记忆提到一个函数或标志 → grep 搜索它
|
||||
- 如果用户即将根据你的建议行动 → 先验证
|
||||
- "记忆说 X 存在"不等于"X 现在存在"
|
||||
- 活动日志、架构快照是冻结在某个时间点的,优先使用 git log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 会话记忆(Session Memory)
|
||||
|
||||
### 5.1 与持久记忆的关键区别
|
||||
|
||||
| 维度 | 会话记忆 | 持久记忆 |
|
||||
|------|----------|----------|
|
||||
| 生命周期 | 当前会话 | 跨会话永久 |
|
||||
| 文件数量 | 1 个 | 多个 |
|
||||
| 触发频率 | 每次后采样(需满足阈值) | 每轮查询结束 |
|
||||
| 主要用途 | **服务于上下文压缩** | 跨会话知识保留 |
|
||||
| 记忆提取者 | Fork Agent(仅 FileEdit) | Fork Agent(Read/Write/Edit/Grep) |
|
||||
| 格式 | 10个固定章节 | 自由格式 + frontmatter |
|
||||
|
||||
### 5.2 触发阈值
|
||||
|
||||
```typescript
|
||||
// 默认配置(可通过 GrowthBook tengu_sm_config 远程调整)
|
||||
const defaults = {
|
||||
minimumMessageTokensToInit: 10_000, // 上下文达到 10K tokens 才激活
|
||||
minimumTokensBetweenUpdate: 5_000, // 每增长 5K tokens 更新一次
|
||||
toolCallsBetweenUpdates: 3, // 且至少 3 次工具调用
|
||||
}
|
||||
|
||||
// 触发条件:
|
||||
// (token 阈值满足 AND 工具调用阈值满足)
|
||||
// OR (token 阈值满足 AND 最后一轮助手消息无工具调用)
|
||||
```
|
||||
|
||||
### 5.3 会话记忆模板(10 个固定章节)
|
||||
|
||||
```markdown
|
||||
# Session Memory
|
||||
|
||||
## Session Title
|
||||
_Brief description of what this session is about_
|
||||
|
||||
## Current State
|
||||
_What is the current status of the work_
|
||||
|
||||
## Task specification
|
||||
_Detailed description of the current task requirements_
|
||||
|
||||
## Files and Functions
|
||||
_Key files and functions being worked on_
|
||||
|
||||
## Workflow
|
||||
_Steps being followed or processes in use_
|
||||
|
||||
## Errors & Corrections
|
||||
_Errors encountered and how they were resolved_
|
||||
|
||||
## Codebase and System Documentation
|
||||
_Important codebase patterns, conventions, and system behavior_
|
||||
|
||||
## Learnings
|
||||
_Insights gained during this session_
|
||||
|
||||
## Key results
|
||||
_Important outputs, measurements, or achievements_
|
||||
|
||||
## Worklog
|
||||
_Chronological log of actions taken_
|
||||
```
|
||||
|
||||
### 5.4 大小限制
|
||||
|
||||
```typescript
|
||||
const MAX_SECTION_LENGTH = 2_000 // 每个章节最大 2K tokens
|
||||
const MAX_TOTAL_SESSION_MEMORY_TOKENS = 12_000 // 整个文件最大 12K tokens
|
||||
```
|
||||
|
||||
### 5.5 与压缩的集成
|
||||
|
||||
Session Memory 是上下文压缩的优先路径(参见 `sessionMemoryCompact.ts`):
|
||||
- 自动压缩触发时,优先尝试用 Session Memory 作为摘要
|
||||
- 保留最近 10K-40K tokens 的消息
|
||||
- 比传统压缩快得多(不调用 LLM),且摘要质量更可预测
|
||||
|
||||
### 5.6 自定义
|
||||
|
||||
用户可以自定义模板和提示词:
|
||||
- 模板:`~/.claude/session-memory/config/template.md`
|
||||
- 提示词:`~/.claude/session-memory/config/prompt.md`(支持 `{{variableName}}` 替换)
|
||||
|
||||
---
|
||||
|
||||
## 6. 团队记忆同步
|
||||
|
||||
### 6.1 前置条件
|
||||
|
||||
同时满足才启用:
|
||||
1. `TEAMMEM` 编译时特性开关开启
|
||||
2. `isTeamMemoryEnabled()` = true(`tengu_herring_clock` GrowthBook 开关)
|
||||
3. 第一方 OAuth + 同时拥有 `INFERENCE_SCOPE` 和 `PROFILE_SCOPE`
|
||||
4. Git remote 是 github.com(非 GitHub 仓库不同步)
|
||||
|
||||
### 6.2 API 端点
|
||||
|
||||
```
|
||||
基础 URL: {baseUrl}/api/claude_code/team_memory?repo={owner/repo}
|
||||
```
|
||||
|
||||
| 方法 | 参数 | 用途 | 关键状态码 |
|
||||
|------|------|------|:----------:|
|
||||
| GET | `repo={slug}` | 拉取全部团队记忆 | 200 / 304 / 404 |
|
||||
| GET | `repo={slug}&view=hashes` | 仅拉取哈希(轻量探测) | 200 / 404 |
|
||||
| PUT | `repo={slug}` | 上传记忆条目(upsert) | 200 / 412 / 413 |
|
||||
|
||||
**认证头:** `Authorization: Bearer {oauthToken}`
|
||||
|
||||
### 6.3 同步协议
|
||||
|
||||
#### 拉取(Pull)
|
||||
|
||||
```
|
||||
1. GET 请求,携带 ETag(条件请求)
|
||||
2. 304 = 未变化,跳过
|
||||
3. 200 = 有更新:
|
||||
a. 对每个条目验证路径(防遍历攻击)
|
||||
b. 跳过 >250KB 的文件
|
||||
c. 跳过本地内容已匹配的文件
|
||||
d. 并行写入本地文件系统
|
||||
e. 刷新 serverChecksums
|
||||
```
|
||||
|
||||
#### 推送(Push — Delta 上传 + 乐观锁)
|
||||
|
||||
```
|
||||
1. readLocalTeamMemory(): 遍历 team/ 目录
|
||||
→ 每个文件扫描秘密(30种规则)
|
||||
→ 跳过 >250KB 的文件
|
||||
→ 计算 SHA-256 哈希
|
||||
|
||||
2. 计算 delta:仅本地哈希与 serverChecksums 不同的 key
|
||||
|
||||
3. 分批上传:贪心装箱,每批 ≤ 200KB (MAX_PUT_BODY_BYTES)
|
||||
|
||||
4. 每批携带 If-Match 头(乐观锁)
|
||||
|
||||
5. 冲突处理:
|
||||
412 Conflict → 探测 ?view=hashes → 刷新 serverChecksums → 重算 delta → 重试(最多 2 次)
|
||||
413 Too Many → 学习 serverMaxEntries 上限,截断后重试
|
||||
|
||||
6. 冲突策略:本地优先(local-wins)
|
||||
→ 当前用户正在编辑的内容覆盖服务端
|
||||
```
|
||||
|
||||
### 6.4 文件监听器
|
||||
|
||||
```typescript
|
||||
// watcher.ts
|
||||
fs.watch(teamMemDir, { recursive: true })
|
||||
// macOS: FSEvents(O(1) 文件描述符)
|
||||
// Linux: inotify(O(子目录数))
|
||||
|
||||
// 2 秒去抖:最后一次变更后 2 秒才触发推送
|
||||
```
|
||||
|
||||
**推送抑制:** 永久失败(no_oauth、no_repo、4xx 非 409/429)后,抑制后续推送,直到发生文件删除(恢复动作)或会话重启。
|
||||
|
||||
### 6.5 团队 vs 私有的作用域划分
|
||||
|
||||
源码注入的系统提示中,每种记忆类型都带有 XML 作用域标签:
|
||||
|
||||
```xml
|
||||
<type>
|
||||
<name>user</name>
|
||||
<scope>always private</scope>
|
||||
...
|
||||
</type>
|
||||
|
||||
<type>
|
||||
<name>project</name>
|
||||
<scope>strongly bias toward team</scope>
|
||||
...
|
||||
</type>
|
||||
```
|
||||
|
||||
额外安全要求:
|
||||
```
|
||||
MUST avoid saving sensitive data within shared team memories
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 秘密扫描保护
|
||||
|
||||
### 7.1 双层防护
|
||||
|
||||
| 层 | 时机 | 文件 | 行为 |
|
||||
|----|------|------|------|
|
||||
| 写入时拦截 | FileWrite/FileEdit 调用 | `teamMemSecretGuard.ts` | 阻止写入,返回错误 |
|
||||
| 上传前扫描 | pushTeamMemory 读取本地文件 | `secretScanner.ts` | 跳过该文件,不上传 |
|
||||
|
||||
### 7.2 检测的 30 种秘密模式
|
||||
|
||||
**云服务商:**
|
||||
- AWS Access Token(A3T/AKIA/ASIA/ABIA/ACCA 前缀)
|
||||
- GCP API Key(AIza 前缀)
|
||||
- Azure AD Client Secret
|
||||
- DigitalOcean PAT / Access Token
|
||||
|
||||
**AI API:**
|
||||
- Anthropic API Key(`sk-ant-api03-` 前缀,运行时拼接避免自身匹配)
|
||||
- Anthropic Admin API Key(`sk-ant-admin01-`)
|
||||
- OpenAI API Key(`sk-proj`/`svcacct`/`admin` + `T3BlbkFJ` 标记)
|
||||
- HuggingFace Access Token(`hf_`)
|
||||
|
||||
**版本控制:**
|
||||
- GitHub PAT / Fine-grained PAT / App Token / OAuth / Refresh Token
|
||||
- GitLab PAT / Deploy Token
|
||||
|
||||
**通信平台:**
|
||||
- Slack Bot/User/App Token(`xoxb-`/`xoxp-`/`xapp-`)
|
||||
- Twilio API Key
|
||||
- SendGrid API Token
|
||||
|
||||
**开发工具:**
|
||||
- npm Access Token
|
||||
- PyPI Upload Token
|
||||
- Databricks API Token
|
||||
- HashiCorp Terraform API Token
|
||||
- Pulumi API Token
|
||||
- Postman API Token
|
||||
|
||||
**可观测性:**
|
||||
- Grafana API Key / Cloud API Token / Service Account Token
|
||||
- Sentry User/Org Token
|
||||
|
||||
**支付:**
|
||||
- Stripe Access Token(`sk_test`/`live`/`prod` 或 `rk_`)
|
||||
- Shopify Access Token / Shared Secret
|
||||
|
||||
**密码学:**
|
||||
- PEM 格式私钥(`BEGIN/END PRIVATE KEY` 块)
|
||||
|
||||
### 7.3 设计原则
|
||||
|
||||
```typescript
|
||||
// 匹配到的秘密值永远不被记录或返回——只返回规则 ID 和人类可读标签
|
||||
// Anthropic API key 前缀在运行时拼接,避免匹配自身的 excluded-strings 检查:
|
||||
const prefix = ['sk', 'ant', 'api'].join('-')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. KAIROS 模式的记忆(每日日志)
|
||||
|
||||
当 KAIROS(AI 助手模式)激活时,记忆范式完全改变:
|
||||
|
||||
```
|
||||
普通模式:写独立文件 + 更新 MEMORY.md 索引
|
||||
KAIROS 模式:追加到 logs/YYYY/MM/YYYY-MM-DD.md 日志文件
|
||||
```
|
||||
|
||||
- 只追加,不编辑已有内容
|
||||
- 每日一个文件,按日期路径组织
|
||||
- 由单独的 `/dream` 技能在夜间蒸馏日志为主题文件和 MEMORY.md
|
||||
- 提示词中使用 `YYYY-MM-DD` 占位符而非实际日期(因为提示词被缓存,日期变化不会触发失效)
|
||||
|
||||
---
|
||||
|
||||
## 9. 记忆系统注入的完整系统提示词
|
||||
|
||||
### 9.1 个人模式(auto memory)
|
||||
|
||||
```
|
||||
# auto memory
|
||||
|
||||
You have a persistent, file-based memory system at `<memoryDir>`.
|
||||
This directory already exists — write to it directly with the Write tool.
|
||||
|
||||
You should build up this memory system over time so that future conversations
|
||||
can have a complete picture of who the user is, how they'd like to collaborate
|
||||
with you, what behaviors to avoid or repeat, and the context behind the work.
|
||||
|
||||
[如果用户要求记住 → 立即保存]
|
||||
[如果用户要求忘记 → 找到并删除]
|
||||
|
||||
## Types of memory
|
||||
[4种类型,每种含 description/when_to_save/how_to_use/examples]
|
||||
|
||||
## What NOT to save in memory
|
||||
[6类排除项]
|
||||
|
||||
## How to save memories
|
||||
Step 1: 写入文件(带 frontmatter)
|
||||
Step 2: 在 MEMORY.md 中添加索引行
|
||||
|
||||
## When to access memories
|
||||
- 看起来相关时
|
||||
- 用户明确要求时(必须访问)
|
||||
- 用户说"忽略记忆"时,假装 MEMORY.md 为空
|
||||
|
||||
## Before recommending from memory
|
||||
- 提到文件路径 → 检查文件是否存在
|
||||
- 提到函数/标志 → grep 搜索
|
||||
- 用户要行动 → 先验证
|
||||
|
||||
## Memory and other forms of persistence
|
||||
- 实施方案 → 用 Plan,不用记忆
|
||||
- 当前对话步骤 → 用 Tasks,不用记忆
|
||||
|
||||
## Searching past context
|
||||
[grep 记忆文件,或搜索会话 transcript]
|
||||
|
||||
## MEMORY.md
|
||||
[实际的 MEMORY.md 内容,或"当前为空"]
|
||||
```
|
||||
|
||||
### 9.2 团队模式额外内容
|
||||
|
||||
在个人模式基础上增加:
|
||||
|
||||
```
|
||||
## Memory scope
|
||||
- 私有记忆:<privateDir> — 你的个人偏好、反馈
|
||||
- 团队记忆:<teamDir> — 项目上下文、外部引用
|
||||
|
||||
[类型定义中增加 <scope> XML 标签]
|
||||
|
||||
额外安全规则:不得在团队记忆中保存敏感数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 团队记忆的路径安全(深度防御)
|
||||
|
||||
`teamMemPaths.ts` 是整个记忆系统中安全措施最密集的文件:
|
||||
|
||||
### 10.1 自定义错误类
|
||||
|
||||
```typescript
|
||||
class PathTraversalError extends Error {
|
||||
name = 'PathTraversalError'
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 sanitizePathKey — 服务端提供的相对路径清理
|
||||
|
||||
```typescript
|
||||
function sanitizePathKey(key: string): string {
|
||||
// 1. 拒绝 null 字节
|
||||
// 2. URL 编码遍历检测:解码 %2e%2e%2f 等
|
||||
// 3. Unicode 规范化攻击:全角字符 \uFF0E\uFF0E\uFF0F → ../
|
||||
// 4. 拒绝反斜杠(Windows 路径遍历)
|
||||
// 5. 拒绝绝对路径
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3 realpathDeepestExisting — 符号链接解析
|
||||
|
||||
```typescript
|
||||
async function realpathDeepestExisting(path: string): Promise<string> {
|
||||
// 逐级向上 realpath() 直到成功
|
||||
// 检测悬挂符号链接(link 存在但 target 不存在)
|
||||
// → 安全威胁:writeFile 会跟随链接在 team 目录外创建文件
|
||||
// 检测符号链接循环(ELOOP)→ PathTraversalError
|
||||
// 不可恢复的错误(EACCES, EIO)→ fail-closed
|
||||
}
|
||||
```
|
||||
|
||||
### 10.4 validateTeamMemWritePath — 双重验证
|
||||
|
||||
```
|
||||
写入团队记忆文件前的完整验证链:
|
||||
|
||||
第1遍:字符串级
|
||||
1. Null 字节检查
|
||||
2. path.resolve() 解析
|
||||
3. startsWith(teamDir) 验证
|
||||
|
||||
第2遍:符号链接级
|
||||
4. realpathDeepestExisting() 解析实际路径
|
||||
5. isRealPathWithinTeamDir() 验证实际路径在团队目录内
|
||||
|
||||
通过 → 返回解析后的路径
|
||||
失败 → 抛出 PathTraversalError
|
||||
```
|
||||
|
||||
### 10.5 前缀攻击防护
|
||||
|
||||
```typescript
|
||||
// 团队目录路径以分隔符结尾:/foo/team/
|
||||
// 这样 /foo/team-evil/ 不会通过 startsWith 检查
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 记忆的生命周期全景
|
||||
|
||||
```
|
||||
会话开始
|
||||
│
|
||||
├─ loadMemoryPrompt()
|
||||
│ → 读取 MEMORY.md → 注入系统提示
|
||||
│
|
||||
├─ initSessionMemory()
|
||||
│ → 注册后采样钩子
|
||||
│
|
||||
├─ startTeamMemoryWatcher()
|
||||
│ → 拉取服务端 → 启动文件监听
|
||||
│
|
||||
▼
|
||||
每轮对话
|
||||
│
|
||||
├─ findRelevantMemories(query)
|
||||
│ → 扫描文件 → Sonnet 选择 → 返回最多 5 条
|
||||
│ → 新鲜度标注(>1天 → 加过期警告)
|
||||
│
|
||||
├─ [模型可能直接读/写记忆文件]
|
||||
│ → 写入团队记忆 → checkTeamMemSecrets() 拦截秘密
|
||||
│ → 文件监听触发 → 2秒后推送到服务端
|
||||
│
|
||||
├─ Session Memory 后采样钩子
|
||||
│ → 检查阈值 → Fork Agent 更新单文件
|
||||
│
|
||||
├─ 模型最终响应(无工具调用)
|
||||
│ → Stop Hooks → executeExtractMemories()
|
||||
│ → 互斥检查 → Fork Agent 提取 → 更新持久记忆文件
|
||||
│
|
||||
▼
|
||||
自动压缩触发时
|
||||
│
|
||||
├─ trySessionMemoryCompaction()(优先路径)
|
||||
│ → 用 Session Memory 内容作为摘要
|
||||
│ → 保留最近 10K-40K tokens 的消息
|
||||
│
|
||||
├─ compactConversation()(回退路径)
|
||||
│ → Fork Agent 生成 9 章节结构化摘要
|
||||
│
|
||||
▼
|
||||
会话结束
|
||||
│
|
||||
├─ drainPendingExtraction()
|
||||
│ → 等待进行中的记忆提取完成
|
||||
│
|
||||
└─ 团队记忆推送最后一批变更
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 关键设计决策总结
|
||||
|
||||
| 决策 | 原因 |
|
||||
|------|------|
|
||||
| 记忆文件是独立的 .md 文件,不是数据库 | 用户可以直接编辑、Git 追踪、跨工具使用 |
|
||||
| MEMORY.md 是索引不是记忆 | 防止单文件膨胀,支持截断不丢核心内容 |
|
||||
| 自动提取在 Stop Hook 中即发即忘 | 不阻塞主对话循环 |
|
||||
| 互斥检查(主代理 vs 自动提取) | 防止覆盖用户显式保存的内容 |
|
||||
| 召回用 Sonnet 不用 Haiku | 需要理解语义相关性,Haiku 不够准确 |
|
||||
| 新鲜度用"X days ago"不用 ISO 时间 | 模型对相对时间的推理比绝对时间好 |
|
||||
| 项目设置排除 autoMemoryDirectory | 防止恶意仓库劫持写入路径 |
|
||||
| 团队记忆双重路径验证 | 符号链接攻击需要在文件系统层面检查 |
|
||||
| 秘密模式在运行时拼接 | 避免自身的 excluded-strings 检查 |
|
||||
| 本地优先的冲突策略 | 用户正在编辑 = 最新意图 |
|
||||
| 断路器(MAX_CONFLICT_RETRIES = 2) | 防止推送冲突的无限重试 |
|
||||
|
||||
---
|
||||
|
||||
*来自:AI超元域 | B站频道:https://space.bilibili.com/3493277319825652*
|
||||
|
||||
*基于 Claude Code 源码逆向分析,2026-03-31*
|
||||
805
docs/cc_analysis/analysis_20260401/Claude_Code隐藏高级功能全景图.md
Normal file
805
docs/cc_analysis/analysis_20260401/Claude_Code隐藏高级功能全景图.md
Normal file
@@ -0,0 +1,805 @@
|
||||
# Claude Code 隐藏高级功能全景图
|
||||
|
||||
> 基于 Claude Code 源码(2026-03-31 快照,512K 行 TypeScript)逆向分析
|
||||
> 发现 55+ 个特性开关、20+ 个隐藏命令、以及多个未公开系统
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [你现在就能用的隐藏功能](#1-你现在就能用的隐藏功能)
|
||||
2. [55+ 个编译时特性开关完整清单](#2-55-个编译时特性开关完整清单)
|
||||
3. [KAIROS — AI 助手守护进程](#3-kairos--ai-助手守护进程)
|
||||
4. [CHICAGO_MCP — Computer Use 电脑控制](#4-chicago_mcp--computer-use-电脑控制)
|
||||
5. [投机执行系统(Speculation)](#5-投机执行系统speculation)
|
||||
6. [Undercover 隐身模式](#6-undercover-隐身模式)
|
||||
7. [Dream Mode 记忆梦境整合](#7-dream-mode-记忆梦境整合)
|
||||
8. [Voice Mode 语音输入](#8-voice-mode-语音输入)
|
||||
9. [Proactive 自主代理模式](#9-proactive-自主代理模式)
|
||||
10. [伴侣精灵系统(Buddy)](#10-伴侣精灵系统buddy)
|
||||
11. [多代理团队/Swarm 系统](#11-多代理团队swarm-系统)
|
||||
12. [Anthropic 内部专用命令](#12-anthropic-内部专用命令)
|
||||
13. [隐藏键盘快捷键](#13-隐藏键盘快捷键)
|
||||
14. [隐藏环境变量](#14-隐藏环境变量)
|
||||
15. [其他彩蛋与冷知识](#15-其他彩蛋与冷知识)
|
||||
|
||||
---
|
||||
|
||||
## 1. 你现在就能用的隐藏功能
|
||||
|
||||
这些功能在当前公开版本中存在,但很少被提及:
|
||||
|
||||
| 功能 | 触发方式 | 说明 |
|
||||
|------|----------|------|
|
||||
| 实体贴纸 | `/stickers` | 打开 Claude Code 实体贴纸购买页 |
|
||||
| 堆转储 | `/heapdump` | 把 JS 堆转储到 `~/Desktop`(隐藏命令,不在 /help 中) |
|
||||
| 裸模式 | `--bare` 或 `CLAUDE_CODE_SIMPLE=1` | 极简模式:只保留 Bash、Read、Edit 三个工具 |
|
||||
| 自定义加载词 | `settings.json` → `spinnerVerbs` | 替换或追加 200+ 个花式加载词("Clauding"、"Flibbertigibbeting"…) |
|
||||
| 输出风格切换 | `/config` → output style | **Explanatory**(教学模式,附 Insight 解说)或 **Learning**(动手练习,含 TODO(human) 标记) |
|
||||
| Vim 模式 | `/vim` | 完整状态机:d/c/y 操作符、h/l/w/b/e/$ 移动、f/t 查找、文本对象、dot-repeat |
|
||||
| 消息动作选择器 | `shift+up` | 进入消息导航:j/k 上下移动,c 复制消息,p 固定消息 |
|
||||
| 年度回顾 | `/think-back` | "Your 2025 Claude Code Year in Review" 动画回顾 |
|
||||
| 转储系统提示 | `--dump-system-prompt` | 打印完整系统提示词后退出(需特性开关) |
|
||||
| 多代理团队 | `--agent-teams` 或 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` | 多 Claude 实例在 tmux/iTerm 分屏中并行工作 |
|
||||
| 后台任务 | `ctrl+b` | 把当前运行中的任务转入后台 |
|
||||
| 历史搜索 | `ctrl+r` | 反向搜索命令历史 |
|
||||
| Transcript 模式 | `ctrl+o` | 查看完整对话记录,支持搜索 |
|
||||
| Todo 面板 | `ctrl+t` | 任务追踪面板 |
|
||||
| 速率限制选项 | `/rate-limit-options` | 隐藏命令,速率限制时显示选项 |
|
||||
| 使用洞察 | `/insights` | 分析你的 Claude Code 使用历史(113KB 延迟加载模块) |
|
||||
| 全局文件搜索 | `ctrl+shift+f` | 跨文件搜索(需 QUICK_SEARCH 开关) |
|
||||
| 快速打开 | `ctrl+shift+p` | 快速打开文件 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 55+ 个编译时特性开关完整清单
|
||||
|
||||
所有开关通过 `feature('FLAG')` 在 Bun 编译时评估。外部构建中为 `false` 的分支会被彻底删除(死代码消除)。
|
||||
|
||||
### 核心功能开关
|
||||
|
||||
| 开关 | 功能 | 状态 |
|
||||
|------|------|:----:|
|
||||
| `VOICE_MODE` | 语音输入(push-to-talk) | 内部 |
|
||||
| `KAIROS` | AI 助手守护进程模式 | 内部 |
|
||||
| `KAIROS_DREAM` | 梦境记忆整合 | 内部 |
|
||||
| `KAIROS_BRIEF` | Brief 摘要工具 | 内部 |
|
||||
| `KAIROS_CHANNELS` | 频道通知系统 | 内部 |
|
||||
| `KAIROS_PUSH_NOTIFICATION` | 推送通知工具 | 内部 |
|
||||
| `KAIROS_GITHUB_WEBHOOKS` | GitHub PR 订阅 | 内部 |
|
||||
| `CHICAGO_MCP` | Computer Use 电脑控制 | 付费用户 |
|
||||
| `PROACTIVE` | 自主代理模式(Sleep + 自动唤醒) | 内部 |
|
||||
| `BRIDGE_MODE` | Remote Control 桥接 | 公开 |
|
||||
| `DAEMON` | 后台守护进程 | 内部 |
|
||||
|
||||
### 上下文管理开关
|
||||
|
||||
| 开关 | 功能 |
|
||||
|------|------|
|
||||
| `CONTEXT_COLLAPSE` | 智能上下文折叠(替代暴力压缩) |
|
||||
| `REACTIVE_COMPACT` | 响应式压缩(API 报 prompt-too-long 时触发) |
|
||||
| `CACHED_MICROCOMPACT` | 缓存感知微压缩(不破坏 prompt cache) |
|
||||
| `HISTORY_SNIP` | 历史裁剪(SnipTool + /force-snip) |
|
||||
| `TOKEN_BUDGET` | Token 预算追踪和递减收益检测 |
|
||||
| `EXTRACT_MEMORIES` | 自动记忆提取 |
|
||||
| `TEAMMEM` | 团队记忆同步 |
|
||||
|
||||
### 工具和代理开关
|
||||
|
||||
| 开关 | 功能 |
|
||||
|------|------|
|
||||
| `COORDINATOR_MODE` | 多代理协调者模式 |
|
||||
| `AGENT_TRIGGERS` | 定时触发器(Cron) |
|
||||
| `AGENT_TRIGGERS_REMOTE` | 远程触发器 |
|
||||
| `MONITOR_TOOL` | 监控工具和任务 |
|
||||
| `WEB_BROWSER_TOOL` | 网页浏览器自动化工具 |
|
||||
| `TERMINAL_PANEL` | 终端面板(meta+j) |
|
||||
| `WORKFLOW_SCRIPTS` | 工作流脚本系统 |
|
||||
| `BG_SESSIONS` | 后台会话(claude ps/logs/attach/kill) |
|
||||
| `OVERFLOW_TEST_TOOL` | 上下文溢出测试工具 |
|
||||
| `BUDDY` | 伴侣精灵系统 |
|
||||
|
||||
### UI 和体验开关
|
||||
|
||||
| 开关 | 功能 |
|
||||
|------|------|
|
||||
| `MESSAGE_ACTIONS` | 消息动作选择器(shift+up) |
|
||||
| `QUICK_SEARCH` | 全局搜索和快速打开 |
|
||||
| `AUTO_THEME` | 自动主题检测 |
|
||||
| `STREAMLINED_OUTPUT` | 流式 JSON 模式优化输出 |
|
||||
| `CONNECTOR_TEXT` | 连接器文本摘要 beta |
|
||||
|
||||
### 安全和调试开关
|
||||
|
||||
| 开关 | 功能 |
|
||||
|------|------|
|
||||
| `BASH_CLASSIFIER` | Bash 命令 ML 安全分类器 |
|
||||
| `TRANSCRIPT_CLASSIFIER` | 基于 transcript 的权限模式分类 |
|
||||
| `NATIVE_CLIENT_ATTESTATION` | 客户端证明头(cch=) |
|
||||
| `HARD_FAIL` | 硬失败模式(任何错误都崩溃) |
|
||||
| `DUMP_SYSTEM_PROMPT` | --dump-system-prompt 隐藏 CLI 标志 |
|
||||
| `ABLATION_BASELINE` | A/B 测试消融基线 |
|
||||
| `PROMPT_CACHE_BREAK_DETECTION` | Prompt 缓存失效检测 |
|
||||
|
||||
### 基础设施开关
|
||||
|
||||
| 开关 | 功能 |
|
||||
|------|------|
|
||||
| `LODESTONE` | `cc://` 深度链接协议注册 |
|
||||
| `DIRECT_CONNECT` | 通过 cc:// 深度链接直连 |
|
||||
| `SSH_REMOTE` | SSH 远程会话 |
|
||||
| `BYOC_ENVIRONMENT_RUNNER` | 自带计算环境运行器 |
|
||||
| `SELF_HOSTED_RUNNER` | 自托管运行器 |
|
||||
| `CCR_REMOTE_SETUP` | /remote-setup 命令 |
|
||||
| `FORK_SUBAGENT` | /fork 子代理分叉命令 |
|
||||
| `MCP_SKILLS` | MCP 提供的技能 |
|
||||
| `EXPERIMENTAL_SKILL_SEARCH` | 实验性技能模糊搜索 |
|
||||
| `REVIEW_ARTIFACT` | 审查工件工具 |
|
||||
| `BUILDING_CLAUDE_APPS` | /claude-api 技能 |
|
||||
| `RUN_SKILL_GENERATOR` | 技能生成器 |
|
||||
| `ULTRAPLAN` | 超级计划模式 |
|
||||
| `TORCH` | /torch 命令 |
|
||||
| `TEMPLATES` | 任务分类器/模板系统 |
|
||||
| `VERIFICATION_AGENT` | 验证代理 |
|
||||
| `COMMIT_ATTRIBUTION` | 提交归属(Co-Authored-By) |
|
||||
| `AWAY_SUMMARY` | 离开摘要生成 |
|
||||
| `FILE_PERSISTENCE` | 跨轮次文件持久化追踪 |
|
||||
| `MEMORY_SHAPE_TELEMETRY` | 记忆文件形状遥测 |
|
||||
| `COWORKER_TYPE_TELEMETRY` | Coworker 类型遥测 |
|
||||
| `DOWNLOAD_USER_SETTINGS` | 设置下载同步 |
|
||||
| `UPLOAD_USER_SETTINGS` | 设置上传同步 |
|
||||
| `BREAK_CACHE_COMMAND` | /break-cache 命令 |
|
||||
|
||||
---
|
||||
|
||||
## 3. KAIROS — AI 助手守护进程
|
||||
|
||||
**代号含义:** KAIROS(希腊语,"决定性时刻")
|
||||
|
||||
### 架构
|
||||
|
||||
```
|
||||
claude assistant ← 启动入口
|
||||
↓
|
||||
永驻守护进程
|
||||
├── 每日日志: logs/YYYY/MM/YYYY-MM-DD.md(仅追加)
|
||||
├── SleepTool: 休眠 → 定时自主唤醒
|
||||
├── PushNotificationTool: 向用户推送通知
|
||||
├── SendUserFileTool: 发送文件给用户
|
||||
├── SubscribePRTool: 订阅 GitHub PR webhook
|
||||
├── BriefTool: 简短状态报告(ctrl+shift+b)
|
||||
├── 频道通知: 通过 MCP 接收外部消息
|
||||
└── /dream: 夜间记忆蒸馏
|
||||
```
|
||||
|
||||
### 关键特性
|
||||
|
||||
- **记忆范式不同**:不写独立记忆文件,而是追加到每日日志
|
||||
- **夜间梦境**:`/dream` 技能自动将日志蒸馏为主题文件
|
||||
- **自主循环**:SleepTool + 自动唤醒 = 完全自主的工作循环
|
||||
- **压缩后行为**:提示词包含 "你正在自主模式中运行,这不是首次唤醒——继续工作循环"
|
||||
- **涉及 6 个子特性开关**:KAIROS + KAIROS_DREAM + KAIROS_BRIEF + KAIROS_CHANNELS + KAIROS_PUSH_NOTIFICATION + KAIROS_GITHUB_WEBHOOKS
|
||||
|
||||
---
|
||||
|
||||
## 4. CHICAGO_MCP — Computer Use 电脑控制
|
||||
|
||||
**代号:** Chicago(子门控以芝加哥地标命名:`tengu_malort_pedway`)
|
||||
|
||||
### 功能
|
||||
|
||||
- 创建**进程内 MCP 服务器**控制屏幕
|
||||
- macOS 上使用**原生 Swift 执行器**
|
||||
- 支持 `pixels` 和 `normalized` 两种坐标模式
|
||||
- 自动列出已安装应用供模型参考
|
||||
- **ESC 热键**紧急中断电脑控制
|
||||
- 可通过 `--computer-use-mcp` 独立启动 MCP 服务器
|
||||
|
||||
### 子功能门控
|
||||
|
||||
| 子门控 | 功能 |
|
||||
|--------|------|
|
||||
| `pixelValidation` | 像素坐标验证 |
|
||||
| `clipboardPasteMultiline` | 多行剪贴板粘贴 |
|
||||
| `mouseAnimation` | 鼠标移动动画 |
|
||||
| `hideBeforeAction` | 操作前隐藏 UI |
|
||||
| `autoTargetDisplay` | 自动目标显示器选择 |
|
||||
| `clipboardGuard` | 剪贴板保护 |
|
||||
|
||||
### 访问控制
|
||||
|
||||
- 需要 **Max 或 Pro 订阅**(外部用户)
|
||||
- Anthropic 员工可直接使用(绕过订阅检查)
|
||||
- 有专用权限 UI(`ComputerUseApproval.tsx`)
|
||||
|
||||
---
|
||||
|
||||
## 5. 投机执行系统(Speculation)
|
||||
|
||||
**仅 Anthropic 内部**(`USER_TYPE === 'ant'`)
|
||||
|
||||
### 工作原理
|
||||
|
||||
```
|
||||
1. 系统生成"下一步建议"提示词
|
||||
↓
|
||||
2. 用户看到建议的同时,后台 Fork Agent 已开始执行
|
||||
↓
|
||||
3. 文件写入到 overlay 目录(copy-on-write 隔离)
|
||||
~/.claude/tmp/speculation/<pid>/<id>/
|
||||
↓
|
||||
4. 用户接受建议 → 投机结果注入对话 + overlay 文件复制到真实文件系统
|
||||
用户拒绝/修改 → 丢弃投机结果
|
||||
```
|
||||
|
||||
### 安全约束
|
||||
|
||||
| 工具类型 | 投机执行中的权限 |
|
||||
|----------|:----------------:|
|
||||
| 只读工具(Read, Glob, Grep) | 允许 |
|
||||
| 写入工具(Edit, Write) | 仅在权限模式允许自动接受时 |
|
||||
| Bash 命令 | 必须通过只读验证 |
|
||||
| 未知工具 | 遇到即暂停(boundary) |
|
||||
|
||||
### 限制
|
||||
|
||||
- 最多 **20 轮**、**100 条消息**
|
||||
- 可以**流水线化**:当前投机完成后预生成下一步建议
|
||||
|
||||
### 用户反馈(内部可见)
|
||||
|
||||
```
|
||||
Speculated 5 tool uses — +12s saved (47s this session)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Undercover 隐身模式
|
||||
|
||||
**仅 Anthropic 员工**,自动激活条件:在公开/开源仓库工作。
|
||||
|
||||
### 激活后的行为
|
||||
|
||||
| 行为 | 说明 |
|
||||
|------|------|
|
||||
| 剥除归属 | 所有 `Co-Authored-By` 行被移除 |
|
||||
| 禁止提及内部代号 | Capybara、Tengu 等动物代号 |
|
||||
| 禁止提及版本号 | 未发布的模型版本 |
|
||||
| 禁止提及内部仓库 | Anthropic 内部仓库名 |
|
||||
| 禁止提及 Slack 频道 | 内部 Slack 频道名 |
|
||||
| 禁止提及 "Claude Code" | commit 消息必须看起来像人类写的 |
|
||||
|
||||
### 控制
|
||||
|
||||
- 自动检测:仓库 remote 不在内部白名单 → 自动开启
|
||||
- 强制开启:`CLAUDE_CODE_UNDERCOVER=1`
|
||||
- 无强制关闭选项
|
||||
- 首次激活有说明对话框
|
||||
|
||||
---
|
||||
|
||||
## 7. Dream Mode 记忆梦境整合
|
||||
|
||||
### 自动触发条件
|
||||
|
||||
同时满足:
|
||||
- 距上次整合 ≥ **24 小时**(`minHours`,可配置)
|
||||
- 且触及 ≥ **5 个会话**(`minSessions`,可配置)
|
||||
- 无其他进程正在整合(锁机制)
|
||||
|
||||
### 四阶段执行
|
||||
|
||||
```
|
||||
阶段 1 — 定向
|
||||
读取记忆目录和 MEMORY.md 索引
|
||||
|
||||
阶段 2 — 收集
|
||||
从每日日志和会话 transcript 中提取新信号
|
||||
|
||||
阶段 3 — 整合
|
||||
将新信息合并到已有主题文件
|
||||
转换相对日期为绝对日期
|
||||
删除被新事实矛盾的旧事实
|
||||
|
||||
阶段 4 — 修剪
|
||||
保持索引在 25KB 以内
|
||||
清理过时条目
|
||||
```
|
||||
|
||||
### 工具限制
|
||||
|
||||
Dream 运行期间,Bash 被限制为只读命令。
|
||||
|
||||
### 手动触发
|
||||
|
||||
`/dream` 技能在前台执行同样的整合流程(需 KAIROS 或 KAIROS_DREAM 开关)。
|
||||
|
||||
---
|
||||
|
||||
## 8. Voice Mode 语音输入
|
||||
|
||||
### 激活方式
|
||||
|
||||
**按住空格键说话**(push-to-talk),通过 `/voice` 命令开启。
|
||||
|
||||
### 技术栈
|
||||
|
||||
```
|
||||
原生音频捕获
|
||||
macOS → CoreAudio (audio-capture-napi / cpal)
|
||||
Linux → ALSA
|
||||
回退 → SoX rec / arecord
|
||||
|
||||
录音参数
|
||||
采样率: 16kHz
|
||||
声道: 单声道
|
||||
静音检测: 2.0秒,3% 阈值(SoX 回退路径)
|
||||
|
||||
STT 流式传输
|
||||
→ claude.ai voice_stream 端点
|
||||
→ 需要 Anthropic OAuth(API key/Bedrock/Vertex 不支持)
|
||||
```
|
||||
|
||||
### UI 元素
|
||||
|
||||
- 音频电平指示器
|
||||
- 语音状态显示
|
||||
- 语言选择器(`LanguagePicker.tsx`)
|
||||
- 自定义关键词词汇表(`voiceKeyterms.ts`)
|
||||
|
||||
### 控制
|
||||
|
||||
- GrowthBook 杀开关:`tengu_amber_quartz_disabled`
|
||||
- 默认 fail-open(新安装时启用)
|
||||
|
||||
---
|
||||
|
||||
## 9. Proactive 自主代理模式
|
||||
|
||||
### 核心工具:SleepTool
|
||||
|
||||
```typescript
|
||||
// 代理可以休眠指定时间后自主唤醒
|
||||
SleepTool.call({ duration: '5m' })
|
||||
// 5 分钟后自动恢复执行
|
||||
```
|
||||
|
||||
### 与 KAIROS 结合
|
||||
|
||||
```
|
||||
claude assistant
|
||||
↓
|
||||
[工作] → [SleepTool 5m] → [自动唤醒] → [继续工作] → [SleepTool 10m] → ...
|
||||
↑ |
|
||||
└──────────────────────────── 无限循环 ────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 压缩后的特殊行为
|
||||
|
||||
普通模式压缩后:提示用户是否有问题
|
||||
|
||||
自主模式压缩后:
|
||||
```
|
||||
你正在自主/主动模式中运行。这不是首次唤醒——你在压缩前已经在自主工作。
|
||||
继续你的工作循环:根据上面的摘要从离开的地方接续。不要问候用户或询问要做什么。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 伴侣精灵系统(Buddy)
|
||||
|
||||
`feature('BUDDY')` — 一个完整的收藏型宠物系统。
|
||||
|
||||
### 物种(18种)
|
||||
|
||||
duck、goose、blob、cat、dragon、octopus、owl、penguin、turtle、snail、ghost、axolotl、capybara、cactus、robot、rabbit、mushroom、chonk
|
||||
|
||||
### 外观组合
|
||||
|
||||
```
|
||||
18 种物种 × 6 种眼睛 × 8 种帽子 = 864 种外观组合
|
||||
× 5 种稀有度 = 4,320 种可能的精灵
|
||||
```
|
||||
|
||||
### 稀有度
|
||||
|
||||
| 等级 | 概率 | 显示 | 属性底值 |
|
||||
|------|:----:|------|:--------:|
|
||||
| Common | 60% | 1星 | 低 |
|
||||
| Uncommon | 25% | 2星 | 略高 |
|
||||
| Rare | 10% | 3星 | 中等 |
|
||||
| Epic | 4% | 4星 | 高 |
|
||||
| Legendary | 1% | 5星 | 最高 |
|
||||
|
||||
### 5种属性
|
||||
|
||||
- **DEBUGGING** — 调试力
|
||||
- **PATIENCE** — 耐心
|
||||
- **CHAOS** — 混沌
|
||||
- **WISDOM** — 智慧
|
||||
- **SNARK** — 吐槽力
|
||||
|
||||
每只精灵有一个巅峰属性和一个低谷属性。
|
||||
|
||||
### 确定性生成
|
||||
|
||||
```typescript
|
||||
// 种子 = hash(userId + 'friend-2026-401')
|
||||
// PRNG = Mulberry32
|
||||
// 无论何时重新生成,同一用户始终得到同一只精灵
|
||||
// 编辑配置文件无法伪造稀有度——bones 从 hash 重新计算
|
||||
```
|
||||
|
||||
### ASCII 动画
|
||||
|
||||
```
|
||||
每种物种 3 帧动画,5行×12字符
|
||||
500ms tick 的闲置动画
|
||||
包含眨眼帧和特殊效果(烟雾、天线发光、墨水泡泡等)
|
||||
```
|
||||
|
||||
### 互动
|
||||
|
||||
```
|
||||
/buddy pet → 触发 2.5 秒心形粒子特效(❤ 字符向上飘浮)
|
||||
模型可以让精灵"说话"(通过 speech bubble 系统)
|
||||
用户对精灵说话时,模型会自动退让
|
||||
```
|
||||
|
||||
### 反作弊
|
||||
|
||||
```
|
||||
物种名中某些与模型代号冲突的名称用 String.fromCharCode 十六进制编码
|
||||
配置文件编辑不影响生成结果(bones 从 hash 重算)
|
||||
```
|
||||
|
||||
### 启动引导
|
||||
|
||||
首次未孵化时显示彩虹色 `/buddy` 提示文本。
|
||||
|
||||
---
|
||||
|
||||
## 11. 多代理团队/Swarm 系统
|
||||
|
||||
### 激活方式
|
||||
|
||||
```bash
|
||||
# 外部用户
|
||||
claude --agent-teams
|
||||
# 或
|
||||
export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
|
||||
```
|
||||
|
||||
### 三种后端
|
||||
|
||||
| 后端 | 实现 | 特点 |
|
||||
|------|------|------|
|
||||
| **TmuxBackend** | 隔离 tmux socket `claude-swarm-<PID>` | 彩色边框,不影响用户的 tmux |
|
||||
| **ITermBackend** | iTerm2 的 `it2` CLI + Python API | 原生分屏 |
|
||||
| **InProcessBackend** | 进程内运行 | 无终端 UI |
|
||||
|
||||
自动检测选择最佳可用后端。
|
||||
|
||||
### Tmux 隔离
|
||||
|
||||
```typescript
|
||||
// Claude 创建自己的 tmux socket,防止命令影响用户会话
|
||||
const SWARM_SESSION_NAME = 'claude-swarm'
|
||||
const HIDDEN_SESSION_NAME = 'claude-hidden'
|
||||
// socket 名: claude-<PID>
|
||||
```
|
||||
|
||||
### Coordinator 模式
|
||||
|
||||
```bash
|
||||
export CLAUDE_CODE_COORDINATOR_MODE=1
|
||||
```
|
||||
|
||||
Claude 变为协调者,通过 `AgentTool`、`SendMessageTool`、`TaskStopTool` 编排 worker 代理。Worker 拥有独立工具访问权限。
|
||||
|
||||
### 团队工具
|
||||
|
||||
| 工具 | 功能 |
|
||||
|------|------|
|
||||
| `TeamCreateTool` | 创建代理团队 |
|
||||
| `TeamDeleteTool` | 删除代理团队 |
|
||||
| `SendMessageTool` | 代理间消息传递 |
|
||||
| `TaskStopTool` | 停止子任务 |
|
||||
| `TungstenTool`(内部) | tmux 会话管理 |
|
||||
|
||||
### 共享便签本
|
||||
|
||||
当 `tengu_scratch` 门控开启时,worker 获得共享 scratchpad 目录,跨 worker 知识交换绕过权限提示。
|
||||
|
||||
---
|
||||
|
||||
## 12. Anthropic 内部专用命令(20+个)
|
||||
|
||||
全部在外部构建中被替换为 `{ isEnabled: false, isHidden: true }` 存根。
|
||||
|
||||
### 调试和诊断
|
||||
|
||||
| 命令 | 用途 |
|
||||
|------|------|
|
||||
| `/bridge-kick` | 注入 bridge 故障(close/poll/register/heartbeat 等 10+ 子命令) |
|
||||
| `/mock-limits` | 模拟各种速率限制场景 |
|
||||
| `/reset-limits` | 重置速率限制状态 |
|
||||
| `/ctx-viz` | 上下文窗口可视化 |
|
||||
| `/debug-tool-call` | 工具调用调试 |
|
||||
| `/ant-trace` | Anthropic 内部追踪 |
|
||||
| `/perf-issue` | 性能问题报告 |
|
||||
| `/env` | 显示环境变量 |
|
||||
| `/stuck` | 诊断冻结/慢会话(扫描 CPU、进程状态、内存泄漏) |
|
||||
| `/force-snip` | 强制历史裁剪 |
|
||||
| `/break-cache` | 使 prompt cache 失效 |
|
||||
|
||||
### 工作流和自动化
|
||||
|
||||
| 命令 | 用途 |
|
||||
|------|------|
|
||||
| `/autofix-pr` | 自动修复 PR 问题 |
|
||||
| `/bughunter` | 远程审查的 bug 猎人模式 |
|
||||
| `/teleport` | 远程传送到其他环境 |
|
||||
| `/backfill-sessions` | 回填会话数据 |
|
||||
| `/agents-platform` | 代理平台管理 |
|
||||
| `/ultraplan` | 超级计划模式 |
|
||||
| `/share` | 分享对话 |
|
||||
|
||||
### 开发辅助
|
||||
|
||||
| 命令 | 用途 |
|
||||
|------|------|
|
||||
| `/lorem-ipsum` | 精确 token 计数的填充文本生成(用 1-token 词汇实现精确计数) |
|
||||
| `/oauth-refresh` | OAuth token 手动刷新 |
|
||||
| `/good-claude` | (已存根化) |
|
||||
| `/onboarding` | 引导流程 |
|
||||
| `/init-verifiers` | 初始化验证器 |
|
||||
|
||||
### 内部专用工具
|
||||
|
||||
| 工具 | 用途 |
|
||||
|------|------|
|
||||
| `ConfigTool` | 直接修改配置 |
|
||||
| `TungstenTool` | tmux 会话管理 |
|
||||
| `REPLTool` | 沙盒 REPL VM |
|
||||
| `SuggestBackgroundPRTool` | 建议后台 PR |
|
||||
| `CtxInspectTool` | 上下文检查 |
|
||||
| `OverflowTestTool` | 溢出测试 |
|
||||
| `SnipTool` | 历史裁剪 |
|
||||
| `MonitorTool` | 监控 |
|
||||
|
||||
### Bridge Kick 详细子命令
|
||||
|
||||
```
|
||||
/bridge-kick close <code> — 触发 WebSocket close
|
||||
/bridge-kick poll 404 [type] — 下次轮询 404
|
||||
/bridge-kick poll transient — 下次轮询 5xx
|
||||
/bridge-kick register fail [N] — 下 N 次注册失败
|
||||
/bridge-kick register fatal — 注册 403(终端失败)
|
||||
/bridge-kick reconnect-session fail — 重连失败
|
||||
/bridge-kick heartbeat <status> — 心跳致命错误
|
||||
/bridge-kick reconnect — 直接触发重连
|
||||
/bridge-kick status — 打印 bridge 状态
|
||||
```
|
||||
|
||||
支持**组合故障序列**,复现真实生产故障链。
|
||||
|
||||
---
|
||||
|
||||
## 13. 隐藏键盘快捷键
|
||||
|
||||
### 全局快捷键
|
||||
|
||||
| 快捷键 | 动作 |
|
||||
|--------|------|
|
||||
| `ctrl+t` | 切换 Todo 面板 |
|
||||
| `ctrl+o` | 切换 Transcript 查看器 |
|
||||
| `ctrl+r` | 历史反向搜索 |
|
||||
| `ctrl+l` | 重绘屏幕 |
|
||||
| `ctrl+b` | 后台运行当前任务 |
|
||||
| `shift+tab` | 循环切换权限模式 |
|
||||
| `meta+p` | 模型选择器 |
|
||||
| `meta+o` | Fast Mode 切换 |
|
||||
| `meta+t` | Thinking 模式切换 |
|
||||
|
||||
### Chord 快捷键(两步组合)
|
||||
|
||||
| 快捷键 | 动作 |
|
||||
|--------|------|
|
||||
| `ctrl+x ctrl+k` | 终止所有代理 |
|
||||
| `ctrl+x ctrl+e` 或 `ctrl+g` | 打开外部编辑器 |
|
||||
|
||||
### 编辑快捷键
|
||||
|
||||
| 快捷键 | 动作 |
|
||||
|--------|------|
|
||||
| `ctrl+_` / `ctrl+shift+-` | 撤销文本输入 |
|
||||
| `ctrl+s` | 暂存当前输入 |
|
||||
| `ctrl+v` / `alt+v`(Win) | 粘贴图片 |
|
||||
|
||||
### 特性门控快捷键
|
||||
|
||||
| 快捷键 | 动作 | 需要 |
|
||||
|--------|------|------|
|
||||
| `shift+up` | 消息动作选择器 | `MESSAGE_ACTIONS` |
|
||||
| `ctrl+shift+f` / `cmd+shift+f` | 全局文件搜索 | `QUICK_SEARCH` |
|
||||
| `ctrl+shift+p` / `cmd+shift+p` | 快速打开 | `QUICK_SEARCH` |
|
||||
| `meta+j` | 终端面板 | `TERMINAL_PANEL` |
|
||||
| `ctrl+shift+b` | Brief 模式切换 | `KAIROS` |
|
||||
| `ctrl+shift+o` | 队友预览切换 | 团队模式 |
|
||||
| `space`(按住) | Push-to-talk 语音 | `VOICE_MODE` |
|
||||
|
||||
### 滚动快捷键
|
||||
|
||||
| 快捷键 | 动作 |
|
||||
|--------|------|
|
||||
| `pageup` / `pagedown` | 翻页滚动 |
|
||||
| `wheelup` / `wheeldown` | 鼠标滚轮滚动 |
|
||||
| `ctrl+shift+c` / `cmd+c` | 复制选中内容(滚动模式中) |
|
||||
|
||||
### 保留快捷键(不可重绑定)
|
||||
|
||||
- `ctrl+c` — 中断
|
||||
- `ctrl+d` — 退出
|
||||
|
||||
---
|
||||
|
||||
## 14. 隐藏环境变量
|
||||
|
||||
### 核心配置
|
||||
|
||||
| 变量 | 效果 |
|
||||
|------|------|
|
||||
| `CLAUDE_CODE_SIMPLE=1` | 极简模式(3个工具) |
|
||||
| `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` | 禁用自动记忆提取 |
|
||||
| `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` | 禁用所有非必要网络流量 |
|
||||
| `CLAUDE_CODE_DISABLE_THINKING=1` | 禁用 thinking 模式 |
|
||||
| `CLAUDE_CODE_DISABLE_FAST_MODE=1` | 禁用 fast mode |
|
||||
| `CLAUDE_CODE_DISABLE_CLAUDE_MDS=1` | 禁用 CLAUDE.md 加载 |
|
||||
| `CLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECK=1` | 禁用命令注入检查 |
|
||||
| `CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1` | 禁用后台任务 |
|
||||
|
||||
### 性能调优
|
||||
|
||||
| 变量 | 效果 |
|
||||
|------|------|
|
||||
| `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY=N` | 最大并发工具数(默认10) |
|
||||
| `CLAUDE_CODE_AUTO_COMPACT_WINDOW=N` | 覆盖自动压缩窗口 |
|
||||
| `CLAUDE_CODE_MAX_OUTPUT_TOKENS=N` | 覆盖最大输出 token |
|
||||
| `CLAUDE_CODE_MAX_RETRIES=N` | 覆盖最大重试次数 |
|
||||
| `CLAUDE_CODE_BLOCKING_LIMIT_OVERRIDE=N` | 覆盖阻塞限制 |
|
||||
| `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80` | 在 80% 上下文时触发压缩 |
|
||||
|
||||
### API 控制
|
||||
|
||||
| 变量 | 效果 |
|
||||
|------|------|
|
||||
| `ANTHROPIC_MODEL=model-id` | 覆盖默认模型 |
|
||||
| `ANTHROPIC_SMALL_FAST_MODEL=model-id` | 覆盖后台辅助任务模型 |
|
||||
| `ANTHROPIC_BASE_URL=url` | 自定义 API 基础 URL |
|
||||
| `ANTHROPIC_CUSTOM_HEADERS='{"k":"v"}'` | 注入自定义 HTTP 头 |
|
||||
| `CLAUDE_CODE_EXTRA_BODY='{"k":"v"}'` | 注入额外 API 请求体 |
|
||||
| `CLAUDE_CODE_EXTRA_METADATA='{"k":"v"}'` | 注入额外元数据 |
|
||||
| `CLAUDE_CODE_USE_BEDROCK=1` | 使用 AWS Bedrock |
|
||||
| `CLAUDE_CODE_USE_VERTEX=1` | 使用 Google Vertex |
|
||||
| `CLAUDE_CODE_USE_FOUNDRY=1` | 使用 Azure Foundry |
|
||||
| `CLAUDE_CODE_UNATTENDED_RETRY=1` | 无人值守无限重试 |
|
||||
|
||||
### 调试
|
||||
|
||||
| 变量 | 效果 |
|
||||
|------|------|
|
||||
| `CLAUDE_CODE_DEBUG=1` | 启用调试日志 |
|
||||
| `CLAUDE_CODE_FRAME_TIMING_LOG=/path` | 记录帧渲染时间 |
|
||||
| `CLAUDE_CODE_BASH_SANDBOX_SHOW_INDICATOR=1` | 显示沙盒指示器 |
|
||||
| `CLAUDE_CODE_SYNTAX_HIGHLIGHT=1` | 启用语法高亮 |
|
||||
| `OTEL_LOG_TOOL_DETAILS=1` | 遥测中记录工具详情 |
|
||||
| `OTEL_LOG_USER_PROMPTS=1` | 遥测中记录用户提示词(默认 REDACTED) |
|
||||
| `DISABLE_COMPACT=1` | 完全禁用压缩 |
|
||||
| `DISABLE_AUTO_COMPACT=1` | 仅禁用自动压缩 |
|
||||
|
||||
### 代理团队
|
||||
|
||||
| 变量 | 效果 |
|
||||
|------|------|
|
||||
| `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` | 启用多代理团队 |
|
||||
| `CLAUDE_CODE_COORDINATOR_MODE=1` | 协调者模式 |
|
||||
| `CLAUDE_CODE_TEAMMATE_COMMAND=cmd` | 队友启动命令 |
|
||||
| `CLAUDE_CODE_AGENT_COLOR=color` | 代理颜色 |
|
||||
| `CLAUDE_CODE_PLAN_MODE_REQUIRED=1` | 强制 plan 模式 |
|
||||
|
||||
---
|
||||
|
||||
## 15. 其他彩蛋与冷知识
|
||||
|
||||
### 200+ 花式加载词
|
||||
|
||||
`spinnerVerbs.ts` 中的精选:
|
||||
|
||||
```
|
||||
Clauding, Boondoggling, Canoodling, Flibbertigibbeting,
|
||||
Hullaballooing, Moonwalking, Prestidigitating, Razzmatazzing,
|
||||
Shenaniganing, Tomfoolering, Whatchamacalliting, Beboppin'
|
||||
```
|
||||
|
||||
完成时的过去式:
|
||||
```
|
||||
Baked for 5s, Cogitated for 12s, Noodled for 8s
|
||||
```
|
||||
|
||||
### VCR 录制/回放模式
|
||||
|
||||
`FORCE_VCR=1`(内部):录制和回放 API 交互,用于测试。
|
||||
|
||||
### Lorem Ipsum 精确 token 生成
|
||||
|
||||
`/lorem-ipsum 50000`(内部):使用经过验证的 1-token 单词生成精确 token 数的填充文本。
|
||||
|
||||
### Fennec 代号
|
||||
|
||||
内部模型迁移中有 `migrateFennecToOpus.ts`:将 `fennec-latest` 映射到 `opus`,`fennec-fast-latest` 映射到 `opus[1m]` + fast mode。
|
||||
|
||||
### 消融基线模式
|
||||
|
||||
`CLAUDE_CODE_ABLATION_BASELINE`:降级功能用于 A/B 测试,验证各功能的实际贡献。
|
||||
|
||||
### 深度链接协议
|
||||
|
||||
`feature('LODESTONE')`:注册 `cc://` URL 协议处理器,其他应用可直接打开 Claude Code 会话。
|
||||
|
||||
### 物种名编码
|
||||
|
||||
```typescript
|
||||
// 伴侣精灵的某个物种名与内部模型代号冲突
|
||||
// 用 String.fromCharCode 十六进制编码避免 excluded-strings 检查
|
||||
```
|
||||
|
||||
### 权限模式循环
|
||||
|
||||
`shift+tab` 在以下模式间循环:
|
||||
```
|
||||
default → acceptEdits → plan → auto → default → ...
|
||||
```
|
||||
|
||||
### Anthropic API Key 自检回避
|
||||
|
||||
```typescript
|
||||
// 秘密扫描器中 Anthropic API key 前缀在运行时拼接
|
||||
// 避免匹配自身源码的 excluded-strings 检查
|
||||
const prefix = ['sk', 'ant', 'api'].join('-')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 总结:冰山模型
|
||||
|
||||
```
|
||||
╭───────────────╮
|
||||
公开版本 │ CLI + 43工具 │ ← 你看到的
|
||||
│ /命令 + UI │
|
||||
╰───────┬───────╯
|
||||
│
|
||||
╭───────────────┼───────────────╮
|
||||
编译时剥离 │ KAIROS守护进程 │ Computer Use │ ← 源码中存在
|
||||
│ Voice Mode │ Speculation │ 但外部构建被删除
|
||||
│ Dream Mode │ Undercover │
|
||||
│ Buddy Pet │ Swarm/Teams │
|
||||
│ Workflows │ BG Sessions │
|
||||
│ Deep Links │ Cron Triggers │
|
||||
╰───────────────┴───────────────╯
|
||||
│
|
||||
╭───────────────┼───────────────╮
|
||||
内部专用 │ 20+ 调试命令 │ bridge-kick │ ← 仅 Anthropic 员工
|
||||
│ mock-limits │ VCR 录放 │
|
||||
│ lorem-ipsum │ 消融基线 │
|
||||
│ stuck 诊断 │ ctx-viz │
|
||||
╰───────────────┴───────────────╯
|
||||
```
|
||||
|
||||
**Claude Code 不只是一个 CLI 工具——它的源码中隐藏着一个完整的 AI 助手操作系统的雏形。** 守护进程、语音输入、电脑控制、投机执行、梦境记忆整合、多代理协作、隐身模式——当前公开版本只暴露了冰山一角。
|
||||
|
||||
---
|
||||
|
||||
*来自:AI超元域 | B站频道:https://space.bilibili.com/3493277319825652*
|
||||
|
||||
*基于 Claude Code 源码逆向分析,2026-03-31*
|
||||
23
docs/cc_analysis/analysis_20260401/README.md
Normal file
23
docs/cc_analysis/analysis_20260401/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
### analysis\_20260401
|
||||
|
||||
|
||||
| Document | Content |
|
||||
| -------- | ------- |
|
||||
| [Claude Code 上下文管理算法学习笔记](https://github.com/chauncygu/collection-claude-code-source-code/blob/main/docs/cc_analysis/analysis_20260401/Claude_Code_Context_Management_Notes.md) | Step-by-step walkthrough of the context management algorithm: `autoCompact`, micro/reactive/trimmed compression strategies, and `toolResultStorage` |
|
||||
| [Claude Code 多 Agent 架构深度分析](claude-code-multi-agent-architecture.md) | Deep analysis of the multi-agent architecture across 37+ files: `src/utils/swarm/`, `AgentTool/`, `coordinator/` |
|
||||
| [Claude Code 值得借鉴的算法与设计模式](Claude_Code_Notable_Algorithms.md) | Notable algorithms and design patterns worth borrowing from the source (complements the context management notes) |
|
||||
| [Claude Code 自动回滚机制解析与版本切换指南](docs/cc_analysis/analysis_20260401/Claude-Code-Version-Rollback.md) | How the automatic rollback mechanism works and a practical version-switching guide |
|
||||
| [Claude Code 上下文压缩算法深度分析](Claude_Code上下文压缩算法深度分析.md) | Detailed reverse-engineering of the 11-file `src/services/compact/` compression pipeline |
|
||||
| [Claude Code 是否偷换模型?模型切换机制深度分析](docs/cc_analysis/analysis_20260401/Claude_Code模型切换机制深度分析.md) | Source-level analysis of model-selection logic: `model.ts`, `withRetry.ts`, and `claude.ts` |
|
||||
| [Claude Code Memory 记忆系统深度分析](Claude_Code记忆系统深度分析.md) | Full analysis of the 7-layer memory system: `memdir/`, `extractMemories/`, `SessionMemory/`, `teamMemorySync/` |
|
||||
| [Claude Code 隐藏高级功能全景图](Claude_Code隐藏高级功能全景图.md) | Map of 55+ feature flags, 20+ hidden commands, and several undisclosed subsystems |
|
||||
| [Claude Code 默认 Effort Level 设置笔记](Claude%20Code%20默认%20Effort%20Level%20设置笔记.md) | How to persist `/effort max` across sessions (default resets to `medium` on restart) |
|
||||
| [清除 Claude Code 追踪数据指南](清除Claude_Code追踪数据指南.md) | macOS guide for clearing telemetry and tracking data stored by Claude Code |
|
||||
| [Claude Code 深度分析报告 (PDF)](Claude_Code_深度分析报告.pdf) | Comprehensive analysis report in PDF format (Chinese) |
|
||||
| [Claude Code Deep Analysis Report (PDF)](Claude_Code_Deep_Analysis_Report.pdf) | Comprehensive analysis report in PDF format (English) |
|
||||
|
||||
---
|
||||
|
||||
Note, here, the original analysis material from the [link](https://github.com/win4r/cc-notebook/tree/main)
|
||||
|
||||
|
||||
@@ -0,0 +1,682 @@
|
||||
# Claude Code 多 Agent 架构深度分析
|
||||
|
||||
> 基于源码约 **13,700 行、37+ 文件**的深度探索,涵盖 `src/utils/swarm/`、`src/tools/AgentTool/`、`src/coordinator/` 等核心模块。
|
||||
|
||||
---
|
||||
|
||||
## 一、整体架构
|
||||
|
||||
系统采用 **Leader-Worker 模型**,核心有三种执行后端和两种编排模式:
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ 用户请求 (REPL/CLI) │
|
||||
└──────────┬──────────────────┘
|
||||
│
|
||||
┌──────────▼──────────────────┐
|
||||
│ Leader Agent (team-lead) │
|
||||
│ QueryEngine → query() │
|
||||
└──┬────────┬────────┬────────┘
|
||||
│ │ │
|
||||
┌────────────▼┐ ┌────▼─────┐ ┌▼────────────┐
|
||||
│ InProcess │ │ Tmux │ │ iTerm2 │
|
||||
│ (同进程) │ │ (分屏) │ │ (分屏) │
|
||||
└──────────────┘ └──────────┘ └─────────────┘
|
||||
│ │ │
|
||||
AsyncLocalStorage 独立进程 独立进程
|
||||
隔离上下文 文件邮箱通信 文件邮箱通信
|
||||
```
|
||||
|
||||
**两种编排模式:**
|
||||
|
||||
- **Team Mode** — 通过 `TeamCreate` 创建团队,手动管理 Worker
|
||||
- **Coordinator Mode** — 自动化编排,Coordinator 只能用 Agent/TaskStop/SendMessage 三个工具
|
||||
|
||||
---
|
||||
|
||||
## 二、Agent Tool — 统一入口
|
||||
|
||||
`src/tools/AgentTool/AgentTool.tsx` 是所有子 Agent 的统一入口。
|
||||
|
||||
### 2.1 输入参数
|
||||
|
||||
| 参数 | 类型 | 作用 |
|
||||
|------|------|------|
|
||||
| `prompt` | string | 任务描述 |
|
||||
| `subagent_type` | string | Agent 类型 (Explore, Plan, 自定义等) |
|
||||
| `model` | `'sonnet'\|'opus'\|'haiku'` | 模型覆盖 |
|
||||
| `run_in_background` | boolean | 后台异步执行 |
|
||||
| `name` | string | 命名,使其可通过 SendMessage 寻址 |
|
||||
| `team_name` | string | 团队名 |
|
||||
| `mode` | string | 权限模式 (plan, acceptEdits 等) |
|
||||
| `isolation` | `'worktree'` | Git worktree 隔离 |
|
||||
|
||||
### 2.2 路由决策树
|
||||
|
||||
```
|
||||
call() 入口 (AgentTool.tsx:284)
|
||||
├── team_name + name → spawnTeammate() → 生成持久化队友
|
||||
├── isolation === 'remote' → Cloud Code Runner
|
||||
├── run_in_background === true → runAsyncAgentLifecycle() (fire-and-forget)
|
||||
└── 默认 → runAgent() 同步执行,阻塞父 Agent
|
||||
```
|
||||
|
||||
### 2.3 关键常量
|
||||
|
||||
```typescript
|
||||
// src/tools/AgentTool/constants.ts
|
||||
AGENT_TOOL_NAME = 'Agent'
|
||||
LEGACY_AGENT_TOOL_NAME = 'Task' // 向后兼容
|
||||
ONE_SHOT_BUILTIN_AGENT_TYPES = {'Explore', 'Plan'}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、Agent 定义系统
|
||||
|
||||
`src/tools/AgentTool/loadAgentsDir.ts` (755行) 负责从多来源加载 Agent 定义。
|
||||
|
||||
### 3.1 AgentDefinition 类型
|
||||
|
||||
```typescript
|
||||
type AgentDefinition = {
|
||||
agentType: string // 唯一标识
|
||||
whenToUse: string // 何时使用的描述
|
||||
tools: string[] // 可用工具列表,['*'] 表示全部
|
||||
disallowedTools: string[] // 禁用工具
|
||||
model: string // 模型选择
|
||||
permissionMode: string // 权限模式
|
||||
maxTurns: number // 最大对话轮次
|
||||
background: boolean // 是否后台运行
|
||||
isolation: 'worktree' // 隔离方式
|
||||
getSystemPrompt() // 系统提示词生成函数
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 三种来源
|
||||
|
||||
- `BuiltInAgentDefinition` — 内置 Agent (source: 'built-in')
|
||||
- `CustomAgentDefinition` — 用户自定义 `.claude/agents/*.md` 文件
|
||||
- `PluginAgentDefinition` — 插件提供的 Agent
|
||||
|
||||
### 3.3 内置 Agent 类型
|
||||
|
||||
| Agent | 模型 | 工具 | 特点 |
|
||||
|-------|------|------|------|
|
||||
| `general-purpose` | 默认 | `['*']` | 全能通用 |
|
||||
| `Explore` | haiku | 只读工具 | 代码探索,禁止编辑/写入/嵌套 Agent |
|
||||
| `Plan` | inherit | 只读工具 | 架构规划,禁止编辑 |
|
||||
| `verification` | inherit | 只读 | 后台对抗性测试,红色标识 |
|
||||
| `statusline-setup` | sonnet | Read, Edit | 状态栏配置专用 |
|
||||
| `fork` (合成) | inherit | `['*']` | 继承父上下文,权限冒泡 |
|
||||
| `claude-code-guide` | — | 有限工具 | Claude Code 使用指南 |
|
||||
|
||||
### 3.4 加载优先级
|
||||
|
||||
```
|
||||
built-in < plugin < userSettings < projectSettings < flagSettings < policySettings
|
||||
```
|
||||
|
||||
后加载的同名 Agent 覆盖先加载的。
|
||||
|
||||
---
|
||||
|
||||
## 四、三大执行后端
|
||||
|
||||
### 4.1 InProcess 后端 (同进程)
|
||||
|
||||
**文件**: `src/utils/swarm/backends/InProcessBackend.ts` (339行)
|
||||
|
||||
最轻量的方式——所有 Worker 运行在**同一个 Node.js 进程**中:
|
||||
|
||||
```
|
||||
Leader 进程
|
||||
├── AsyncLocalStorage<TeammateContext> #1 → Worker A
|
||||
├── AsyncLocalStorage<TeammateContext> #2 → Worker B
|
||||
└── AsyncLocalStorage<TeammateContext> #3 → Worker C
|
||||
```
|
||||
|
||||
**核心流程:**
|
||||
|
||||
1. `spawn()` → `spawnInProcessTeammate()` 注册到 AppState
|
||||
2. `startInProcessTeammate()` fire-and-forget 启动 Agent 循环
|
||||
3. 通过 `runWithTeammateContext(context, fn)` 包裹执行,实现上下文隔离
|
||||
4. 权限请求直接使用 Leader 的 `ToolUseConfirm` 对话框(通过 `leaderPermissionBridge.ts`)
|
||||
|
||||
**上下文隔离** (`src/utils/teammateContext.ts`, 96行):
|
||||
|
||||
```typescript
|
||||
// AsyncLocalStorage 实现进程内隔离
|
||||
const teammateContextStorage = new AsyncLocalStorage<TeammateContext>()
|
||||
|
||||
function runWithTeammateContext(context: TeammateContext, fn: () => T): T {
|
||||
return teammateContextStorage.run(context, fn)
|
||||
}
|
||||
|
||||
function isInProcessTeammate(): boolean {
|
||||
return teammateContextStorage.getStore() !== undefined
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Tmux 后端 (终端分屏)
|
||||
|
||||
**文件**: `src/utils/swarm/backends/TmuxBackend.ts` (764行)
|
||||
|
||||
每个 Worker 是一个**独立的 Claude CLI 进程**,运行在 tmux 分屏中。
|
||||
|
||||
**两种模式:**
|
||||
|
||||
**Leader 在 tmux 内:**
|
||||
```
|
||||
┌─────────────────┬──────────────────┐
|
||||
│ │ Worker A │
|
||||
│ Leader ├──────────────────┤
|
||||
│ (30%) │ Worker B │
|
||||
│ ├──────────────────┤
|
||||
│ │ Worker C │
|
||||
└─────────────────┴──────────────────┘
|
||||
main-vertical 布局
|
||||
```
|
||||
|
||||
**Leader 在 tmux 外:** 创建 `claude-swarm-{pid}` 独立 session,tiled 布局。
|
||||
|
||||
**关键细节:**
|
||||
- `acquirePaneCreationLock()` 序列化并行 spawn,防止竞态
|
||||
- 200ms shell 初始化延迟等待 rc 文件加载
|
||||
- 通过 `tmux send-keys` 向 pane 发送命令
|
||||
- 支持 `hidePane()` (break-pane) / `showPane()` (join-pane)
|
||||
|
||||
### 4.3 iTerm2 后端
|
||||
|
||||
**文件**: `src/utils/swarm/backends/ITermBackend.ts` (370行)
|
||||
|
||||
通过 `it2` CLI (Python 自动化工具) 控制 iTerm2:
|
||||
|
||||
- 首个 Worker 垂直分割,后续水平分割
|
||||
- 死会话恢复:split 失败时验证 session list 并重试
|
||||
- `setPaneBorderColor`/`rebalancePanes` 为 no-op(避免频繁启动 Python 进程)
|
||||
- `supportsHideShow = false`(无等效的 tmux break-pane)
|
||||
|
||||
### 4.4 后端选择逻辑
|
||||
|
||||
`src/utils/swarm/backends/registry.ts` 的 `detectAndGetBackend()` (line 136):
|
||||
|
||||
```
|
||||
优先级瀑布:
|
||||
1. 在 tmux 内? → TmuxBackend (原生)
|
||||
2. 在 iTerm2 且有 it2 CLI? → ITermBackend
|
||||
3. 在 iTerm2 无 it2? → 回退 tmux,提示安装 it2
|
||||
4. 有 tmux? → TmuxBackend (外部 session)
|
||||
5. 非交互模式 (-p)? → InProcessBackend
|
||||
6. teammateMode 配置为 'in-process'? → InProcessBackend
|
||||
7. 都没有 → 报错并给出平台特定安装指引
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、核心通信机制 — 文件邮箱
|
||||
|
||||
### 5.1 邮箱结构
|
||||
|
||||
`src/utils/teammateMailbox.ts` (1,183行)
|
||||
|
||||
每个 Agent 拥有一个 JSON 文件邮箱:
|
||||
|
||||
```
|
||||
~/.claude/teams/{team_name}/inboxes/{agent_name}.json
|
||||
```
|
||||
|
||||
```typescript
|
||||
type TeammateMessage = {
|
||||
from: string // 发送者名称
|
||||
text: string // 消息内容
|
||||
timestamp: string // 时间戳
|
||||
read: boolean // 是否已读
|
||||
color?: string // 发送者 UI 颜色
|
||||
summary?: string // 5-10 字摘要
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 核心操作
|
||||
|
||||
| 函数 | 作用 |
|
||||
|------|------|
|
||||
| `writeToMailbox()` | 原子写入 + `proper-lockfile` 文件锁(10次重试,5-100ms 退避) |
|
||||
| `readMailbox()` | 读取所有消息 |
|
||||
| `readUnreadMessages()` | 过滤未读消息 |
|
||||
| `markMessagesAsRead()` | 标记已读 |
|
||||
|
||||
### 5.3 结构化消息类型
|
||||
|
||||
邮箱不仅传递文本,还定义了一套协议消息:
|
||||
|
||||
- `createShutdownRequestMessage` / `createShutdownApprovedMessage` — 关闭协议
|
||||
- `createPermissionRequestMessage` / `createPermissionResponseMessage` — 权限请求/响应
|
||||
- `createSandboxPermissionRequestMessage` / `createSandboxPermissionResponseMessage` — 沙箱网络权限
|
||||
- `createIdleNotification` — Worker 空闲通知
|
||||
|
||||
### 5.4 轮询机制
|
||||
|
||||
| Agent 类型 | 轮询方式 |
|
||||
|------------|----------|
|
||||
| Pane 类 Worker | `useInboxPoller` React hook 定期轮询 |
|
||||
| InProcess Worker | `waitForNextPromptOrShutdown()` 直接读邮箱 |
|
||||
| Leader | `useInboxPoller` 处理权限请求、空闲通知等 |
|
||||
|
||||
---
|
||||
|
||||
## 六、SendMessage Tool — Agent 间通信
|
||||
|
||||
`src/tools/SendMessageTool/SendMessageTool.ts` (917行)
|
||||
|
||||
### 6.1 输入参数
|
||||
|
||||
```typescript
|
||||
{
|
||||
to: string // 收件人名称、"*" 广播、"uds:<socket>"、"bridge:<session-id>"
|
||||
summary: string // 5-10 字摘要
|
||||
message: string | ShutdownRequest | ShutdownResponse | PlanApprovalResponse
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 路由逻辑
|
||||
|
||||
```
|
||||
SendMessage.call() (line 741)
|
||||
├── to: "bridge:<session-id>" → postInterClaudeMessage (跨机器 Remote Control)
|
||||
├── to: "uds:<socket>" → sendToUdsSocket (Unix Domain Socket 本地通信)
|
||||
├── to: "*" → 广播到所有团队成员邮箱
|
||||
├── to: "<name>" → 查 agentNameRegistry:
|
||||
│ ├── InProcess Agent running → queuePendingMessage (内存队列)
|
||||
│ ├── InProcess Agent stopped → resumeAgentBackground (自动唤醒!)
|
||||
│ └── Pane Agent → writeToMailbox (文件邮箱)
|
||||
└── 结构化消息 → 分发到对应处理器
|
||||
```
|
||||
|
||||
**关键设计:Agent 的纯文本输出对其他 Agent 不可见,必须通过 SendMessage 通信。**
|
||||
|
||||
---
|
||||
|
||||
## 七、权限委托系统
|
||||
|
||||
### 7.1 完整流程
|
||||
|
||||
`src/utils/swarm/permissionSync.ts` (928行)
|
||||
|
||||
```
|
||||
Worker 遇到需要权限的操作
|
||||
↓
|
||||
检查 bash classifier 能否自动批准 (swarmWorkerHandler.ts:52)
|
||||
↓ 不能
|
||||
创建 PermissionRequest 对象 (line 71)
|
||||
↓
|
||||
注册回调 BEFORE 发送请求 (避免竞态, line 79)
|
||||
↓
|
||||
发送 permission_request 到 Leader 邮箱 (line 123)
|
||||
↓
|
||||
显示 "waiting for leader" 状态 (line 126)
|
||||
↓
|
||||
Leader 轮询检测到请求
|
||||
↓
|
||||
在 Leader UI 展示权限对话框(带 worker badge)
|
||||
↓
|
||||
用户批准/拒绝
|
||||
↓
|
||||
Leader 发送 permission_response 到 Worker 邮箱
|
||||
↓
|
||||
Worker 轮询获取响应(每 500ms),继续执行
|
||||
```
|
||||
|
||||
### 7.2 InProcess 优化路径
|
||||
|
||||
通过 `leaderPermissionBridge.ts` (54行),InProcess Worker 直接使用 Leader 的 `ToolUseConfirm` 队列:
|
||||
|
||||
```typescript
|
||||
// REPL 注册权限 UI
|
||||
registerLeaderPermissionQueue(setToolUseConfirmQueue, setToolPermissionContext)
|
||||
|
||||
// Worker 推送权限请求到 Leader UI,带 worker badge
|
||||
pushToLeaderPermissionQueue(request, workerBadge)
|
||||
```
|
||||
|
||||
跳过文件邮箱的 I/O 开销,提供与 Leader 自身工具相同的 UI 体验。
|
||||
|
||||
### 7.3 SwarmPermissionRequest 结构
|
||||
|
||||
```typescript
|
||||
type SwarmPermissionRequest = {
|
||||
id: string
|
||||
workerId: string
|
||||
workerName: string
|
||||
toolName: string
|
||||
toolUseId: string
|
||||
description: string
|
||||
input: any
|
||||
permissionSuggestions: any
|
||||
status: 'pending' | 'approved' | 'rejected'
|
||||
resolvedBy?: string
|
||||
feedback?: string
|
||||
updatedInput?: any
|
||||
permissionUpdates?: any
|
||||
}
|
||||
```
|
||||
|
||||
### 7.4 权限模式继承
|
||||
|
||||
当 Leader 批准 Worker 的 plan 时:
|
||||
|
||||
```typescript
|
||||
const modeToInherit = leaderMode === 'plan' ? 'default' : leaderMode
|
||||
```
|
||||
|
||||
团队文件中每个成员有独立的 `mode` 字段,支持通过 `setMemberMode()` / `setMultipleMemberModes()` 动态调整。
|
||||
|
||||
---
|
||||
|
||||
## 八、Agent 执行引擎
|
||||
|
||||
### 8.1 runAgent() — 子 Agent 核心驱动
|
||||
|
||||
`src/tools/AgentTool/runAgent.ts` (973行)
|
||||
|
||||
`runAgent()` 是一个 `AsyncGenerator<Message, void>`:
|
||||
|
||||
```
|
||||
runAgent() (line 248)
|
||||
1. 解析模型 → getAgentModel()
|
||||
2. 创建隔离上下文 → createSubagentContext()
|
||||
- fork 父消息到独立上下文
|
||||
- 隔离的文件状态缓存
|
||||
3. 初始化 Agent 专属 MCP servers → initializeAgentMcpServers()
|
||||
4. 解析工具集 → resolveAgentTools()
|
||||
5. 构建系统提示词 (Agent 自身 + 环境信息)
|
||||
6. 注册 Perfetto 追踪, hooks
|
||||
7. 调用 query() — 与主 REPL 完全相同的 agentic 循环
|
||||
8. yield 每条消息回父 Agent
|
||||
9. 清理 MCP servers, shell tasks, agent tracking
|
||||
```
|
||||
|
||||
**核心设计:子 Agent 复用完全相同的 `query()` 循环**,递归地拥有完整的工具执行能力。
|
||||
|
||||
### 8.2 异步 Agent 生命周期
|
||||
|
||||
`agentToolUtils.ts` 的 `runAsyncAgentLifecycle()` (line 508):
|
||||
|
||||
```
|
||||
registerAsyncAgent() → 创建 task entry
|
||||
↓
|
||||
注册 name 到 agentNameRegistry (用于 SendMessage 路由)
|
||||
↓
|
||||
void runWithAgentContext(...) → fire-and-forget
|
||||
↓
|
||||
迭代 runAgent() 的消息流
|
||||
↓
|
||||
ProgressTracker 追踪:
|
||||
- tool use 次数
|
||||
- token 消耗
|
||||
- 最近活动
|
||||
↓
|
||||
完成时 finalizeAgentTool():
|
||||
- 提取最终文本内容
|
||||
- 计算 totalDurationMs, totalTokens, totalToolUseCount
|
||||
↓
|
||||
completeAsyncAgent() → 标记 task 完成
|
||||
↓
|
||||
发送 <task-notification> XML 通知父 Agent
|
||||
```
|
||||
|
||||
**多个异步 Agent 是真正并行的**——每个都是独立的 async 操作。
|
||||
|
||||
### 8.3 工具过滤
|
||||
|
||||
`agentToolUtils.ts` 的 `filterToolsForAgent()` (line 70) 使用多层禁用列表:
|
||||
|
||||
| 禁用列表 | 适用范围 | 禁用的工具 |
|
||||
|----------|----------|-----------|
|
||||
| `ALL_AGENT_DISALLOWED_TOOLS` | 所有 Agent | TaskOutput, ExitPlanMode, EnterPlanMode, AskUserQuestion, TaskStop |
|
||||
| `CUSTOM_AGENT_DISALLOWED_TOOLS` | 非内置 Agent | 同上 + AgentTool |
|
||||
| `ASYNC_AGENT_ALLOWED_TOOLS` | 后台 Agent | 白名单制:Read, Grep, Glob, Edit, Write, WebSearch 等 |
|
||||
| `COORDINATOR_MODE_ALLOWED_TOOLS` | Coordinator | 仅 Agent, TaskStop, SendMessage, SyntheticOutput |
|
||||
|
||||
---
|
||||
|
||||
## 九、Coordinator Mode — 自动化编排
|
||||
|
||||
`src/coordinator/coordinatorMode.ts` (369行)
|
||||
|
||||
### 9.1 激活条件
|
||||
|
||||
```typescript
|
||||
function isCoordinatorMode(): boolean {
|
||||
return feature('COORDINATOR_MODE') && process.env.CLAUDE_CODE_COORDINATOR_MODE === '1'
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 工作流程
|
||||
|
||||
```
|
||||
Coordinator (只能用 Agent + TaskStop + SendMessage)
|
||||
│
|
||||
├── Research Phase → 并行派出多个 Worker 调研
|
||||
│ ├── Worker A: 搜索代码
|
||||
│ ├── Worker B: 读取文档
|
||||
│ └── Worker C: 分析依赖
|
||||
│
|
||||
├── Synthesis Phase → Coordinator 综合分析研究结果
|
||||
│
|
||||
├── Implementation Phase → Worker 执行代码实现
|
||||
│
|
||||
└── Verification Phase → Worker 验证实现结果
|
||||
```
|
||||
|
||||
### 9.3 Coordinator 系统提示词要点
|
||||
|
||||
`getCoordinatorSystemPrompt()` (line 111) 的 369 行提示词规定:
|
||||
|
||||
- Coordinator 通过 `Agent` 工具派出 Worker,通过 `SendMessage` 继续对话,通过 `TaskStop` 终止
|
||||
- Worker 完成时发送 `<task-notification>` XML
|
||||
- 明确的 spawn vs continue 决策指导
|
||||
- 并发管理策略
|
||||
|
||||
---
|
||||
|
||||
## 十、Team Mode — 持久化协作
|
||||
|
||||
### 10.1 团队文件结构
|
||||
|
||||
`~/.claude/teams/{team-name}/config.json`:
|
||||
|
||||
```typescript
|
||||
type TeamFile = {
|
||||
name: string
|
||||
description: string
|
||||
createdAt: string
|
||||
leadAgentId: string
|
||||
leadSessionId: string
|
||||
hiddenPaneIds: string[]
|
||||
teamAllowedPaths: string[]
|
||||
members: [{
|
||||
agentId: string // 格式: name@teamName
|
||||
name: string
|
||||
agentType: string
|
||||
model: string
|
||||
color: string
|
||||
planModeRequired: boolean
|
||||
joinedAt: string
|
||||
tmuxPaneId?: string
|
||||
cwd: string
|
||||
worktreePath?: string
|
||||
sessionId: string
|
||||
subscriptions: string[]
|
||||
backendType: 'tmux' | 'iterm2' | 'in-process'
|
||||
isActive: boolean
|
||||
mode: string
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 团队工作流
|
||||
|
||||
```
|
||||
1. TeamCreate → 创建 config.json + tasks 目录
|
||||
2. TaskCreate → 在 ~/.claude/tasks/{team-name}/ 创建任务
|
||||
3. Agent tool (team_name + name) → 派出 teammate
|
||||
4. TaskUpdate → 分配任务 owner
|
||||
5. Teammate 工作 → 完成后自动发送 idle notification
|
||||
6. SendMessage(shutdown_request) → 优雅关闭 teammate
|
||||
```
|
||||
|
||||
### 10.3 Teammate 系统提示词附加
|
||||
|
||||
`src/utils/swarm/teammatePromptAddendum.ts`:
|
||||
|
||||
> "You are running as an agent in a team. To communicate with anyone on your team, use the SendMessage tool. Just writing a response in text is not visible to others."
|
||||
|
||||
---
|
||||
|
||||
## 十一、Worktree 隔离
|
||||
|
||||
`src/utils/worktree.ts` 的 `createAgentWorktree()` (line 902)
|
||||
|
||||
### 11.1 创建流程
|
||||
|
||||
```
|
||||
Agent spawn 时 isolation='worktree'
|
||||
→ 生成 slug: agent-{agentId前8字符}
|
||||
→ validateWorktreeSlug() — 拒绝路径穿越,限制64字符
|
||||
→ 路径: .claude/worktrees/<slug>
|
||||
→ 分支: worktree-<slug>
|
||||
→ git worktree add -B worktree-<slug>
|
||||
→ performPostCreationSetup():
|
||||
- 复制 settings.local.json
|
||||
- 配置 git hooks
|
||||
- 符号链接目录
|
||||
- 复制 .worktreeinclude 文件
|
||||
```
|
||||
|
||||
### 11.2 清理流程
|
||||
|
||||
```
|
||||
Agent 完成时:
|
||||
→ hasWorktreeChanges()?
|
||||
├── 有改动 → 保留 worktree,在 <task-notification> 中报告路径和分支
|
||||
└── 无改动 → removeAgentWorktree() 自动清理
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、Worker 完整生命周期
|
||||
|
||||
### 12.1 诞生
|
||||
|
||||
```
|
||||
Leader 调用 Agent tool
|
||||
├── InProcess: spawnInProcessTeammate()
|
||||
│ 1. 生成 agentId = name@teamName
|
||||
│ 2. 创建独立 AbortController(不链接到 Leader)
|
||||
│ 3. 创建 TeammateContext for AsyncLocalStorage
|
||||
│ 4. 注册 InProcessTeammateTaskState 到 AppState
|
||||
│ 5. startInProcessTeammate() → runWithTeammateContext() → runAgent()
|
||||
│
|
||||
└── Pane: PaneBackendExecutor.spawn()
|
||||
1. assignTeammateColor() 分配颜色
|
||||
2. createTeammatePaneInSwarmView() 创建分屏
|
||||
3. 构建 CLI 命令:
|
||||
claude --agent-id X --agent-name Y --team-name Z
|
||||
--agent-color C --parent-session-id P
|
||||
4. sendCommandToPane() 发送命令
|
||||
5. writeToMailbox() 写入初始 prompt
|
||||
```
|
||||
|
||||
### 12.2 执行
|
||||
|
||||
```
|
||||
InProcess Runner (inProcessRunner.ts, 1552行):
|
||||
runWithTeammateContext() 包裹:
|
||||
→ runAgent() → query() 循环
|
||||
→ 轮询邮箱获取新消息(注入为 user-turn messages)
|
||||
→ 权限请求转发到 Leader UI
|
||||
→ ProgressTracker 追踪工具使用和 token
|
||||
→ 支持 auto-compact(上下文过大时自动压缩)
|
||||
```
|
||||
|
||||
### 12.3 通信
|
||||
|
||||
```
|
||||
Worker → Leader: writeToMailbox() 或 queuePendingMessage (InProcess)
|
||||
Leader → Worker: writeToMailbox() 或 SendMessage
|
||||
Worker → Worker: SendMessage tool → writeToMailbox()
|
||||
广播: SendMessage(to: "*") → 写入所有成员邮箱
|
||||
```
|
||||
|
||||
### 12.4 终止
|
||||
|
||||
三条终止路径:
|
||||
|
||||
| 方式 | 触发 | 流程 |
|
||||
|------|------|------|
|
||||
| 优雅关闭 | `shutdown_request` via mailbox | Worker 处理请求 → 退出 → idle notification |
|
||||
| 强制终止 (InProcess) | `killInProcessTeammate()` | abort AbortController → 更新 task 状态为 'killed' → 移出团队文件 |
|
||||
| 强制终止 (Pane) | `backend.killPane(paneId)` | 杀死 tmux/iTerm2 pane |
|
||||
|
||||
### 12.5 会话清理
|
||||
|
||||
`cleanupSessionTeams()` 在 Leader 退出时运行:
|
||||
- 杀死所有孤立 pane
|
||||
- 移除团队和任务目录
|
||||
- 销毁 git worktree
|
||||
|
||||
---
|
||||
|
||||
## 十三、Feature Gates 汇总
|
||||
|
||||
| Feature Flag | 控制内容 | 激活方式 |
|
||||
|-------------|---------|---------|
|
||||
| `COORDINATOR_MODE` | Coordinator 自动编排 | 编译时 + `CLAUDE_CODE_COORDINATOR_MODE=1` |
|
||||
| `FORK_SUBAGENT` | Fork 模式子 Agent | 编译时 feature gate |
|
||||
| `BUILTIN_EXPLORE_PLAN_AGENTS` | Explore/Plan 内置 Agent | 编译时 + A/B test `tengu_amber_stoat` |
|
||||
| `VERIFICATION_AGENT` | 验证 Agent | 编译时 + gate `tengu_hive_evidence` |
|
||||
| Agent Teams (Swarm) | 团队协作模式 | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` + GrowthBook gate |
|
||||
|
||||
---
|
||||
|
||||
## 十四、通信协议总览
|
||||
|
||||
| 通道 | 机制 | 方向 | 用途 |
|
||||
|------|------|------|------|
|
||||
| 文件邮箱 `inboxes/{name}.json` | JSON + 文件锁 | 任意 Agent → 任意 Agent | 所有 teammate 消息、权限、关闭协议 |
|
||||
| 内存队列 `pendingUserMessages` | AppState | 父 → InProcess 子 | 运行中 Agent 的即时消息 |
|
||||
| Leader Permission Bridge | 模块级函数注册 | InProcess Worker → Leader UI | 权限弹窗 |
|
||||
| UDS Socket | Unix Domain Socket | Session → Session (本地) | 跨 session 消息 |
|
||||
| Bridge (Remote Control) | HTTP via Anthropic | Session → Session (跨机器) | 远程控制消息 |
|
||||
| Task 系统 | 文件 `~/.claude/tasks/` | 所有团队成员 | 工作项追踪、状态更新 |
|
||||
| `<task-notification>` XML | 注入对话 | 后台 Agent → 父 Agent | 完成/失败通知 |
|
||||
|
||||
---
|
||||
|
||||
## 十五、架构规模统计
|
||||
|
||||
| 层次 | 核心组件 | 代码规模 |
|
||||
|------|---------|---------|
|
||||
| 入口 | AgentTool | ~800行 |
|
||||
| 执行引擎 | runAgent + query() 循环 | ~2,700行 |
|
||||
| Agent 定义 | loadAgentsDir + builtInAgents | ~850行 |
|
||||
| 后端管理 | registry + 3个后端实现 | ~1,800行 |
|
||||
| 通信 | teammateMailbox + SendMessageTool | ~2,100行 |
|
||||
| 权限委托 | permissionSync + leaderPermissionBridge | ~1,000行 |
|
||||
| 团队管理 | teamHelpers + spawnMultiAgent | ~1,800行 |
|
||||
| 上下文隔离 | agentContext + teammateContext | ~300行 |
|
||||
| Coordinator | coordinatorMode + workerAgent | ~400行 |
|
||||
| InProcess Runner | inProcessRunner | ~1,550行 |
|
||||
| **总计** | **37+ 文件** | **~13,700行** |
|
||||
|
||||
---
|
||||
|
||||
## 十六、核心设计理念
|
||||
|
||||
1. **query() 循环复用** — 子 Agent 使用与主 REPL 完全相同的 agentic 循环,天然具备完整工具能力
|
||||
2. **AsyncLocalStorage 隔离** — InProcess 模式下零 IPC 开销,通过 Node.js 原生机制隔离上下文
|
||||
3. **文件邮箱统一通信** — 跨进程、跨后端的统一消息协议,用文件锁保证并发安全
|
||||
4. **权限始终由人类把控** — 无论多少层 Agent 嵌套,危险操作最终都路由到 Leader 的 UI 由用户决定
|
||||
5. **优雅降级** — 从 iTerm2 → tmux → InProcess,自动选择最佳可用后端
|
||||
6. **Fire-and-forget 异步** — 后台 Agent 通过 `<task-notification>` XML 非侵入式通知父 Agent
|
||||
274
docs/cc_analysis/analysis_20260401/清除Claude_Code追踪数据指南.md
Normal file
274
docs/cc_analysis/analysis_20260401/清除Claude_Code追踪数据指南.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# macOS 上清除 Claude Code 追踪数据指南
|
||||
|
||||
> 基于 Claude Code 源码(2026-03-31 泄露快照,512K 行 TypeScript)的逆向分析。
|
||||
> 所有文件路径和字段名均从源码中确认。
|
||||
|
||||
---
|
||||
|
||||
## 背景:Claude Code 追踪了什么?
|
||||
|
||||
Claude Code **不收集硬件指纹**(无 MAC 地址、CPU 型号、内存大小、GPU 信息),但通过以下机制实现用户追踪:
|
||||
|
||||
| 追踪标识 | 持久性 | 存储位置 | 说明 |
|
||||
|----------|--------|----------|------|
|
||||
| `userID` | 永久(直到手动删除) | `~/.claude.json` | 随机生成的 64 位十六进制字符串,跨会话追踪主键 |
|
||||
| `anonymousId` | 永久 | `~/.claude.json` | 格式 `claudecode.v1.<uuid>`,备用追踪 ID |
|
||||
| `accountUuid` | 永久(绑定账号) | `~/.claude.json` → `oauthAccount` | OAuth 登录后直接关联身份 |
|
||||
| `emailAddress` | 永久 | `~/.claude.json` → `oauthAccount` | 登录邮箱 |
|
||||
| `rh` (仓库哈希) | 按仓库 | 每次 API 请求 Header | git remote URL 的 SHA256 前 16 位 |
|
||||
| Statsig Stable ID | 永久 | `~/.claude/statsig/` | 特性开关系统的设备标识 |
|
||||
|
||||
**数据流向:**
|
||||
- **Anthropic 1P** → `/api/event_logging/batch`(完整环境数据 + Auth)
|
||||
- **Datadog** → `https://http-intake.logs.us5.datadoghq.com`(白名单事件,已脱敏)
|
||||
- **OTLP**(可选)→ 用户自配的端点(默认关闭)
|
||||
|
||||
---
|
||||
|
||||
## 第一级:重置设备标识(最重要)
|
||||
|
||||
这是跨会话追踪的主键。清除后你对 Anthropic 来说就是一台"全新设备"。
|
||||
|
||||
```bash
|
||||
# 查看当前的追踪 ID
|
||||
grep -E '"userID"|"anonymousId"|"firstStartTime"|"claudeCodeFirstTokenDate"' ~/.claude.json
|
||||
```
|
||||
|
||||
```bash
|
||||
# 删除追踪标识(保留其他配置不变)
|
||||
python3 -c "
|
||||
import json, os
|
||||
p = os.path.expanduser('~/.claude.json')
|
||||
with open(p, 'r') as f: d = json.load(f)
|
||||
removed = []
|
||||
for k in ['userID', 'anonymousId', 'firstStartTime', 'claudeCodeFirstTokenDate']:
|
||||
if k in d:
|
||||
removed.append(k)
|
||||
del d[k]
|
||||
with open(p, 'w') as f: json.dump(d, f, indent=2)
|
||||
print(f'已删除: {removed}')
|
||||
print('下次启动 Claude Code 会自动生成新的 userID')
|
||||
"
|
||||
```
|
||||
|
||||
**效果:** 下次启动时会生成全新的 `userID`,之前的使用记录无法与你关联。
|
||||
|
||||
---
|
||||
|
||||
## 第二级:清除遥测和分析数据
|
||||
|
||||
```bash
|
||||
# 未成功上报的分析事件(包含完整的环境信息、会话数据)
|
||||
rm -rf ~/.claude/telemetry/
|
||||
|
||||
# Statsig/GrowthBook 特性开关缓存(包含 stable_id 设备标识)
|
||||
rm -rf ~/.claude/statsig/
|
||||
|
||||
# 统计缓存
|
||||
rm -f ~/.claude/stats-cache.json
|
||||
```
|
||||
|
||||
**效果:** 清除本地缓存的遥测数据和特性开关系统的设备标识。
|
||||
|
||||
---
|
||||
|
||||
## 第三级:清除会话和历史记录
|
||||
|
||||
```bash
|
||||
# 完整命令历史(你输入过的所有提示词)
|
||||
rm -f ~/.claude/history.jsonl
|
||||
|
||||
# 会话快照
|
||||
rm -rf ~/.claude/sessions/
|
||||
|
||||
# 大段粘贴内容的哈希缓存
|
||||
rm -rf ~/.claude/paste-cache/
|
||||
|
||||
# Shell 环境快照
|
||||
rm -rf ~/.claude/shell-snapshots/
|
||||
|
||||
# 会话环境变量
|
||||
rm -rf ~/.claude/session-env/
|
||||
|
||||
# 文件编辑历史(Claude 做过的每次文件修改)
|
||||
rm -rf ~/.claude/file-history/
|
||||
|
||||
# 调试日志
|
||||
rm -rf ~/.claude/debug/
|
||||
```
|
||||
|
||||
**效果:** 清除所有本地会话痕迹。不影响 Claude Code 正常使用。
|
||||
|
||||
---
|
||||
|
||||
## 第四级:清除 OAuth 账号关联
|
||||
|
||||
```bash
|
||||
# 查看当前关联的账号信息
|
||||
python3 -c "
|
||||
import json, os
|
||||
with open(os.path.expanduser('~/.claude.json')) as f: d = json.load(f)
|
||||
oa = d.get('oauthAccount', {})
|
||||
print(f\"账号 UUID: {oa.get('accountUuid', '无')}\")
|
||||
print(f\"邮箱: {oa.get('emailAddress', '无')}\")
|
||||
"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 从 macOS Keychain 删除 OAuth Token
|
||||
security delete-generic-password -s "claude-code" 2>/dev/null
|
||||
security delete-generic-password -s "claude-code-credentials" 2>/dev/null
|
||||
|
||||
# 清除配置文件中的账号缓存
|
||||
python3 -c "
|
||||
import json, os
|
||||
p = os.path.expanduser('~/.claude.json')
|
||||
with open(p, 'r') as f: d = json.load(f)
|
||||
removed = []
|
||||
for k in ['oauthAccount', 's1mAccessCache', 'groveConfigCache',
|
||||
'passesEligibilityCache', 'clientDataCache',
|
||||
'cachedExtraUsageDisabledReason', 'githubRepoPaths']:
|
||||
if k in d:
|
||||
removed.append(k)
|
||||
del d[k]
|
||||
with open(p, 'w') as f: json.dump(d, f, indent=2)
|
||||
print(f'已删除: {removed}')
|
||||
"
|
||||
```
|
||||
|
||||
**效果:** 断开与 Claude.ai 账号的本地关联。下次使用需要重新登录。
|
||||
|
||||
---
|
||||
|
||||
## 第五级:完全重置(核弹选项)
|
||||
|
||||
```bash
|
||||
# 1. 备份你的自定义配置
|
||||
mkdir -p ~/Desktop/claude-backup
|
||||
cp ~/.claude/CLAUDE.md ~/Desktop/claude-backup/ 2>/dev/null
|
||||
cp ~/.claude/settings.json ~/Desktop/claude-backup/ 2>/dev/null
|
||||
cp -r ~/.claude/skills ~/Desktop/claude-backup/ 2>/dev/null
|
||||
cp -r ~/.claude/hooks ~/Desktop/claude-backup/ 2>/dev/null
|
||||
echo "已备份到 ~/Desktop/claude-backup/"
|
||||
|
||||
# 2. 删除所有 Claude Code 数据
|
||||
rm -rf ~/.claude/
|
||||
rm -f ~/.claude.json
|
||||
|
||||
# 3. 清除 Keychain 中的 Token
|
||||
security delete-generic-password -s "claude-code" 2>/dev/null
|
||||
security delete-generic-password -s "claude-code-credentials" 2>/dev/null
|
||||
|
||||
echo "已完全重置。下次启动 Claude Code 会重新初始化。"
|
||||
```
|
||||
|
||||
**效果:** 等同于全新安装。所有配置、历史、记忆、技能、插件设置全部清除。
|
||||
|
||||
---
|
||||
|
||||
## 防止未来追踪
|
||||
|
||||
### 方法 1:禁用非必要网络流量
|
||||
|
||||
在 `~/.claude/settings.json` 中添加:
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**效果:** 禁用分析上报、GrowthBook 特性开关拉取、配额预检等非必要请求。
|
||||
|
||||
### 方法 2:使用第三方云后端
|
||||
|
||||
源码确认:使用 Bedrock 或 Vertex 时,`isAnalyticsDisabled()` 返回 `true`,完全跳过所有分析代码。
|
||||
|
||||
```bash
|
||||
# 使用 AWS Bedrock(需要 AWS 凭证)
|
||||
export CLAUDE_CODE_USE_BEDROCK=1
|
||||
|
||||
# 或使用 Google Vertex AI(需要 GCP 凭证)
|
||||
export CLAUDE_CODE_USE_VERTEX=1
|
||||
```
|
||||
|
||||
### 方法 3:定期自动清理
|
||||
|
||||
创建一个定时清理脚本 `~/claude-privacy-clean.sh`:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 清除 Claude Code 追踪数据(保留配置)
|
||||
|
||||
rm -rf ~/.claude/telemetry/
|
||||
rm -rf ~/.claude/statsig/
|
||||
rm -f ~/.claude/stats-cache.json
|
||||
rm -f ~/.claude/history.jsonl
|
||||
rm -rf ~/.claude/sessions/
|
||||
rm -rf ~/.claude/paste-cache/
|
||||
rm -rf ~/.claude/shell-snapshots/
|
||||
rm -rf ~/.claude/session-env/
|
||||
rm -rf ~/.claude/debug/
|
||||
|
||||
# 重置 device ID
|
||||
python3 -c "
|
||||
import json, os
|
||||
p = os.path.expanduser('~/.claude.json')
|
||||
if os.path.exists(p):
|
||||
with open(p,'r') as f: d = json.load(f)
|
||||
for k in ['userID','anonymousId','firstStartTime','claudeCodeFirstTokenDate']:
|
||||
d.pop(k, None)
|
||||
with open(p,'w') as f: json.dump(d,f,indent=2)
|
||||
"
|
||||
|
||||
echo "[$(date)] Claude Code 追踪数据已清除"
|
||||
```
|
||||
|
||||
```bash
|
||||
# 添加执行权限
|
||||
chmod +x ~/claude-privacy-clean.sh
|
||||
|
||||
# 可选:添加到 crontab 每天自动执行
|
||||
# crontab -e
|
||||
# 0 3 * * * ~/claude-privacy-clean.sh >> ~/claude-clean.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 各级清理的影响对比
|
||||
|
||||
| 操作 | 对 Anthropic 的效果 | 对你的影响 |
|
||||
|------|---------------------|------------|
|
||||
| **重置 Device ID** | 无法关联历史使用数据 | 无感知,自动生成新 ID |
|
||||
| **清除遥测** | 本地缓存的分析事件不会补发 | 无感知 |
|
||||
| **清除历史** | — | 丢失命令历史和 ctrl+r 搜索 |
|
||||
| **清除 OAuth** | 断开账号关联 | 需要重新登录 |
|
||||
| **完全重置** | 等同全新用户 | 丢失所有自定义配置 |
|
||||
| **禁用非必要流量** | 不再接收分析数据 | 特性开关可能不更新 |
|
||||
| **使用 Bedrock/Vertex** | 分析代码完全不执行 | 需要云厂商凭证 |
|
||||
|
||||
---
|
||||
|
||||
## 附:数据文件速查表
|
||||
|
||||
| 文件/目录 | 包含的追踪数据 |
|
||||
|-----------|----------------|
|
||||
| `~/.claude.json` | userID, anonymousId, oauthAccount, 首次使用时间, GitHub 仓库映射 |
|
||||
| `~/.claude/telemetry/` | 未上报的 1P 分析事件(JSON,含完整 EnvContext) |
|
||||
| `~/.claude/statsig/` | Statsig stable_id, 特性开关缓存 |
|
||||
| `~/.claude/stats-cache.json` | 统计数据缓存 |
|
||||
| `~/.claude/history.jsonl` | 完整命令历史(你输入的每一条提示词) |
|
||||
| `~/.claude/sessions/` | 会话元数据 |
|
||||
| `~/.claude/paste-cache/` | 粘贴内容的哈希地址缓存 |
|
||||
| `~/.claude/file-history/` | Claude 做过的文件修改记录 |
|
||||
| `~/.claude/debug/` | 调试日志 |
|
||||
| `~/.claude/shell-snapshots/` | Shell 环境快照 |
|
||||
| macOS Keychain → `claude-code` | OAuth access/refresh token |
|
||||
|
||||
---
|
||||
|
||||
*来自:AI超元域 | B站频道:https://space.bilibili.com/3493277319825652*
|
||||
|
||||
*基于 Claude Code 源码逆向分析,2026-03-31*
|
||||
Reference in New Issue
Block a user