# 7-40 Page AI MNote skill library and context tool contract v1

> 创建时间：2026-05-29
>
> 状态：`done`
>
> Owner：Page AI skill/tool capability surface + MNote host-side context provider
>
> 上位依据：
> - `design/07-ai/done/7-39-page-ai-agent-selector-context-authorization-settings-v1.md`
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
> - `design/07-ai/process/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
> - `design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
> - `design/07-ai/reference/7-12-page-ai-hermes-tool-routing-and-review-surface-v1.md`
>
> 参考代码：
> - `reference-code/PilotDeck/src/context/prompt/PromptAssembler.ts`
> - `reference-code/PilotDeck/src/context/extension/ExtensionResolver.ts`
> - `reference-code/PilotDeck/src/tool/builtin/readSkill.ts`
> - `reference-code/PilotDeck/src/context/input/InputProcessor.ts`
>
> 关键口径：Hermes 和 Reasonix 本身已经是完整 agent，拥有自己的记忆、会话隔离、agent loop、工具调度和运行时状态。MNote 不建设第三套 agent runtime，不把 MNote 上下文、工具说明或页面正文强行注入每条用户 prompt。MNote 要提供一个专用 skill library 和结构化 context tools，让 agent 在需要时自行选择读取。

## 1. 背景与问题

`7-39` 已经完成第一轮 Page AI UI 收口：

- `sidebar-page-ai-runtime.js` 已有 `PAGE_AI_AGENT_REGISTRY`。
- `PAGE_AI_CONTEXT_REF_REGISTRY` 已包含 `current_page / selection / active_editor / file / folder / changed_files`。
- 发送 `/api/hermes/client/runs` 时 payload 已包含 `agentId`、`contextRefs`、`allowedRoots`、`editorTarget`、`runTargetSnapshot`。
- SQLite directory grants 和 user preferences 已作为授权与偏好控制面。

但当前暴露出一个更关键的系统问题：

1. 简单聊天请求，例如“收到请回复收到”，仍可能触发大量 `mnote_doc_fetch` 等工具调用。
2. 当前实现倾向把 MNote page context、tool guidance、runTargetSnapshot 等内容拼成大段 instructions 注入上游 prompt。
3. 这种方式会诱导 agent 把所有请求都理解成 MNote 文档任务，也会增加 token、工具误调用和失败噪音。
4. UI 上 contextRefs 与授权区域已经可勾选，但后台语义仍混杂：勾选范围被当成“必须塞给模型的上下文”，而不是“允许 agent 按需读取的能力边界”。

因此本稿替代原先以 `AgentRunEnvelope` 为中心的方案。`AgentRunEnvelope` 仍保留为 audit / permission / receipt 的宿主侧结构，但不再是默认 prompt 注入中心。

## 2. PilotDeck 对照结论

### 2.1 可借鉴模型

PilotDeck 的 `PromptAssembler` 采用分层上下文：

- `ExtensionResolver.listSkills()` 只返回 skill 名称、描述和 namespace。
- `formatSkills()` 只生成 `<available-skills>` 摘要，并明确提示 `Use the read_skill tool to load the full content of any skill listed below.`
- skill 正文不默认进入每轮 prompt。
- slash command 由 `InputProcessor` 识别后作为用户意图进入 agent loop，不把所有 command body 默认注入。
- MCP instructions 也是单独 `<mcp-instructions>` 块，不与用户原文混写。

这些模型适合 MNote：

- Page AI 只暴露“MNote 有哪些能力”。
- 详细技能说明通过 `mnote_skill.read` 或 agent 原生 skill 读取。
- 当前页、选区、文件夹、changed files 通过 context tools 按需读取。
- 用户 prompt 保持干净，避免把普通聊天污染成文档任务。

### 2.2 只作参考实现

PilotDeck 的完整 RouterRuntime、Model Canonical Protocol、AgentLoop、MemoryResolver 和 CompactionEngine 不直接移植。MNote 当前已有 Hermes / Reasonix ACP runtime，不应复制第三套 agent runtime。

可参考但不直接搬运：

- `ExtensionResolver` 的只读 contribution snapshot。
- `read_skill` 懒加载模式。
- tool result budget / tool_result_reference 思路。
- permission runtime 的统一决策链。

