aacode-rs 1.8.15

Rust port of the AACode ReAct coding agent, built on fastshell for mobile AI agents
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
# AACode-rs 设计文档

> Rust 版 AACode 编码 Agent —— 用于集成到 AACodeApp 安卓客户端
>
> 位置:`/Volumes/lenovops9/fastshell_local/aacode-rs/`
> 状态:设计阶段(尚未开始编码)
> python版位置:/Users/xiefujin_mac2025/PycharmProjects/aacode_local
>
> 说明:Rust crate 名与目录名统一为 `aacode-rs`,以区别于 Python 版 `aacode`。

---

## 1. 背景与目标

### 1.1 现状

AACode 目前是一个 **100% Python 的 ReAct 架构 AI 编码 Agent**(源码:`PycharmProjects/aacode_local/aacode/`)。它通过 DeepSeek/OpenAI/Anthropic 兼容 API 驱动,核心能力是"用 `run_shell` 作为万能适配器 + 文件化上下文 + 分层工具系统"完成编码任务。目前已经经过几十个版本优化,有不少用户,运行良好。

安卓客户端 `AACodeApp` 的既定方案是:
- 用 Rust 写的 `fastshell` 提供沙箱 Shell(180+ 命令)与内嵌 CPython 3.12;
- 把 aacode 的 Python 源码 + pip 依赖打包进 APK assets,运行时拷贝到沙箱;
- 通过 JNI → `fastshell_execute_python_script()` 在内嵌 CPython 里跑 aacode,用文件轮询方式把 JSONL 事件回传给 Kotlin UI。

**问题**:内嵌 CPython 这条路走不通(`libpython3.12.so` 动态加载、pip 依赖 native 扩展、asyncio/子进程拦截、ARM64 MTE、冷启动与体积等一系列脆弱点),Python 在安卓上跑不起来或极不稳定。

### 1.2 目标

**用 Rust 重新实现 aacode 的完整功能**,直接编译进 `libfastshell.a`/`libaacode_rs.a`,彻底去掉对 CPython 与 pip 依赖的运行时需求:

- Agent 循环、LLM 调用、工具系统全部原生 Rust;
- 工具执行复用 `fastshell` 已有的沙箱 Shell 引擎(`Fastshell::execute()`),无需子进程、无需系统 `/bin/sh`;
- 通过 C ABI + JNI 暴露给安卓,**输出协议与现有 Kotlin `AgentOutputParser` 完全兼容**,尽量少改 App 端;
- 保持桌面 CLI 可运行(便于本地开发调试)。

### 1.3 范围说明

**本次为一次性完整实现**:复刻 Python 版 aacode 的全部核心功能(Agent 循环、LLM 双网关、完整工具集、会话/上下文/压缩、安全、多模态、MCP、Skills、Sub-Agent 委托),不做分期裁剪。

仅有两点因平台性质天然不同:
- 不内嵌 Python(Rust 版不依赖 CPython)。因此 Python 型 skill 通过内嵌 CPython 执行的能力不适用;`run_skills` 采用"文档型 skill + 借助 `run_shell` 执行"的等价实现(见 §5.3)。
- 不实现桌面 Tauri GUI(那是 Python 版的桌面客户端;本 crate 只提供 CLI + FFI)。

---

## 2. 源工程分析总结(三方对照)

### 2.1 Python 版 aacode 核心结构

| 模块 | 文件 | 职责 |
|---|---|---|
| 入口 | `main.py` (836) | CLI 解析、`AICoder` 类、交互式会话循环 |
| 主 Agent | `core/main_agent.py` (1705) | 模型调用器(OpenAI/Anthropic 流式 + 原生 function calling)、工具装配、会话/todo 编排、`execute()` |
| ReAct 循环 | `core/react_loop.py` (2213) | 迭代循环、tool_calls 执行、上下文压缩(round-aware compact view)、死循环检测、自适应截断 |
| Agent 基类 | `core/agent.py` (248) | `BaseAgent`、文本回退解析 |
| 子 Agent | `core/sub_agent.py` | 专用子 Agent(code/test/research)|
| 提示词 | `core/prompts.py` (131) | 主系统提示词(工具说明 + TDD 规则 + 工作流)|
| 原子工具 | `tools/atomic_tools.py` (195) | 仅 `run_shell`(异步子进程 + 安全检查 + 流式行读取 + 截断/归档)|
| 网络工具 | `tools/web_tools.py` | `search_web`(SearXNG/Brave/Google/Bing/SerpAPI + HTML 回退)、`fetch_url`、`search_code` |
| Todo 工具 | `tools/todo_tools.py` (256) | add/mark/update/summary/list,按 session 隔离 |
| Skills | `tools/skills_tools.py` | `run_skills`(__list__/__info__/execute 三模式),从 `SKILL.md` 自动发现 |
| 多模态 | `tools/multimodal_tools.py` | 图片/视频/UI 稿理解 |
| 工具 Schema | `utils/tool_schemas.py` (616) | 所有工具的参数 schema(含别名、示例)|
| 工具注册表 | `utils/tool_registry.py` (267) | 参数校验、别名归一化、文档生成、相似工具建议 |
| 工具适配 | `utils/tool_adapter.py` (101) | Schema → OpenAI/Anthropic native tools 格式 |
| 会话管理 | `utils/session_manager.py` (686) | `.aacode/sessions/*.json` 持久化、token 计数、多轮衔接、原子写盘 + 文件锁 |
| Todo 管理 | `utils/todo_manager.py` | markdown todo 文件读写 |
| 上下文管理 | `utils/context_manager.py` (550) | 文件化上下文、大输出归档到 `.aacode/context/` |
| 消息工具 | `utils/message_utils.py` | token 估算、按 round 拆分、compact view 构建 |
| 安全 | `utils/safety.py` (2400+) | 命令风险评估、路径检查、危险命令确认、AST 检查 |
| 配置 | `config.py` (704) | 模型/工具/安全/上下文/超时/限制/skills/多模态 配置,env > yaml |
| 服务器 | `server/runner.py` (191) | `AICoderRunner`:流式事件生成、API key 校验、会话列表 |
| 多 Agent | `core/multi_agent.py` | 多 Agent 系统:任务委托与协调 |

