# nanoPencil 当前架构优化方案

---

## 一、当前架构现状评估

### 1.1 整体结构

当前项目采用 monorepo 结构，顶层为 nanoPencil 主包，`packages/` 下有 7 个子包：

| 包 | 职责 | 状态 |
|---|---|---|
| `agent-core` | Agent 循环、状态管理、工具执行 | 稳定 |
| `ai` | 统一 LLM API、多 Provider 适配 | 稳定 |
| `tui` | 终端 UI 渲染 | 稳定 |
| `nano-mem` | 持久记忆引擎 | 稳定 |
| `soul` / `nanosoul` / `agent-soul` | AI 人格进化引擎 | 三包并存，职责重叠 |

主包内部分为：`core/`（核心逻辑）、`modes/`（运行模式）、`extensions/`（内置扩展）、`cli/`（CLI 辅助）、`utils/`（工具函数）。

### 1.2 核心枢纽：AgentSession

`agent-session.ts` 是全系统最重的模块，直接依赖 15+ 个内部模块：

- compaction、extensions（loader/runner/wrapper）、model-registry、session-manager、settings-manager
- bash-executor、tools/*、soul-integration、system-prompt、prompt-templates、messages、resource-loader
- config、theme、utils/frontmatter、utils/sleep

**问题**：AgentSession 承担了"会话管理 + 模型切换 + 工具编排 + compaction 协调 + 扩展绑定 + Soul 集成 + HTML 导出"等过多职责，是一个典型的 God Object。

### 1.3 扩展系统

扩展系统设计较为完善，包含：
- 丰富的事件类型（20+ 种，覆盖会话、Agent、工具、模型、输入等全生命周期）
- 工具注册、命令注册、快捷键注册、CLI 标志注册
- Provider 注册（扩展可以注册新的 LLM Provider）
- UI 抽象层（`ExtensionUIContext`），支持三种运行模式

当前已实现的内置扩展：

| 扩展 | 位置 | 功能 |
|---|---|---|
| link-world | `extensions/link-world/` | 联网搜索 skill + agent-reach 安装 |
| simplify | `extensions/simplify/` | 基于 Git diff 的代码简化/重构 |
| security-audit | `extensions/security-audit/` | 审计日志、危险模式检测、可选拦截 |
| nano-mem | `packages/nano-mem/` | 持久记忆（独立包，通过扩展接口集成） |

### 1.4 运行模式

三种模式（Interactive / Print / RPC）共享同一 `AgentSession`，仅 I/O 层不同：

- Interactive：完整 TUI + 完整 `uiContext`
- Print：stdout/stdin，无 `uiContext`（使用 noOp 占位）
- RPC：JSON 协议，`uiContext` 通过 RPC 桥接到宿主

这一设计是合理的，核心与 I/O 分离较好。

---

## 二、问题诊断

按照 `架构演进.md` 中"最小核心、最大扩展性"的原则，对当前架构进行逐项诊断。

### 问题 1：AgentSession 职责过重

**现象**：AgentSession 直接管理了会话生命周期、模型切换、工具编排、compaction 协调、扩展绑定、Soul 集成、HTML 导出等全部功能。

**风险**：
- 任何子系统的修改都可能波及 AgentSession
- 难以单独测试某一子系统
- 新开发者理解成本高

**建议**：将 AgentSession 拆分为多个"协调者"：
- `AgentSession` 只保留会话生命周期和事件协调
- 将 compaction 编排逻辑收敛到 `CompactionCoordinator`
- 将工具编排逻辑收敛到 `ToolOrchestrator`
- 将模型切换逻辑收敛到 `ModelSwitcher`
- AgentSession 持有这些协调者的引用，委托调用

### 问题 2：Soul 相关包三重冗余

**现象**：`packages/` 下存在 `soul`、`nanosoul`、`agent-soul` 三个包，职责高度重叠（均为"AI 人格进化引擎"）。

**风险**：
- 维护成本翻倍
- 使用者和贡献者困惑（该用哪个？）
- 构建和依赖链条冗余

**建议**：统一为一个包（建议保留 `@pencil-agent/soul`），废弃其余两个，提供明确的迁移路径。

### 问题 3：Soul 集成硬编码在 Core

**现象**：`core/soul-integration.ts` 将 Soul 的初始化、system prompt 注入、会话结束时的人格更新等逻辑直接放在核心层。`sdk.ts` 中也有专门的 Soul 初始化分支。

**按照演进文档判定**：
- 必需性？→ 否（不是所有用户都需要人格系统）
- 紧密耦合？→ 中等（主要是往 system prompt 注入内容 + 会话结束时回调）
- 外部依赖？→ 是（依赖 soul 包）
- 用户比例 < 50%？→ 很可能

**结论**：Soul 应该作为**默认扩展**存在，而非核心模块。可通过现有扩展事件（`before_agent_start` 注入 prompt、`agent_end` 回调更新）完整实现。

### 问题 4：pencil-mem-integration 的定位模糊

**现象**：`pencil-mem-integration.ts` 的实际职责仅是"返回内置扩展路径列表"（nano-mem、simplify、link-world、security-audit），文件名暗示仅与 nanomem 相关，但实际管理了所有内置扩展路径。

**建议**：
- 重命名为 `builtin-extensions.ts`（或 `default-extension-paths.ts`），使职责与命名一致
- 将内置扩展路径管理从硬编码改为声明式配置（如 `builtin-extensions.json`），便于增删

### 问题 5：system-prompt 中工具描述硬编码

**现象**：`core/system-prompt.ts` 中对 read、bash、edit、write、grep、find、ls 等工具的使用指南直接以字符串拼接在系统提示中。

**风险**：
- 新增工具时必须修改 system-prompt.ts
- 不支持多语言或可配置
- 工具定义和工具指南分散在两个地方（`tools/*.ts` + `system-prompt.ts`）

**建议**：
- 工具注册时同时携带 `guidance` 字段（使用指南）
- system-prompt 的工具指南部分改为动态聚合已注册工具的 guidance
- 或将工具指南抽到独立的配置文件 / prompt 模板中

### 问题 6：MCP 模块的归属

**现象**：`core/mcp/` 包含 MCP 客户端、配置、适配器、指南，`core/mcp-manager.ts` 管理 MCP 工具。

**按照演进文档判定**：
- MCP 是外部协议集成，依赖外部服务
- 不是所有用户都使用 MCP
- 存在可替换性（不同 MCP 服务器）

**但**：当前 MCP 已深度集成到 `sdk.ts` 的启动流程和 `AgentSession` 的工具管理中。

**建议**：短期保持在 core 中（因为已深度耦合），中期将 MCP 抽象为"工具源"接口，使 MCP 成为"工具源"的一种实现，可以与扩展提供的工具源并列。这样 MCP 的具体实现可以逐步迁移到扩展层，core 只保留"工具源"抽象。

### 问题 7：utils/ 缺乏归属

**现象**：`utils/` 目录下 13 个文件，涵盖 clipboard、git、image、mime、shell、sleep、tools-manager 等，部分被 core 依赖，部分被 modes 依赖，部分被扩展依赖。

**风险**：
- 没有清晰的依赖方向（谁可以用 utils？）
- git.ts、clipboard*.ts 等是场景特定的，不应视为通用工具

**建议**：
- 将 core 必需的（shell、sleep、tools-manager）移入 `core/utils/`
- 将 modes 专用的（clipboard、image 相关）移入 `modes/utils/`
- 将独立通用的（mime、frontmatter）保留在顶层 `utils/`

### 问题 8：export-html 放在 core 中

**现象**：`core/export-html/` 包含 HTML 模板、CSS、JS、ANSI 转换、vendor 依赖等，体积较大。

**按照演进文档判定**：
- 必需性？→ 否（仅 `/export` 命令触发）
- 紧密耦合？→ 低（只需读取会话消息）
- 外部依赖？→ 含 vendor（highlight.min.js）

**建议**：迁移为内置扩展或独立工具包。通过扩展的 `commands` 机制注册 `/export` 命令。

### 问题 9：扩展目录结构不够清晰

**现象**：当前 `extensions/` 下的三个扩展（link-world、simplify、security-audit）平铺在一起，没有"默认扩展 vs 可选扩展"的区分。`packages/nano-mem` 虽然也是扩展，但放在 packages 下作为独立包。

**建议**：统一归类：
- `extensions/defaults/`：默认启用的扩展（nano-mem、link-world、security-audit）
- `extensions/optional/`：可选扩展（simplify 等）
- 或者至少在 `pencil-mem-integration.ts`（建议重命名后的 `builtin-extensions.ts`）中明确标注每个扩展是否默认启用

---

## 三、优化路径（按优先级排序）

### 第一优先级：消除冗余、澄清命名

| 项目 | 动作 | 影响范围 |
|---|---|---|
| Soul 三包合一 | 保留 `@pencil-agent/soul`，废弃 `nanosoul`、`agent-soul` | packages/ |
| pencil-mem-integration 重命名 | 重命名为 `builtin-extensions.ts`，清晰反映"内置扩展路径管理"职责 | 根目录 |
| nanopencil-defaults.ts 职责收窄 | 只负责"nanoPencil 产品默认配置"（模型列表、首次配置引导），不涉及扩展路径 | 根目录 |

### 第二优先级：Soul 迁移至扩展层

| 项目 | 动作 | 影响范围 |
|---|---|---|
| soul-integration → 扩展 | 将 `core/soul-integration.ts` 的逻辑改写为标准扩展，利用 `before_agent_start`（注入 prompt）和 `agent_end`（人格更新）事件 | core/、extensions/ |
| sdk.ts 简化 | 移除 sdk.ts 中 Soul 相关的初始化分支 | core/sdk.ts |
| 配置开关保留 | 在 settings 中保留 `disable-soul` 开关，但实现方式变为"是否加载 Soul 扩展" | settings |

### 第三优先级：AgentSession 职责拆分

| 项目 | 动作 | 影响范围 |
|---|---|---|
| 抽取 CompactionCoordinator | 将 compaction 的触发判断、执行、结果处理封装为独立协调者 | core/ |
| 抽取 ToolOrchestrator | 将工具注册、查找、执行、包装（扩展 hook）封装为独立协调者 | core/ |
| 抽取 ModelSwitcher | 将模型切换、cycling、fallback 逻辑封装为独立协调者 | core/ |
| AgentSession 瘦身 | AgentSession 只保留生命周期管理、事件协调、对外 API | core/ |

### 第四优先级：system-prompt 动态化

| 项目 | 动作 | 影响范围 |
|---|---|---|
| 工具 guidance 机制 | 工具注册时携带 `guidance` 字段 | core/tools/ |
| system-prompt 聚合 | system-prompt 构建时动态收集已注册工具的 guidance，不再硬编码 | core/system-prompt.ts |
| 扩展工具的 guidance | 扩展注册的工具也可以携带 guidance，统一参与 system-prompt 构建 | core/extensions/ |

### 第五优先级：export-html 迁移

| 项目 | 动作 | 影响范围 |
|---|---|---|
| export-html → 扩展 | 将 `core/export-html/` 改写为内置扩展，通过 `commands` 注册 `/export` | core/、extensions/ |
| AgentSession 移除导出逻辑 | AgentSession 中的 `exportToHtml` 方法改为由扩展实现 | core/agent-session.ts |

### 第六优先级：MCP 抽象化

| 项目 | 动作 | 影响范围 |
|---|---|---|
| 定义 ToolSource 接口 | 抽象"工具来源"概念，内置工具、MCP 工具、扩展工具都是 ToolSource | core/ |
| MCP 实现 ToolSource | `core/mcp/` 实现 ToolSource 接口 | core/mcp/ |
| sdk.ts 统一工具注册 | sdk.ts 中通过 ToolSource 统一注册所有来源的工具 | core/sdk.ts |

### 第七优先级：utils 归类

| 项目 | 动作 | 影响范围 |
|---|---|---|
| core 专用 utils | shell、sleep、tools-manager → `core/utils/` | core/、utils/ |
| modes 专用 utils | clipboard*、image* → `modes/utils/` | modes/、utils/ |
| 通用 utils 保留 | mime、frontmatter 保留在 `utils/` | - |

---

## 四、优化后目标结构（概览）

### 4.1 设计原则

- **最小内核**：`core/runtime/` 只保留 agent-session、event-bus、sdk 三个文件，这是不可再分的运行时内核
- **领域子模块**：`core/` 内部按领域划分子目录（tools/、model/、session/、config/、prompt/、extensions/），消除平铺混杂
- **外置大脑**：Soul / Memory 等高级能力以 `*-core + extension adapter` 双层接入，不进入 core/
- **MCP 外移**：MCP 作为外部协议适配，从 core/ 迁出至扩展层

### 4.2 目录结构

```
nanoPencil/
├── cli.ts                          # CLI 入口
├── main.ts                         # 主入口
├── index.ts                        # SDK 导出
├── config.ts                       # 路径配置
├── nanopencil-defaults.ts          # 产品默认模型/配置
├── builtin-extensions.ts           # 内置扩展注册表（manifest + 路径解析）
│
├── core/
│   ├── runtime/                    # 运行时内核（最小不可分割单元）
│   │   ├── agent-session.ts        # 会话生命周期 + 事件协调 + 对外 API
│   │   ├── event-bus.ts            # 事件总线
│   │   └── sdk.ts                  # 引导启动（工厂函数）
│   │
│   ├── extensions/                 # 扩展运行时
│   │   ├── loader.ts
│   │   ├── runner.ts
│   │   ├── types.ts
│   │   └── wrapper.ts
│   │
│   ├── tools/                      # 工具框架 + 内置工具
│   │   ├── orchestrator.ts         # [新] 工具编排 + ToolSource 接口
│   │   ├── bash.ts                 # 内置工具
│   │   ├── bash-executor.ts        # bash 执行引擎
│   │   ├── read.ts, write.ts, edit.ts, grep.ts, find.ts, ls.ts
│   │   └── truncate.ts
│   │
│   ├── model/                      # 模型管理
│   │   ├── registry.ts             # 模型注册表
│   │   ├── switcher.ts             # [新] 切换 + fallback
│   │   └── resolver.ts             # 模型解析
│   │
│   ├── session/                    # 会话持久化 + 上下文管理
│   │   ├── manager.ts              # 会话持久化
│   │   ├── compaction-coordinator.ts  # [新] compaction 编排
│   │   └── compaction/             # compaction 算法
│   │
│   ├── config/                     # 配置基础设施
│   │   ├── settings-manager.ts
│   │   ├── auth-storage.ts
│   │   └── resource-loader.ts
│   │
│   └── prompt/                     # Prompt 构建
│       └── system-prompt.ts        # 动态聚合工具 guidance
│
├── modes/
│   ├── interactive/                # 不变
│   ├── print-mode.ts               # 不变
│   ├── rpc/                        # 不变
│   └── utils/                      # [新] 从顶层 utils 迁入 modes 专用部分
│
├── extensions/
│   ├── defaults/                   # 默认扩展（默认启用）
│   │   ├── nano-mem/               # 记忆扩展适配层（外置大脑入口）
│   │   ├── soul/                   # 人格扩展适配层（外置大脑入口）
│   │   ├── link-world/             # 联网搜索
│   │   ├── security-audit/         # 安全审计
│   │   └── mcp/                    # [新] MCP 协议适配（从 core/mcp/ 迁出）
│   ├── optional/                   # 可选扩展
│   │   ├── simplify/               # 代码简化
│   │   └── export-html/            # [新] HTML 导出
│
├── packages/
│   ├── agent-core/                 # 不变
│   ├── ai/                         # 不变
│   ├── tui/                        # 不变
│   ├── mem-core/                   # 记忆核心库（算法/存储/管理器，宿主无关）
│   └── soul-core/                  # Soul 核心库（演化/注入/管理器，宿主无关）
│
├── cli/                            # 不变
├── utils/                          # 瘦身后：仅保留通用工具
└── docs/
```

### 4.3 core/ 子域职责一览

| 子域 | 文件数 | 职责 | 变更频率 |
|------|--------|------|----------|
| `runtime/` | 3 | 会话生命周期、事件总线、引导启动 | 极低（内核稳定后几乎不改） |
| `extensions/` | 4 | 扩展加载、运行、类型、包装 | 低 |
| `tools/` | ~10 | 工具编排框架 + 内置工具实现 | 中（新增工具时扩展） |
| `model/` | 3 | 模型注册、切换、解析 | 低 |
| `session/` | 3+子目录 | 会话持久化、compaction | 低 |
| `config/` | 3 | 配置、认证、资源加载 | 低 |
| `prompt/` | 1 | system prompt 动态构建 | 低 |

打开 `core/` 后看到 7 个子域目录（而非 19 个混杂条目），新人可在 5 秒内定位要改的领域。

### 4.4 分层依赖规则

```
core/ 不直接 import → packages/mem-core、packages/soul-core
core/ 不直接 import → extensions/*
extensions/* 可以 import → packages/*-core
builtin-extensions.ts 只做 manifest，不写业务桥接
```

**明确禁止**：
- `core/` 直接依赖 `mem-core`、`soul-core` 等高级能力库
- `builtin-extensions.ts` 实现 Soul / Memory / 未来 `xxx-core` 的具体集成逻辑
- 将高级能力重新塞回 `core/`，破坏"最小核心、最大扩展性"

---

## 五、优化效果预期

### 核心瘦身

- `core/` 一级条目从 19 个（13 文件 + 6 目录）降至 7 个子域目录，零平铺文件
- 运行时内核 `core/runtime/` 仅 3 个文件（agent-session、event-bus、sdk）
- soul-integration、export-html、mcp/ 全部迁出 core/
- AgentSession 的直接依赖从 15+ 降至 ≤ 8
- sdk.ts 启动流程简化（移除 Soul 分支）

### 扩展能力增强

- Soul / Memory 以标准扩展运行，采用 `*-core + extension adapter` 双层接入
- HTML 导出以扩展运行，可由社区增强（如支持 PDF、Markdown 导出）
- MCP 迁至扩展层，通过 ToolSource 接口与核心对接
- 工具 guidance 机制使扩展工具获得与内置工具同等的 system prompt 待遇

### 维护性改善

- core/ 按领域子模块划分，新人可在 5 秒内定位要改的领域
- 职责边界清晰，每个子域独立演进、独立测试
- Soul 三包合一，消除维护困惑
- utils 归类后依赖方向明确

### 对现有用户的影响

- 所有优化对终端用户透明（不改变 CLI 接口、不改变配置格式）
- 扩展 API 向后兼容（事件类型、注册接口不变）
- 功能不做任何删减，仅调整内部归属

---

## 六、风险与注意事项

1. **AgentSession 拆分是最大风险项**：涉及面广，建议最后执行，且需要充分的集成测试覆盖。
2. **Soul 迁移为扩展**：需确保扩展 API 能完整支持 Soul 当前的所有行为（prompt 注入、会话结束回调、配置读写）。如有缺口，优先补全扩展 API，再执行迁移。
3. **export-html 迁移**：需确保扩展可以访问完整的会话消息历史。当前 `ExtensionContext` 中已有 `sessionManager`，理论上可行。
4. **system-prompt 动态化**：需注意 prompt 长度预算管理，动态聚合时应有截断/优先级策略。
5. **所有优化应逐步推进**：每完成一项后验证功能完整性，再进入下一项。避免一次性大重构。

---

## 七、与架构演进文档的对照

| 演进文档原则 | 本优化方案的落实 |
|---|---|
| 最小核心 | core/ 按子域拆分，runtime/ 仅 3 文件；Soul、export-html、MCP 迁出 core/ |
| 最大扩展性 | Soul/Memory 采用 `*-core + extension adapter` 双层接入；ToolSource 抽象统一工具来源 |
| 外置大脑 | Soul/Memory 始终以 extension 形态接入，packages/*-core 保持宿主无关 |
| 自我进化轨道 | 扩展层能力增强后，为后续 `self_edit` / `self_eval` 工具提供更干净的实现基础 |
| 安全写入边界 | AgentSession 瘦身后，"核心不可由 Agent 修改的区域"边界更清晰 |
| 可观测性 | ToolOrchestrator 统一管理工具执行，便于后续增加结构化日志 |

---

*本文档应与 `架构演进.md` 配合阅读，前者定义原则与方向，本文档定义当前状态到目标状态的具体路径。*