### 2.3 不适合 MNote 的内容

- 不做 PilotDeck 式全局模型 router。
- 不做 PilotDeck 式后台 always-on agent runtime。
- 不做独立于 SQLite control-plane 的另一套权限真相。
- 不用定时轮询来刷新 Page AI、文件树或页面树。
- 不把 PilotDeck 的项目 memory dataDir 作为 MNote 默认记忆存储；MNote 若后续做记忆，应按 `workspace_id + user_id` 落 SQLite control-plane 或明确的本地数据目录。

## 3. 第一结论

本阶段目标从“把 envelope 注入得更干净”改为：

1. 建立 MNote 专用 skill library 合同。
2. 建立 MNote context tools 合同。
3. Page AI 发送时保留用户原文，不把 MNote context/tool guidance 强行拼到 prompt_blocks。
4. `contextRefs` 只作为用户授权的上下文范围，agent 需要时自行调用工具读取。
5. `AgentRunEnvelope` 只作为宿主侧 audit / permission / tool input snapshot，不默认进入 prompt。
6. Chat-only agent 不挂载 MNote context tools；Hermes / Reasonix 是否暴露 MNote tools 由用户勾选的 `contextRefs` 与授权边界决定，普通消息是否调用工具由 agent 自己判断。
7. UI 继续按 7-39 的 Cline 式模型收敛：输入区只保留 `+ / Agent / 上下文 / 停止 / 发送`，不显示 `write · /path` 黑色授权提示。

## 4. 产品设计：Page AI 输入区

### 4.1 默认输入区

Page AI 输入区默认只显示：

```text
[+] [Agent] [上下文]                         [停止] [发送]
```

要求：

- `Agent` 是按钮 + popover，不在输入区平铺 Hermes / Reasonix / Chat-only chip。
- `上下文` 是按钮 + popover，不在输入区平铺 6 个 context chip。
- 授权区域只在上下文 popover 中展示，不再在输入区显示 `write · /mnt/Data1T/mnote` 黑色提示。
- 输入区不显示 profile、model、gateway、runtime、tool trace 等技术噪音。

### 4.2 Agent popover

Agent popover 显示：

```text
选择 Agent

(x) Reasonix
    适合工作区任务和文件编辑

( ) Hermes
    适合 MNote 内置工具和页面操作

( ) Chat-only
    只聊天，不申请文件读写能力
```

选择 agent 后：

- payload 显式携带 `agentId`。
- `chat_only` 强制不挂载 MNote context tools。
- Hermes / Reasonix 可挂载 skill/tool capability，但是否读取由 agent 决定。

### 4.3 Context popover

Context popover 显示：

```text
发送给 AI 的上下文权限

[x] 当前页
    允许 agent 按需读取当前 Markdown 页面

[ ] 选区
    当前没有选区

[x] 打开资源
    允许 agent 按需读取当前打开资源

[ ] 文件
    允许 agent 按需读取当前文件

[ ] 文件夹
    允许 agent 在授权根内按需读取文件夹

[ ] 最近修改
    允许 agent 读取上次 run 的 changed files 摘要

授权区域
    write · /mnt/Data1T/mnote

[恢复默认] [完成]
```

语义：

- 勾选项表达“允许 agent 读取的上下文范围”，不是“强制把内容发给模型”。
- `current_page` 勾选后，只代表工具可读取当前页；页面正文不默认塞进 prompt。
- `selection` 勾选且有选区时，agent 可通过 tool 读取选区文本；选区文本不默认塞进 prompt，除非后续用户明确选择“直接附加选区文本”模式。
- `folder` 必须由服务端 SQLite grants 重算 allowed roots。

## 5. MNote Skill Library 合同

### 5.1 Skill registry

新增 MNote 专用 skill registry，第一阶段可以用静态文件或 Rust 静态 registry，后续可落 SQLite / filesystem。

推荐初始技能：

