Files
metona-ai-desktop/docs/MetonaAI-Desktop 架构与交互设计.html
T
thzxx 656c6b7af1 feat: 升级至 v0.3.4 — 接入 Xiaomi MiMo Provider + 文档全量校准
新增 MiMo (小米) LLM Provider 适配器,支持 mimo-v2.5-pro 和 mimo-v2.5 两个文本模型,复用 OpenAI 兼容 SSE 流式解析,支持 Thinking 模式和 Function Calling。同步校准全量 docs 文档与 README 使其与实际代码一致。

主要变更:
- 新增 mimo.adapter.ts 适配器(SSE + thinking.type + max_completion_tokens)
- 修复 thinking 逻辑 bug:禁用思考时未传 temperature/top_p
- 补全 sse-stream.ts 的 MiMo 缓存字段映射(prompt_tokens_details.cached_tokens)
- 补全 sse-stream.ts 的 finish_reason 映射(repetition_truncation)
- 注册 MiMo 适配器到 adapters/index.ts、main.ts 工厂
- handlers.ts 添加 mimo.contextWindow 热重载触发
- database.service.ts seed 添加 mimo 默认配置
- SettingsModal/OnboardingWizard/Header 添加 MiMo Provider UI
- constants.ts PROVIDER_LABELS 添加 mimo
- .env.example 添加 MIMO_API_KEY/MIMO_BASE_URL
- 反向修改 4 个 docs HTML 设计文档(工具数量/版本日期/适配器列表/数据库表)
- 反向修改 Agent网络工具通用设计-v2.md 附录 B 文件索引
- 完全重写 README.md(v0.3.4、27 工具、4 适配器、9 表)
2026-07-15 22:28:09 +08:00