**关键运行流程**:
```
AICoder.run(task)
  → 分析项目结构(class-method map)
  → 创建 todo list
  → MainAgent.execute(task, ...)
       → 组装完整 system prompt(SYSTEM_PROMPT + skills + working_dir + analysis + init + todo)
       → 载入历史消息(多轮衔接)
       → AsyncReActLoop.run()
            for iteration in max_iterations:
              messages = build_compact_view(messages)   # round-aware 压缩
              response = model_caller(messages)          # 流式,返回 {text, tool_calls, reasoning_content}
              if no tool_calls: 任务完成,输出总结 → break
              for each tool_call: execute → observation
              append assistant(tool_calls) + tool(results) 到 messages
              增量持久化 messages 到 session 文件
              if tokens > trigger: compact_context()     # AI 生成三段式摘要
```

**LLM 调用要点**(`main_agent.py`):
- OpenAI 网关:`client.chat.completions.create(stream=True, tools=..., tool_choice="auto")`,逐 chunk 解析 `delta.content` / `delta.reasoning_content` / `delta.tool_calls`(流式累积 tool_calls 的 name/arguments);`finish_reason == "length"` 检测截断。
- Anthropic 网关:`client.messages.stream(...)`,解析 `content_block_delta`(thinking_delta/text_delta)+ `get_final_message()` 拿 tool_use。
- 两个网关的 base_url 会按模型名自动推断(deepseek/kimi/minimax/claude/gpt)。

### 2.2 fastshell(Rust)现状

- 单 workspace 成员 `fastshell/`,`crate-type = ["lib", "cdylib", "staticlib"]`。
- **可直接复用**:`Fastshell` SDK(`sdk/mod.rs`),`Fastshell::execute(command) -> CommandResult { stdout, stderr, exit_code }`,沙箱 VFS,180+ 命令,网络权限门控。
- **已有 C ABI**(`sdk/ffi.rs`):`fastshell_init/execute/execute_python/get_cwd/set_permission/cancel_execution/register_stream_callback/start_agent_server/submit_task/free_string`。
- **已有流式回调基建**(历史):`fastshell_register_stream_callback` + C 侧 `stream_trampoline` → Kotlin `onChunk(String)`。aacode-rs 的 Agent 流式改走**句柄式 + userdata**(`aacode_task_start` 的 `cb(line, userdata)`),不再复用该注册槽。
- **`start_agent_server`/`submit_task` 目前委托给 Python 引擎**(stub),Rust 版可接管。
- 依赖已含:`serde/serde_json`、`ureq`(同步 HTTP + rustls)、`tokio`(rt/net/io-util/macros)、`regex`、`uuid`、`base64`、`sha2`。**没有 LLM 客户端**。

### 2.3 AACodeApp(安卓)集成契约

- Kotlin `com.fastshell.Sdk` 通过 `System.loadLibrary("fastshell_jni")` 加载,`external fun nativeXxx(...)` → `jni_glue.c` → Rust C ABI。
- 现用 **文件轮询** 读 Agent 输出:Python 把 JSONL 写到 `tmp/agent_<uuid>.jsonl`,Kotlin `AgentBridge` 轮询解析。
- **`AgentOutputParser` 期望的事件协议**(这是 Rust 版必须严格对齐的输出契约):
  - 以 `{` 开头的行按 JSON 事件解析,`type` 取值:`seg_content`(含 `seg` ∈ {thinking, thought, action, observation}、`content`)、`tool_progress`(`state` ∈ {building, done}、`name`、`chars`)、`done`、`error`、`start`、`session_created`、`session_switched`;
  - 其它行按"流式 token"处理,`\x00` 需还原为 `\n`(管道模式下 aacode 用 `\x00` 转义 token 内换行)。
- App 只编 `arm64-v8a`,NDK 27,`minSdk 26`,CMake 链接 `libfastshell.a` + `jni_glue.c` → `libfastshell_jni.so`。
- `AndroidManifest` 已设 `memtagMode="off"`。

**结论**:Rust 版只要 (1) 复用 `Fastshell::execute` 作为 run_shell 后端,(2) 通过流式回调按上面的 JSONL 协议 emit 事件,就能在**几乎不改 App UI 层**的前提下替换掉 Python Agent。

---

## 3. 总体架构

```
┌──────────────────────────────────────────────────────────────┐
│                    Android App (Kotlin)                        │
│   ChatViewModel → AgentBridge → com.fastshell.Sdk (JNI)        │
└───────────────────────────┬──────────────────────────────────┘
                            │  nativeAgentRunTaskWithCallback(taskJson, cb) → jlong
┌───────────────────────────▼──────────────────────────────────┐
│                fastshell_c/jni_glue.c (C ABI 桥)                │
└───────────────────────────┬──────────────────────────────────┘
                            │  aacode_task_start() / wait / cancel / free
┌───────────────────────────▼──────────────────────────────────┐
│                  aacode-rs crate (Rust)  ★新增                │
│  ┌────────────┐  ┌───────────┐  ┌──────────┐  ┌────────────┐  │
│  │  ffi.rs    │  │  agent/   │  │  llm/    │  │  tools/    │  │
│  │ C ABI +    │→ │ react loop│→ │ openai   │  │ registry   │  │
│  │ JSONL emit │  │ main agent│  │ anthropic│  │ shell/web/ │  │
│  └────────────┘  └───────────┘  │ sse parse│  │ todo/...   │  │
│  ┌────────────┐  ┌───────────┐  └──────────┘  └─────┬──────┘  │
│  │  session   │  │  context  │  ┌──────────┐        │         │
│  │  todo      │  │  compact  │  │ config   │        │         │
│  └────────────┘  └───────────┘  └──────────┘        │         │
└──────────────────────────────────────────────────────┼────────┘
                                                        │ run_shell
┌───────────────────────────────────────────────────────▼────────┐
│              fastshell crate (Rust, 已有)                        │
│   Fastshell::execute() → Shell(180+ cmds) → VFS 沙箱             │
└──────────────────────────────────────────────────────────────┘
```

### 3.1 Crate 组织方案

**方案 A(推荐):`aacode-rs` 独立 workspace 成员,依赖 `fastshell`**