| skill id | 简述 | 默认 agent |
| --- | --- | --- |
| `mnote-current-page` | 如何读取当前页、判断 dirty/conflict、刷新页面 | Hermes / Reasonix |
| `mnote-selection` | 如何读取和使用选区 | Hermes / Reasonix |
| `mnote-local-file` | 如何解析 MNote target / allowed roots，并让 agent 使用自身文件能力读写本地 Markdown | Reasonix |
| `mnote-attachments` | 如何处理 Markdown 标准链接、图片、PDF/Office 附件 | Hermes / Reasonix |
| `mnote-workspace-search` | 如何在授权 workspace 内搜索文件和引用 | Reasonix |
| `mnote-agent-receipt` | agent 写入后如何报告 changed files 与刷新需求 | Hermes / Reasonix |
| `mnote-chat-only` | 只聊天时不得调用 MNote 文件/页面工具 | Chat-only |

Skill 元数据：

```json
{
  "id": "mnote-local-file",
  "title": "MNote local file editing",
  "description": "Resolve MNote targets and allowed roots before using the agent runtime's native local file tools.",
  "agentIds": ["reasonix", "hermes"],
  "readOnly": false,
  "requiresContextRefs": ["current_page", "file", "folder"],
  "toolNames": ["mnote.context.snapshot", "mnote.context.resolve_target"],
  "path": "skills/mnote-local-file/SKILL.md"
}
```

### 5.2 Prompt 中只出现摘要

Page AI 上游 prompt 中最多允许出现类似摘要：

```xml
<available-skills>
Use mnote_skill.read to load the full content of any skill listed below.
- mnote-current-page — Read the current MNote Markdown page when the task needs page content.
- mnote-local-file — Resolve MNote targets and then use native file tools inside allowed roots.
- mnote-attachments — Resolve and open Markdown attachment links.
</available-skills>
```

禁止：

- 把每个 skill 的完整正文默认塞入 prompt。
- 把当前页全文默认塞入 prompt。
- 把 runTargetSnapshot 的正文、pageXml、contextBlocks 默认塞入 prompt。
- 把工具长说明拼进用户消息。

### 5.3 Skill 读取工具

新增或适配工具：

```json
{
  "name": "mnote_skill.read",
  "description": "Read a MNote skill by id when the task requires this MNote capability.",
  "input_schema": {
    "type": "object",
    "properties": {
      "skillId": { "type": "string" }
    },
    "required": ["skillId"]
  }
}
```

返回：

```json
{
  "skillId": "mnote-local-file",
  "content": "...SKILL.md...",
  "tools": ["mnote_context.resolve_target", "mnote_file.read", "mnote_file.patch"],
  "constraints": {
    "allowedRootsRequired": true,
    "mustReadBackAfterWrite": true
  }
}
```

## 6. MNote Context Tool 合同

### 6.1 工具列表

第一阶段建议提供最小工具集：

| tool | 职责 |
| --- | --- |
| `mnote_context.snapshot` | 返回本次 run 可用上下文摘要，不含正文全文 |
| `mnote_context.read_current_page` | 在 `current_page` 被授权时读取当前页 Markdown |
| `mnote_context.read_selection` | 在 `selection` 被授权且存在时读取选区 |
| `mnote_context.resolve_target` | 返回当前 rootUri、relativePath、documentId、file version |
| `mnote_file.read` | 在 allowed roots 内读取文件 |
| `mnote_file.patch` | 在 allowed roots 内 patch 文件，写入后回读 |
| `mnote_receipt.changed_files` | agent 完成后提交 changed files 或读取 audit 结果 |

### 6.2 权限原则

- 前端 `allowedRoots` 只作为 UI 展示与用户选择，不作为服务端真相。
- 服务端必须按当前 SQLite user session 重算 grants。
- 每次 tool 调用都按 `user_id + workspace_id + contextRefs + allowedRoots` 判定。
- `chat_only` 不注册文件读写工具。
- 未勾选 `current_page` 时，`mnote_context.read_current_page` 返回 blocked。
- 未勾选 `folder` 时，`mnote_file.read` 只能读 primary target 或当前文件。

### 6.3 上下文快照

`mnote_context.snapshot` 返回示例：

```json
{
  "schema": "mnote.context_snapshot.v1",
  "runId": "page-ai-run-abc",
  "agentId": "reasonix",
  "workspace": {
    "sourceKind": "local_folder",
    "rootUri": "file:///mnt/Data1T/mnote"
  },
  "contextRefs": ["current_page", "active_editor"],
  "primaryTarget": {
    "documentId": "local-md:README.md",
    "relativePath": "README.md",
    "fileVersion": "mtime:size:hash"
  },
  "availableReads": {
    "currentPage": true,
    "selection": false,
    "folder": false,
    "changedFiles": false
  }
}
```

