feat: MetonaAI Desktop 初始项目
- Electron + React + TypeScript 架构 - 三栏布局: Sidebar | ChatPanel | DetailPanel - 9 个内置工具 (文件系统/网络/记忆/命令) - SQLite 持久化 (better-sqlite3) - MUI 暗色/亮色主题系统 - Agent Loop ReAct 状态机引擎 - DeepSeek / Agnes AI / Ollama Provider 适配器 - MCP 协议集成 - 系统托盘 + 全局快捷键 - Tailwind CSS v4 + Tailwind Merge - 修复: Sidebar 缺失 TextField 导入导致黑屏
This commit is contained in:
@@ -0,0 +1,998 @@
|
||||
<!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.0</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>🏗️ MetonaAI-Desktop</h2>
|
||||
</div>
|
||||
<div class="sidebar-section">架构</div>
|
||||
<a href="#overview">📋 总览</a>
|
||||
<a href="#arch">🏗️ 系统架构</a>
|
||||
<a href="#workspace">📁 工作空间</a>
|
||||
<a href="#db-config">💾 数据库配置</a>
|
||||
|
||||
<div class="sidebar-section">9 个基础工具</div>
|
||||
<a href="#tools-overview">📊 工具总表</a>
|
||||
<a href="#tool-filesystem">📄 文件系统工具</a>
|
||||
<a href="#tool-web">🌐 网络搜索与抓取</a>
|
||||
<a href="#tool-memory">🧠 记忆工具</a>
|
||||
<a href="#tool-command">⚒️ 命令工具</a>
|
||||
|
||||
<div class="sidebar-section">4 个磁盘文件</div>
|
||||
<a href="#disk-files">💾 文件总览</a>
|
||||
<a href="#file-soul">✨ SOUL.md</a>
|
||||
<a href="#file-agents">📋 AGENTS.md</a>
|
||||
<a href="#file-memory">🧩 MEMORY.md</a>
|
||||
<a href="#file-users">👤 USERS.md</a>
|
||||
|
||||
<div class="sidebar-section">可追踪 & 日志</div>
|
||||
<a href="#trace">🔍 全链路透明</a>
|
||||
<a href="#logging">📝 日志设计</a>
|
||||
<a href="#interaction">🔄 交互流程</a>
|
||||
</nav>
|
||||
|
||||
<div class="main">
|
||||
|
||||
<div class="hero">
|
||||
<h1>MetonaAI-Desktop 架构与交互设计</h1>
|
||||
<p>基于「生产级通用 AI Agent 桌面应用构建指南」+「Metona 内部 IR 标准」,定义完整的系统架构、9 个基础工具、4 个用户级磁盘文件、工作空间机制、数据库配置规范及全链路可追踪日志体系。</p>
|
||||
<div class="hero-meta">
|
||||
<span><span class="dot dot-cyan"></span> 版本: <strong>v1.0.0</strong></span>
|
||||
<span><span class="dot dot-green"></span> 技术栈: <strong>React + Electron + SQLite</strong></span>
|
||||
<span><span class="dot dot-amber"></span> 日期: <strong>2026-06-26</strong></span>
|
||||
</div>
|
||||
<div class="note-box" style="margin-top:16px">
|
||||
<strong>📋 文档层级:</strong>本文档是 <strong>工作空间、9 个基础工具、4 个磁盘文件、数据库配置的权威定义</strong>,与《构建指南》第三、五、六章对应。冲突时以本文档为准。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
|
||||
<!-- ====== 总览 ====== -->
|
||||
<section class="api-section" id="overview">
|
||||
<h2>📋 设计总览</h2>
|
||||
<p class="desc">
|
||||
MetonaAI-Desktop 是一个运行在用户本地桌面上的通用 AI Agent 应用。它以<strong>工作空间(Workspace)</strong>为基本组织单元,
|
||||
通过 <strong>4 个 Markdown 磁盘文件</strong> 定义 Agent 的灵魂、行为、记忆和用户画像,
|
||||
提供 <strong>9 个基础工具</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">│ │ 9 Base Tools (统一 IR) │ │</span>
|
||||
<span class="hl-box">│ │ read_file | write_file | list_dir | search_files │ │</span>
|
||||
<span class="hl-box">│ │ web_search | web_extract │ │</span>
|
||||
<span class="hl-box">│ │ memory_store | memory_search │ │</span>
|
||||
<span class="hl-box">│ │ run_command │ │</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>🏗️ 系统架构</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 UI:聊天界面、Agent 监控、设置面板、Trace Viewer</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、MemorySystem(SQLite)</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>📁 工作空间(Workspace)</h2>
|
||||
<p class="desc">
|
||||
工作空间是 Metona 的组织核心。每个工作空间是一个<strong>本地磁盘目录</strong>,包含该上下文的全部文件。
|
||||
Agent 启动时加载工作空间下的配置/状态文件,所有工具操作默认限制在工作空间内。
|
||||
</p>
|
||||
|
||||
<h3>默认工作空间</h3>
|
||||
<div class="note-box">
|
||||
<strong>📍 默认路径:</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>✅ 自动创建策略:</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>💾 数据库配置:.metona/agent.db</h2>
|
||||
<p class="desc">
|
||||
所有运行时配置存储在工作空间的 SQLite 数据库中(<code>.metona/agent.db</code>),而非外部配置文件。
|
||||
这确保了配置与工作空间的强绑定,支持事务性更新和版本迁移。
|
||||
</p>
|
||||
|
||||
<div class="note-box">
|
||||
<strong>💡 设计决策:</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>🔧 配置管理:</strong>用户通过设置界面修改配置,变更即时生效并持久化到数据库。
|
||||
首次创建工作空间时,系统自动插入所有配置项的默认值。
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<hr class="section-divider">
|
||||
|
||||
<!-- ====== 9 个基础工具 ====== -->
|
||||
<section class="api-section" id="tools-overview">
|
||||
<h2>📊 9 个基础工具 — 总表</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_extract</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>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<!-- --- 文件系统工具 --- -->
|
||||
<section class="api-section" id="tool-filesystem">
|
||||
<h2>📄 类别一:文件系统工具(4个)</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>💡</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>🌐 类别二:网络搜索与抓取(2个)</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_extract</h3>
|
||||
<p class="desc">抓取网页内容并转换为 Markdown。支持 HTML 页面和 PDF 链接。超过 5000 字符自动摘要。</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>🧠 类别三:记忆工具(2个)</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>⚒️ 类别四:命令工具(1个)</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>⚠ 安全规则(命令解析 + 模式匹配):</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>🔧 实现要求:</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>💾 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>✅ 自动创建策略:</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>✨ SOUL.md — AI 灵魂定义</h2>
|
||||
<p class="desc">定义 Agent 的身份、性格和核心价值观。加载后注入 System Prompt 的最高优先级静态区。<strong>此文件完全由用户自定义,Metona 不提供默认内容。</strong></p>
|
||||
|
||||
<div class="file-card">
|
||||
<h4>✨ SOUL.md</h4>
|
||||
<div class="path">~/MetonaWorkspaces/my-project/SOUL.md</div>
|
||||
<p>用户自定义文件,定义 Agent 的灵魂</p>
|
||||
</div>
|
||||
|
||||
<div class="note-box">
|
||||
<strong>📝 用户自定义:</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>📋 AGENTS.md — AI 行为定义</h2>
|
||||
<p class="desc">定义 Agent 的行为规则、边界、工作流程和工具使用权限。<strong>此文件完全由用户自定义</strong>,Metona 仅提供内置最小安全规则作为兜底。</p>
|
||||
|
||||
<div class="file-card">
|
||||
<h4>📋 AGENTS.md</h4>
|
||||
<div class="path">~/MetonaWorkspaces/my-project/AGENTS.md</div>
|
||||
<p>用户自定义文件,定义 Agent 行为边界</p>
|
||||
</div>
|
||||
|
||||
<div class="note-box">
|
||||
<strong>📝 用户自定义:</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>🛡 无论 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>🧩 MEMORY.md — AI 记忆文件</h2>
|
||||
<p class="desc">跨会话持久记忆。Agent 启动时读取注入上下文,会话结束后自动追加新记忆。<strong>此文件有严格的格式规范,Agent 写入时必须遵循,用户编辑时也应遵守。</strong></p>
|
||||
|
||||
<div class="file-card">
|
||||
<h4>🧩 MEMORY.md</h4>
|
||||
<div class="path">~/MetonaWorkspaces/my-project/MEMORY.md</div>
|
||||
<p>Agent 维护 + 用户可编辑的记忆文件</p>
|
||||
</div>
|
||||
|
||||
<h4>格式规范</h4>
|
||||
<div class="warn-box">
|
||||
<strong>📋 强制格式:</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>💡 格式保护:</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>🔄 同步策略:</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>👤 USERS.md — 用户信息画像</h2>
|
||||
<p class="desc">定义用户的背景、技能、偏好和当前目标。Agent 据此调整回答深度、技术栈偏向和交互风格。<strong>此文件完全由用户自定义。</strong></p>
|
||||
|
||||
<div class="file-card">
|
||||
<h4>👤 USERS.md</h4>
|
||||
<div class="path">~/MetonaWorkspaces/my-project/USERS.md</div>
|
||||
<p>用户自定义文件,描述用户画像</p>
|
||||
</div>
|
||||
|
||||
<div class="note-box">
|
||||
<strong>📝 用户自定义:</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>🔍 全链路透明可追踪</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>📝 日志设计</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>🔄 完整交互流程</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 UI(Chromium 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 组装 MetonaContext:System 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">(如有 ToolCall)Policy 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>💡 完整 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>🏗️ 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-06-26</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;
|
||||
">↑</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>
|
||||
Reference in New Issue
Block a user