- 目录:`fastshell_local/aacode-rs/`(`Cargo.toml` + `src/`)。crate 名 `aacode-rs`(lib 名 `aacode_rs`),FFI 符号前缀仍用 `aacode_*`(C 标识符不能带 `-`)。
- `aacode-rs/Cargo.toml`:`[package] name = "aacode-rs"`,`crate-type = ["lib", "staticlib", "cdylib"]`,`[dependencies] fastshell = { path = "../fastshell" }`。
- 根 `Cargo.toml` `members = ["fastshell", "aacode-rs"]`。
- 安卓构建切换为 `cargo build -p aacode-rs --target aarch64-linux-android --lib` → `libaacode_rs.a`(静态包含 fastshell)。`jni_glue.c` 链接 `libaacode_rs.a`,可同时使用 `fastshell_*` 与 `aacode_*` 两套 C ABI(fastshell 的符号仍在归档里)。
- 优点:物理隔离清晰、无循环依赖、fastshell 保持纯运行时不被 Agent 逻辑污染。
- 代价:安卓 CMake/`build.sh` 需把 `-p fastshell` 改成 `-p aacode-rs`,产物名 `libfastshell.a` → `libaacode_rs.a`(`c_dist/arm64-v8a/`)。

> 备选方案 B:把 Agent 作为 `fastshell` 的 feature-gated 模块(`--features agent`),复用现有 `fastshell_submit_task` 符号,App 端零改动。缺点是 Agent 逻辑与运行时耦合。**采用方案 A**,并在 ffi 层保留一组"形状"与 `fastshell_submit_task` 一致的入口以便平滑迁移。

### 3.2 运行模型(并发/线程)

- Android/JNI 侧:`aacode_task_start` 在**共享 tokio runtime 的 worker 线程**运行(不阻塞 JNI 调用线程),通过 `cb(line, userdata)` 流式回调把 JSONL 行推给 Kotlin(每任务独立 userdata,比文件轮询延迟更低、更简单)。
- LLM HTTP 采用**同步 `ureq` + 手写 SSE 行解析**(在 worker 线程里阻塞读取 response body 的 `Read`),避免引入 `reqwest` + 全量 tokio,控制二进制体积。(备选:`reqwest`+`tokio` 异步流,若后续需要并发多请求再切换。)
- 取消:`aacode_task_cancel(handle)` 置 `AtomicBool`,ReAct 循环与 SSE 读取在检查点响应取消;同时调用 `fastshell_cancel_execution()` 打断正在跑的 shell。
- 全局单例:`OnceLock<Mutex<AgentRuntime>>`,与 fastshell FFI 单例风格一致。

---

## 4. 代码结构(模块设计)

```
aacode-rs/
├── Cargo.toml
├── design.md                  # 本文档
├── README.md                  # 使用说明(后续)
└── src/
    ├── lib.rs                 # crate 根,pub mod 声明与再导出
    ├── config.rs              # AgentConfig:模型/网关/超时/限制/安全,env + JSON
    ├── error.rs               # AacodeError 统一错误类型(thiserror 风格,手写或引入)
    │
    ├── llm/
    │   ├── mod.rs             # LlmClient trait + 网关分发 + base_url 自动推断
    │   ├── openai.rs          # OpenAI 兼容:chat/completions 流式 + tool_calls 累积
    │   ├── anthropic.rs       # Anthropic 兼容:messages stream + tool_use
    │   ├── sse.rs             # SSE 行解析器(data: {...} 分帧)
    │   └── types.rs           # ChatMessage, ToolCall, LlmResponse{text,tool_calls,reasoning}
    │
    ├── agent/
    │   ├── mod.rs
    │   ├── main_agent.rs      # MainAgent:装配工具、组装 system prompt、execute()
    │   ├── react_loop.rs      # ReactLoop:迭代、tool_calls 执行、完成判定、重试、死循环检测
    │   ├── sub_agent.rs       # SubAgent:code/test/research 专用子 Agent
    │   ├── prompts.rs         # SYSTEM_PROMPT 常量(移植 core/prompts.py)
    │   └── compact.rs         # 上下文压缩:round 拆分 + compact view + 三段式摘要
    │
    ├── tools/
    │   ├── mod.rs
    │   ├── registry.rs        # ToolRegistry:注册、校验、别名归一化、not-found 建议
    │   ├── schema.rs          # ToolSchema/ToolParameter + to_openai_tools/to_anthropic_tools
    │   ├── shell.rs           # run_shell:转发 fastshell::Fastshell::execute + 截断/归档
    │   ├── web.rs             # search_web / fetch_url / search_code(ureq)
    │   ├── todo.rs            # add/mark/update/summary/list(markdown 文件)
    │   ├── session_tools.rs   # new/continue/list/switch/delete/history/stats 会话工具
    │   ├── skills.rs          # run_skills(三模式,SKILL.md 自动发现,文档型 skill)
    │   ├── mcp.rs             # list/call/status(MCP stdio + sse 客户端)
    │   ├── multimodal.rs      # understand_image/video/ui_design/consistency(vision API)
    │   └── delegate.rs        # delegate_task / create_sub_agent 工具入口
    │
    ├── mcp/
    │   └── mod.rs             # MCP 管理器:stdio/sse 传输、工具发现、调用
    │
    ├── session/
    │   └── mod.rs             # SessionManager:.aacode/sessions/*.json 读写、多轮衔接
    │
    ├── context/
    │   └── mod.rs             # 大输出归档 .aacode/context|extracts/、init.md 载入、项目结构分析
    │
    ├── stream/
    │   └── mod.rs             # EventEmitter:seg_content/tool_progress/done/error/token
    │                          #   —— 严格对齐 Kotlin AgentOutputParser 协议
    │
    ├── bin/
    │   └── aacode.rs          # 桌面 CLI 入口(-p/-t/--session/--plan-first/--interactive)
    │
    └── ffi.rs                 # C ABI:aacode_task_start/wait/cancel/free...
```

### 4.1 关键类型草图(示意,非最终 API)