注意：snapshot 是工具返回，不是默认 prompt 注入。

## 7. AgentRunEnvelope 与 Receipt 的新位置

`AgentRunEnvelope` 不废弃，但职责调整：

- 宿主侧构建，用于 audit、权限判定、工具输入和 receipt 关联。
- 可以被 `mnote_context.snapshot` 精简返回。
- 不默认进入 ACP `prompt_blocks`。
- 不作为普通聊天请求的 system instructions。

`AgentRunReceipt` 仍保留：

- run 完成后记录 changed files、touchesCurrentFile、shouldRefreshEditor、conflict。
- clean buffer 下 agent 写入当前 `.md` 后触发事件驱动刷新。
- dirty buffer 下进入 `external-change-conflict`。
- 不通过轮询等待结果；使用 ACP events、watcher、WS/SSE 或现有浏览器事件。

## 8. 后端数据流

```text
Page AI composer
  -> 用户选择 Agent / contextRefs
  -> sendPageAiMessage()
  -> payload: agentId + contextRefs + editorTarget + runTargetSnapshot metadata
  -> 服务端认证 + SQLite grants 重算
  -> 构建 host-side AgentRunEnvelope
  -> 判断是否挂载 MNote skill/tool capability
     - chat_only: 不挂载
     - simple chat: 不挂载
     - Hermes/Reasonix + 文档任务: 挂载 skill summary + context tools
  -> ACP run prompt_blocks 只包含用户原文
  -> agent 按需调用 mnote_skill.read / mnote_context.* / mnote_file.*
  -> run completed
  -> AgentRunReceipt / agentAudit.changedFiles
  -> 事件驱动刷新当前页、文件树、页面树或显示 conflict
```

## 9. “是否挂载能力”的判定

第一阶段采用保守规则：

暴露 MNote skill/tool capability：

- agentId 是 `hermes` 或 `reasonix`。
- 用户在 context popover 中勾选了 `current_page / selection / active_editor / file / folder / changed_files` 这类 MNote 上下文能力。
- 用户 prompt 原文只用于 agent 自己推理，不由 MNote 侧按关键词分类成“普通聊天 / 文档任务”。

不挂载：

- agentId 是 `chat_only`。
- 用户没有勾选任何 MNote contextRef。
- 当前没有有效 workspace / rootUri / session。

能力暴露不等于工具调用。MNote 只提供边界、授权和 skill/tool 描述；是否读取当前页、文件或附件由 agent 根据任务自行选择。

## 10. 与当前半成品实现的差异

当前半成品中已有一些方向需要修正：

- `acp_stream_events` 已改为 prompt_blocks 只放用户原文，这是正确方向。
- `should_skip_mnote_tool_context` 这类短句特判不应保留；应升级成只看 agentId / contextRefs / 授权边界的 capability attach policy。
- `build_run_upstream_body(...).instructions` 仍可作为 legacy Hermes route 兼容，但不应进入 ACP prompt。
- `toolGuidance` 不应变成长文本默认 instructions；应拆入 skill 正文，按需读取。
- `AgentRunEnvelope` 应保留为 audit/tool input，不作为默认 prompt 文本。

## 11. 验收 Checklist

### Batch A：冻结现状与 PilotDeck 对照

- [x] 记录当前“收到请回复收到”触发工具调用的真实浏览器证据。证据：用户截图/反馈记录了旧 UI 下短消息出现大量工具调用；本轮用 `task502-page-ai-agent-selector-context-smoke` 固化回归断言：短消息无 tool card，payload 不默认上传正文。
- [x] 记录当前 ACP payload / prompt_blocks 是否包含 MNote instructions。证据：`acp_stream_events` 现只构造用户原文 `ContentBlock::Text`，不再调用 `build_run_upstream_body(...).instructions` 塞入 ACP prompt。
- [x] 对照 PilotDeck `PromptAssembler.formatSkills()`，确认 MNote 只注入 skill 摘要。证据：参考 `reference-code/PilotDeck/src/context/prompt/PromptAssembler.ts`，MNote 新增 skill registry 摘要与 `mnote.skill.read` 懒加载。
- [x] 对照 PilotDeck `InputProcessor`，确认 slash/command 不强行注入所有 command body。证据：参考 `reference-code/PilotDeck/src/context/input/InputProcessor.ts`，本轮未把 MNote skill 正文塞入普通用户 prompt。

