Files
metona-ai-desktop/docs/MetonaAI-Desktop UI UX 设计集成方案.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

741 lines
54 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 — UI/UX 设计集成方案 | v1.0</title>
<style>
:root {
--bg:#0f1117; --bg-card:#1a1d27; --bg-code:#12141c; --bg-nav:#141620;
--text:#e1e4ed; --text-dim:#8b8fa7; --accent:#6366f1; --accent2:#818cf8;
--green:#34d399; --orange:#fb923c; --red:#f87171; --amber:#fbbf24;
--cyan:#22d3ee; --purple:#a855f7; --pink:#f472b6; --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),var(--purple));-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 .15s}
.sidebar a:hover,.sidebar a.active{color:var(--text);background:rgba(99,102,241,.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(99,102,241,.07),rgba(244,114,182,.05));border-bottom:1px solid var(--border);padding:56px 60px 48px}
.hero h1{font-size:30px;font-weight:800;background:linear-gradient(135deg,var(--accent),var(--purple),var(--pink));-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}
.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:16px;display:flex;align-items:center;gap:10px}
.api-section h3{font-size:16px;font-weight:600;margin:32px 0 12px;color:var(--accent2)}
.api-section .desc{color:var(--text-dim);font-size:14.5px;margin-bottom:16px}
.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:.8px}
table.spec td{padding:10px 14px;border-bottom:1px solid rgba(42,45,58,.5);vertical-align:top;transition:background .15s}
table.spec tr:hover td{background:rgba(99,102,241,.03)}
table.spec tr:last-child td{border-bottom:none}
.f1{font-family:'SF Mono',monospace;color:var(--cyan);font-weight:600;font-size:13px}
.f2{font-family:'SF Mono',monospace;color:var(--accent2);font-size:11.5px}
.f3{color:var(--red);font-size:11px;font-weight:600}
.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 .2s}
.code-block:hover{border-color:rgba(99,102,241,.3)}
.code-block pre{margin:0;font-family:'SF Mono','Fira 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:var(--cyan)}
.note-box{background:rgba(99,102,241,.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 .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,.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 .2s}
.warn-box:hover{border-left-color:var(--orange)}
.arch-diagram{background:var(--bg-card);border:1px solid var(--border);border-radius:10px;padding:24px;margin:20px 0 30px;overflow-x:auto;transition:border-color .2s}
.arch-diagram:hover{border-color:rgba(99,102,241,.3)}
.arch-diagram pre{font-family:'SF Mono',monospace;font-size:12px;line-height:1.55;color:var(--text);margin:0}
.node{display:inline-block;padding:6px 14px;border-radius:8px;margin:3px;font-size:12px;font-family:'SF Mono',monospace}
.node-core{background:rgba(99,102,241,.15);border:1px solid rgba(99,102,241,.3);color:var(--accent2)}
.node-data{background:rgba(34,211,238,.1);border:1px solid rgba(34,211,238,.2);color:var(--cyan)}
.node-ui{background:rgba(168,85,247,.12);border:1px solid rgba(168,85,247,.25);color:var(--purple)}
.node-tool{background:rgba(244,114,182,.1);border:1px solid rgba(244,114,182,.2);color:var(--pink)}
.section-divider{border:none;height:1px;background:var(--border);margin:56px 0}
::-webkit-scrollbar{width:6px;height:6px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}
@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>&#x1F3A8; MetonaAI Desktop UI/UX</h2></div>
<div class="sidebar-section">研究综述</div>
<a href="#trends">&#x1F4CA; 2026 UI/UX 趋势</a>
<a href="#patterns">&#x1F9E9; Agent 设计模式</a>
<a href="#references">&#x1F517; 参考项目</a>
<div class="sidebar-section">MetonaToast</div>
<a href="#metona-toast">&#x1F4E2; 项目分析</a>
<a href="#toast-integration">&#x2699;&#xFE0F; 集成方案</a>
<div class="sidebar-section">UI 设计</div>
<a href="#layout">&#x1F3D7;&#xFE0F; 整体布局</a>
<a href="#chat-panel">&#x1F4AC; 聊天面板</a>
<a href="#trace-viewer">&#x1F50D; Trace Viewer</a>
<a href="#tool-call">&#x1F527; 工具调用 UI</a>
<a href="#settings">&#x2699;&#xFE0F; 设置面板</a>
<div class="sidebar-section">组件系统</div>
<a href="#component-tree">&#x1F332; 组件树</a>
<a href="#theme-system">&#x1F3A8; 主题系统</a>
<a href="#animation">&#x2728; 动效规范</a>
</nav>
<div class="main">
<div class="hero">
<h1>MetonaAI Desktop — UI/UX 设计集成方案</h1>
<p>综合 2026 年 AI Agent 交互设计前沿趋势 + MetonaToast 组件库研究成果,产出 MetonaAI Desktop 完整的用户界面设计方案,确保"可见思维、可控行动、可信结果"。</p>
<div class="hero-meta">
<span>&#x1F4CA; 研究来源: <strong>Fuselab Creative / Ant Design X / A2UI / Hermes Agent</strong></span>
<span>&#x1F4E6; 集成组件: <strong>MetonaToast v2.0.0</strong></span>
</div>
<div class="note-box" style="margin-top:16px">
<strong>&#x1F4CB; 文档层级:</strong>本文档是 <strong>用户界面与交互设计的权威定义</strong>,与《构建指南》第九章(React 前端)对应。冲突时以本文档为准。
</div>
</div>
<div class="content">
<!-- ===== 行业趋势 ===== -->
<section class="api-section" id="trends">
<h2>&#x1F4CA; 2026 AI Agent UI/UX 趋势综述</h2>
<p class="desc">通过分析 Fuselab Creative、UX Tigers、Ant Design X、Google A2UI、The Skins Factory 等权威来源,提炼出 6 大核心趋势:</p>
<table class="spec">
<tr><th>#</th><th>趋势</th><th>核心要求</th><th>Metona 对应</th></tr>
<tr>
<td class="f1">1</td>
<td><strong>可解释 AIExplainable AI</strong></td>
<td>用户必须看到 Agent 在<strong>想什么</strong><strong>做什么</strong><strong>为什么</strong></td>
<td class="f2">TraceViewer 实时展示 Thought → ToolCall → Observation 全链路</td>
</tr>
<tr>
<td class="f1">2</td>
<td><strong>Agentic UX / RICH 范式</strong></td>
<td>角色(Role) + 意图(Intention) + 会话(Conversation) + 混合界面(Hybrid UI)</td>
<td class="f2">SOUL.md 定义角色 + Chat 对话 + Tool Panel 混合 UI</td>
</tr>
<tr>
<td class="f1">3</td>
<td><strong>透明与可控</strong></td>
<td>每步提供 override 控制、用户可随时中断/修正</td>
<td class="f2">Abort 按钮、工具调用前确认弹窗、参数可编辑</td>
</tr>
<tr>
<td class="f1">4</td>
<td><strong>A2UI — AI 说出 UI</strong></td>
<td>Agent 以声明式 JSON 描述 UI 意图,客户端原生渲染</td>
<td class="f2">预留 A2UI 接口,Agent 可动态生成卡片/表格/图表</td>
</tr>
<tr>
<td class="f1">5</td>
<td><strong>多模态混合界面</strong></td>
<td>文本 + 代码 + 图表 + 图片 + 3D 混合呈现</td>
<td class="f2">MessageItem 支持 Markdown + 代码高亮 + 图片 + Mermaid 图表</td>
</tr>
<tr>
<td class="f1">6</td>
<td><strong>优雅错误恢复</strong></td>
<td>错误不是终点,是引导用户修正的入口</td>
<td class="f2">MetonaToast error/warning 通知 + 错误上下文面板</td>
</tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; Fuselab Creative 核心论断:</strong>"Agent UX 与传统 UI 的根本区别在于 — Agent 界面必须传达系统正在做什么、解释其推理逻辑、在每一步提供覆盖控制、并从错误中优雅恢复。设计挑战是在保持用户信任的同时允许系统自主操作。"
</div>
</section>
<hr class="section-divider">
<!-- ===== 设计模式 ===== -->
<section class="api-section" id="patterns">
<h2>&#x1F9E9; Agent 交互设计模式</h2>
<h3>Ant Design X — RICH 范式</h3>
<table class="spec">
<tr><th>维度</th><th>含义</th><th>Metona 实现</th></tr>
<tr><td class="f1">Role(角色)</td><td>Agent 的身份、性格、能力边界</td><td class="f2">SOUL.md → System Prompt RoleDefinition</td></tr>
<tr><td class="f1">Intention(意图)</td><td>理解用户目标,主动规划</td><td class="f2">ReAct Loop → Thought 思考过程实时展示</td></tr>
<tr><td class="f1">Conversation(会话)</td><td>多轮对话 + 历史上下文</td><td class="f2">ChatPanel + Session 管理 + Memory 检索</td></tr>
<tr><td class="f1">Hybrid UI(混合界面)</td><td>对话 + 传统 UI 混合</td><td class="f2">Chat + Tool Panel + TraceViewer + Settings 同屏</td></tr>
</table>
<h3>Agent UI 五大核心面板</h3>
<div class="arch-diagram">
<pre>
<span class="node node-core">1. 对话面板</span><span class="node node-data">2. 思维面板</span><span class="node node-tool">3. 工具面板</span><span class="node node-ui">4. 工作区面板</span><span class="node node-core">5. 状态栏</span>
核心交互链路: 用户输入 → Agent思考 → 工具执行 → 结果展示 → 反馈通知
│ │ │ │
实时流式 折叠/展开 参数+耗时 Markdown渲染
│ │ │ │
MetonaToast TraceViewer ToolCallCard MessageItem</pre>
</div>
</section>
<hr class="section-divider">
<!-- ===== MetonaToast 分析 ===== -->
<section class="api-section" id="metona-toast">
<h2>&#x1F4E2; MetonaToast 项目分析</h2>
<p class="desc">
<code>metona-toast</code> v2.0.0 — 你的自研通知组件库,已发布到 npm。
纯 JavaScript,零依赖,gzip &lt;10KB,设计精致。
</p>
<table class="spec">
<tr><th>特性</th><th>详情</th><th>Metona Desktop 用途</th></tr>
<tr><td class="f1">80+ 图标</td><td class="f2">success/error/warning/info/loading 及扩展</td><td>工具结果通知、LLM 错误提示、操作确认</td></tr>
<tr><td class="f1">11 种动画</td><td class="f2">slide/fade/scale/bounce/flip/rotate/zoom/slideUp/Down/Left/Right</td><td><strong>bounce</strong> 表示重要通知,<strong>fade</strong> 表示信息</td></tr>
<tr><td class="f1">主题系统</td><td class="f2">light/dark/auto/warm + registerTheme()</td><td>与 Electron 暗色模式无缝同步,auto 跟随系统</td></tr>
<tr><td class="f1">国际化</td><td class="f2">zh-CN / en-US + addTranslations()</td><td>根据用户系统语言自动切换</td></tr>
<tr><td class="f1">插件系统</td><td class="f2">keyboard(ESC关闭)/persistence(localStorage)/accessibility</td><td>keyboard 插件让用户 ESC 关闭所有通知</td></tr>
<tr><td class="f1">可拖拽关闭</td><td class="f2">Pointer Events 拖拽,旋转+透明反馈</td><td>自然手势关闭,符合现代交互习惯</td></tr>
<tr><td class="f1">毛玻璃效果</td><td class="f2">backdrop-filter: blur(14px) saturate(180%)</td><td>与 Electron 窗口背景融合,有层次感</td></tr>
<tr><td class="f1">链式调用</td><td class="f2">loading()→success() / loading()→error()</td><td>工具执行中显示 loading,完成后转为 success/error</td></tr>
<tr><td class="f1">confirm/prompt</td><td class="f2">对话框式确认和输入</td><td>高风险工具调用前的用户确认</td></tr>
<tr><td class="f1">progress/countdown</td><td class="f2">进度条和倒计时</td><td>长时间操作(模型下载、文件处理)</td></tr>
</table>
</section>
<section class="api-section" id="toast-integration">
<h2>&#x2699;&#xFE0F; MetonaToast 集成方案</h2>
<h3>安装与配置</h3>
<div class="code-block">
<pre><span class="hl-cm">// electron/main.ts — 主进程不直接使用(Node 环境无 DOM)</span>
<span class="hl-cm">// src/main.tsx — React 渲染进程入口</span>
<span class="hl-kw">import</span> MeToast <span class="hl-kw">from</span> <span class="hl-str">'metona-toast'</span>;
<span class="hl-cm">// 全局配置(应用启动时执行一次)</span>
MeToast.<span class="hl-fn">configure</span>({
<span class="hl-prop">position</span>: <span class="hl-str">'top-right'</span>,
<span class="hl-prop">duration</span>: <span class="hl-num">4000</span>,
<span class="hl-prop">max</span>: <span class="hl-num">6</span>,
<span class="hl-prop">theme</span>: <span class="hl-str">'auto'</span>, <span class="hl-cm">// 跟随系统暗色模式</span>
<span class="hl-prop">animation</span>: <span class="hl-str">'slide'</span>,
<span class="hl-prop">pauseOnHover</span>: <span class="hl-kw">true</span>,
<span class="hl-prop">closeOnClick</span>: <span class="hl-kw">true</span>,
<span class="hl-prop">showProgress</span>: <span class="hl-kw">true</span>,
<span class="hl-prop">draggable</span>: <span class="hl-kw">true</span>,
<span class="hl-prop">locale</span>: <span class="hl-str">'zh-CN'</span>,
});
<span class="hl-cm">// 安装插件</span>
MeToast.<span class="hl-fn">use</span>(<span class="hl-str">'keyboard'</span>); <span class="hl-cm">// ESC 关闭所有</span>
MeToast.<span class="hl-fn">use</span>(<span class="hl-str">'persistence'</span>); <span class="hl-cm">// 配置持久化</span>
MeToast.<span class="hl-fn">use</span>(<span class="hl-str">'accessibility'</span>); <span class="hl-cm">// 屏幕阅读器</span></pre>
</div>
<h3>场景映射表</h3>
<table class="spec">
<tr><th>Metona 场景</th><th>Toast 调用</th><th>动画</th></tr>
<tr><td>工具执行成功</td><td class="f1"><code>MeToast.success('文件读取完成')</code></td><td class="f2">slide</td></tr>
<tr><td>工具执行失败</td><td class="f1"><code>MeToast.error('网络请求超时')</code></td><td class="f2">bounce</td></tr>
<tr><td>权限校验被拒</td><td class="f1"><code>MeToast.warning('需要权限确认')</code></td><td class="f2">scale</td></tr>
<tr><td>LLM 开始推理</td><td class="f1"><code>MeToast.info('正在思考...', {duration:0})</code></td><td class="f2">fade</td></tr>
<tr><td>Session 保存</td><td class="f1"><code>MeToast.success('会话已保存')</code></td><td class="f2">slide</td></tr>
<tr><td>MCP Server 连接</td><td class="f1"><code>MeToast.success('MCP 已连接', {title:'filesystem'})</code></td><td class="f2">slideUp</td></tr>
<tr><td>上下文压缩</td><td class="f1"><code>MeToast.info('上下文已压缩', {duration:2000})</code></td><td class="f2">fade</td></tr>
<tr><td>模型下载进度</td><td class="f1"><code>MeToast.progress('下载中...').setProgress(60)</code></td><td class="f2">slide</td></tr>
<tr><td>高风险操作确认</td><td class="f1"><code>MeToast.confirm('确定删除文件?')</code></td><td class="f2">scale</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 主进程通知桥接:</strong>Electron 主进程(Node.js 环境)无法直接调用 DOM Toast。通过 IPC 发送
<code>mainWindow.webContents.send('toast:show', { type:'success', message:'...' })</code>
渲染进程监听并调用 <code>MeToast[event.type](event.message)</code>
</div>
</section>
<hr class="section-divider">
<!-- ===== 整体布局 ===== -->
<section class="api-section" id="layout">
<h2>&#x1F3D7;&#xFE0F; 整体布局设计</h2>
<p class="desc">参考 Claude Code / Cursor / Hermes Agent 桌面版的布局设计,采用经典的 IDE 式三栏布局。</p>
<div class="arch-diagram">
<pre>
<span class="hl-cm">┌──────────────────────────────────────────────────────────────┐</span>
<span class="hl-cm">│ Header Bar [🔮 MetonaAI Desktop] [会话] [设置] [— □ ✕] │</span>
<span class="hl-cm">├──────────┬────────────────────────────────┬──────────────────┤</span>
<span class="hl-cm">│ │ │ │</span>
<span class="hl-cm">│ Sidebar │ Main Chat Area │ Detail Panel │</span>
<span class="hl-cm">│ │ │ (可折叠) │</span>
<span class="hl-cm">│ ┌──────┐ │ ┌──────────────────────────┐ │ ┌──────────────┐│</span>
<span class="hl-cm">│ │ 会话 │ │ │ [Agent] 💭 思考过程... │ │ │ Trace Viewer ││</span>
<span class="hl-cm">│ │ 列表 │ │ │ [Agent] 🔧 read_file │ │ │ ││</span>
<span class="hl-cm">│ │ │ │ │ [Agent] 📄 文件内容 │ │ │ #1 THINKING ││</span>
<span class="hl-cm">│ │ + 新建│ │ │ [Agent] 结论: ... │ │ │ #2 PARSING ││</span>
<span class="hl-cm">│ │ │ │ │ │ │ │ #3 EXECUTING ││</span>
<span class="hl-cm">│ │ ──── │ │ │ │ │ │ #4 OBSERVING ││</span>
<span class="hl-cm">│ │ 工具 │ │ │ │ │ │ #5 REFLECTING ││</span>
<span class="hl-cm">│ │ 管理 │ │ │ │ │ │ #6 COMPRESSING ││</span>
<span class="hl-cm">│ │ 工具 │ │ ├──────────────────────────┤ │ ├──────────────┤│</span>
<span class="hl-cm">│ │ 管理 │ │ │ [输入框..............] [发送] │ │ │ Token 用量 ││</span>
<span class="hl-cm">│ │ │ │ │ [📎文件] [🔧工具] [⚙️] │ │ │ 输入: 1240 ││</span>
<span class="hl-cm">│ │ ──── │ │ └──────────────────────────┘ │ │ 输出: 350 ││</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">│ Status Bar 🟢 Agent Ready | deepseek-v4-pro | Tokens: 1.2K │</span>
<span class="hl-cm">└──────────────────────────────────────────────────────────────┘</span>
</pre>
</div>
<table class="spec">
<tr><th>区域</th><th>宽度</th><th>内容</th></tr>
<tr><td class="f1">Header Bar</td><td class="f2">全宽</td><td>Logo + 窗口控制 + 快捷操作</td></tr>
<tr><td class="f1">Sidebar (可折叠)</td><td class="f2">260px</td><td>会话列表、工具管理、记忆搜索、MCP 管理</td></tr>
<tr><td class="f1">Main Chat Area</td><td class="f2">弹性</td><td>消息流 + 输入框 + 流式渲染</td></tr>
<tr><td class="f1">Detail Panel (可折叠)</td><td class="f2">320px</td><td>TraceViewer + Token 用量 + 工具状态</td></tr>
<tr><td class="f1">Status Bar</td><td class="f2">全宽</td><td>Agent 状态、Provider 信息、Token 统计</td></tr>
</table>
<h3>布局模式</h3>
<p class="desc">为适应不同场景和屏幕尺寸,提供三种布局模式:</p>
<table class="spec">
<tr><th>模式</th><th>Sidebar</th><th>DetailPanel</th><th>Chat 区域</th><th>触发方式</th></tr>
<tr><td class="f1">默认模式</td><td class="f2">展开 260px</td><td class="f2">展开 320px</td><td class="f2">弹性(约 1340px @1920</td><td class="f2">默认状态</td></tr>
<tr><td class="f1">紧凑模式</td><td class="f2">折叠 56px 图标条</td><td class="f2">折叠 48px 图标条</td><td class="f2">弹性(约 1816px @1920</td><td class="f2"><code>Cmd/Ctrl+B</code> + <code>Cmd/Ctrl+J</code></td></tr>
<tr><td class="f1">专注模式</td><td class="f2">隐藏</td><td class="f2">隐藏</td><td class="f2">全宽(约 1920px</td><td class="f2"><code>Cmd/Ctrl+Shift+F</code></td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 布局设计原则:</strong>Sidebar 和 DetailPanel 均为<strong>可折叠抽屉式</strong>,默认展开完整面板,折叠后只保留图标条(悬停可预览,点击展开为浮层)。Chat 区域在两侧折叠时获得最大宽度,适合宽屏代码展示和 Markdown 渲染。
</div>
<h3>消息布局:全宽卡片流</h3>
<p class="desc">放弃传统聊天应用的左右分栏气泡布局,采用<strong>全宽卡片流</strong>布局(参考 Claude / ChatGPT)。Agent 的核心交互是任务执行而非聊天,工具调用结果、代码块、表格都需要全宽展示。</p>
<table class="spec">
<tr><th>消息类型</th><th>布局</th><th>对齐</th><th>宽度</th></tr>
<tr><td class="f1">User Message</td><td class="f2">浅色背景卡片 + 用户头像</td><td class="f2">左对齐</td><td class="f2">全宽(max-width: 768px 居中)</td></tr>
<tr><td class="f1">Agent Thought</td><td class="f2">缩进灰色虚线框</td><td class="f2">左对齐</td><td class="f2">全宽(可折叠)</td></tr>
<tr><td class="f1">Agent ToolCall</td><td class="f2">缩进彩色卡片 + 状态图标</td><td class="f2">左对齐</td><td class="f2">全宽</td></tr>
<tr><td class="f1">Agent Answer</td><td class="f2">无背景或极浅背景 + Agent 头像</td><td class="f2">左对齐</td><td class="f2">全宽 Markdown 渲染</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 为什么不用气泡布局:</strong>传统左右分栏气泡将用户消息右对齐,导致 Agent 的长回复(含代码块、表格、图表)被压缩到一半宽度。全宽卡片流让所有内容都能利用完整宽度,阅读体验显著提升。用户消息虽然全宽,但通过 <code>max-width: 768px</code> 居中限制可读性。
</div>
</section>
<!-- ===== 聊天面板 ===== -->
<section class="api-section" id="chat-panel">
<h2>&#x1F4AC; 聊天面板设计</h2>
<h3>消息类型矩阵</h3>
<table class="spec">
<tr><th>消息角色</th><th>视觉样式</th><th>内容渲染</th><th>交互</th></tr>
<tr>
<td class="f1">User Message</td>
<td class="f2">全宽 / 浅色背景卡片 / 用户头像 / 左对齐</td>
<td>纯文本 + 附件缩略图</td>
<td>双击编辑 / 右键菜单</td>
</tr>
<tr>
<td class="f1">Agent Thought</td>
<td class="f2">左对齐 / 虚线边框 / 💭 图标 / 可折叠</td>
<td>纯文本(等宽字体)</td>
<td>默认折叠,点击展开</td>
</tr>
<tr>
<td class="f1">Agent Tool Call</td>
<td class="f2">左对齐 / 紫色边框 / 🔧 图标</td>
<td>工具名 + JSON 参数 + 状态图标</td>
<td>悬停显示参数详情、点击跳转 Trace</td>
</tr>
<tr>
<td class="f1">Agent Tool Result</td>
<td class="f2">左对齐 / 青色边框 / 📄 图标</td>
<td>结果摘要 + 文件路径/行数/耗时</td>
<td>点击打开完整结果</td>
</tr>
<tr>
<td class="f1">Agent Answer</td>
<td class="f2">左对齐 / 无背景 / Agent 头像</td>
<td>Markdown + 代码高亮 + 图表</td>
<td>代码块一键复制、链接可点击</td>
</tr>
<tr>
<td class="f1">System Notification</td>
<td class="f2">居中 / 灰色 / 小字</td>
<td>时间戳 / 状态变化</td>
<td>不可交互</td>
</tr>
</table>
<h3>流式渲染策略</h3>
<p class="desc">
使用 <code>requestAnimationFrame</code> + 节流(每 16ms 一次)平滑更新 DOM。
Thought 内容进入时显示 <code>💭 思考中...</code> 加载动画,收到 <code>thinking_end</code> 后折叠。
工具调用使用 <code>ToolCallCard</code> 骨架屏先行占位,结果到达时填充。
</p>
</section>
<!-- ===== Trace Viewer ===== -->
<section class="api-section" id="trace-viewer">
<h2>&#x1F50D; Trace Viewer 设计</h2>
<p class="desc">置于右侧 Detail Panel,以时间轴方式展示每次 ReAct 迭代的完整过程。用户可展开每一步查看细节。</p>
<div class="arch-diagram">
<pre>
<span class="hl-cm">┌─ Trace Viewer ──────────────────────────────────┐</span>
<span class="hl-cm">│ Session: 数据分析任务 迭代: 2/20 │</span>
<span class="hl-cm">│─────────────────────────────────────────────────│</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▼ #1 THINKING 1.2s 120 tok │</span>
<span class="hl-cm">│ 💭 "需要先读取目标文件..." │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▶ #2 PARSING 0.1s │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▼ #3 EXECUTING 0.3s │</span>
<span class="hl-cm">│ 🔧 read_file: /data.csv ✓ 5ms │</span>
<span class="hl-cm">│ 📄 1000 rows, 3 cols │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▶ #4 OBSERVING 0.1s │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▶ #5 REFLECTING 0.2s │</span>
<span class="hl-cm">│ 💭 "数据结构清晰,可以进行下一步分析..." │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ▶ #6 COMPRESSING 0.1s │</span>
<span class="hl-cm">│ 📦 上下文已压缩 (3.2K → 1.8K) │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│ ○ #7 THINKING (当前) │</span>
<span class="hl-cm">│ ⏳ 正在调用 LLM... │</span>
<span class="hl-cm">│ │</span>
<span class="hl-cm">│─────────────────────────────────────────────────│</span>
<span class="hl-cm">│ Token: 入 1.2K | 出 0.4K | 总计 1.6K │</span>
<span class="hl-cm">│ 耗时: 2.3s | Provider: DeepSeek v4-pro │</span>
<span class="hl-cm">└─────────────────────────────────────────────────┘</span>
</pre>
</div>
</section>
<!-- ===== 工具调用 UI ===== -->
<section class="api-section" id="tool-call">
<h2>&#x1F527; 工具调用 UI</h2>
<h3>ToolCallCard 状态机</h3>
<table class="spec">
<tr><th>状态</th><th>图标</th><th>颜色</th><th>行为</th></tr>
<tr><td class="f1">pending</td><td class="f2">⏳ 旋转</td><td class="f2" style="color:var(--amber)">#fbbf24</td><td>骨架屏占位,等待工具执行</td></tr>
<tr><td class="f1">executing</td><td class="f2">🔧 脉冲</td><td class="f2" style="color:var(--purple)">#a855f7</td><td>显示参数摘要</td></tr>
<tr><td class="f1">success</td><td class="f2"></td><td class="f2" style="color:var(--green)">#34d399</td><td>显示结果摘要 + 执行耗时</td></tr>
<tr><td class="f1">error</td><td class="f2"></td><td class="f2" style="color:var(--red)">#f87171</td><td>显示错误信息 + 重试按钮</td></tr>
<tr><td class="f1">blocked</td><td class="f2">🚫</td><td class="f2" style="color:var(--orange)">#fb923c</td><td>显示拒绝原因 + 手动授权按钮</td></tr>
</table>
<h3>高风险操作确认流程</h3>
<div class="code-block">
<pre><span class="hl-cm"># 用户在聊天面板看到:</span>
┌─────────────────────────────────────────┐
│ 🔧 write_file │
│ 目标: /home/user/config.yaml │
│ 风险: ⚠️ MEDIUM — 将覆盖已有文件 │
│ │
│ [查看差异] [✅ 确认执行] [❌ 取消] │
└─────────────────────────────────────────┘
<span class="hl-cm"># 用户点击「确认执行」后:</span>
MeToast.<span class="hl-fn">success</span>({ <span class="hl-prop">title</span>: <span class="hl-str">'已授权'</span>, <span class="hl-prop">message</span>: <span class="hl-str">'write_file 正在执行...'</span> });
<span class="hl-cm"># 用户点击「取消」后:</span>
MeToast.<span class="hl-fn">warning</span>(<span class="hl-str">'操作已取消'</span>);</pre>
</div>
<h3>确认流程优化:信任会话</h3>
<p class="desc">为避免密集操作场景(如批量重构代码)下逐次确认打断流程,引入<strong>信任会话</strong>机制:</p>
<table class="spec">
<tr><th>模式</th><th>行为</th><th>触发方式</th></tr>
<tr><td class="f1">默认模式</td><td class="f2">MEDIUM+ 操作逐次确认</td><td class="f2">默认</td></tr>
<tr><td class="f1">信任会话</td><td class="f2">MEDIUM 操作不逐次确认,会话结束时生成操作摘要供审查</td><td class="f2">设置中开启</td></tr>
<tr><td class="f1">同类免确认</td><td class="f2">同一会话内同类操作(如 write_file)首次确认后不再确认</td><td class="f2">确认弹窗勾选「本次会话不再确认同类操作」</td></tr>
<tr><td class="f1">批量确认</td><td class="f2">连续多个同类操作合并为一个确认弹窗</td><td class="f2">Agent 连续发起 ≥3 个同类操作时自动触发</td></tr>
</table>
<div class="warn-box">
<strong>&#x26A0; HIGH 级别操作始终需要确认</strong>,不受信任会话影响。CRITICAL 级别需要双人复核(未来计划)。
</div>
<div class="note-box">
<strong>&#x1F4A1; 确认弹窗增强:</strong>增加「查看命令」展开区域,显示完整的工具调用参数(JSON 格式),让用户做出知情决策。
</div>
</section>
<!-- ===== 设置面板 ===== -->
<section class="api-section" id="settings">
<h2>&#x2699;&#xFE0F; 设置面板</h2>
<p class="desc">分 Tab 展示,配置变更即时持久化到 SQLite 数据库。</p>
<table class="spec">
<tr><th>Tab</th><th>内容</th></tr>
<tr><td class="f1">LLM 配置</td><td class="f2">Provider 选择、API Key、模型名称、参数滑块(temperature/maxTokens/contextWindow</td></tr>
<tr><td class="f1">Agent 配置</td><td class="f2">最大迭代次数、超时、Thinking 开关、反思模式、压缩阈值</td></tr>
<tr><td class="f1">工具管理</td><td class="f2">27 个内置工具开关、风险级别配置、路径白名单、命令黑名单</td></tr>
<tr><td class="f1">MCP 服务</td><td class="f2">Server 列表、添加/删除/启停、连接状态指示灯</td></tr>
<tr><td class="f1">外观</td><td class="f2">主题(light/dark/auto)、字体大小、消息密度、动画开关</td></tr>
<tr><td class="f1">日志与数据</td><td class="f2">日志级别、数据库位置、数据导出/清理、使用统计</td></tr>
</table>
</section>
<hr class="section-divider">
<!-- ===== 组件树 ===== -->
<section class="api-section" id="component-tree">
<h2>&#x1F332; 组件树</h2>
<div class="note-box">
<strong>&#x1F3A8; UI 组件库:</strong>所有 UI 交互组件强制使用 <strong>Material UI (MUI)</strong><code>@mui/material</code>)。按钮、输入框、弹窗、选择器、表单控件、标签页、提示、布局、进度条、卡片等均使用 MUI 组件。除非 MUI 确认不存在对应组件,否则<strong>禁止自写 UI 组件</strong>。Tailwind CSS 仅作为 MUI 的辅助样式补充(间距、颜色变量),不可替代 MUI 组件。
</div>
<div class="arch-diagram">
<pre>
<span class="hl-cm">AppLayout</span>
├── <span class="hl-box">Header</span> (Logo + SessionSelector + SettingsButton)
├── <span class="hl-box">Sidebar</span>
│ ├── SessionList (会话列表 + 新建/搜索/分组/置顶)
│ ├── ToolManager (工具状态 + MCP 管理)
│ └── MemorySearch (记忆检索面板)
├── <span class="hl-box">ChatPanel</span>
│ ├── MessageList (虚拟滚动 · 全宽卡片流)
│ │ ├── MessageItem (User/Assistant/Tool/System)
│ │ ├── ThoughtBlock (可折叠思考内容)
│ │ ├── ToolCallCard (工具调用卡片)
│ │ └── ToolResultBlock (工具结果块)
│ ├── StreamingIndicator (流式加载)
│ └── ChatInput (输入框 + 附件 + 工具选择 + 上下文指示器)
├── <span class="hl-box">DetailPanel</span> (右侧,可折叠为图标条)
│ ├── TraceViewer (ReAct 迭代追踪)
│ ├── TokenUsage (Token 统计图表)
│ └── AgentMonitor (Agent 状态指示)
├── <span class="hl-box">StatusBar</span> (状态栏)
├── <span class="hl-box">ToastContainer</span> (MetonaToast 通知层)
├── <span class="hl-box">OnboardingWizard</span> (首次使用引导)
└── <span class="hl-box">CommandPalette</span> (Cmd+K 快速搜索)
</pre>
</div>
</section>
<!-- ===== 首次使用引导 ===== -->
<section class="api-section" id="onboarding">
<h2>&#x1F44B; 首次使用引导(Onboarding</h2>
<p class="desc">首次启动应用时自动展示引导向导,帮助用户完成初始配置。向导完成后不再显示(可通过设置重新触发)。</p>
<h3>引导流程</h3>
<div class="flow-step" style="display:flex;gap:14px;margin-bottom:14px;align-items:flex-start"><span style="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">1</span><span style="font-size:14px"><strong>欢迎页</strong>:Metona 是什么、能做什么(3 句话 + 动图展示)</span></div>
<div class="flow-step" style="display:flex;gap:14px;margin-bottom:14px;align-items:flex-start"><span style="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">2</span><span style="font-size:14px"><strong>配置 LLM</strong>:选择 ProviderDeepSeek/Agnes/Ollama)→ 输入 API Key 或 Ollama 地址 → 测试连接</span></div>
<div class="flow-step" style="display:flex;gap:14px;margin-bottom:14px;align-items:flex-start"><span style="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">3</span><span style="font-size:14px"><strong>自定义 Agent</strong>:选择预设角色或自定义 SOUL.md → 填写 USERS.md(技术栈、偏好)</span></div>
<div class="flow-step" style="display:flex;gap:14px;margin-bottom:14px;align-items:flex-start"><span style="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">4</span><span style="font-size:14px"><strong>工作空间</strong>:确认默认路径 <code>~/MetonaWorkspaces/default/</code> 或选择自定义路径</span></div>
<div class="flow-step" style="display:flex;gap:14px;margin-bottom:14px;align-items:flex-start"><span style="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">5</span><span style="font-size:14px"><strong>开始使用</strong>:展示一个示例对话,让用户感受 Agent 能力</span></div>
<div class="note-box">
<strong>&#x1F4A1; 设计要点:</strong>每一步都可以「跳过」,不强制完成。跳过配置 LLM 的用户会在首次发送消息时提示配置。向导状态记录在 <code>app_config</code> 表中(<code>onboarding.completed = true/false</code>)。
</div>
</section>
<!-- ===== 快捷键 ===== -->
<section class="api-section" id="shortcuts">
<h2>⌨️ 快捷键体系</h2>
<p class="desc">快捷键是桌面 Agent 应用的核心生产力工具。所有快捷键支持 macOSCmd)和 Windows/LinuxCtrl)。</p>
<table class="spec">
<tr><th>快捷键</th><th>功能</th><th>分类</th></tr>
<tr><td class="f1"><code>Cmd/Ctrl + N</code></td><td>新建会话</td><td class="f2">会话</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + K</code></td><td>快速搜索(会话/记忆/文件)</td><td class="f2">全局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + Enter</code></td><td>发送消息</td><td class="f2">输入</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + Shift + Enter</code></td><td>换行(多行输入)</td><td class="f2">输入</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + .</code></td><td>中断 Agent 执行</td><td class="f2">Agent</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + Shift + F</code></td><td>专注模式(隐藏 Sidebar + DetailPanel</td><td class="f2">布局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + B</code></td><td>折叠/展开 Sidebar</td><td class="f2">布局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + J</code></td><td>折叠/展开 DetailPanel</td><td class="f2">布局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + ,</code></td><td>打开设置</td><td class="f2">全局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + [ / ]</code></td><td>历史会话切换(上一个/下一个)</td><td class="f2">会话</td></tr>
<tr><td class="f1"><code>Esc</code></td><td>关闭弹窗/取消焦点</td><td class="f2">全局</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + L</code></td><td>聚焦输入框</td><td class="f2">输入</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + Shift + C</code></td><td>复制最后一条 Agent 回复</td><td class="f2">编辑</td></tr>
<tr><td class="f1"><code>Cmd/Ctrl + D</code></td><td>切换暗色/亮色主题</td><td class="f2">外观</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 输入框智能特性:</strong>
<br><strong>多行自适应</strong>:输入框默认单行,输入多行时自动扩展(最大 6 行后滚动)
<br><strong>文件拖拽</strong>:拖拽文件到输入框自动添加为附件,显示文件名 + 大小
<br><strong>图片粘贴</strong>:粘贴剪贴板图片自动转为 base64 附件
<br><strong><code>/</code> 命令</strong>:输入 <code>/</code> 弹出命令菜单(<code>/tool</code> 选择工具、<code>/memory</code> 搜索记忆、<code>/clear</code> 清空会话、<code>/export</code> 导出会话)
<br><strong><code>@</code> 提及</strong>:输入 <code>@</code> 弹出文件/会话提及菜单,快速引用上下文
<br><strong>上下文指示器</strong>:输入框下方显示当前上下文使用率(如 "Context: 12K / 128K (9%)"),接近上限时变色警告
<br><strong>草稿自动保存</strong>:未发送的输入内容自动保存,切换会话后恢复
</div>
<h3>右键菜单设计</h3>
<table class="spec">
<tr><th>对象</th><th>菜单项</th></tr>
<tr><td class="f1">消息</td><td class="f2">复制 · 引用回复 · 编辑(仅用户消息) · 删除 · 重新生成(仅 Agent 消息)</td></tr>
<tr><td class="f1">工具调用卡片</td><td class="f2">查看参数 · 查看完整结果 · 复制结果 · 重新执行</td></tr>
<tr><td class="f1">会话项</td><td class="f2">重命名 · 置顶 · 归档 · 删除 · 导出</td></tr>
<tr><td class="f1">代码块</td><td class="f2">复制代码 · 在编辑器中打开</td></tr>
<tr><td class="f1">Trace 步骤</td><td class="f2">复制 Thought · 复制工具参数 · 导出步骤详情</td></tr>
</table>
</section>
<!-- ===== 主题系统 ===== -->
<section class="api-section" id="theme-system">
<h2>&#x1F3A8; 主题系统</h2>
<p class="desc">双主题引擎:CSS Variables(应用级)+ MetonaToast Theme API(通知级),统一 token 体系。</p>
<h3>CSS 变量 Token 体系</h3>
<div class="code-block">
<pre><span class="hl-cm">/* 亮色主题 */</span>
:root[data-theme=<span class="hl-str">"light"</span>] {
--bg-primary: <span class="hl-str">#ffffff</span>;
--bg-secondary: <span class="hl-str">#f8fafc</span>;
--bg-tertiary: <span class="hl-str">#f1f5f9</span>;
--text-primary: <span class="hl-str">#0f172a</span>;
--text-secondary: <span class="hl-str">#334155</span>; <span class="hl-cm">/* 对比度 ~8:1,满足 WCAG AA */</span>
--border-color: <span class="hl-str">#e2e8f0</span>;
--accent: <span class="hl-str">#6366f1</span>;
}
<span class="hl-cm">/* 暗色主题 */</span>
:root[data-theme=<span class="hl-str">"dark"</span>] {
--bg-primary: <span class="hl-str">#0f1117</span>;
--bg-secondary: <span class="hl-str">#1a1d27</span>;
--bg-tertiary: <span class="hl-str">#252836</span>;
--text-primary: <span class="hl-str">#e1e4ed</span>;
--text-secondary: <span class="hl-str">#64748b</span>; <span class="hl-cm">/* 对比度 ~4.6:1,满足 WCAG AA */</span>
--border-color: <span class="hl-str">#2a2d3a</span>;
--accent: <span class="hl-str">#818cf8</span>;
}</pre>
</div>
<div class="note-box">
<strong>&#x1F4A1; 主题同步:</strong>Electron 的 <code>nativeTheme.themeSource</code> 控制 Chromium 的 <code>prefers-color-scheme</code>
MetonaToast 的 <code>theme:'auto'</code> 自动跟随。应用级 CSS 通过 <code>matchMedia('(prefers-color-scheme: dark)')</code> 监听切换。
</div>
</section>
<!-- ===== 动效 ===== -->
<section class="api-section" id="animation">
<h2>&#x2728; 动效规范</h2>
<table class="spec">
<tr><th>场景</th><th>动效</th><th>时长</th><th>缓动</th></tr>
<tr><td class="f1">消息进入</td><td class="f2">从下方淡入 + 上移 10px</td><td>300ms</td><td class="f2">ease-out</td></tr>
<tr><td class="f1">流式文本</td><td class="f2">逐字出现(CSS typing 模拟)</td><td></td><td class="f2"></td></tr>
<tr><td class="f1">Thought 展开</td><td class="f2">max-height 过渡 + 淡入</td><td>250ms</td><td class="f2">ease</td></tr>
<tr><td class="f1">Tool 状态切换</td><td class="f2">图标旋转/脉冲 + 边框颜色渐变</td><td>400ms</td><td class="f2">ease-in-out</td></tr>
<tr><td class="f1">Sidebar 折叠</td><td class="f2">width 过渡</td><td>300ms</td><td class="f2">cubic-bezier(0.4,0,0.2,1)</td></tr>
<tr><td class="f1">Toast 通知</td><td class="f2">11 种(MetonaToast</td><td>400-650ms</td><td class="f2">cubic-bezier (库内)</td></tr>
<tr><td class="f1">加载骨架屏</td><td class="f2">shimmer 光泽扫过</td><td>1.5s loop</td><td class="f2">linear infinite</td></tr>
<tr><td class="f1">悬停反馈</td><td class="f2">scale(1.02) + shadow 提升</td><td>150ms</td><td class="f2">ease-out</td></tr>
</table>
<h3>性能保护机制</h3>
<p class="desc">动效在低性能设备和用户偏好下自动降级:</p>
<table class="spec">
<tr><th>条件</th><th>降级策略</th></tr>
<tr><td class="f1"><code>prefers-reduced-motion: reduce</code></td><td class="f2">所有动效即时切换(duration: 0ms),流式文本改为闪烁光标</td></tr>
<tr><td class="f1">FPS &lt; 30(检测到掉帧)</td><td class="f2">骨架屏 shimmer 改为静态灰色背景,悬停 scale 改为仅 shadow</td></tr>
<tr><td class="f1">设置中关闭「动画效果」</td><td class="f2">等同于 <code>prefers-reduced-motion</code>,所有动效禁用</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 流式文本优化:</strong>放弃逐字 DOM 更新方案(性能差),改为 <code>caret-color</code> 闪烁光标 + CSS <code>animation</code> 实现打字机效果。文本内容通过 <code>requestAnimationFrame</code> 批量插入(每帧一次),避免高频 DOM 操作。
</div>
<div class="note-box">
<strong>&#x1F4A1; 设置面板增加「动画效果」开关:</strong>三档选项——<code>开启</code>(全动效)/ <code>关闭</code>(禁用所有动效)/ <code>自动跟随系统</code>(默认,读取 <code>prefers-reduced-motion</code>)。配置存储在 <code>app_config</code> 表中(<code>ui.animationMode = 'auto' | 'on' | 'off'</code>)。
</div>
</section>
<!-- ===== 错误恢复 ===== -->
<section class="api-section" id="error-recovery">
<h2>&#x1F6A7; 错误恢复体验</h2>
<p class="desc">错误不是终点,是引导用户修正的入口。不同错误类型采用不同的交互策略:</p>
<table class="spec">
<tr><th>错误类型</th><th>UI 展示</th><th>恢复策略</th><th>用户操作</th></tr>
<tr><td class="f1">工具执行错误<br>(如文件不存在)</td><td class="f2">内联在聊天流中<br>红色边框卡片</td><td class="f2">Agent 自动分析错误 → 决定重试或换策略</td><td class="f2">通常无需操作;如需用户输入,Agent 在聊天中内联提问</td></tr>
<tr><td class="f1">LLM 调用错误<br>(如 API 超时)</td><td class="f2">错误卡片 + 操作按钮</td><td class="f2">等待用户决策</td><td class="f2"><code>[重试]</code> / <code>[切换 Provider]</code> / <code>[查看详情]</code></td></tr>
<tr><td class="f1">解析错误<br>LLM 输出不符合格式)</td><td class="f2">用户无感知<br>(静默重试)</td><td class="f2">静默重试(最多 3 次),超出后显示提示</td><td class="f2">超出重试后显示「模型输出异常」+ <code>[重试]</code></td></tr>
<tr><td class="f1">权限拒绝<br>(用户取消操作)</td><td class="f2">灰色卡片</td><td class="f2">Agent 收到取消信号,调整策略</td><td class="f2"><code>[修改权限设置]</code> 链接</td></tr>
<tr><td class="f1">网络连接错误</td><td class="f2">StatusBar 红色指示灯 + Toast</td><td class="f2">自动检测网络恢复后提示用户</td><td class="f2"><code>[重试]</code> / <code>[离线模式]</code>(仅 Ollama 可用)</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 所有错误在 TraceViewer 中留痕:</strong>每个错误作为一个独立 Trace 步骤,记录完整的错误信息、堆栈、重试历史。用户可以事后展开查看,不影响正常对话流。
</div>
</section>
<!-- ===== 会话管理 ===== -->
<section class="api-section" id="session-management">
<h2>&#x1F4C1; 会话管理</h2>
<p class="desc">Sidebar 会话列表支持搜索、分组、置顶、归档,适应长期使用场景。</p>
<h3>会话列表功能</h3>
<table class="spec">
<tr><th>功能</th><th>交互方式</th><th>说明</th></tr>
<tr><td class="f1">搜索</td><td class="f2">会话列表顶部搜索框</td><td class="f2">按标题和消息内容模糊搜索(<code>fuse.js</code></td></tr>
<tr><td class="f1">置顶</td><td class="f2">右键菜单 → 置顶</td><td class="f2">置顶会话固定在列表顶部,显示 📌 图标</td></tr>
<tr><td class="f1">分组</td><td class="f2">自动按工作空间分组</td><td class="f2">每个工作空间一个折叠组,可展开/收起</td></tr>
<tr><td class="f1">归档</td><td class="f2">右键菜单 → 归档</td><td class="f2">归档的会话移入「归档」折叠区,不占主列表空间,可恢复</td></tr>
<tr><td class="f1">重命名</td><td class="f2">双击会话标题 / 右键菜单</td><td class="f2">内联编辑,回车保存</td></tr>
<tr><td class="f1">导出</td><td class="f2">右键菜单 → 导出</td><td class="f2">导出为 Markdown / JSON</td></tr>
<tr><td class="f1">删除</td><td class="f2">右键菜单 → 删除</td><td class="f2">移入回收站(可恢复 30 天)</td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 会话项信息:</strong>每个会话项显示——会话标题(自动生成或用户重命名)、最后活跃时间(如「3 分钟前」)、消息数、Agent 状态指示灯(进行中显示绿色脉冲)。
</div>
</section>
<!-- ===== 窗口管理 ===== -->
<section class="api-section" id="window-management">
<h2>&#x1F5A5; 窗口管理</h2>
<p class="desc">Electron 桌面应用的窗口管理习惯设计:</p>
<table class="spec">
<tr><th>功能</th><th>行为</th><th>配置项</th></tr>
<tr><td class="f1">关闭窗口</td><td class="f2">最小化到系统托盘(默认),不退出应用</td><td class="f2"><code>app.closeToTray = true</code>(可关闭)</td></tr>
<tr><td class="f1">托盘图标</td><td class="f2">显示 Agent 状态:空闲(白色)/ 思考中(蓝色脉冲)/ 执行中(绿色旋转)</td><td class="f2"></td></tr>
<tr><td class="f1">托盘菜单</td><td class="f2">新建会话 · 显示窗口 · 退出</td><td class="f2"></td></tr>
<tr><td class="f1">多窗口</td><td class="f2">每个工作空间可独立开窗口,窗口标题显示工作空间名称</td><td class="f2"><code>app.multiWindow = true</code></td></tr>
<tr><td class="f1">全局快捷键</td><td class="f2"><code>Cmd/Ctrl+Shift+M</code> 从任意应用切换到 Metona 窗口</td><td class="f2">可自定义快捷键</td></tr>
<tr><td class="f1">系统通知</td><td class="f2">Agent 完成长时间任务时发送系统通知(点击跳转到对应会话)</td><td class="f2"><code>app.notifications = true</code></td></tr>
<tr><td class="f1">开机自启</td><td class="f2">系统启动时自动启动 Metona(最小化到托盘)</td><td class="f2"><code>app.autoStart = false</code></td></tr>
</table>
<div class="note-box">
<strong>&#x1F4A1; 托盘图标实现:</strong>使用 <code>electron Tray</code> API,动态切换图标以反映 Agent 状态。托盘图标右键菜单通过 <code>Menu.buildFromTemplate()</code> 构建。全局快捷键使用 <code>globalShortcut.register()</code>
</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>&#x1F3A8; MetonaAI Desktop UI/UX 设计集成方案</p>
<p>研究来源: <strong style="color:var(--accent)">Fuselab Creative · Ant Design X · Google A2UI · Hermes Agent · Siyu's Newsletter</strong></p>
<p style="margin-top:6px">集成组件: <strong style="color:var(--purple)">MetonaToast v2.0.0</strong> · 版本 <strong style="color:var(--accent2)">v1.0.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:#fff;border:none;cursor:pointer;font-size:20px;
display:none;align-items:center;justify-content:center;
box-shadow:0 4px 12px rgba(99,102,241,.3);transition:transform .2s,opacity .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>