```rust
// llm/types.rs
pub struct ChatMessage {
    pub role: String,                       // system|user|assistant|tool
    pub content: String,
    pub tool_calls: Option<Vec<ToolCall>>,  // assistant
    pub tool_call_id: Option<String>,       // tool
    pub reasoning_content: Option<String>,
}
pub struct ToolCall { pub id: String, pub name: String, pub arguments: String /* JSON */ }
pub struct LlmResponse {
    pub text: String,
    pub tool_calls: Vec<ToolCall>,
    pub reasoning_content: Option<String>,
    pub finish_reason: Option<String>,      // "length" => 截断告警
}

// llm/mod.rs
pub trait LlmClient: Send {
    /// 流式调用;每个可显示片段通过 emitter 推送(thinking/thought token)
    fn chat_stream(
        &self,
        messages: &[ChatMessage],
        tools: &[serde_json::Value],
        emitter: &dyn EventSink,
        cancel: &AtomicBool,
    ) -> Result<LlmResponse, AacodeError>;
}

// tools/registry.rs
pub trait Tool: Send + Sync {
    fn name(&self) -> &str;
    fn schema(&self) -> &ToolSchema;
    fn call(&self, args: serde_json::Value) -> Result<String, AacodeError>; // 返回 observation
}

// stream/mod.rs —— 输出协议核心
pub trait EventSink: Send {
    fn seg(&self, seg: &str, content: &str);        // seg_content
    fn tool_progress(&self, state: &str, name: &str, chars: usize);
    fn token(&self, text: &str);                    // 流式 token(\n → \x00)
    fn started(&self, task: &str);                  // start
    fn session(&self, ev: &str, session_id: &str);  // session_created/switched
    fn done(&self, session_id: &str);
    fn error(&self, message: &str);
}
```

### 4.2 run_shell(工具层与 fastshell 的对接)

```rust
// tools/shell.rs
pub struct ShellTool { fs: Arc<Mutex<fastshell::Fastshell>>, sandbox: PathBuf }
impl Tool for ShellTool {
    fn call(&self, args: Value) -> Result<String, AacodeError> {
        let cmd = args["command"].as_str().ok_or(...)?;
        let max_output = args["max_output"].as_u64();
        let r = self.fs.lock().unwrap().execute(cmd); // CommandResult{stdout,stderr,exit_code}
        // 组装 JSON:{success, returncode, stdout, stderr, command}
        // 超长时写入 .aacode/extracts/ 并返回预览 + 归档路径(对齐 Python 行为)
    }
}
```
> 注意:fastshell 已在 VFS 沙箱内执行,`timeout` 由 `Fastshell::execute` 支持(`config.timeout`)。危险命令确认在移动端默认放行/或走权限回调(见 §8 安全)。

---

## 5. 功能清单(Feature List)

**全部一次性实现,不分优先级。** 以下为对齐 Python 版的完整能力清单,均为本次交付范围。

### 5.1 Agent 核心
- ReAct 迭代循环(max_iterations、完成判定:无 tool_calls 即完成并输出总结)
- 原生 function calling(OpenAI tools / Anthropic tools)
- 流式输出(token 级 + thinking/reasoning 分离)
- 多工具并行调用(一轮多个 tool_calls)
- 工具执行错误重试(可重试错误:timeout/connection,指数退避)
- 完成后自包含总结
- 上下文压缩(round-aware compact view + 触发阈值,保护首轮 + 最近 N 轮 user)
- AI 生成三段式历史摘要(文件内容 / 工具执行 / 保留信息)
- 死循环检测(fetch_url stale domain:同域名连续 N 次无可读内容时告警)
- Sub-Agent 委托(delegate_task / create_sub_agent,code/test/research 专用提示词)
- Plan-first 模式(`--plan-first`:先在 thought 中规划再执行)
- 项目结构分析(class-method map 生成,任务前注入上下文)

### 5.2 LLM 客户端
- OpenAI 兼容网关(DeepSeek/Kimi/GPT 等)流式 + tool_calls 分片累积
- Anthropic 兼容网关(MiniMax/Claude)messages stream + tool_use + thinking
- base_url 按模型名 + gateway 自动推断(deepseek/kimi/minimax/claude/gpt → 端点)
- `finish_reason == length` / `stop_reason == max_tokens` 截断告警
- 网络错误自动重试(指数退避,5xx/连接/超时)
- API key 缺失/401/配额 友好错误分类
- API key 校验(validate_api_key 等价,轻量探测请求)
- 流式失败降级为非流式(Anthropic 路径)

### 5.3 工具集(全部实现)
- `run_shell`(转发 fastshell,截断/归档,max_output,stdin_input,timeout)
- `add_todo_item` / `mark_todo_completed` / `update_todo_item` / `get_todo_summary` / `list_todo_files` / `add_execution_record`
- `search_web`(SearXNG / Brave / Google CSE / Bing / SerpAPI 多后端 + HTML 回退抓取)
- `fetch_url`(ureq + HTML 清洗/预览 + JS 重定向探测 + 结果落盘)
- `search_code`(代码示例搜索)
- 会话管理工具(new_session / continue_session / list_sessions / switch_session / delete_session / get_conversation_history / get_session_stats)
- `run_skills`(三模式 `__list__` / `__info__` / execute;从 `SKILL.md` 自动发现;文档型 skill 返回指令由模型借 `run_shell` 执行)
- MCP 工具(list_mcp_tools / call_mcp_tool / get_mcp_status;stdio + sse 客户端)
- 多模态工具(understand_image / understand_video / understand_ui_design / analyze_image_consistency,走 vision API)
- Sub-Agent 委托工具(delegate_task / create_sub_agent)

### 5.4 会话 / 上下文 / 持久化
- Session:`.aacode/sessions/<id>.json` 读写、`sessions_index.json` 索引、增量持久化、多轮衔接
- 原子写盘(临时文件 + rename)+ 文件锁(跨进程并发保护 + index 合并)
- token 计数(字符估算 4:1;不依赖 tiktoken)
- `init.md` 项目指令载入(不存在时生成默认模板)
- 大输出归档到 `.aacode/context/`、`.aacode/extracts/`(预览 + 归档路径)
- 会话恢复保护(上次中断在 tool 消息时注入恢复提示)
- 旧版 session JSON 格式兼容(float 时间戳、占位 system 消息过滤)

### 5.5 工具注册 / 校验
- ToolSchema + 参数别名归一化 + 必填/类型校验
- Schema → OpenAI / Anthropic tools 格式转换
- 未知工具的相似名建议 + 工具文档回传
- 参数缺失 / 类型错误 的友好错误消息(复刻 Python 体验)

### 5.6 配置
- 模型配置(name/api_key/base_url/gateway/temperature/max_tokens/multimodal)
- env 优先(`LLM_API_KEY`/`LLM_API_URL`/`LLM_MODEL_NAME`/`LLM_GATEWAY`/`LLM_MULTIMODAL`)
- 通过 `aacode_task_start` 的 taskJson 传入运行时配置(App 从设置页下发)
- JSON 配置文件(沙箱内 `aacode_config.json`)
- 搜索引擎配置(`SEARCHXNG_URL`/`SEARCH_API_KEY` 等)
- 安全 / 上下文 / 超时 / 限制 / skills / 多模态 各分区配置