### Batch B：Skill registry 设计与最小实现

- [x] 新增 MNote skill metadata registry。证据：`rust/crates/mnote-web/src/hermes_tools/skill.rs`。
- [x] 新增 `mnote_skill.read` 或等价工具。证据：`mnote.skill.read` manifest + route dispatch。
- [x] 添加 `mnote-current-page`、`mnote-local-file`、`mnote-chat-only` 三个最小 skill 正文。证据：`skills/mnote-*/SKILL.md`。
- [x] 单测覆盖 skill id lookup、未知 skill、agentId 过滤。证据：`cargo test --manifest-path rust/Cargo.toml -p mnote-web skill_lookup -- --nocapture`。

### Batch C：Context tools 合同

- [x] 新增或收口 `mnote_context.snapshot`。证据：`mnote.context.snapshot` manifest + `context_tools::context_snapshot`。
- [x] 新增或收口 `mnote_context.read_current_page`。证据：`mnote.context.read_current_page` manifest + current_page contextRef guard。
- [x] 新增或收口 `mnote_context.resolve_target`。证据：`mnote.context.resolve_target` manifest + route dispatch。
- [x] 工具返回结构化 JSON，不把正文混入 prompt。证据：context snapshot / resolve target 只返回 JSON；读取正文必须显式调用 read_current_page。
- [x] Rust 定点测试覆盖 contextRefs 权限。证据：`cargo test --manifest-path rust/Cargo.toml -p mnote-web context_ref_enabled -- --nocapture`。

### Batch D：Capability attach policy

- [x] 实现 `PageAiCapabilityPolicy` 或等价函数。证据：`page_ai_capability_policy`。
- [x] `chat_only` 永不挂载 MNote 文件/页面工具。证据：policy 单测 + Reasonix wrapper chatLoop 使用空 ToolRegistry。
- [x] MNote 不按“收到/你好/总结当前页”等 prompt 文本强行分类能力；普通消息是否调用工具由 agent 自己判断。证据：`page_ai_capability_policy_exposes_selected_context_without_prompt_classifying`、`capability_policy_does_not_text_classify_ack_prompt`。
- [x] 只在 Hermes / Reasonix 且用户勾选 MNote contextRefs 时暴露 skill/tool capability；没有 contextRefs 或 Chat-only 时不挂载。证据：`page_ai_capability_policy_does_not_attach_without_context_refs`、`page_ai_capability_policy_never_attaches_for_chat_only`。
- [x] 单测覆盖 selected contextRefs、无 contextRefs、Chat-only、ack prompt 不文本分类四类输入。证据：`cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_capability_policy -- --nocapture`。

### Batch E：ACP prompt 收口

- [x] ACP `prompt_blocks` 只包含用户原文和用户显式附件，不包含 MNote tool guidance。证据：`acp_stream_events` 只传 `input.to_string()`。
- [x] skill 摘要如果需要进入 system/context，只作为短 `<available-skills>`。证据：Reasonix wrapper mnoteLoop system prompt 仅保留短摘要，正文走 `mnote_skill_read`。
- [x] `AgentRunEnvelope` 不进入 prompt_blocks。证据：ACP path 不再使用 upstream instructions。
- [x] `build_run_upstream_body` 的 legacy instructions 不再被 ACP path 直接使用。证据：`acp_stream_events` 不调用 `build_run_upstream_body`。

### Batch F：UI 收口

- [x] Agent selector 改为 `+` 旁边的 Agent 按钮 + popover。证据：`task502-page-ai-agent-selector-context-smoke` 通过。
- [x] Context refs 改为 `+` 旁边的上下文按钮 + popover。证据：`task502-page-ai-agent-selector-context-smoke` 通过。
- [x] 输入区不显示 `write · /path` 黑色授权提示。证据：截图 `tmp/task502-page-ai-agent-selector-context-smoke/01-agent-selector-context.png`。
- [x] 默认聊天面不显示 profile/model/gateway/runtime/tool trace。证据：`task502-page-ai-agent-selector-context-smoke` 断言通过。
- [x] 浏览器截图验证 popover、选中态、输入区清爽度。证据：`tmp/task502-page-ai-agent-selector-context-smoke/01-agent-selector-context.png`。

