Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions 02-cli-bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,18 +580,18 @@ main().catch(err => {

```mermaid
graph TD
A["my-agent-cli.ts 入口"] --> B["顶层副作用\nvoid prefetchApiKey()"]
A --> C{args[0] == --version?}
C -->|是| D["输出版本号,return\n零模块加载"]
C -->|否| E["new Command()\nCommander.js 注册参数"]
A["my-agent-cli.ts 入口"] --> B["顶层副作用<br/>void prefetchApiKey()"]
A --> C{"args[0] == --version?"}
C -->|是| D["输出版本号,return<br/>零模块加载"]
C -->|否| E["new Command()<br/>Commander.js 注册参数"]
E --> F[".action() 回调触发"]
F --> G["判断 isInteractive\n!options.print && isTTY"]
F --> G["判断 isInteractive<br/>!options.print && isTTY"]
G --> H["initializeState(cwd, model, ...)"]
H --> I["await setup(cwd)"]
I --> J{isInteractive?}
J -->|是| K["launchRepl()\nInk + React TUI"]
J -->|否| L["runHeadless(prompt)\n单次执行"]
L --> M["outputResult(result, format)\ntext / json 输出,退出"]
I --> J{"isInteractive?"}
J -->|是| K["launchRepl()<br/>Ink + React TUI"]
J -->|否| L["runHeadless(prompt)<br/>单次执行"]
L --> M["outputResult(result, format)<br/>text / json 输出,退出"]
```

---
Expand Down
63 changes: 30 additions & 33 deletions 03-tool-system.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,34 +412,34 @@ const ASSISTANT_BLOCKING_BUDGET_MS = 15_000

```mermaid
flowchart TD
Input[用户输入命令\ne.g. rm -rf /tmp/foo] --> Parse[parseForSecurity\n解析命令 AST]
Parse --> Pipes{有管道符?}
Pipes -->|是| AllParts[拆分所有管道片段\n逐一分析]
Pipes -->|否| Single[分析单条命令]
AllParts --> ReadCheck{所有片段\n都是只读命令?}
Input["用户输入命令<br/>e.g. rm -rf /tmp/foo"] --> Parse["parseForSecurity<br/>解析命令 AST"]
Parse --> Pipes{"有管道符?"}
Pipes -->|是| AllParts["拆分所有管道片段<br/>逐一分析"]
Pipes -->|否| Single["分析单条命令"]
AllParts --> ReadCheck{"所有片段<br/>都是只读命令?"}
Single --> ReadCheck
ReadCheck -->|是\ncat/grep/ls...| IsReadOnly[标记 isReadOnly=true\nisConcurrencySafe=true]
ReadCheck -->|否| IsWrite[标记 isReadOnly=false]
ReadCheck -->|"是<br/>cat/grep/ls..."| IsReadOnly["标记 isReadOnly=true<br/>isConcurrencySafe=true"]
ReadCheck -->|否| IsWrite["标记 isReadOnly=false"]

IsReadOnly --> PermCheck[checkPermissions]
IsReadOnly --> PermCheck["checkPermissions"]
IsWrite --> PermCheck

PermCheck --> RuleMatch{匹配用户配置规则?\ne.g. Bash(git *)}
RuleMatch -->|命中规则 allow| Allow[直接执行]
RuleMatch -->|命中规则 deny| Deny[拒绝执行]
RuleMatch -->|无匹配规则| AutoMode{auto 模式?}
PermCheck --> RuleMatch{"匹配用户配置规则?<br/>e.g. Bash git *"}
RuleMatch -->|命中规则 allow| Allow["直接执行"]
RuleMatch -->|命中规则 deny| Deny["拒绝执行"]
RuleMatch -->|无匹配规则| AutoMode{"auto 模式?"}

AutoMode -->|是| AIClassifier[bashClassifier.ts\nAI 语义分类器]
AutoMode -->|否| AskUser[弹出确认框\n等待用户决策]
AutoMode -->|是| AIClassifier["bashClassifier.ts<br/>AI 语义分类器"]
AutoMode -->|否| AskUser["弹出确认框<br/>等待用户决策"]

AIClassifier -->|安全| Allow
AIClassifier -->|不确定/危险| AskUser

AskUser -->|用户批准| Allow
AskUser -->|用户拒绝| Deny

Allow --> ExecBash[执行命令\n超 15s 自动后台化]
Deny --> ErrorResult[返回拒绝信息]
Allow --> ExecBash["执行命令<br/>超 15s 自动后台化"]
Deny --> ErrorResult["返回拒绝信息"]

style Allow fill:#eafaf1,stroke:#27ae60
style Deny fill:#fdedec,stroke:#e74c3c
Expand Down Expand Up @@ -552,48 +552,45 @@ isolation: z.enum(['worktree', 'remote']).optional()
sequenceDiagram
participant P as 父 Agent
participant AT as AgentTool
participant R as runAgent()
participant R as runAgent
participant SA as 子 Agent
participant FS as 文件系统 / Git
participant FS as 文件系统 Git

P->>AT: call({ prompt, tools, isolation?, run_in_background? })
P->>AT: call prompt tools isolation run_in_background

AT->>AT: assembleToolPool()\n过滤 ALL_AGENT_DISALLOWED_TOOLS
AT->>AT: assembleToolPool 过滤 ALL_AGENT_DISALLOWED_TOOLS

alt isolation = "worktree"
alt isolation worktree
AT->>FS: 创建独立 git worktree
FS-->>AT: worktree 路径
end

alt run_in_background = true
AT-->>P: 立即返回 { agentId }\n父 Agent 继续工作
alt run_in_background true
AT-->>P: 立即返回 agentId Agent 继续工作
AT->>R: 异步启动子 Agent
else 同步执行
AT->>R: 启动子 Agent(阻塞)
AT->>R: 启动子 Agent 阻塞
end

R->>SA: 初始化 QueryEngine\n注入工具池 + 上下文
R->>SA: 初始化 QueryEngine 注入工具池和上下文

loop Agent 执行循环
SA->>SA: 调用 LLM
SA->>SA: 执行工具调用
end

SA-->>R: 执行完成 / 出错
SA-->>R: 执行完成或出错

alt isolation = "worktree"
alt isolation worktree
R->>FS: 清理 worktree
end

alt run_in_background = true
R->>P: 通知系统推送结果\n{ agentId, result }
alt run_in_background true
R->>P: 通知系统推送结果 agentId result
else 同步执行
R-->>AT: SubAgentResult
AT-->>P: tool_result { output }
AT-->>P: tool_result output
end

style SA fill:#e8f4fd,stroke:#1a73e8
style FS fill:#eafaf1,stroke:#27ae60
```

---
Expand Down
4 changes: 2 additions & 2 deletions 04-conversation-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,7 @@ mindmap
root((对话与上下文管理))
三层上下文
System Prompt
工具描述 prompt()
工具描述 prompt
Git 状态快照
环境信息
User Context
Expand All @@ -775,7 +775,7 @@ mindmap
tool_use + tool_result 强制配对
mutableMessages 跨轮持久化
系统提示构建
fetchSystemPromptParts()
fetchSystemPromptParts
Promise.all 并行加载
Prompt Cache 友好设计
上下文窗口管理
Expand Down
18 changes: 9 additions & 9 deletions 05-agent-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,28 +376,28 @@ for (const result of streamingToolExecutor.getCompletedResults()) {

```mermaid
graph TD
ADD["addTool(block)\n加入执行队列"] --> PQ["processQueue()\n尝试调度"]
ADD["addTool(block)<br/>加入执行队列"] --> PQ["processQueue()<br/>尝试调度"]
PQ --> CHECK{"canExecuteTool()?"}
CHECK --> |"无正在执行的工具"| RUN["立即执行"]
CHECK --> |"当前全是并发安全工具\n且新工具也是并发安全"| RUN
CHECK --> |"当前有非并发安全工具\n或新工具非并发安全"| WAIT["等待队列,status=queued"]
CHECK -->|"无正在执行的工具"| RUN["立即执行"]
CHECK -->|"当前全是并发安全工具<br/>且新工具也是并发安全"| RUN
CHECK -->|"当前有非并发安全工具<br/>或新工具非并发安全"| WAIT["等待队列,status=queued"]

subgraph 并发安全工具(只读)
subgraph Safe["并发安全工具 只读"]
RT1["ReadFile #1"]
RT2["ReadFile #2"]
RT3["SearchCode #3"]
RT1 & RT2 & RT3 --> PARALLEL["同时执行"]
end

subgraph 非并发安全工具写操作
subgraph Unsafe["非并发安全工具 写操作"]
WT1["BashCmd #4"] --> WT2["WriteFile #5"]
WT2 --> WT3["BashCmd #6"]
WT1 & WT2 & WT3 --> SERIAL["严格串行"]
end

RUN --> COMPLETE["完成 status=completed\n有序放入结果队列"]
COMPLETE --> GCR["getCompletedResults()\n按添加顺序返回结果"]
WAIT --> |"前序工具完成后重新调度"| PQ
RUN --> COMPLETE["完成 status=completed<br/>有序放入结果队列"]
COMPLETE --> GCR["getCompletedResults()<br/>按添加顺序返回结果"]
WAIT -->|"前序工具完成后重新调度"| PQ
```

---
Expand Down
28 changes: 14 additions & 14 deletions 06-hooks-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,28 +110,28 @@ export type ToolPermissionContext = {

```mermaid
stateDiagram-v2
[*] --> default: 会话启动
[*] --> DefaultMode: 会话启动

default --> acceptEdits: 用户开启"自动接受编辑"
default --> plan: 进入规划模式\n(保存 prePlanMode)
default --> bypassPermissions: CI/CD 启动参数\n⚠️ 高风险,标红色
default --> dontAsk: 非交互式场景
DefaultMode --> acceptEdits: 用户开启自动接受编辑
DefaultMode --> plan: 进入规划模式 保存 prePlanMode
DefaultMode --> bypassPermissions: CI/CD 启动参数 高风险标红色
DefaultMode --> dontAsk: 非交互式场景

acceptEdits --> default: 关闭自动接受
acceptEdits --> DefaultMode: 关闭自动接受
acceptEdits --> plan: 进入规划模式

plan --> default: 退出规划模式\n(还原 prePlanMode)
plan --> acceptEdits: 退出到 acceptEdits\n(prePlanMode=acceptEdits)
plan --> DefaultMode: 退出规划模式 还原 prePlanMode
plan --> acceptEdits: 退出到 acceptEdits prePlanMode=acceptEdits

bypassPermissions --> default: 重置权限模式
bypassPermissions --> DefaultMode: 重置权限模式

dontAsk --> default: 恢复交互式
dontAsk --> DefaultMode: 恢复交互式

default --> auto: 启用 TRANSCRIPT_CLASSIFIER\nAI 自动判定
DefaultMode --> auto: 启用 TRANSCRIPT_CLASSIFIER AI 自动判定

note right of bypassPermissions: 绕过所有权限检查\nhooks 仍然执行
note right of plan: 只读操作\n禁止写入
note right of dontAsk: ask deny\n完全非交互
note right of bypassPermissions: 绕过所有权限检查 hooks 仍然执行
note right of plan: 只读操作 禁止写入
note right of dontAsk: ask deny 完全非交互
```

---
Expand Down
40 changes: 20 additions & 20 deletions 08-build-your-own.md
Original file line number Diff line number Diff line change
Expand Up @@ -1119,44 +1119,44 @@ export class AgentLoop {
sequenceDiagram
participant User as 用户
participant CLI as CLI REPL
participant Loop as AgentLoop
participant AL as AgentLoop
participant Ctx as ContextManager
participant API as Claude API
participant Tools as ToolSystem

User->>CLI: 输入任务
CLI->>Loop: run(userMessage, onDelta)
CLI->>AL: run userMessage onDelta

Loop->>Ctx: addUserMessage(text)
Ctx-->>Loop: 当前消息历史
AL->>Ctx: addUserMessage text
Ctx-->>AL: 当前消息历史

loop Agent 主循环
Loop->>API: messages.create(messages, tools)
API-->>Loop: 流式响应
AL->>API: messages.create messages tools
API-->>AL: 流式响应

alt stop_reason = "end_turn"
Loop->>CLI: 输出最终文本
Loop-->>CLI: 循环结束
else stop_reason = "tool_use"
Loop->>CLI: 输出思考文本(流式)
alt stop_reason end_turn
AL->>CLI: 输出最终文本
AL-->>CLI: 循环结束
else stop_reason tool_use
AL->>CLI: 输出思考文本 流式

loop 每个 tool_use block
Loop->>Tools: checkPermission(tool, input)
Tools-->>Loop: allow / deny
AL->>Tools: checkPermission tool input
Tools-->>AL: allow deny

alt allow
Loop->>Tools: executeTool(name, input)
Tools-->>Loop: 结果字符串
Loop->>CLI: 显示 [工具调用] + [工具结果]
AL->>Tools: executeTool name input
Tools-->>AL: 结果字符串
AL->>CLI: 显示工具调用和工具结果
else deny
Loop->>Ctx: 添加拒绝消息
AL->>Ctx: 添加拒绝消息
end
end

Loop->>Ctx: addAssistantMessage(tool_use blocks)
Loop->>Ctx: addUserMessage(tool_result blocks)
AL->>Ctx: addAssistantMessage tool_use blocks
AL->>Ctx: addUserMessage tool_result blocks

Note over Ctx: 检查是否需要压缩\n(丢弃旧 tool_result
Note over Ctx: 检查是否需要压缩 丢弃旧 tool_result
end
end
```
Expand Down