### 5.7 平台集成
- C ABI:`aacode_task_start` / `aacode_task_wait` / `aacode_task_cancel` / `aacode_task_free` / `aacode_free_string` / `aacode_validate_api_key` / `aacode_list_sessions` / `aacode_get_session_messages`
- JSONL 事件输出协议(对齐 Kotlin `AgentOutputParser`)
- 桌面 CLI(`bin/aacode.rs`:`-p <project> "task"`,交互式会话模式)
- JNI glue(`jni_glue.c`:`nativeAgentRunTaskWithCallback`(返回句柄)/ `nativeAgentWaitTask` / `nativeAgentCancelTask` / `nativeAgentFreeTask`)
- 会话列表 / 消息读取 C ABI(供 App 历史页)

---

## 6. LLM 流式与工具调用设计(重点)

### 6.1 OpenAI 兼容流式解析(`llm/openai.rs`)

请求体:`{model, messages, temperature, max_tokens, stream:true, tools, tool_choice:"auto"}`。用 `ureq` POST,`Accept: text/event-stream`,读取响应 body 的 `Read`,按 SSE 行解析(`sse.rs`):

```
每行 "data: {json}":
  delta.reasoning_content → emitter.seg("thinking", ...) + token 累积到 reasoning_content
  delta.content           → emitter.seg/token 到 thought,累积到 text
  delta.tool_calls[i]     → 按 index 累积 id/function.name/function.arguments
                            首次拿到 name 时 emitter.tool_progress("building", name, 0)
                            arguments 每增长 ~500 字符 emit 一次 tool_progress
  choices[0].finish_reason=="length" → 记录截断告警
"data: [DONE]" → 结束
```
流结束后:组装 `tool_calls` 列表,对每个 emit `tool_progress("done", name, 0)` 与 `🛠️ Action: {name}` 行(对齐 Python 管道输出)。thinking 与正文分离返回。

### 6.2 Anthropic 兼容流式(`llm/anthropic.rs`)

`messages` 端点 SSE:`content_block_start/delta`(`thinking_delta`/`text_delta`)+ `content_block_stop`;最终从 `message_stop` 或聚合的 content blocks 提取 `tool_use`(id/name/input)。system 消息单独提到顶层 `system` 字段;tool 结果转成 `role:user` 的 `tool_result` block。base_url 处理 `/v1` → `/anthropic` 的适配(复刻 Python 逻辑)。流式失败时降级为非流式 `messages.create`。

### 6.3 ReAct 循环(`agent/react_loop.rs`)

```rust
messages = [system_prompt] + history + [user_task];
for it in 0..max_iterations {
    if cancel.load() { emit error("cancelled"); break; }
    let view = compact::build_view(&messages, &cfg);      // round-aware 压缩视图
    let resp = llm.chat_stream(&view, &tools_json, emitter, cancel)?;
    if resp.tool_calls.is_empty() {                        // 完成
        messages.push(assistant(resp.text));
        persist(&messages);
        emitter.done(session_id); break;
    }
    if let Some(w) = detect_stale_loop(&resp.tool_calls) { // 死循环检测
        messages.push(system(format!("[SYSTEM WARNING]: {w}")));
    }
    messages.push(assistant_with_tool_calls(resp));
    for tc in &resp.tool_calls {
        let obs = registry.execute(&tc.name, parse(tc.arguments), cancel);
        emitter.seg("observation", &preview(obs));
        messages.push(tool_result(tc.id, obs));
    }
    persist(&messages);                                    // 增量持久化
    if estimate_tokens(&messages) > trigger { compact(&mut messages); } // 上下文压缩
}
```

**完成判定**与 Python 一致:模型不再返回 tool_calls 即视为完成,其文本作为最终总结。

---

## 7. 输出事件协议(与 Android 对齐 —— 必须严格遵守)

`stream::EventSink` 产出的每一行写入回调(管道模式),格式:

| 事件 | JSON 形状 | 触发时机 |
|---|---|---|
| start | `{"type":"start","task":"..."}` | 任务开始 |
| session_created | `{"type":"session_created","session_id":"..."}` | 新建会话 |
| session_switched | `{"type":"session_switched","session_id":"..."}` | 切换会话 |
| thinking 段 | `{"type":"seg_content","seg":"thinking","content":"..."}` | reasoning 段结束 |
| thought 段 | `{"type":"seg_content","seg":"thought","content":"..."}` | 正文段结束 |
| action | `🛠️ Action: {name}\x00Action Input: {args}` (非 `{` 开头,走 token 分支) | 工具调用声明 |
| tool_progress | `{"type":"tool_progress","state":"building\|done","name":"...","chars":N}` | 参数流式累积/完成 |
| observation | `{"type":"seg_content","seg":"observation","content":"..."}` | 工具执行结果 |
| token | 原始文本行(`\n` → `\x00`) | 流式 token |
| done | `{"type":"done","session_id":"..."}` | 任务完成 |
| error | `{"type":"error","message":"..."}` | 出错 |

> 这些 `type`/`seg` 取值直接来自 Kotlin `AgentOutputParser.parseLine()` 与 Python `main_agent.py` 的 `seg_content` 输出,Rust 版逐字复刻即可零改 App 解析层。

**双模式**:
- 管道模式(Android/子进程):JSON 事件独占一行;token 行内换行用 `\x00` 转义。
- TTY 模式(桌面 CLI):直接彩色打印,不转义。
用 `is_tty`(`libc::isatty`)区分,与 Python `_is_tty` 一致。

---

## 8. 安全模型

Python 版有 2400 行 `SafetyGuard`(命令风险评估、路径限制、AST 检查、危险命令弹窗确认)。Rust 版分层处理:

- **首要防线复用 fastshell**:所有命令都在 VFS 沙箱内执行,路径逃逸已被 `Vfs::resolve` 拦截;网络访问有 `network_ask_permission` 门控。**移动端不再需要重造大部分 SafetyGuard**。
- **危险命令策略**(`config.safety.dangerous_command_action`):
  - `log`(移动端默认):记录不拦截;
  - `reject`:命中危险模式(`rm -rf /`、fork bomb、写系统路径等,用 `regex` 维护一份精简黑名单)直接拒绝;
  - `ask`:通过 fastshell 的权限回调/App 弹窗确认。