### Batch G：Tool card 降噪

- [x] 普通聊天不显示 MNote tool card。证据：`task502-page-ai-agent-selector-context-smoke` 对“收到请回复收到”断言无 tool card。
- [x] Page AI run payload 不默认上传 `pageText/pageXml/contextBlocks/selectedText/evidence` 正文；当前页/选区正文必须由 agent 通过 context tools 按需读取。证据：`pageAiPageContextForRefs()` 默认裁剪正文，`task502-page-ai-agent-selector-context-smoke` 断言通过。
- [x] tool 调用失败时卡片默认折叠，显示简短错误和展开入口。证据：tool message 使用 `<details class="wolai-page-ai-tool-details">`，默认不加 `open`。
- [x] debug/raw trace 进入高级/调试区，不污染默认聊天。证据：trace/auditId 只在 tool `<details>` 内显示；默认聊天 smoke 截图无 runtime/raw trace。
- [x] “收到请回复收到”真实浏览器测试只显示用户消息与 assistant 回复。证据：`task502-page-ai-agent-selector-context-smoke` 通过并生成截图。

### Batch H：Receipt 与事件驱动刷新

- [x] 保留 `AgentRunReceipt` / `agentAudit.changedFiles`。证据：`local_agent_audit_event` 写入 `agentRunReceipt`，`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_agent_audit_event_carries_agent_run_receipt -- --nocapture`。
- [x] clean buffer agent 写入后事件驱动刷新当前页。证据：前端优先消费 `agentRunReceipt.refresh.touchesCurrentFile` 并派发 `mnote:page-ai-tool-write-completed`，`document-session-runtime.js` 负责 clean refresh / dirty conflict。
- [x] dirty buffer agent 写入后进入 conflict。证据：`document-session-runtime.js` 的 `refreshDocumentSessionsFromExternalWrite` 对 dirty / saving / recent input 标记 `external-change-conflict`，事件来源改为 receipt。
- [x] 不引入定时轮询。证据：本轮只使用 ACP SSE `run.completed`、浏览器 CustomEvent、现有 watcher/WS/SSE 事件，没有新增 `setInterval` 或轮询。
- [x] changed files 与文件树/页面树刷新走 watcher、ACP event、WS/SSE 或现有事件。证据：`agentRunReceipt.changedFiles` 转为 `tree:local-folder-watch-batch`，由 `sidebar-tree-live-apply-runtime.js` 事件驱动刷新 affected parents。

### Batch I：验证矩阵与归档

- [x] Rust targeted tests：skill registry、capability policy、context tool auth。证据：`page_ai_capability_policy`、`skill_lookup`、`context_ref_enabled` 定点测试通过。
- [x] JS `node --check`：Page AI runtime 与 smoke。证据：`node --check scripts/reasonix-acp-wrapper.mjs rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js rust/crates/mnote-web/browser/sidebar-tree-runtime.js scripts/task502-page-ai-agent-selector-context-smoke.js`。
- [x] 浏览器 smoke：Agent popover、Context popover、纯聊天无工具调用、payload 不默认上传正文、receipt 事件驱动刷新。证据：`node scripts/task502-page-ai-agent-selector-context-smoke.js`。
- [x] 浏览器截图：输入区不显示授权黑 chip。证据：`tmp/task502-page-ai-agent-selector-context-smoke/01-agent-selector-context.png`。
- [x] `git diff --check`。
- [x] `codegraph sync .`，必要时 `codegraph index . --force`。
- [x] checklist 全部完成后移动到 `design/07-ai/done/`。

## 12. 归档条件

满足以下条件后，本稿可移动到 `design/07-ai/done/`：

- Page AI 已采用 MNote skill library + context tools 模型。
- ACP 用户 prompt 保持干净，不再默认注入 MNote instructions。
- 纯聊天请求不会触发 MNote doc/page/file 工具。
- 文档任务仍能通过 skill/tool 按需读取当前页或文件。
- Agent / Context UI 已收敛为输入区按钮 + popover。
- 真实浏览器截图与 smoke 证明默认聊天面没有冗余技术噪音。
