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

18 KiB
Raw Blame History

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 四种记忆类型

---
name: <名称>
description: <一行描述>
type: user | feedback | project | reference
---

<内容>
类型 用途 示例
user 用户角色/偏好/知识 "用户是资深 Go 开发者"
feedback 用户反馈的行为规范 "不要 mock 数据库测试"
project 项目上下文/目标 "下周四冻结合并"
reference 外部系统指针 "Bug 在 Linear INGEST 项目里"

7. Hook 系统

7.1 可用 Hook 事件

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 源码状态生成