- 不移植 Python AST 安全检查(Rust 版不执行 Python 代码)。
- 秘钥安全:API key 仅存于内存/App 加密存储,日志脱敏,绝不写入 session 文件明文(沿用 Python 只存对话不存 key 的做法)。

---

## 9. 代码执行与测试策略

Agent"写完代码要能测"是核心闭环。这里区分两件**性质完全不同**的事:

- **跑 aacode 这个 Agent 框架本身**(openai/anthropic/aiohttp/pydantic + asyncio + 大量带 native 扩展的 pip 包)——又重又脆,是"Python 在安卓走不通"的真正原因,故用 Rust 重写。
- **跑用户写的代码做测试**(`python3 test.py`、`pytest` 等)——轻量得多,只要有 Python 运行时即可,无需 Agent 依赖栈。

**关键事实**:`fastshell` 已内嵌 CPython 3.12(Chaquopy 提供的 `libpython3.12.so` + 标准库 + `site-packages`)。Rust 版 aacode 自己不带 Python,但它的 `run_shell` 转发到 `Fastshell::execute()`,fastshell 的 shell 引擎会**识别 `python`/`python3` 命令并路由到内嵌 CPython 引擎执行**(`bridge/executor.rs::is_python_command`、`python/mod.rs`)。`wrap_code_with_syspath()` 已把 `python/site-packages` 注入 `sys.path`。

### 9.1 Python 测试链路(本地内嵌 CPython)

```
模型: run_shell("python3 -c 'import unittest; ...'")
  → aacode-rs tools::shell
  → fastshell Runtime.is_python_command() 识别
  → 内嵌 CPython VM 执行 → stdout/stderr/exit_code 回传给模型
  → 模型据 returncode 判断通过与否,决定是否继续修复
```

语法快检同理:`run_shell("python3 -c 'import ast; ast.parse(open(\"x.py\").read())'")`。

### 9.2 fastshell 前置依赖(必须补齐,否则 Python 测试不闭环)⚠️

审阅 `bridge/executor.rs` 后发现**当前内嵌 CPython 仅稳妥支持 `python -c "内联代码"`**,以下常用形式尚不支持,需在 **fastshell 侧**补齐(属 fastshell 能力,非 aacode-rs):

| 命令形式 | 现状 | 需要的改动 |
|---|---|---|
| `python3 -c "code"` | ✅ 正确路由到 `execute()` | —— |
| `python3 test.py [args]` | ❌ 整串被当作 Python 源码 → SyntaxError | `extract_python_code` 增加脚本分支 → 路由到 `execute_script`(该函数已存在可用)|
| `python -m pytest` / `-m unittest` | ❌ `is_python_command` 不识别 `-m` 语义 | 支持 `python -m <module> [args]` |
| 裸 `pytest` / `pytest tests/` | ❌ 走 shell fallthrough,找不到命令 | 可选:rewrite 成 `python -m pytest`;或注册为内嵌入口 |

> `execute_python_script(script_path, cwd)` 在 `python/mod.rs:396`、`bridge/executor.rs:444` 已实现且可用,补齐主要是 `is_python_command` / `extract_python_code` 的分派逻辑。

**aacode-rs 侧的配合**(在 fastshell 增强落地前的兜底):系统提示词引导模型优先用**已确认可用的调用形式**(如 `python3 -c "..."` 内联,或 `execute_script` 对应形式)跑测试;并把上述 fastshell 增强列为**本项目的硬依赖项**,随 aacode-rs 一并推进。

### 9.3 能力边界

| 场景 | 手机本地能否测 | 说明 |
|---|---|---|
| 纯 Python + 标准库 | ✅ | 内嵌 CPython 直接跑 |
| 带 native 扩展的 pip 包(numpy/pandas…) | ⚠️ | 需预置对应 Android ABI 的 wheel 到 `site-packages`,否则 import 失败 |
| Shell 脚本 / fastshell 180+ 命令可验证的 | ✅ | fastshell 原生执行 |
| 语法/静态检查(任意语言) | ✅ | `ast.parse`、lint 等不需运行时 |
| Node / Go / Rust / C / Java 等 | ❌ | 手机上无对应运行时,见 §9.5 远程扩展点 |
| 重型/长时/需 GPU 的测试 | ❌ | 受手机 CPU/内存限制,见 §9.5 |

### 9.4 分层测试策略(Agent 提示词与工具引导)

1. **静态校验优先**:语法解析(CPython `ast`)、lint —— 最稳、零运行时依赖。
2. **内嵌 CPython 执行**:Python 单测(stdlib + 已打包 wheel)。
3. **fastshell shell 级验证**:文件存在性、grep、diff、git 状态等。
4. **兜底**:本地跑不动的 → 走 §9.5。

### 9.5 远程执行扩展点(其他语言 / 重型测试)

对于手机本地无法执行的场景(其它语言运行时、重型/长时测试),提供**远程执行扩展点**(本次为可选/预留接口,非强依赖):

- **git commit & push → 远程 CI**:复用 AACodeApp 已有的 Git 能力(`ChangesScreen` 的 commit & push),把代码推到远端仓库触发 CI,回读 CI 状态/日志作为测试结果。
- **远程执行沙箱**:可选接一个服务端沙箱 API(发送代码/测试命令 → 服务端执行 → 回传 stdout/stderr/exit_code),作为 `run_shell` 的旁路工具(如 `run_remote`)。这也是手机端 coding agent 的通用做法。
- 设计上以 `tools::` 下新增工具的形式接入,不影响本地执行主链路;具体后端 URL/鉴权走配置下发。

---

## 10. 配置与初始化

### 10.1 配置来源优先级
`taskJson 内联配置 > 环境变量 > 沙箱内 aacode_config.json > 默认值`

### 10.2 `aacode_task_start` 的 taskJson 结构(示意)
```json
{
  "task": "给登录表单加输入校验",
  "project_path": "/sandbox/projects/demo",
  "session_id": "session_2026...",        // 可选,续接会话
  "model": {
    "name": "deepseek-chat",
    "api_key": "sk-...",
    "base_url": "https://api.deepseek.com/v1",
    "gateway": "openai",
    "temperature": 0.1,
    "max_tokens": 8192
  },
  "max_iterations": 30,
  "plan_first": false,                      // 可选,Plan-first 模式
  "search": { "searxng_url": "https://..." },
  "multimodal": {                           // 可选,vision 模型配置
    "name": "kimi-k2.5", "api_key": "...", "base_url": "https://api.moonshot.cn/v1"
  }
}
```