999 lines
69 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MetonaAI-Desktop 架构与交互设计文档 | v1.1</title>
<style>
:root {
--bg: #0f1117;
--bg-card: #1a1d27;
--bg-code: #12141c;
--bg-nav: #141620;
--text: #e1e4ed;
--text-dim: #8b8fa7;
--accent: #06b6d4;
--accent2: #22d3ee;
--green: #34d399;
--orange: #fb923c;
--red: #f87171;
--amber: #fbbf24;
--purple: #a855f7;
--border: #2a2d3a;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif;
background: var(--bg); color: var(--text); line-height: 1.7; display: flex;
scroll-behavior: smooth;
}
.sidebar {
position: fixed; top: 0; left: 0; width: 300px; height: 100vh;
background: var(--bg-nav); border-right: 1px solid var(--border);
overflow-y: auto; z-index: 100; padding: 24px 0;
}
.sidebar-logo { padding: 0 20px 20px; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
.sidebar-logo h2 {
font-size: 19px;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.sidebar-section {
padding: 8px 20px; font-size: 10.5px; text-transform: uppercase;
letter-spacing: 1.2px; color: var(--text-dim); font-weight: 600;
}
.sidebar a {
display: flex; align-items: center; gap: 10px; padding: 7px 20px;
color: var(--text-dim); text-decoration: none; font-size: 13px; transition: all 0.15s;
}
.sidebar a:hover, .sidebar a.active { color: var(--text); background: rgba(6,182,212,0.06); }
.sidebar a.active { border-right: 2px solid var(--accent); }
.main { margin-left: 300px; flex: 1; min-height: 100vh; }
.hero {
background: linear-gradient(135deg, rgba(6,182,212,0.07), rgba(34,211,238,0.05));
border-bottom: 1px solid var(--border); padding: 56px 60px 48px;
}
.hero h1 {
font-size: 32px; font-weight: 800;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px;
}
.hero p { color: var(--text-dim); font-size: 15px; max-width: 740px; }
.hero-meta { display: flex; gap: 24px; margin-top: 18px; flex-wrap: wrap; }
.hero-meta span { font-size: 13px; color: var(--text-dim); display: flex; align-items: center; gap: 6px; }
.hero-meta .dot { width: 6px; height: 6px; border-radius: 50%; }
.dot-cyan { background: var(--accent); } .dot-green { background: var(--green); } .dot-amber { background: var(--amber); }
.content { padding: 40px 60px 100px; max-width: 1080px; }
.api-section { margin-bottom: 60px; scroll-margin-top: 20px; }
.api-section h2 { font-size: 22px; font-weight: 700; margin-bottom: 8px; display: flex; align-items: center; gap: 10px; }
.api-section h3 { font-size: 17px; font-weight: 600; margin: 36px 0 12px; color: var(--accent); }
.api-section h4 { font-size: 14.5px; font-weight: 600; margin: 24px 0 8px; color: var(--accent2); }
.api-section .desc { color: var(--text-dim); font-size: 14.5px; margin-bottom: 20px; }
.api-section .desc code { color: var(--cyan); background: var(--bg-code); padding: 2px 6px; border-radius: 4px; font-size: 13px; }
table.spec { width: 100%; border-collapse: collapse; margin-bottom: 24px; font-size: 13.5px; }
table.spec th { text-align: left; padding: 10px 14px; background: var(--bg-card); border-bottom: 1px solid var(--border); color: var(--text-dim); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.8px; }
table.spec td { padding: 10px 14px; border-bottom: 1px solid rgba(42,45,58,0.5); vertical-align: top; transition: background 0.15s; }
table.spec tr:hover td { background: rgba(6,182,212,0.03); }
table.spec tr:last-child td { border-bottom: none; }
.f-name { font-family: 'SF Mono','Fira Code',monospace; color: #22d3ee; font-weight: 600; font-size: 13px; }
.f-type { font-family: 'SF Mono','Fira Code',monospace; color: var(--accent2); font-size: 11.5px; }
.f-req { color: var(--red); font-size: 11px; font-weight: 600; }
.f-opt { color: var(--text-dim); font-size: 11px; }
.f-risk { font-weight: 700; }
.risk-safe { color: var(--green); } .risk-medium { color: var(--amber); } .risk-high { color: var(--red); }
.code-block { background: var(--bg-code); border: 1px solid var(--border); border-radius: 10px; padding: 20px; overflow-x: auto; margin-bottom: 24px; transition: border-color 0.2s; }
.code-block:hover { border-color: rgba(6,182,212,0.3); }
.code-block pre { margin: 0; font-family: 'SF Mono','Fira Code','Cascadia Code',monospace; font-size: 13px; line-height: 1.6; color: var(--text); }
.hl-kw { color: var(--purple); } .hl-str { color: var(--green); } .hl-num { color: var(--orange); }
.hl-cm { color: var(--text-dim); font-style: italic; } .hl-fn { color: var(--accent); } .hl-prop { color: #22d3ee; }
.hl-type { color: var(--amber); } .hl-box { color: var(--accent); font-weight: 700; }
.note-box { background: rgba(6,182,212,0.05); border-left: 3px solid var(--accent); border-radius: 0 8px 8px 0; padding: 14px 18px; margin-bottom: 24px; font-size: 13.5px; color: var(--text-dim); transition: border-color 0.2s; }
.note-box:hover { border-left-color: var(--accent2); }
.note-box strong { color: var(--accent); }
.note-box code { color: var(--cyan); background: var(--bg-code); padding: 1px 5px; border-radius: 3px; font-size: 12.5px; }
.warn-box { background: rgba(251,191,36,0.05); border-left: 3px solid var(--amber); border-radius: 0 8px 8px 0; padding: 14px 18px; margin-bottom: 24px; font-size: 13.5px; color: var(--text-dim); transition: border-color 0.2s; }
.warn-box:hover { border-left-color: var(--orange); }
.warn-box strong { color: var(--amber); }
.arch-diagram { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 28px; margin: 20px 0 30px; overflow-x: auto; transition: border-color 0.2s; }
.arch-diagram:hover { border-color: rgba(6,182,212,0.3); }
.arch-diagram pre { font-family: 'SF Mono','Fira Code',monospace; font-size: 12.5px; line-height: 1.55; color: var(--text); margin: 0; }
.section-divider { border: none; height: 1px; background: var(--border); margin: 56px 0; }
.flow-step { display: flex; gap: 14px; margin-bottom: 14px; align-items: flex-start; transition: transform 0.15s; }
.flow-step:hover { transform: translateX(4px); }
.flow-num { min-width: 28px; height: 28px; background: var(--accent); color: #000; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; flex-shrink: 0; transition: transform 0.2s; }
.flow-step:hover .flow-num { transform: scale(1.1); }
.flow-text { padding-top: 2px; font-size: 14px; }
.flow-text code { color: var(--cyan); background: var(--bg-code); padding: 1px 5px; border-radius: 3px; font-size: 12.5px; }
.file-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 20px 24px; margin-bottom: 16px; transition: border-color 0.2s, transform 0.2s; }
.file-card:hover { border-color: rgba(6,182,212,0.3); transform: translateY(-2px); }
.file-card h4 { color: var(--accent); font-size: 15px; margin-bottom: 6px; display: flex; align-items: center; gap: 10px; }
.file-card .path { font-family: 'SF Mono',monospace; font-size: 12px; color: var(--amber); margin-bottom: 10px; }
.file-card p { font-size: 13.5px; color: var(--text-dim); }
.tree { font-family: 'SF Mono','Fira Code',monospace; font-size: 12.5px; line-height: 1.7; color: var(--text-dim); }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--text-dim); }
@media (max-width: 900px) { .sidebar { display: none; } .main { margin-left: 0; } .hero,.content { padding: 30px 24px; } }
</style>
</head>
<body>
<nav class="sidebar">
<div class="sidebar-logo">
<h2>&#x1F3D7;&#xFE0F; MetonaAI-Desktop</h2>
</div>
<div class="sidebar-section">架构</div>
<a href="#overview">&#x1F4CB; 总览</a>
<a href="#arch">&#x1F3D7;&#xFE0F; 系统架构</a>
<a href="#workspace">&#x1F4C1; 工作空间</a>
<a href="#db-config">&#x1F4BE; 数据库配置</a>
<div class="sidebar-section">27 个内置工具</div>
<a href="#tools-overview">&#x1F4CA; 工具总表</a>
<a href="#tool-filesystem">&#x1F4C4; 文件系统工具</a>
<a href="#tool-web">&#x1F310; 网络搜索与抓取</a>
<a href="#tool-memory">&#x1F9E0; 记忆工具</a>
<a href="#tool-command">&#x2692;&#xFE0F; 命令工具</a>
<div class="sidebar-section">4 个磁盘文件</div>
<a href="#disk-files">&#x1F4BE; 文件总览</a>
<a href="#file-soul">&#x2728; SOUL.md</a>
<a href="#file-agents">&#x1F4CB; AGENTS.md</a>
<a href="#file-memory">&#x1F9E9; MEMORY.md</a>
<a href="#file-users">&#x1F464; USERS.md</a>
<div class="sidebar-section">可追踪 &amp; 日志</div>
<a href="#trace">&#x1F50D; 全链路透明</a>
<a href="#logging">&#x1F4DD; 日志设计</a>
<a href="#interaction">&#x1F504; 交互流程</a>
</nav>
<div class="main">
<div class="hero">
<h1>MetonaAI-Desktop 架构与交互设计</h1>
<p>基于「生产级通用 AI Agent 桌面应用构建指南」+「Metona 内部 IR 标准」,定义完整的系统架构、27 个内置工具、4 个用户级磁盘文件、工作空间机制、数据库配置规范及全链路可追踪日志体系。</p>
<div class="hero-meta">
<span><span class="dot dot-cyan"></span> 版本: <strong>v1.1.0</strong></span>
<span><span class="dot dot-green"></span> 技术栈: <strong>React + Material UI (MUI) + Electron + SQLite</strong></span>
<span><span class="dot dot-amber"></span> 日期: <strong>2026-07-15</strong></span>
</div>
<div class="note-box" style="margin-top:16px">
<strong>&#x1F4CB; 文档层级:</strong>本文档是 <strong>工作空间、27 个内置工具、4 个磁盘文件、数据库配置的权威定义</strong>,与《构建指南》第三、五、六章对应。冲突时以本文档为准。
</div>
</div>
<div class="content">
<!-- ====== 总览 ====== -->
<section class="api-section" id="overview">
<h2>&#x1F4CB; 设计总览</h2>
<p class="desc">
MetonaAI-Desktop 是一个运行在用户本地桌面上的通用 AI Agent 应用。它以<strong>工作空间(Workspace</strong>为基本组织单元,
通过 <strong>4 个 Markdown 磁盘文件</strong> 定义 Agent 的灵魂、行为、记忆和用户画像,
提供 <strong>27 个内置工具</strong> 赋予 Agent 操作文件系统、网络、记忆和命令行的能力。
全链路操作<strong>透明可追踪</strong>,所有决策过程、工具调用、LLM 推理记录在本地 SQLite 日志中。
</p>
<div class="arch-diagram">
<pre>
<span class="hl-box">┌──────────────────────────────────────────────────────────┐</span>
<span class="hl-box">│ MetonaAI-Desktop │</span>
<span class="hl-box">│ │</span>
<span class="hl-box">│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │</span>
<span class="hl-box">│ │ SOUL.md │ │ AGENTS.md│ │ MEMORY.md│ │ USERS.md│ │</span> ← 用户磁盘文件
<span class="hl-box">│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │</span>
<span class="hl-box">│ │ │ │ │ │</span>
<span class="hl-box">│ ┌────▼─────────────▼─────────────▼─────────────▼────┐ │</span>
<span class="hl-box">│ │ Agent Engine (ReAct Loop) │ │</span>
<span class="hl-box">│ │ INIT → THINKING → PARSING → EXECUTING → OBSERVING → REFLECTING → COMPRESSING → TERMINATED │ │</span>
<span class="hl-box">│ └────┬──────────────────────────────────────────────┘ │</span>
<span class="hl-box">│ │ │</span>
<span class="hl-box">│ ┌────▼──────────────────────────────────────────────┐ │</span>
<span class="hl-box">│ │ 27 Base Tools (统一 IR) │ │</span>
<span class="hl-box">│ │ filesystem(5) | editor | code_search | diff │ │</span>
<span class="hl-box">│ │ web_search | web_fetch | web_browser | http │ │</span>
<span class="hl-box">│ │ memory(2) | run_command | delegate_task │ │</span>
<span class="hl-box">│ │ git(4) | dev_tools(3) | task_mgr | todo | think │ │</span>
<span class="hl-box">│ └────┬──────────────────────────────────────────────┘ │</span>
<span class="hl-box">│ │ │</span>
<span class="hl-box">│ ┌────▼──────────────────────────────────────────────┐ │</span>
<span class="hl-box">│ │ Trace & Audit Logger (全链路 SQLite) │ │</span>
<span class="hl-box">│ └───────────────────────────────────────────────────┘ │</span>
<span class="hl-box">└──────────────────────────────────────────────────────────┘</span>
</pre>
</div>
</section>
<hr class="section-divider">
<!-- ====== 系统架构 ====== -->
<section class="api-section" id="arch">
<h2>&#x1F3D7;&#xFE0F; 系统架构</h2>
<h3>进程架构</h3>
<table class="spec">
<tr><th>进程</th><th>运行时</th><th>职责</th></tr>
<tr><td class="f-name">Main Process</td><td class="f-type">Node.js</td><td>Agent 引擎、工具调度、数据库、MCP 管理、配置加载</td></tr>
<tr><td class="f-name">Preload Script</td><td class="f-type">沙箱 Node</td><td>通过 contextBridge 安全暴露 API 给渲染进程</td></tr>
<tr><td class="f-name">Renderer</td><td class="f-type">Chromium</td><td>React + Material UI (MUI) 界面:聊天、Agent 监控、设置面板、Trace Viewer。所有 UI 组件强制使用 MUI,禁止自写。</td></tr>
</table>
<h3>四层 Harness 架构</h3>
<table class="spec">
<tr><th>层级</th><th>名称</th><th>核心模块</th><th>使用的 IR 类型</th></tr>
<tr><td>L1</td><td class="f-name">推理与编排层</td><td>ReAct Loop 状态机、Plan Mode 执行器、SubAgent 编排器</td><td class="f-type">MetonaRequest / MetonaResponse / MetonaStreamEvent</td></tr>
<tr><td>L2</td><td class="f-name">上下文与记忆层</td><td>Context Builder、MemorySystemSQLite</td><td class="f-type">MetonaContext / MetonaMemoryItem</td></tr>
<tr><td>L3</td><td class="f-name">工具与安全执行层</td><td>Tool Registry、Sandbox Manager、Policy Engine、MCP Adapter</td><td class="f-type">MetonaToolDef / MetonaToolCall / MetonaToolResult</td></tr>
<tr><td>L4</td><td class="f-name">支撑与基础架构层</td><td>Config Manager、Logging System、OTel Tracing、Error Boundary</td><td class="f-type">MetonaError / 内置类型</td></tr>
</table>
</section>
<hr class="section-divider">
<!-- ====== 工作空间 ====== -->
<section class="api-section" id="workspace">
<h2>&#x1F4C1; 工作空间(Workspace</h2>
<p class="desc">
工作空间是 Metona 的组织核心。每个工作空间是一个<strong>本地磁盘目录</strong>,包含该上下文的全部文件。
Agent 启动时加载工作空间下的配置/状态文件,所有工具操作默认限制在工作空间内。
</p>
<h3>默认工作空间</h3>
<div class="note-box">
<strong>&#x1F4CD; 默认路径:</strong><code>~/MetonaWorkspaces/default/</code>
<br>首次启动时自动创建。用户可在设置界面修改默认路径或为不同项目创建独立工作空间。
</div>
<h3>自定义工作空间</h3>
<p class="desc">
用户可通过以下方式选择自定义工作空间目录:
</p>
<ul style="margin-bottom:20px; padding-left:20px; color:var(--text-dim); font-size:14px;">
<li><strong>启动时选择</strong>:应用启动界面的"选择工作空间"按钮</li>
<li><strong>菜单切换</strong>:菜单栏 → 文件 → 打开/创建工作空间</li>
<li><strong>拖拽导入</strong>:将文件夹拖入应用窗口</li>
<li><strong>命令行参数</strong><code>metona --workspace /path/to/dir</code></li>
</ul>
<h3>工作空间目录结构</h3>
<div class="code-block">
<pre><span class="hl-cm"># ~/MetonaWorkspaces/my-project/</span>
<span class="hl-tree">├──</span> <span class="hl-box">SOUL.md</span> <span class="hl-cm"># [必需] AI 灵魂定义 — 角色、性格、核心价值观(用户自定义)</span>
<span class="hl-tree">├──</span> <span class="hl-box">AGENTS.md</span> <span class="hl-cm"># [必需] AI 行为定义 — 规则、边界、工作流(用户自定义)</span>
<span class="hl-tree">├──</span> <span class="hl-box">MEMORY.md</span> <span class="hl-cm"># [必需] AI 持久记忆 — 跨会话保留的知识(Agent 维护 + 用户编辑)</span>
<span class="hl-tree">├──</span> <span class="hl-box">USERS.md</span> <span class="hl-cm"># [必需] 用户画像 — 背景、技能、偏好(用户自定义)</span>
<span class="hl-tree">├──</span> logs/ <span class="hl-cm"># [自动创建] 会话日志(每次对话一个 .jsonl)</span>
<span class="hl-tree">├──</span> traces/ <span class="hl-cm"># [自动创建] 执行追踪(每次 ReAct 迭代一条 trace</span>
<span class="hl-tree">├──</span> .metona/ <span class="hl-cm"># [自动创建] Metona 内部目录</span>
<span class="hl-tree">│ └──</span> agent.db <span class="hl-cm"># SQLite 数据库(配置、记忆、审计日志、会话记录)</span>
<span class="hl-tree">└──</span> src/ <span class="hl-cm"># [可选] 用户项目文件(Agent 可读写)</span></pre>
</div>
<h3>必需文件说明</h3>
<table class="spec">
<tr><th>文件</th><th>状态</th><th>缺失时处理</th><th>说明</th></tr>
<tr><td class="f-name">SOUL.md</td><td class="f-req">必需</td><td>自动创建空文件,Agent 以通用模式运行</td><td>定义 Agent 身份和价值观</td></tr>
<tr><td class="f-name">AGENTS.md</td><td class="f-req">必需</td><td>自动创建空文件,使用内置最小安全规则</td><td>定义 Agent 行为规则</td></tr>
<tr><td class="f-name">MEMORY.md</td><td class="f-req">必需</td><td>自动创建带元数据头的规范文件</td><td>跨会话记忆(有严格格式要求)</td></tr>
<tr><td class="f-name">USERS.md</td><td class="f-req">必需</td><td>自动创建空文件,Agent 以通用模式运行</td><td>用户画像信息</td></tr>
</table>
<div class="note-box">
<strong>&#x2705; 自动创建策略:</strong>打开工作空间时,Metona 会校验 4 个必需文件是否存在。
<br>任何文件缺失都会<strong>自动创建</strong>,不会阻止启动。创建后提示用户编辑自定义内容。
<br><code>MEMORY.md</code> 创建时会自动包含符合格式规范的元数据头。
</div>
<h3>工作空间生命周期</h3>
<div class="flow-step"><span class="flow-num">1</span><span class="flow-text">用户选择/创建工作空间目录(或使用默认路径 <code>~/MetonaWorkspaces/default/</code></span></div>
<div class="flow-step"><span class="flow-num">2</span><span class="flow-text">校验必需文件,缺失则自动创建(<code>MEMORY.md</code> 带元数据头)</span></div>
<div class="flow-step"><span class="flow-num">3</span><span class="flow-text">加载 4 个磁盘文件,构建 System Prompt(空文件不影响启动)</span></div>
<div class="flow-step"><span class="flow-num">4</span><span class="flow-text">连接 <code>.metona/agent.db</code>,加载配置、恢复历史会话</span></div>
<div class="flow-step"><span class="flow-num">5</span><span class="flow-text">Agent 就绪,开始对话。所有工具操作默认以工作空间为根</span></div>
<div class="flow-step"><span class="flow-num">6</span><span class="flow-text">会话结束后,<code>MEMORY.md</code>(更新时间戳)和 <code>.metona/agent.db</code> 自动更新</span></div>
</section>
<hr class="section-divider">
<!-- ====== 数据库配置 ====== -->
<section class="api-section" id="db-config">
<h2>&#x1F4BE; 数据库配置:.metona/agent.db</h2>
<p class="desc">
所有运行时配置存储在工作空间的 SQLite 数据库中(<code>.metona/agent.db</code>),而非外部配置文件。
这确保了配置与工作空间的强绑定,支持事务性更新和版本迁移。
</p>
<div class="note-box">
<strong>&#x1F4A1; 设计决策:</strong>采用数据库存储配置而非 YAML/JSON 文件,原因:
<br>1. 配置与工作空间数据原子性一致
<br>2. 支持并发访问和事务保护
<br>3. 统一备份和迁移策略
<br>4. 避免文件格式解析错误
</div>
<h3>配置表结构</h3>
<div class="code-block">
<pre><span class="hl-cm">-- .metona/agent.db > app_config</span>
<span class="hl-kw">CREATE TABLE</span> app_config (
<span class="hl-prop">key</span> TEXT <span class="hl-kw">PRIMARY KEY</span>,
<span class="hl-prop">value</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- JSON 格式值</span>
<span class="hl-prop">category</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- llm | agent | tools | security | logging | mcp</span>
<span class="hl-prop">updated_at</span> TEXT <span class="hl-kw">DEFAULT</span> (datetime(<span class="hl-str">'now'</span>))
);
<span class="hl-cm">-- 配置分类索引</span>
<span class="hl-kw">CREATE INDEX</span> idx_config_category <span class="hl-kw">ON</span> app_config(category);</pre>
</div>
<h3>配置项一览</h3>
<table class="spec">
<tr><th>分类</th><th></th><th>类型</th><th>默认值</th><th>说明</th></tr>
<tr><td class="f-type" rowspan="5">llm</td><td class="f-name">provider</td><td>string</td><td>"deepseek"</td><td>LLM 提供商</td></tr>
<tr><td class="f-name">model</td><td>string</td><td>"deepseek-v4-pro"</td><td>模型名称</td></tr>
<tr><td class="f-name">apiKey</td><td>string</td><td>""</td><td>API 密钥(加密存储)</td></tr>
<tr><td class="f-name">baseURL</td><td>string</td><td>""</td><td>API 基础 URL</td></tr>
<tr><td class="f-name">params</td><td>JSON</td><td>{temperature:0, maxTokens:8192}</td><td>生成参数</td></tr>
<tr><td class="f-name">fallbackProvider</td><td>string</td><td>""</td><td>备选 LLM 提供商(故障转移)</td></tr>
<tr><td class="f-name">fallbackModel</td><td>string</td><td>""</td><td>备选模型名称</td></tr>
<tr><td class="f-type" rowspan="4">agent</td><td class="f-name">maxIterations</td><td>number</td><td>20</td><td>最大迭代次数</td></tr>
<tr><td class="f-name">totalTimeoutMs</td><td>number</td><td>600000</td><td>总超时(毫秒)</td></tr>
<tr><td class="f-name">enableThinking</td><td>boolean</td><td>true</td><td>启用思考模式</td></tr>
<tr><td class="f-name">thinkingEffort</td><td>string</td><td>"high"</td><td>思考强度: low/medium/high/max</td></tr>
<tr><td class="f-type" rowspan="3">tools</td><td class="f-name">filesystem.enabled</td><td>boolean</td><td>true</td><td>文件系统工具开关</td></tr>
<tr><td class="f-name">web.enabled</td><td>boolean</td><td>true</td><td>网络工具开关</td></tr>
<tr><td class="f-name">command.enabled</td><td>boolean</td><td>true</td><td>命令工具开关</td></tr>
<tr><td class="f-type" rowspan="3">security</td><td class="f-name">requireWriteConfirmation</td><td>boolean</td><td>true</td><td>写操作需确认</td></tr>
<tr><td class="f-name">maxFileWriteSizeKB</td><td>number</td><td>1024</td><td>最大写入文件大小</td></tr>
<tr><td class="f-name">promptInjectionDefense</td><td>boolean</td><td>true</td><td>注入防护开关</td></tr>
<tr><td class="f-type" rowspan="3">logging</td><td class="f-name">level</td><td>string</td><td>"info"</td><td>日志级别</td></tr>
<tr><td class="f-name">auditEnabled</td><td>boolean</td><td>true</td><td>审计日志开关</td></tr>
<tr><td class="f-name">traceEnabled</td><td>boolean</td><td>true</td><td>追踪日志开关</td></tr>
</table>
<h3>MCP Server 配置表</h3>
<div class="code-block">
<pre><span class="hl-cm">-- .metona/agent.db > mcp_servers</span>
<span class="hl-kw">CREATE TABLE</span> mcp_servers (
<span class="hl-prop">id</span> TEXT <span class="hl-kw">PRIMARY KEY</span>,
<span class="hl-prop">name</span> TEXT <span class="hl-kw">NOT NULL UNIQUE</span>,
<span class="hl-prop">transport</span> TEXT <span class="hl-kw">CHECK</span>(transport <span class="hl-kw">IN</span> (<span class="hl-str">'stdio'</span>, <span class="hl-str">'sse'</span>)),
<span class="hl-prop">command</span> TEXT, <span class="hl-cm">-- stdio 模式的命令</span>
<span class="hl-prop">args</span> TEXT, <span class="hl-cm">-- JSON 数组格式的参数</span>
<span class="hl-prop">url</span> TEXT, <span class="hl-cm">-- SSE 模式的 URL</span>
<span class="hl-prop">enabled</span> BOOLEAN <span class="hl-kw">DEFAULT</span> TRUE,
<span class="hl-prop">created_at</span> TEXT <span class="hl-kw">DEFAULT</span> (datetime(<span class="hl-str">'now'</span>)),
<span class="hl-prop">updated_at</span> TEXT <span class="hl-kw">DEFAULT</span> (datetime(<span class="hl-str">'now'</span>))
);</pre>
</div>
<div class="note-box">
<strong>&#x1F527; 配置管理:</strong>用户通过设置界面修改配置,变更即时生效并持久化到数据库。
首次创建工作空间时,系统自动插入所有配置项的默认值。
</div>
</section>
<hr class="section-divider">
<!-- ====== 27 个内置工具 ====== -->
<section class="api-section" id="tools-overview">
<h2>&#x1F4CA; 27 个内置工具 — 总表</h2>
<p class="desc">所有工具使用 <strong>Metona IR 的 MetonaToolDef / MetonaToolCall / MetonaToolResult</strong> 结构。内置在 Tool Registry 中,Adaper 为 LLM 生成 JSON Schema 格式的描述。</p>
<table class="spec">
<tr><th>#</th><th>工具名</th><th>分类</th><th>风险</th><th>需确认</th><th>核心功能</th></tr>
<tr><td class="f-name">1</td><td class="f-name">read_file</td><td class="f-type">filesystem</td><td class="f-risk risk-safe">SAFE</td><td></td><td>读取文件内容,支持分页</td></tr>
<tr><td class="f-name">2</td><td class="f-name">write_file</td><td class="f-type">filesystem</td><td class="f-risk risk-medium">MEDIUM</td><td>是(可配)</td><td>写入/覆盖/追加文件内容</td></tr>
<tr><td class="f-name">3</td><td class="f-name">list_directory</td><td class="f-type">filesystem</td><td class="f-risk risk-safe">SAFE</td><td></td><td>列出目录内容</td></tr>
<tr><td class="f-name">4</td><td class="f-name">search_files</td><td class="f-type">filesystem</td><td class="f-risk risk-safe">SAFE</td><td></td><td>按模式搜索文件(名称/内容)</td></tr>
<tr><td class="f-name">5</td><td class="f-name">web_search</td><td class="f-type">network</td><td class="f-risk risk-medium">LOW</td><td></td><td>网络搜索,返回结果列表</td></tr>
<tr><td class="f-name">6</td><td class="f-name">web_fetch</td><td class="f-type">network</td><td class="f-risk risk-medium">LOW</td><td></td><td>抓取网页内容转 Markdown</td></tr>
<tr><td class="f-name">7</td><td class="f-name">memory_store</td><td class="f-type">database</td><td class="f-risk risk-medium">MEDIUM</td><td></td><td>存储一条记忆到 SQLite</td></tr>
<tr><td class="f-name">8</td><td class="f-name">memory_search</td><td class="f-type">database</td><td class="f-risk risk-safe">SAFE</td><td></td><td>检索记忆(关键词匹配)</td></tr>
<tr><td class="f-name">9</td><td class="f-name">run_command</td><td class="f-type">code_execution</td><td class="f-risk risk-high">HIGH</td><td></td><td>执行 Shell 命令,沙箱限制</td></tr>
<tr><td colspan="6" style="padding:14px;color:var(--text-dim);font-size:13px;">完整 27 个工具列表详见 README.md「内置工具」章节。新增工具涵盖:file_editor、code_search、diff_viewer、web_browser、http_request、git_status/git_diff/git_log/git_commit、lint_code、run_tests、project_info、delegate_task、task_manager、todo_write、think、view_image。</td></tr>
</table>
</section>
<!-- --- 文件系统工具 --- -->
<section class="api-section" id="tool-filesystem">
<h2>&#x1F4C4; 类别一:文件系统工具(5个)</h2>
<h3>1. read_file</h3>
<p class="desc">读取文件完整内容。支持行偏移和行数限制,自动检测二进制文件。文件超过 100K 字符时返回截断提示。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">file_path</td><td class="f-type">string</td><td class="f-req">必填</td><td>文件路径(相对于工作空间)</td></tr>
<tr><td class="f-name">offset</td><td class="f-type">number</td><td class="f-opt">可选</td><td>起始行号(1-indexed,默认 1</td></tr>
<tr><td class="f-name">limit</td><td class="f-type">number</td><td class="f-opt">可选</td><td>最大行数(默认 500,最大 2000)</td></tr>
</table>
<div class="note-box"><strong>&#x1F4A1;</strong> 返回格式:<code>{ content, total_lines, truncated, file_size }</code>。truncated=true 时须提示用户指定 offset 继续读取。</div>
<h3>2. write_file</h3>
<p class="desc">写入内容到文件。默认覆盖模式,支持追加。写操作前校验路径白名单,默认需用户确认。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">file_path</td><td class="f-type">string</td><td class="f-req">必填</td><td>目标文件路径</td></tr>
<tr><td class="f-name">content</td><td class="f-type">string</td><td class="f-req">必填</td><td>写入内容</td></tr>
<tr><td class="f-name">mode</td><td class="f-type">string</td><td class="f-opt">可选</td><td>"overwrite"(默认)/ "append"</td></tr>
</table>
<h3>3. list_directory</h3>
<p class="desc">列出目录内容,支持递归深度控制和 glob 过滤。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">dir_path</td><td class="f-type">string</td><td class="f-opt">可选</td><td>目录路径(默认工作空间根)</td></tr>
<tr><td class="f-name">depth</td><td class="f-type">number</td><td class="f-opt">可选</td><td>递归深度(默认 1,最大 5</td></tr>
<tr><td class="f-name">glob</td><td class="f-type">string</td><td class="f-opt">可选</td><td>文件名过滤 (如 "*.ts")</td></tr>
</table>
<h3>4. search_files</h3>
<p class="desc">在目录中按正则/glob 搜索文件内容或文件名。底层使用 ripgrep。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">pattern</td><td class="f-type">string</td><td class="f-req">必填</td><td>搜索正则或 glob 模式</td></tr>
<tr><td class="f-name">target</td><td class="f-type">string</td><td class="f-opt">可选</td><td>"content"(默认)/ "files"</td></tr>
<tr><td class="f-name">path</td><td class="f-type">string</td><td class="f-opt">可选</td><td>搜索目录(默认工作空间根)</td></tr>
<tr><td class="f-name">file_glob</td><td class="f-type">string</td><td class="f-opt">可选</td><td>限定文件名(如 "*.py"</td></tr>
<tr><td class="f-name">limit</td><td class="f-type">number</td><td class="f-opt">可选</td><td>最大结果数(默认 50</td></tr>
</table>
</section>
<!-- --- 网络工具 --- -->
<section class="api-section" id="tool-web">
<h2>&#x1F310; 类别二:网络搜索与抓取(2个)(另有 18 个工具见 README.md</h2>
<h3>5. web_search</h3>
<p class="desc">执行网络搜索,返回标题、摘要和 URL。支持搜索运算符(site:、filetype: 等)。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">query</td><td class="f-type">string</td><td class="f-req">必填</td><td>搜索关键词(支持 site:domain filetype:pdf 等)</td></tr>
<tr><td class="f-name">limit</td><td class="f-type">number</td><td class="f-opt">可选</td><td>结果数(默认 5,最大 100</td></tr>
</table>
<h3>6. web_fetch</h3>
<p class="desc">抓取网页内容,三阶段回退(HTTP + 反爬 + 浏览器渲染),10MB 限制</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">urls</td><td class="f-type">string[]</td><td class="f-req">必填</td><td>待抓取的 URL 列表(最多 5 个)</td></tr>
</table>
</section>
<!-- --- 记忆工具 --- -->
<section class="api-section" id="tool-memory">
<h2>&#x1F9E0; 类别三:记忆工具(2个)(另有 18 个工具见 README.md</h2>
<h3>7. memory_store</h3>
<p class="desc">将一条内容存入持久记忆。写入 SQLite,支持关键词检索。Agent 可在对话中保存重要信息。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">content</td><td class="f-type">string</td><td class="f-req">必填</td><td>记忆内容</td></tr>
<tr><td class="f-name">type</td><td class="f-type">string</td><td class="f-req">必填</td><td>"episodic"(情节)/ "semantic"(语义)/ "working"(工作)</td></tr>
<tr><td class="f-name">importance</td><td class="f-type">number</td><td class="f-opt">可选</td><td>重要程度 0-1(默认 0.5</td></tr>
<tr><td class="f-name">source</td><td class="f-type">string</td><td class="f-opt">可选</td><td>来源标识(默认 "agent"</td></tr>
<tr><td class="f-name">tags</td><td class="f-type">string[]</td><td class="f-opt">可选</td><td>标签列表</td></tr>
</table>
<h3>8. memory_search</h3>
<p class="desc">检索记忆库:关键词精确匹配,返回相关性排序结果。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">query</td><td class="f-type">string</td><td class="f-req">必填</td><td>搜索关键词或语义查询</td></tr>
<tr><td class="f-name">type</td><td class="f-type">string</td><td class="f-opt">可选</td><td>过滤记忆类型</td></tr>
<tr><td class="f-name">topK</td><td class="f-type">number</td><td class="f-opt">可选</td><td>返回结果数(默认 5</td></tr>
<tr><td class="f-name">threshold</td><td class="f-type">number</td><td class="f-opt">可选</td><td>相似度阈值(默认 0.7</td></tr>
</table>
</section>
<!-- --- 命令工具 --- -->
<section class="api-section" id="tool-command">
<h2>&#x2692;&#xFE0F; 类别四:命令工具(1个)(另有 18 个工具见 README.md</h2>
<h3>9. run_command</h3>
<p class="desc">在沙箱环境中执行 Shell 命令。命令在工作空间目录下运行,有超时限制和输出截断。高危命令需用户确认。</p>
<table class="spec">
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
<tr><td class="f-name">command</td><td class="f-type">string</td><td class="f-req">必填</td><td>Shell 命令</td></tr>
<tr><td class="f-name">workdir</td><td class="f-type">string</td><td class="f-opt">可选</td><td>执行目录(默认工作空间根)</td></tr>
<tr><td class="f-name">timeout</td><td class="f-type">number</td><td class="f-opt">可选</td><td>超时毫秒(默认 120000</td></tr>
</table>
<div class="warn-box">
<strong>&#x26A0; 安全规则(命令解析 + 模式匹配):</strong>使用 <code>shell-quote</code> 库解析命令为 token 数组,再对每个 token 做模式匹配。<strong>不使用</strong>简单字符串匹配(易被绕过)。
<br><br><strong>硬阻止列表(绝对禁止执行):</strong>
<ul style="margin-top:8px;padding-left:20px;">
<li><code>rm</code> + 包含 <code>/</code> 的路径参数(阻止删除根/系统目录)</li>
<li><code>sudo</code> / <code>su</code> / <code>doas</code>(提权命令)</li>
<li><code>shutdown</code> / <code>reboot</code> / <code>halt</code> / <code>poweroff</code></li>
<li><code>curl ... | sh</code> / <code>curl ... | bash</code> / <code>wget ... | sh</code>(远程执行)</li>
<li><code>dd</code> + <code>of=/dev/</code>(写设备文件)</li>
<li><code>mkfs</code> / <code>fdisk</code>(格式化磁盘)</li>
<li><code>chmod 777</code> / <code>chown</code> 到非当前用户</li>
</ul>
<strong>需确认列表(用户显式确认后执行):</strong>
<ul style="margin-top:8px;padding-left:20px;">
<li><code>eval</code> / <code>exec</code>(动态执行)</li>
<li>修改系统配置文件的命令</li>
<li>安装/卸载软件的命令(<code>apt</code> / <code>brew</code> / <code>npm install -g</code></li>
<li>网络请求类命令(<code>curl</code> / <code>wget</code> 不含管道)</li>
</ul>
</div>
<div class="note-box">
<strong>&#x1F527; 实现要求:</strong><code>SandboxManager</code> 中实现 <code>validateCommand(command: string): {allowed: boolean; reason?: string}</code> 方法。使用 <code>shell-quote</code>(npm 包)解析命令,检查每个 token。安全规则配置存储在 <code>app_config</code> 表中(<code>security.commandBlocklist</code> / <code>security.commandConfirmList</code>),用户可在设置界面自定义。
</div>
</section>
<hr class="section-divider">
<!-- ====== 4 个用户级磁盘文件 ====== -->
<section class="api-section" id="disk-files">
<h2>&#x1F4BE; 4 个用户级磁盘文件</h2>
<p class="desc">
4 个 <code>.md</code> 文件位于工作空间根目录,是工作空间的<strong>必需文件</strong>
其中 <code>SOUL.md</code><code>AGENTS.md</code><code>USERS.md</code> 完全由用户自定义,<code>MEMORY.md</code> 由 Agent 维护但用户可编辑。
</p>
<table class="spec">
<tr><th>文件</th><th>必需</th><th>注入阶段</th><th>作用</th><th>内容来源</th><th>缺失时处理</th></tr>
<tr><td class="f-name">SOUL.md</td><td class="f-req"></td><td class="f-type">静态区(优先)</td><td>定义 Agent 身份、性格、核心价值观</td><td>用户自定义</td><td>自动创建空文件</td></tr>
<tr><td class="f-name">AGENTS.md</td><td class="f-req"></td><td class="f-type">静态区</td><td>定义行为规则、边界、工作流</td><td>用户自定义</td><td>自动创建空文件</td></tr>
<tr><td class="f-name">MEMORY.md</td><td class="f-req"></td><td class="f-type">动态区</td><td>跨会话持久记忆</td><td>Agent 维护 + 用户可编辑</td><td>自动创建带元数据头的规范文件</td></tr>
<tr><td class="f-name">USERS.md</td><td class="f-req"></td><td class="f-type">静态区</td><td>用户画像:背景、技能、偏好</td><td>用户自定义</td><td>自动创建空文件</td></tr>
</table>
<div class="note-box">
<strong>&#x2705; 自动创建策略:</strong>所有必需文件缺失时都会自动创建,不会阻止启动。
<br><code>SOUL.md</code><code>AGENTS.md</code><code>USERS.md</code>:创建空文件,提示用户编辑
<br><code>MEMORY.md</code>:创建带完整元数据头的规范文件(格式版本、创建时间、工作空间路径)
</div>
</section>
<section class="api-section" id="file-soul">
<h2>&#x2728; SOUL.md — AI 灵魂定义</h2>
<p class="desc">定义 Agent 的身份、性格和核心价值观。加载后注入 System Prompt 的最高优先级静态区。<strong>此文件完全由用户自定义,Metona 不提供默认内容。</strong></p>
<div class="file-card">
<h4>&#x2728; SOUL.md</h4>
<div class="path">~/MetonaWorkspaces/my-project/SOUL.md</div>
<p>用户自定义文件,定义 Agent 的灵魂</p>
</div>
<div class="note-box">
<strong>&#x1F4DD; 用户自定义:</strong>SOUL.md 的内容完全由用户决定。Metona 不会预设任何角色、性格或价值观。
<br>用户可以定义任何类型的 Agent:编程助手、写作伙伴、学习导师、虚拟角色等。
</div>
<h4>推荐结构(仅供参考)</h4>
<div class="code-block">
<pre><span class="hl-cm"># SOUL.md — 用户自定义 Agent 灵魂</span>
<span class="hl-cm">## 身份</span>
<span class="hl-cm"># 定义 Agent 是谁:名称、角色、核心特征</span>
<span class="hl-cm">## 性格与语气</span>
<span class="hl-cm"># 定义 Agent 如何与用户交流:风格、语气、态度</span>
<span class="hl-cm">## 核心价值观</span>
<span class="hl-cm"># 定义 Agent 的行为准则和底线</span></pre>
</div>
<h4>SOUL.md 作用域</h4>
<table class="spec">
<tr><th>对象</th><th>影响</th></tr>
<tr><td>LLM 推理</td><td>全部轮次注入,决定回复语气、风格和价值观</td></tr>
<tr><td>工具调用</td><td>影响安全决策和行为边界</td></tr>
<tr><td>记忆存储</td><td>影响哪些信息被认为值得记忆</td></tr>
<tr><td>错误处理</td><td>决定错误回复的风格和态度</td></tr>
</table>
</section>
<section class="api-section" id="file-agents">
<h2>&#x1F4CB; AGENTS.md — AI 行为定义</h2>
<p class="desc">定义 Agent 的行为规则、边界、工作流程和工具使用权限。<strong>此文件完全由用户自定义</strong>,Metona 仅提供内置最小安全规则作为兜底。</p>
<div class="file-card">
<h4>&#x1F4CB; AGENTS.md</h4>
<div class="path">~/MetonaWorkspaces/my-project/AGENTS.md</div>
<p>用户自定义文件,定义 Agent 行为边界</p>
</div>
<div class="note-box">
<strong>&#x1F4DD; 用户自定义:</strong>AGENTS.md 的内容完全由用户决定。Metona 不预设行为规则。
<br>用户可以定义任意复杂度的规则体系,从简单的行为准则到详细的多层规则架构。
</div>
<h4>推荐结构(仅供参考)</h4>
<div class="code-block">
<pre><span class="hl-cm"># AGENTS.md — 用户自定义行为规则</span>
<span class="hl-cm">## 行为准则</span>
<span class="hl-cm"># 定义 Agent 必须遵守的规则</span>
<span class="hl-cm">## 工具使用规范</span>
<span class="hl-cm"># 定义哪些工具可用、何时需要确认</span>
<span class="hl-cm">## 安全边界</span>
<span class="hl-cm"># 定义 Agent 的行为底线</span>
<span class="hl-cm">## 工作流程</span>
<span class="hl-cm"># 定义 Agent 的推理和执行流程</span></pre>
</div>
<h4>内置最小安全规则(兜底)</h4>
<div class="warn-box">
<strong>&#x1F6E1; 无论 AGENTS.md 如何定义,以下规则始终生效:</strong>
<ul style="margin-top:8px; padding-left:20px;">
<li>不执行明确违法的操作</li>
<li>不泄露用户隐私数据</li>
<li>不可逆操作前必须确认</li>
<li>工具调用失败必须如实报告</li>
</ul>
</div>
<h4>AGENTS.md 作用域</h4>
<table class="spec">
<tr><th>对象</th><th>影响</th></tr>
<tr><td>Agent 决策</td><td>所有行为受用户定义的规则约束</td></tr>
<tr><td>工具权限</td><td>定义哪些工具可用、需要确认、被禁用</td></tr>
<tr><td>输出验证</td><td>根据用户规则验证输出合规性</td></tr>
<tr><td>工作流</td><td>引导 Agent 的推理和执行流程</td></tr>
</table>
</section>
<section class="api-section" id="file-memory">
<h2>&#x1F9E9; MEMORY.md — AI 记忆文件</h2>
<p class="desc">跨会话持久记忆。Agent 启动时读取注入上下文,会话结束后自动追加新记忆。<strong>此文件有严格的格式规范,Agent 写入时必须遵循,用户编辑时也应遵守。</strong></p>
<div class="file-card">
<h4>&#x1F9E9; MEMORY.md</h4>
<div class="path">~/MetonaWorkspaces/my-project/MEMORY.md</div>
<p>Agent 维护 + 用户可编辑的记忆文件</p>
</div>
<h4>格式规范</h4>
<div class="warn-box">
<strong>&#x1F4CB; 强制格式:</strong>MEMORY.md 必须遵循以下结构,否则 Agent 写入时会自动修正格式。
</div>
<h4>创建时的初始模板(自动填充)</h4>
<p class="desc">当 MEMORY.md 不存在时,Agent 自动创建以下带元数据头的规范文件:</p>
<div class="code-block">
<pre><span class="hl-cm"># MEMORY.md — AI 持久记忆</span>
<span class="hl-cm">#</span>
<span class="hl-cm"># 格式版本: 1.0</span>
<span class="hl-cm"># 创建时间: 2026-06-25T12:00:00Z</span>
<span class="hl-cm"># 最后更新: 2026-06-25T12:00:00Z</span>
<span class="hl-cm"># 工作空间: /home/user/MetonaWorkspaces/my-project</span>
<span class="hl-cm">#</span>
<span class="hl-cm"># 此文件由 Metona Agent 自动维护,用户可手动编辑。</span>
<span class="hl-cm"># 格式规范详见文档,Agent 写入时会自动校验格式。</span>
<span class="hl-cm">## 用户偏好</span>
<span class="hl-cm"># 格式: - [类别] 内容描述</span>
<span class="hl-cm"># 示例: - [沟通风格] 用户喜欢简洁的回答</span>
<span class="hl-cm">## 项目上下文</span>
<span class="hl-cm"># 格式: - [项目名] 关键信息</span>
<span class="hl-cm"># 示例: - [MyApp] 技术栈: React + TypeScript</span>
<span class="hl-cm">## 重要决策</span>
<span class="hl-cm"># 格式: - YYYY-MM-DD: 决策内容</span>
<span class="hl-cm"># 示例: - 2026-06-25: 选择 sql.js 作为数据库方案</span>
<span class="hl-cm">## 待办事项</span>
<span class="hl-cm"># 格式: - [状态] 任务描述 (状态: pending/done/cancelled)</span>
<span class="hl-cm"># 示例: - [pending] 实现用户登录功能</span>
<span class="hl-cm">## 已知问题</span>
<span class="hl-cm"># 格式: - 问题描述 | 影响范围 | 解决方案</span>
<span class="hl-cm"># 示例: - 首次加载慢 | 启动 | 预加载优化</span></pre>
</div>
<h4>完整示例(有内容时)</h4>
<div class="code-block">
<pre><span class="hl-cm"># MEMORY.md — AI 持久记忆</span>
<span class="hl-cm">#</span>
<span class="hl-cm"># 格式版本: 1.0</span>
<span class="hl-cm"># 创建时间: 2026-06-25T12:00:00Z</span>
<span class="hl-cm"># 最后更新: 2026-06-25T15:30:00Z</span>
<span class="hl-cm"># 工作空间: /home/user/MetonaWorkspaces/my-project</span>
<span class="hl-cm">## 用户偏好</span>
- [沟通风格] 用户喜欢简洁的回答,不需要过度解释
- [代码风格] 代码块使用 TypeScript 语法高亮
- [工具偏好] 项目使用 pnpm 而非 npm
<span class="hl-cm">## 项目上下文</span>
- [MetonaAI-Desktop] 技术栈: React 18 + Electron 28 + TypeScript 5.x
- [MetonaAI-Desktop] 构建工具: Vite + electron-builder
<span class="hl-cm">## 重要决策</span>
- 2026-06-20: 选择 sql.js 作为 SQLite 实现
- 2026-06-22: 决定采用四层 Harness 架构
<span class="hl-cm">## 待办事项</span>
- [pending] 实现 MCP Server 动态加载
- [done] 完成 Agent Loop 状态机
<span class="hl-cm">## 已知问题</span>
- Windows 下 electron-builder 签名需要证书 | 部署 | 使用代码签名证书</pre>
</div>
<h4>格式校验规则</h4>
<table class="spec">
<tr><th>规则</th><th>说明</th><th>违反处理</th></tr>
<tr><td class="f-name">元数据头</td><td>必须包含 <code># 格式版本</code><code># 创建时间</code><code># 最后更新</code><code># 工作空间</code></td><td>自动补充缺失的元数据</td></tr>
<tr><td class="f-name">分区结构</td><td>必须包含 <code>## 用户偏好</code><code>## 项目上下文</code><code>## 重要决策</code> 三个分区</td><td>自动创建缺失分区</td></tr>
<tr><td class="f-name">条目前缀</td><td>每个条目必须以 <code>- </code> 开头,后跟 <code>[类别/标签]</code></td><td>自动添加默认标签</td></tr>
<tr><td class="f-name">日期格式</td><td>决策条目必须使用 <code>YYYY-MM-DD</code> 格式</td><td>自动格式化为 ISO 日期</td></tr>
<tr><td class="f-name">状态标记</td><td>待办事项必须包含 <code>[pending/done/cancelled]</code> 状态</td><td>默认标记为 <code>[pending]</code></td></tr>
<tr><td class="f-name">时间戳更新</td><td>每次写入时自动更新 <code># 最后更新</code> 时间戳</td><td>自动更新</td></tr>
</table>
<h4>MEMORY.md 生命周期</h4>
<div class="flow-step"><span class="flow-num">1</span><span class="flow-text"><strong>首次创建</strong>:文件不存在时自动创建,包含完整元数据头(格式版本、创建时间、工作空间路径)</span></div>
<div class="flow-step"><span class="flow-num">2</span><span class="flow-text"><strong>启动读取</strong>Agent 初始化时解析 MEMORY.md,校验格式,注入 System Prompt 动态区</span></div>
<div class="flow-step"><span class="flow-num">3</span><span class="flow-text"><strong>会话中使用</strong>Agent 可通过 <code>memory_search</code> 检索 MEMORY.md 内容</span></div>
<div class="flow-step"><span class="flow-num">4</span><span class="flow-text"><strong>会话结束后</strong>:Agent 自动分析本次会话,按格式规范追加新记忆条目,更新时间戳</span></div>
<div class="flow-step"><span class="flow-num">5</span><span class="flow-text"><strong>格式校验</strong>:每次写入前校验格式,不合规内容自动修正</span></div>
<div class="flow-step"><span class="flow-num">6</span><span class="flow-text"><strong>用户编辑</strong>:用户可随时编辑,Agent 下次启动时重新校验格式</span></div>
<div class="note-box">
<strong>&#x1F4A1; 格式保护:</strong>Agent 写入 MEMORY.md 时会严格遵循格式规范。
如果用户手动编辑导致格式不合规,Agent 会在下次启动时提示并尝试自动修正,不会丢失已有内容。
</div>
<h4>MEMORY.md 与 SQLite 记忆系统的关系</h4>
<p class="desc">MEMORY.md 磁盘文件与 SQLite 数据库中的记忆表是<strong>互补关系</strong>,各有明确职责:</p>
<table class="spec">
<tr><th>维度</th><th>MEMORY.md(磁盘文件)</th><th>SQLite memories(数据库)</th></tr>
<tr><td class="f-name">定位</td><td>用户可读可编辑的跨会话记忆摘要</td><td>结构化记忆存储,支持检索/评分/过期</td></tr>
<tr><td class="f-name">格式</td><td>Markdown,有严格格式规范</td><td>结构化表(episodic_memories / semantic_memories / working_memories</td></tr>
<tr><td class="f-name">谁写入</td><td>Agent 会话结束后追加 + 用户手动编辑</td><td>Agent 运行时通过 memory_store 工具写入</td></tr>
<tr><td class="f-name">谁读取</td><td>Agent 启动时解析,注入 System Prompt</td><td>Agent 运行时通过 memory_search 检索</td></tr>
<tr><td class="f-name">检索方式</td><td>全量注入上下文(不检索)</td><td>关键词/语义检索,按相关性排序</td></tr>
</table>
<div class="note-box">
<strong>&#x1F504; 同步策略:</strong>
<br><strong>Agent 启动时</strong>:读取 MEMORY.md → 解析 → 注入 System Prompt 动态区(不写入 SQLite
<br><strong>Agent 运行时</strong>memory_store / memory_search 操作 SQLite(不读写 MEMORY.md
<br><strong>会话结束后</strong>Agent 从 SQLite 提取本次会话的重要记忆 → 追加到 MEMORY.md(按格式规范)
<br><strong>用户编辑后</strong>:下次启动时 Agent 重新解析 MEMORY.md,不回写 SQLite
<br><strong>Source of Truth</strong>:MEMORY.md 是用户可见的“记忆摘要”,SQLite 是 Agent 运行时的“记忆工作区”。两者不强制实时同步,通过启动读取 + 会话结束追加实现单向流动。
</div>
</section>
<section class="api-section" id="file-users">
<h2>&#x1F464; USERS.md — 用户信息画像</h2>
<p class="desc">定义用户的背景、技能、偏好和当前目标。Agent 据此调整回答深度、技术栈偏向和交互风格。<strong>此文件完全由用户自定义。</strong></p>
<div class="file-card">
<h4>&#x1F464; USERS.md</h4>
<div class="path">~/MetonaWorkspaces/my-project/USERS.md</div>
<p>用户自定义文件,描述用户画像</p>
</div>
<div class="note-box">
<strong>&#x1F4DD; 用户自定义:</strong>USERS.md 的内容完全由用户决定。Metona 不预设任何用户信息。
<br>用户可以描述自己的背景、技能、偏好、目标等,帮助 Agent 更好地理解和服务用户。
</div>
<h4>推荐结构(仅供参考)</h4>
<div class="code-block">
<pre><span class="hl-cm"># USERS.md — 用户自定义画像</span>
<span class="hl-cm">## 基本信息</span>
<span class="hl-cm"># 称呼、角色、经验等</span>
<span class="hl-cm">## 技术栈</span>
<span class="hl-cm"># 熟悉的技术、工具、框架</span>
<span class="hl-cm">## 偏好</span>
<span class="hl-cm"># 工具偏好、沟通风格、工作习惯</span>
<span class="hl-cm">## 当前目标</span>
<span class="hl-cm"># 正在做什么、想要达成什么</span></pre>
</div>
<h4>USERS.md 作用域</h4>
<table class="spec">
<tr><th>对象</th><th>影响</th></tr>
<tr><td>技术回答</td><td>根据用户技术栈调整回答深度和示例</td></tr>
<tr><td>工具选择</td><td>根据用户偏好选择工具和命令</td></tr>
<tr><td>安全策略</td><td>根据用户角色调整权限级别</td></tr>
<tr><td>语气风格</td><td>匹配用户的沟通习惯和偏好</td></tr>
</table>
</section>
<hr class="section-divider">
<!-- ====== 全链路透明 ====== -->
<section class="api-section" id="trace">
<h2>&#x1F50D; 全链路透明可追踪</h2>
<p class="desc">
用户可在任意时刻<strong>完整回溯</strong> Agent 的每一步决策过程。所有数据分为三个可见层级:
</p>
<h3>三层可见性</h3>
<table class="spec">
<tr><th>层级</th><th>名称</th><th>存储位置</th><th>可见内容</th><th>用户访问方式</th></tr>
<tr>
<td class="f-name">L0</td>
<td>UI 实时展示</td>
<td class="f-type">内存</td>
<td>Thought 过程、ToolCall 参数/结果、最终答案</td>
<td>聊天界面 / TraceViewer 面板</td>
</tr>
<tr>
<td class="f-name">L1</td>
<td>会话日志</td>
<td class="f-type">logs/session_{id}.jsonl</td>
<td>每轮 ReAct 迭代的完整状态、LLM 原始输入/输出、工具调用详情</td>
<td>直接打开 .jsonl 或内置日志查看器</td>
</tr>
<tr>
<td class="f-name">L2</td>
<td>审计数据库</td>
<td class="f-type">.metona/agent.db</td>
<td>结构化审计记录:谁(actor)、做了什么(target)、结果(outcome)、耗时</td>
<td>SQLite 浏览器 / 内置控制台</td>
</tr>
</table>
<h3>会话日志格式 (.jsonl)</h3>
<div class="code-block">
<pre><span class="hl-cm"># logs/session_s_abc_20260625T120000Z.jsonl</span>
{"seq":0,"ts":"2026-06-25T12:00:00.000Z","event":"session_start","sessionId":"s_abc","workspace":"/home/user/my-project"}
{"seq":1,"ts":"2026-06-25T12:00:01.000Z","event":"context_built","sessionId":"s_abc","tokens":1240,"ratio":0.01}
{"seq":2,"ts":"2026-06-25T12:00:01.500Z","event":"iteration_start","sessionId":"s_abc","iteration":1}
{"seq":3,"ts":"2026-06-25T12:00:02.100Z","event":"llm_request","sessionId":"s_abc","iteration":1,"provider":"deepseek","model":"deepseek-v4-pro","messages":[...]}
{"seq":4,"ts":"2026-06-25T12:00:03.800Z","event":"llm_response","sessionId":"s_abc","iteration":1,"content":"Thought: 需要读取文件...","finishReason":"tool_calls","usage":{"inputTokens":1240,"outputTokens":85,"totalTokens":1325}}
{"seq":5,"ts":"2026-06-25T12:00:03.810Z","event":"tool_call","sessionId":"s_abc","iteration":1,"tool":"read_file","args":{"file_path":"data.csv"}}
{"seq":6,"ts":"2026-06-25T12:00:03.820Z","event":"tool_result","sessionId":"s_abc","iteration":1,"tool":"read_file","success":true,"durationMs":5,"result":"..."}
{"seq":7,"ts":"2026-06-25T12:00:04.500Z","event":"iteration_end","sessionId":"s_abc","iteration":1,"durationMs":3000}
{"seq":8,"ts":"2026-06-25T12:00:10.000Z","event":"session_end","sessionId":"s_abc","totalIterations":3,"totalTokens":5430,"totalDurationMs":10000}</pre>
</div>
</section>
<!-- ====== 日志设计 ====== -->
<section class="api-section" id="logging">
<h2>&#x1F4DD; 日志设计</h2>
<p class="desc">四层日志体系,覆盖从系统级到业务级的全部可观测需求。</p>
<h3>日志分层</h3>
<table class="spec">
<tr><th>层级</th><th>日志类型</th><th>存储</th><th>内容</th></tr>
<tr><td class="f-name">SYS</td><td>系统日志</td><td class="f-type">electron-log 文件</td><td>进程启动/退出、崩溃堆栈、内存/CPU 异常、更新事件</td></tr>
<tr><td class="f-name">AGENT</td><td>Agent 引擎日志</td><td class="f-type">logs/agent.log</td><td>状态转换、迭代计数、超时、压缩触发、错误恢复</td></tr>
<tr><td class="f-name">TOOL</td><td>工具执行日志</td><td class="f-type">.metona/agent.db (audit_logs)</td><td>每次工具调用的参数、结果、耗时、权限校验</td></tr>
<tr><td class="f-name">TRACE</td><td>全链路追踪</td><td class="f-type">logs/session_*.jsonl</td><td>完整会话记录(见上文),可导出分析</td></tr>
</table>
<h3>数据库审计表结构</h3>
<div class="code-block">
<pre><span class="hl-cm">-- .metona/agent.db > audit_logs</span>
<span class="hl-kw">CREATE TABLE</span> audit_logs (
<span class="hl-prop">id</span> INTEGER <span class="hl-kw">PRIMARY KEY AUTOINCREMENT</span>,
<span class="hl-prop">session_id</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- 会话 ID</span>
<span class="hl-prop">iteration</span> INTEGER, <span class="hl-cm">-- ReAct 迭代轮次</span>
<span class="hl-prop">event_type</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- tool_call | permission_check | error | llm_request | llm_response</span>
<span class="hl-prop">actor</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- 'agent' | 'user' | 'system'</span>
<span class="hl-prop">target</span> TEXT <span class="hl-kw">NOT NULL</span>, <span class="hl-cm">-- 操作对象 (工具名 / 模块名)</span>
<span class="hl-prop">details</span> TEXT, <span class="hl-cm">-- JSON 格式详细信息</span>
<span class="hl-prop">outcome</span> TEXT, <span class="hl-cm">-- 'success' | 'denied' | 'error'</span>
<span class="hl-prop">duration_ms</span> INTEGER, <span class="hl-cm">-- 耗时</span>
<span class="hl-prop">created_at</span> TEXT <span class="hl-kw">DEFAULT</span> (datetime(<span class="hl-str">'now'</span>))
);</pre>
</div>
<h3>日志级别</h3>
<table class="spec">
<tr><th>级别</th><th>含义</th><th>示例</th></tr>
<tr><td class="f-name">DEBUG</td><td>开发调试细节</td><td>State transition: THINKING → PARSING</td></tr>
<tr><td class="f-name">INFO</td><td>正常业务流程</td><td>MCP server 'filesystem' connected with 8 tools</td></tr>
<tr><td class="f-name">WARN</td><td>非预期但可恢复</td><td>Context compression triggered at iteration 15</td></tr>
<tr><td class="f-name">ERROR</td><td>需要关注的错误</td><td>Tool 'web_search' failed: network timeout</td></tr>
</table>
</section>
<hr class="section-divider">
<!-- ====== 交互流程 ====== -->
<section class="api-section" id="interaction">
<h2>&#x1F504; 完整交互流程</h2>
<p class="desc">从用户启动应用到一次完整对话结束的端到端流程。</p>
<h3>启动流程</h3>
<div class="flow-step"><span class="flow-num">1</span><span class="flow-text">Electron Main Process 启动 → 初始化日志系统</span></div>
<div class="flow-step"><span class="flow-num">2</span><span class="flow-text">选择/创建工作空间 → 校验必需文件(缺失则自动创建)</span></div>
<div class="flow-step"><span class="flow-num">3</span><span class="flow-text">连接 SQLite.metona/agent.db)→ 执行 schema 迁移 → 加载配置</span></div>
<div class="flow-step"><span class="flow-num">4</span><span class="flow-text">初始化 Provider Adapter(根据数据库配置选择)</span></div>
<div class="flow-step"><span class="flow-num">5</span><span class="flow-text">加载 4 个磁盘文件,构建 System Prompt(空文件不影响启动)</span></div>
<div class="flow-step"><span class="flow-num">6</span><span class="flow-text">连接启用的 MCP Servers → 动态加载 MCP 工具</span></div>
<div class="flow-step"><span class="flow-num">7</span><span class="flow-text">启动 React UIChromium Renderer),Agent 就绪</span></div>
<div class="flow-step"><span class="flow-num">8</span><span class="flow-text">(可选)提示用户编辑 SOUL.md / AGENTS.md / USERS.md 以自定义 Agent</span></div>
<h3>对话流程(一次 ReAct 迭代)</h3>
<div class="flow-step"><span class="flow-num">1</span><span class="flow-text">用户在 ChatInput 输入消息 → IPC <code>agent:sendMessage</code> 发送 MetonaRequest</span></div>
<div class="flow-step"><span class="flow-num">2</span><span class="flow-text">Context Builder 组装 MetonaContextSystem Prompt + 历史 + 记忆 + 工具列表</span></div>
<div class="flow-step"><span class="flow-num">3</span><span class="flow-text">Provider Adapter 将 MetonaContext → 外部 API 格式 → 发送 LLM 请求</span></div>
<div class="flow-step"><span class="flow-num">4</span><span class="flow-text">流式接收响应 → 转换为 MetonaStreamEvent → 实时推送 UI</span></div>
<div class="flow-step"><span class="flow-num">5</span><span class="flow-text">Parser 解析 LLM 输出 → 提取 Thought / ToolCall 或 FinalAnswer</span></div>
<div class="flow-step"><span class="flow-num">6</span><span class="flow-text">(如有 ToolCallPolicy Engine 校验权限 → 执行工具 → 收集 MetonaToolResult</span></div>
<div class="flow-step"><span class="flow-num">7</span><span class="flow-text">Observation 注入上下文 → 写入审计日志 → 进入下一轮迭代或输出最终答案</span></div>
<div class="flow-step"><span class="flow-num">8</span><span class="flow-text">会话结束 → 更新 MEMORY.md + SQLite → 生成 Session Report</span></div>
<h3>IPC 通道总览</h3>
<p class="desc">以下为核心 Agent 交互通道。完整 IPC 通道列表(含会话管理、MCP 管理、应用工具等)见<strong>《构建指南》第八章 IPC 架构</strong>,以构建指南为权威定义。</p>
<table class="spec">
<tr><th>通道</th><th>方向</th><th>数据类型</th><th>用途</th></tr>
<tr><td class="f-name">agent:sendMessage</td><td>Renderer → Main</td><td class="f-type">MetonaRequest</td><td>发送用户消息</td></tr>
<tr><td class="f-name">agent:streamEvent</td><td>Main → Renderer</td><td class="f-type">MetonaStreamEvent</td><td>流式推送 LLM 输出</td></tr>
<tr><td class="f-name">agent:stateChange</td><td>Main → Renderer</td><td class="f-type">AgentLoopState</td><td>状态机状态变化</td></tr>
<tr><td class="f-name">agent:abortSession</td><td>Renderer → Main</td><td class="f-type">{sessionId}</td><td>用户中断会话</td></tr>
<tr><td class="f-name">agent:providerSwitched</td><td>Main → Renderer</td><td class="f-type">{from, to, reason}</td><td>故障转移通知</td></tr>
<tr><td class="f-name">db:searchMemories</td><td>Renderer → Main</td><td class="f-type">MemorySearchOptions</td><td>UI 查询记忆</td></tr>
<tr><td class="f-name">config:get / config:set</td><td>双向</td><td class="f-type">{key, value}</td><td>读写配置</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 完整 IPC 通道分组:</strong>构建指南第八章定义了 4 组 IPC 通道:<br>
<strong>Agent 交互</strong>6 个):上表所列<br>
<strong>会话管理</strong>6 个):<code>sessions:list / create / rename / delete / getMessages / pin</code><br>
<strong>MCP 管理</strong>4 个):<code>mcp:listServers / addServer / removeServer / toggleServer</code><br>
<strong>应用工具</strong>4 个):<code>app:getVersion / getAppDataPath / openExternal / showItemInFolder</code><br>
所有 IPC 通道均通过 Preload <code>contextBridge</code> 安全暴露,渲染进程无 Node.js 访问权限。
</div>
</section>
<!-- FOOTER -->
<div style="text-align:center; padding: 40px 0 20px; color: var(--text-dim); font-size: 13px; border-top: 1px solid var(--border);">
<p>&#x1F3D7;&#xFE0F; MetonaAI-Desktop 架构与交互设计文档</p>
<p>基于: <strong style="color:var(--accent)">生产级通用 AI Agent 构建指南</strong> + <strong style="color:var(--accent)">Metona 内部 IR 标准</strong></p>
<p style="margin-top:6px;">版本 <strong style="color:var(--accent)">v1.1.0</strong> · 2026-07-15</p>
</div>
<!-- Back to Top Button -->
<button id="backToTop" onclick="window.scrollTo({top:0,behavior:'smooth'})" style="
position: fixed;
bottom: 30px;
right: 30px;
width: 44px;
height: 44px;
border-radius: 50%;
background: var(--accent);
color: #000;
border: none;
cursor: pointer;
font-size: 20px;
display: none;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(6,182,212,0.3);
transition: transform 0.2s, opacity 0.2s;
z-index: 1000;
">&#x2191;</button>
</div>
</div>
<script>
document.querySelectorAll('.sidebar a[href^="#"]').forEach(a=>{a.addEventListener('click',e=>{e.preventDefault();const t=document.querySelector(a.getAttribute('href'));t&&t.scrollIntoView({behavior:'smooth',block:'start'})})});
const S=document.querySelectorAll('.api-section'),L=document.querySelectorAll('.sidebar a[href^="#"]'),B=document.getElementById('backToTop');
window.addEventListener('scroll',()=>{let c='';S.forEach(s=>{if(window.scrollY>=s.offsetTop-100)c=s.id});L.forEach(a=>{a.classList.toggle('active',a.getAttribute('href')==='#'+c)});if(B)B.style.display=window.scrollY>300?'flex':'none'});
</script>
</body>
</html>