Files
aiagent/clode/dataflow.md
renjianbo beff3fac8d fix: delete agent 500 error + dynamic personality + deployment guide
- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions,
  schedules, executions, team_members) and unbind goals/tasks before delete
- Remove hardcoded personality templates in Android, replace with dynamic
  system prompt generation from name + description
- Set promptSectionsEnabled=false to bypass PromptComposer for personality
- Add Tencent Cloud Linux deployment guide (Docker Compose)
- Accumulated backend service updates, frontend UI fixes, Android app changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-29 01:17:21 +08:00

527 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Claude Code 数据流与生命周期
## 1. 启动流程
### 1.1 完整启动序列
```
终端执行: bun run dev (→ bun run src/entrypoints/cli.tsx)
├── Phase 0: 预加载
│ ├── globalThis.MACRO 注入 (版本号、构建信息)
│ ├── process.env 初始化 (COREPACK_ENABLE_AUTO_PIN, NODE_OPTIONS)
│ └── Ablation baseline 环境变量设置
├── Phase 1: 快速路径路由
│ ├── --version → console.log(MACRO.VERSION) → 退出
│ ├── --dump-system-prompt → 渲染系统提示词 → 退出
│ ├── --claude-in-chrome-mcp → 启动 Chrome MCP Server
│ ├── --chrome-native-host → 启动 Chrome Native Host
│ └── --computer-use-mcp → 启动 Computer Use MCP
├── Phase 2: CLI 初始化 (cli.tsx main())
│ ├── import startupProfiler → profileCheckpoint('cli_entry')
│ ├── import commander → 解析命令行参数
│ ├── import enableConfigs() → 加载用户配置
│ ├── 注册所有 Command (commands.ts, 60+)
│ ├── 挂载 hook 系统
│ └── commander.parse() → 路由到对应命令
├── Phase 3: REPL 启动 (默认模式)
│ ├── import main.tsx → 启动 Ink 渲染器
│ │ ├── 注册 bun:bundle polyfill (entry.ts)
│ │ └── import App.tsx
│ │
│ ├── <App> 组件挂载
│ │ ├── 检查环境 (Bun版本/终端能力)
│ │ ├── 加载认证状态 (auth.ts)
│ │ ├── 初始化 AppStore (createStore)
│ │ ├── 运行 preflightChecks (网络可达性)
│ │ └── 加载 MCP 服务端配置
│ │
│ └── 进入 REPL 主循环
│ ├── 加载历史会话 (sessionRestore.ts)
│ ├── 显示欢迎信息和系统提示
│ └── 等待用户输入
└── Phase 4: UI 就绪
├── VirtualMessageList 渲染历史消息
├── StatusLine 显示模型/成本/快捷键
└── TextInput 获得焦点,等待输入
```
### 1.2 启动优化策略
- **延迟加载**: `cli.tsx` 中的 `await import()` 确保快速路径不加载不必要模块
- **Feature Flag DCE**: `feature('PROACTIVE')` 在构建时消除死代码
- **Profile Checkpoint**: `startupProfiler.ts` 记录各阶段耗时
- **预连接**: `apiPreconnect.ts` 在启动时预建立 HTTPS 连接
---
## 2. 对话循环(核心数据流)
### 2.1 主循环
```
用户输入 "帮我重构这个函数"
├── Step 1: 输入处理 (handlePromptSubmit.ts)
│ ├── 解析 @file / @agent 等提及
│ ├── 处理剪贴板图片粘贴
│ ├── 处理引用消息 (↑ 历史选取)
│ └── 构建 UserMessage { role: 'user', content: [...] }
├── Step 2: 预处理 Hooks (hooks.ts, 164KB)
│ ├── UserPromptSubmit hook: 修改/拦截用户输入
│ ├── 注入 CLAUDE.md 系统上下文
│ ├── 加载 MEMORY.md 记忆内容
│ └── 加载 Skills 和 MCP 指令
├── Step 3: 构建 Query (QueryEngine.ts)
│ ├── 构建 System Prompt:
│ │ ├── 基础系统提示词 (constants/prompts.ts, 55KB)
│ │ ├── 环境信息 (OS/Shell/Git/日期)
│ │ ├── 工具清单 (所有可用工具的 name + description + schema)
│ │ ├── CLAUDE.md 内容 (项目级 + 用户级)
│ │ ├── MEMORY.md 内容 (自动记忆)
│ │ └── MCP 服务端提供的上下文
│ │
│ ├── 构建 Messages:
│ │ ├── 历史消息 (截断至 Token 预算)
│ │ ├── 当前 UserMessage
│ │ └── Tool Results (若有待回传)
│ │
│ └── 选择模型: getMainLoopModel() → Claude Opus/Sonnet/Haiku
├── Step 4: API 调用
│ ├── POST https://api.anthropic.com/v1/messages
│ ├── Headers: x-api-key, anthropic-version, ...
│ ├── Body: { model, system, messages, tools, max_tokens, ... }
│ ├── Stream: true (SSE 流式响应)
│ │
│ └── 处理响应流 (server-sent events)
│ ├── message_start → 新消息开始
│ ├── content_block_start → 文本块/工具调用块开始
│ ├── content_block_delta → 增量内容 (text_delta / input_json_delta)
│ ├── content_block_stop → 块结束
│ ├── message_delta → 用量/结束原因
│ └── message_stop → 消息完成
├── Step 5: 响应处理
│ ├── 解析 content_block 类型:
│ │ ├── text → 实时渲染 Markdown (打字机效果)
│ │ ├── tool_use → 进入工具调用流程 (见 Step 6)
│ │ └── thinking → 渲染扩展思考 (可选展示)
│ │
│ └── 更新会话状态:
│ ├── 追加 AssistantMessage 到消息列表
│ ├── 更新 Token 使用量 / 成本
│ └── 持久化到 sessionStorage
├── Step 6: 工具调用循环 (Tool Use Loop)
│ ├── 解析 tool_use 参数 (JSON → Zod 校验)
│ ├── 权限检查 (useCanUseTool)
│ │ ├── 需要用户确认 → 弹出权限 UI → 等待用户决策
│ │ │ ├── 批准 → 继续
│ │ │ └── 拒绝 → 返回拒绝消息
│ │ └── 自动批准 → 继续
│ │
│ ├── 执行工具:
│ │ ├── 触发 PreToolUse hooks
│ │ ├── tool.toolUseOutput(params)
│ │ │ ├── BashTool: spawn 子进程 + 流式输出
│ │ │ ├── FileEditTool: 读取文件 + 字符串替换 + 写回
│ │ │ ├── AgentTool: fork 子 Agent + 等待完成
│ │ │ └── WebFetchTool: HTTP GET + HTML→Markdown + AI 提取
│ │ └── 触发 PostToolUse hooks
│ │
│ ├── 构建 ToolResult:
│ │ { role: 'user', content: [{ type: 'tool_result', tool_use_id, content }] }
│ │
│ ├── 回传模型 (回到 Step 4)
│ │ 模型收到工具结果后继续生成回复或调用更多工具
│ │
│ └── 循环终止条件:
│ ├── 模型仅返回 text (不再调用工具)
│ ├── 达到最大工具轮次
│ ├── 用户手动中断 (Ctrl+C)
│ └── Token 预算用尽 (触发自动压缩)
├── Step 7: 响应完成
│ ├── 触发 Stop hooks
│ ├── 自动内存提取 (extractMemories)
│ ├── 文件历史快照 (fileHistoryMakeSnapshot)
│ ├── 更新会话标题 (sessionTitle.ts)
│ └── 统计记录 (成本/时间/工具调用次数)
└── 回到 Step 1: 等待下一条用户输入
```
### 2.2 流式渲染管道
```
API SSE Stream
Stream Processor (query.ts)
│ 解析 SSE events, 拼接 JSON fragments
Message Builder (messages.ts)
│ 构建 Message 对象树
React State Update (useReplBridge.tsx)
│ setState(newMessage) → React re-render
Ink Reconciler (ink/reconciler.ts)
│ Virtual DOM diff
Node → ANSI Renderer (ink/render-node-to-output.ts)
│ React 元素 → ANSI 字符串
Screen Buffer (ink/screen.ts)
│ 计算 diff, 仅输出变化部分
Terminal Output (ink/output.ts)
│ process.stdout.write(ansiString)
用户终端
```
---
## 3. Task 生命周期
### 3.1 主会话任务
```
用户连接 REPL
├── 创建 LocalMainSessionTask
│ ├── status: 'pending'
│ ├── 开始首次对话 → status: 'running'
│ │ ├── 每次对话循环 (QueryEngine)
│ │ └── 工具执行 (Bash/Agent/...)
│ │
│ └── 结束条件:
│ ├── 用户退出 (Ctrl+C / /exit) → status: 'completed'
│ ├── 崩溃/异常 → status: 'failed'
│ └── 用户中断 (Ctrl+C during run) → status: 'cancelled'
└── 会话持久化 (sessionStorage.ts)
└── ~/.claude/projects/<repo>/<session-id>.jsonl
```
### 3.2 子 Agent 任务
```
AgentTool.toolUseOutput()
├── 创建 LocalAgentTask 或 RemoteAgentTask
│ ├── status: 'pending'
│ ├── 分配工具子集 (根据 subagent_type)
│ │ ├── general-purpose → 全部工具
│ │ ├── explore → Glob + Grep + Read (只读)
│ │ └── plan → 仅计划工具
│ │
│ ├── 构建独立系统提示词 (Agent 角色描述)
│ │
│ └── 开始执行:
│ ├── status: 'running'
│ ├── 独立对话循环 (独立的 QueryEngine)
│ │ ├── 上下文隔离 (不共享主会话消息)
│ │ └── 消耗独立 Token 预算
│ │
│ ├── run_in_background: true
│ │ ├── 后台执行,不阻塞
│ │ └── 完成时通过 notification 通知
│ │
│ └── run_in_background: false (默认)
│ ├── 前台阻塞等待
│ └── 完成时返回结果给调用者
└── 结果归并:
├── 成功 → 提取关键产出 + 清理临时上下文
└── 失败 → 错误信息 + 部分产出
```
### 3.3 Shell 后台任务
```
BashTool 长时间命令
├── 创建 LocalShellTask
│ ├── 后台执行: spawn(command, { detached: true })
│ ├── 实时输出: stdout/stderr → stream
│ │ └── UI 实时显示在 TaskListV2 面板
│ │
│ └── 完成: exitCode + 完整输出
└── 生命周期管理:
├── 用户可随时取消: task.kill()
├── 超时自动终止: setTimeout(kill, timeout)
└── 退出清理: gracefulShutdown 等待所有任务完成
```
---
## 4. 会话持久化与恢复
### 4.1 会话存储结构
```
~/.claude/
├── projects/
│ └── <project_hash>/
│ ├── <session_id>.jsonl # 完整对话记录 (JSONL)
│ ├── <session_id>.meta.json # 会话元数据
│ └── memory/
│ └── MEMORY.md # 自动记忆索引
├── settings.json # 用户全局设置
├── credentials.json # API Key 等凭证 (加密)
└── stats/
└── usage.json # 用量统计
```
### 4.2 会话恢复流程
```
claude --resume (或 /resume 命令)
├── listSessionsImpl() 列出所有历史会话
│ └── 解析 <session_id>.meta.json → 标题/时间/模型
├── ResumeConversation 界面
│ └── 用户选择要恢复的会话
├── sessionRestore.ts 加载会话
│ ├── 读取 .jsonl 文件
│ ├── 解析所有 Message 对象
│ ├── 重建 AppState (消息列表/任务状态)
│ └── 恢复上下文 (模型/配置/权限模式)
└── 继续对话 (从上次中断处)
```
### 4.3 会话导出
```
ExportDialog
├── Markdown: 渲染对话为 .md 文件
├── JSON: 原始 JSON 格式
├── HTML: 静态 HTML 页面 (含样式)
└── PNG: 终端截图 (通过 ansiToPng, 215KB)
```
---
## 5. Bridge 模式数据流
### 5.1 Bridge 连接流程
```
本地 Claude Code (Client) 远程环境 (Server)
│ │
├── claude remote-control │
│ (启动 Bridge 监听) │
│ │
├── WebSocket/TCP 连接 ────────────────►│
│ ├── 鉴权 (JWT/TrustedDevice)
│ ├── 环境信息交换
│ ◄── Handshake OK ────────────────│ ├── 创建工作目录
│ │
├── 会话同步 (replBridge.ts, 102KB) │
│ ├── 发送 AppState 快照 ───────────►│ ├── 应用状态到远程
│ ├── 发送用户消息 ──────────────────►│ ├── 执行查询
│ │ │ ├── 工具调用在远程执行
│ │ ◄── 流式响应 ────────────────│ ├── 文件操作在远程执行
│ │ │
│ ◄── 状态同步 ────────────────────│ ├── 远程文件变化回传
│ ◄── 进度通知 ────────────────────│ │
│ │
└── 双向同步维持 │
├── 心跳 (keep-alive) │
├── 断线重连 (replBridgeTransport) │
└── 会话恢复 (sessionRunner) │
```
### 5.2 Bridge 状态机
```
DISCONNECTED
│ (用户触发连接)
CONNECTING
│ (WebSocket 连接建立)
├── 成功 → HANDSHAKE
└── 失败 → DISCONNECTED (显示错误, 可重试)
HANDSHAKE
│ (JWT 验证 + 设备信任)
├── 成功 → CONNECTED
└── 失败 → DISCONNECTED (认证错误)
CONNECTED
│ (会话同步初始化)
SYNCED
│ (正常双向通信)
├── 断线 → RECONNECTING
└── 用户断开 → DISCONNECTED
RECONNECTING
├── 重连成功 → SYNCED
└── 超时 → DISCONNECTED
```
---
## 6. Memory 系统数据流
### 6.1 记忆生命周期
```
会话启动
├── memdir.loadMemoryPrompt()
│ ├── 扫描 ~/.claude/projects/<project>/memory/
│ ├── 读取 MEMORY.md 索引
│ ├── 读取每个 .md 记忆文件
│ │ ├── 解析 frontmatter (name/description/type)
│ │ └── 提取正文内容
│ │
│ └── findRelevantMemories()
│ ├── 基于当前会话上下文匹配相关记忆
│ └── 按新鲜度排序 (memoryAge)
├── 拼入 System Prompt
│ └── "# Memory\n... (相关记忆内容) ..."
└── 会话中
├── 模型使用 Write 工具 → 写入新的 .md 文件
│ └── 更新 MEMORY.md 索引
├── extractMemories 服务 → 自动从对话中提取
│ └── 后台异步写入
└── 会话结束
└── 记忆文件保持不变 (跨会话持久化)
```
### 6.2 四种记忆类型
```markdown
---
name: <名称>
description: <一行描述>
type: user | feedback | project | reference
---
<内容>
```
| 类型 | 用途 | 示例 |
|---|---|---|
| **user** | 用户角色/偏好/知识 | "用户是资深 Go 开发者" |
| **feedback** | 用户反馈的行为规范 | "不要 mock 数据库测试" |
| **project** | 项目上下文/目标 | "下周四冻结合并" |
| **reference** | 外部系统指针 | "Bug 在 Linear INGEST 项目里" |
---
## 7. Hook 系统
### 7.1 可用 Hook 事件
```typescript
interface Hooks {
// 事件触发型
UserPromptSubmit: (messages) => messages // 用户提交前
PreToolUse: (toolName, params) => params // 工具执行前
PostToolUse: (toolName, result) => void // 工具执行后
Stop: (session) => void // 对话完成
// 通知型
Notification: (event) => void // 各类事件通知
SessionStart: (info) => void // 会话启动
// 配置型 (settings.json)
// "hooks": { "PreToolUse": [{ "matcher": "Bash", "command": "..." }] }
}
```
### 7.2 Hook 执行流程
```
事件触发
├── 加载 hooks 配置 (hooks.ts)
│ ├── settings.json 中的 hooks 数组
│ └── 项目级 .claude/settings.json
├── 匹配规则
│ ├── matcher: 工具名/正则/通配符
│ └── 仅匹配的 hook 执行
└── 执行
├── shell command hooks: spawn(command, args)
├── 内置 hooks: 调用内部函数
└── 超时控制: 长时间 hook 被终止
```
---
## 8. 工具结果存储
`toolResultStorage.ts` (39KB) 负责工具调用结果(特别是大文件)的存储策略:
- **小结果** (< 阈值): 直接存在消息对象中
- **大结果**: 写入临时文件,消息中只存文件引用路径
- **图片结果**: 存为 Base64 或文件引用,带缩放缓存
- **清理**: 会话关闭时自动清理临时文件
---
## 9. 错误处理与恢复
### 9.1 API 错误分类
```
API 错误
├── 可重试错误 (retryable)
│ ├── 429 Rate Limit → 指数退避重试
│ ├── 5xx Server Error → 线性退避重试
│ └── 网络超时 → 立即重试 (最多3次)
├── 不可重试错误
│ ├── 401 Unauthorized → 提示检查 API Key
│ ├── 403 Forbidden → 提示检查权限
│ ├── 400 Bad Request → 显示错误详情
│ └── Token 超限 → 触发自动压缩
└── 流式中断
├── SSE 连接断开 → 尝试重连 + 部分结果
└── 解析错误 → 丢弃损坏chunk继续
```
### 9.2 对话崩溃恢复
```
异常发生
├── conversationRecovery.ts
│ ├── 自动保存当前状态 (crash snapshot)
│ ├── 标记会话为 interrupted
│ └── 下次启动时提示恢复
└── 用户重启 Claude Code
├── 检测到未完成会话
├── 显示 ResumeConversation 界面
└── 从崩溃点恢复对话 (最多丢失最后一条消息)
```
---
*本文档基于 2026-06-11 源码状态生成*