### 10.3 AgentConfig(`config.rs`)
移植 Python `ModelConfig` 的 base_url 自动推断(deepseek/kimi/minimax/claude/gpt → 对应端点与 gateway),字段:`name/api_key/base_url/gateway/temperature/max_tokens/multimodal`;并含 `max_react_iterations`、`timeouts`、`limits`、`safety`、`context`、`skills`、`mcp`、`multimodal` 各分区(对齐 Python `config.py` 全部分区)。

---

## 11. FFI / JNI 接口设计

### 11.1 C ABI(`aacode-rs/src/ffi.rs`,句柄式 + userdata 回调)
```c
typedef void (*aacode_event_fn)(const char* line, void* userdata);

void* aacode_task_start(const char* task_json, aacode_event_fn cb, void* userdata); // 非阻塞,返回句柄
char* aacode_task_wait(void* handle);   // 阻塞到结束,返回终态 JSON
void  aacode_task_cancel(void* handle); // 非阻塞,按句柄取消
void  aacode_task_free(void* handle);
char* aacode_validate_api_key(const char* config_json);
char* aacode_list_sessions(const char* project_path);
char* aacode_get_session_messages(const char* project_path, const char* session_id);
void  aacode_free_string(char* ptr);
```
> 设计要点:**句柄**代替字符串取消(`client_task_id` 已移除)、**userdata** 回调上下文
> (消除 TLS/全局 trampoline)、**单一事件流**(早退失败也发 `error` 事件,终态为富化
> `done`,见 §7)。事件从共享 `TOKIO_RT` 的 worker 线程发出(非调用线程)。
> `fastshell_init` 仍由 App 先调用完成 VFS/沙箱初始化;`aacode_task_start` 内部拿到同一个
> 沙箱路径构造 `Fastshell`。

### 11.2 JNI 层(`fastshell_c/jni_glue.c`)
`nativeAgentRunTaskWithCallback(json, cb) -> jlong`(start)、`nativeAgentWaitTask`(wait)、
`nativeAgentCancelTask(handle)`(cancel)、`nativeAgentFreeTask(handle)`(free)。流式回调用
每任务 `jni_cb_ctx`(GlobalRef + methodID)作 userdata,`event_trampoline` 经 `get_env` 按线程
attach 后转发 `onChunk`;handle→ctx 注册表 `g_agent_tasks` 在 free 时释放 GlobalRef。

### 11.3 App 侧改动(最小化)
- `Sdk.kt` / `NativeFFI.swift` 增加对应声明;
- `AgentBridge` 改为 `start → wait → free`,取消按句柄;`AgentOutputParser` **不变**
  (`done` 富化字段向后兼容,`ignoreUnknownKeys` 丢弃多余字段);
- 构建脚本产物名与 `-p` 目标见 §12。

---

## 12. 构建与集成

1. 根 `Cargo.toml`:`members = ["fastshell", "aacode-rs"]`。
2. `aacode-rs/Cargo.toml`:`name = "aacode-rs"`,依赖 `fastshell`(path),复用树内 `ureq`/`serde`/`regex`/`uuid`/`base64`;如需异步再评估 `reqwest`。`crate-type=["lib","staticlib","cdylib"]`。
3. 桌面验证:`cargo build -p aacode-rs`;`cargo run -p aacode-rs --bin aacode -- -p ./demo "写个 hello"`。
4. 安卓:`cargo build --release -p aacode-rs --target aarch64-linux-android --lib` → `libaacode_rs.a` → `c_dist/arm64-v8a/`。
5. `fastshell_c/CMakeLists.txt`:`FASTSHELL_A` 指向 `libaacode_rs.a`(或并列链接);`jni_glue.c` 增加 aacode JNI 方法。
6. `AACodeApp/build.sh`:`-p fastshell` → `-p aacode-rs`,产物拷贝名同步。
7. `release` profile 已含 `lto/codegen-units=1/strip`,控制体积。

---

## 13. 实现顺序(一次性完整交付的内部构建次序)

**功能不分期,全部实现**;下表仅为工程上"由底向上"的搭建次序,用于组织开发与联调,最终交付包含全部功能。

| 次序 | 模块 | 说明 |
|---|---|---|
| 1 | 骨架 | crate + Cargo.toml + lib.rs + `config` + `error` + `stream` 协议 |
| 2 | LLM 层 | `llm/sse` + `llm/openai` + `llm/anthropic` + 网关分发 + base_url 推断 |
| 3 | 工具基座 | `tools/schema` + `tools/registry` + `tools/shell`(对接 fastshell) |
| 4 | 会话/上下文 | `session` + `context` + `agent/compact` |
| 5 | Agent 循环 | `agent/react_loop` + `agent/main_agent` + `agent/prompts` + `agent/sub_agent` |
| 6 | 完整工具 | `tools/{web,todo,session_tools,skills,mcp,multimodal,delegate}` + `mcp` |
| 7 | 平台入口 | `bin/aacode`(CLI)+ `ffi.rs`(C ABI) |
| 8 | 安卓联调 | `jni_glue.c` 扩展 + `CMakeLists`/`build.sh` 调整 + App AgentBridge 切换 |
| 9 | 测试固化 | 单元 + 协议一致性 + 集成 + FFI + 真机冒烟(见 §14) |

---

## 14. 测试要点(Testing Strategy)

### 14.1 单元测试(`#[cfg(test)]`,纯 Rust,无网络)
- **SSE 解析**:喂入录制的 OpenAI/Anthropic SSE 字节流,断言 `LlmResponse.text/tool_calls/reasoning/finish_reason` 正确;覆盖 tool_calls 分片累积、`[DONE]`、截断。
- **工具注册/校验**:别名归一化(`cmd→command`)、必填缺失错误消息、类型错误、未知工具相似建议。
- **Schema 转换**:`to_openai_tools`/`to_anthropic_tools` 生成的 JSON 结构(type/function/parameters、required)。
- **run_shell 转发**:mock/真实 `Fastshell`,断言返回 JSON 含 returncode/stdout;超长归档到 `extracts/` 且返回预览。
- **Python 执行/测试链路**:通过 `run_shell` 跑 `python3 -c "print(1+1)"` 断言 stdout;跑抛异常代码断言非零 returncode;(fastshell 增强落地后)`python3 test.py` 与 `python -m pytest` 的返回码与输出。
- **Session 持久化**:创建/追加/读取/多轮衔接;原子写(中断不损坏);索引合并;旧格式兼容。
- **Todo**:add 返回 id、mark by id、summary 统计、markdown 往返。
- **配置**:env > json > 默认;base_url 自动推断各模型分支。
- **上下文压缩**:round 拆分不切断 tool_calls/tool 配对;compact view token 下降;保护首轮 + 最近 N 轮 user。
- **完成判定**:无 tool_calls → done;有 → 继续。

### 14.2 流式协议一致性测试(关键!保护 App 契约)
- 用 `EventSink` 的测试实现收集所有输出行,断言:
  - 每个 JSON 事件独占一行、字段与 §7 表格逐字一致;
  - token 行内 `\n` 被 `\x00` 转义(管道模式)、TTY 模式不转义;
  - 事件顺序:start → (thinking/thought/tool_progress/action/observation)* → done。
- 可加一个"契约快照"测试:固定输入下生成的 JSONL 与预期快照比对(对齐 Kotlin `AgentOutputParser` 的 golden case)。

### 14.3 集成测试
- **Mock LLM server**:起一个本地 HTTP(`std::net::TcpListener` 或 `tiny_http`)返回预设 SSE,跑完整 ReAct 一轮(含一次 run_shell),断言 session 文件与事件流。
- **端到端(真实 API,标 `#[ignore]`)**:设 `LLM_API_KEY` 后手动跑,验证 DeepSeek 真实返回。
- **取消测试**:长命令中途 `aacode_task_cancel`,断言循环退出并 emit `error("cancelled")`。
- **Python 编码任务闭环(真实 API,标 `#[ignore]`)**:给 Agent "写一个函数并写 unittest 跑通"的任务,验证写码 → `run_shell` 跑测 → 据结果修复 → 完成的完整链路。

### 14.4 安卓/FFI 测试
- C ABI round-trip:`aacode_task_wait` 返回字符串可被 `aacode_free_string` 释放,无泄漏(valgrind/asan 桌面侧)。
- 句柄生命周期:start/wait/cancel/free、早退错误事件、userdata 上下文回传、多句柄并发、同 session 拒绝(`tests/concurrency.rs` + `ffi.rs` 单测)。
- 回调线程安全:事件从 tokio worker 线程 emit、宿主线程取消,无数据竞争。
- 真机冒烟:安装后跑一条简单任务,观察 UI 是否正确渲染 thinking/observation/done;真机验证内嵌 RustPython 能跑 `python3 -c` 与脚本测试。

### 14.5 性能/体积
- `libaacode_rs.a` 体积对比、link 后 `.so` 体积;
- 冷启动到首个 token 延迟;
- 单轮迭代内存占用(对齐 fastshell ≤30MB 目标)。

---

## 15. 风险与开放问题

1. **HTTP 客户端选型**:`ureq`(同步、体积小、已在树)vs `reqwest`(异步、生态好、体积大)。默认用 ureq + 手写 SSE;若并发/性能不足再切 reqwest。**待定**。
2. **TLS 证书**:Android 上 rustls 的根证书来源(`webpki-roots` 已在树);需验证真机 TLS 握手。
3. **tiktoken 不移植**:token 计数用字符估算(4:1),压缩阈值需据此调参,可能与 Python 略有偏差 —— 可接受。
4. **危险命令确认(ask 模式)**:移动端交互式确认需 App 弹窗回调;无回调时回退 `log` 策略。
5. **run_skills / MCP / 多模态依赖**:`run_skills` 因不内嵌 Python 采用文档型 skill(返回指令由模型借 `run_shell` 执行);MCP 需 stdio/sse 传输实现;多模态需 vision API 配置。三者均在本次范围内实现,但对运行环境有额外要求(网络、外部 MCP server、vision 模型)。
6. **fastshell 单例 vs 多实例**:`aacode_task_start` 是否复用 `fastshell` 的全局单例,需与 `fastshell_init` 的调用时序协调(当前:App 先 `fastshell_init`,aacode 复用同沙箱 vfs_root,每任务另建独立 Fastshell 实例)。
7. **产物改名影响**:`libfastshell.a` → `libaacode_rs.a` 影响 App 构建与 CI,需同步文档与脚本(或方案 B 保持原符号)。

---

## 16. 附:与 Python 版的功能映射速查(全部实现)

| Python | Rust (aacode-rs) |
|---|---|
| `main.py / AICoder` | `bin/aacode.rs` + `agent::MainAgent` |
| `core/main_agent.py` 模型调用器 | `llm::{openai,anthropic}` + `agent::main_agent` |
| `core/react_loop.py` | `agent::react_loop` + `agent::compact` |
| `core/prompts.py` | `agent::prompts` |
| `core/sub_agent.py` / `multi_agent.py` | `agent::sub_agent` + `tools::delegate` |
| `tools/atomic_tools.py` run_shell | `tools::shell`(→ fastshell) |
| `tools/web_tools.py` | `tools::web` |
| `tools/todo_tools.py` | `tools::todo` |
| `tools/skills_tools.py` | `tools::skills` |
| `tools/multimodal_tools.py` | `tools::multimodal` |
| `utils/mcp_manager.py` + `sandbox/mcp_client.py` | `mcp` + `tools::mcp` |
| `utils/tool_registry.py` | `tools::registry` |
| `utils/tool_schemas.py` | `tools::schema` |
| `utils/tool_adapter.py` | `tools::schema::to_*_tools` |
| `utils/session_manager.py` | `session` |
| `utils/context_manager.py` + `class_method_mapper.py` | `context` |
| `utils/todo_manager.py` | `tools::todo`(markdown 读写) |
| `utils/message_utils.py` | `agent::compact` |
| `utils/safety.py` | 复用 fastshell + `config::safety` 精简黑名单 |
| `server/runner.py` 流式事件 | `stream::EventSink` + `ffi` |
| `config.py` | `config` |
| 会话管理工具(new/continue/...) | `tools::session_tools` |