diff --git a/.env.example b/.env.example index b23f33c..bb2f023 100644 --- a/.env.example +++ b/.env.example @@ -9,6 +9,10 @@ DEEPSEEK_BASE_URL=https://api.deepseek.com AGNES_API_KEY=your_agnes_api_key_here AGNES_BASE_URL=https://apihub.agnes-ai.com/v1 +# Xiaomi MiMo API +MIMO_API_KEY=your_mimo_api_key_here +MIMO_BASE_URL=https://api.xiaomimimo.com/v1 + # Ollama API (local) OLLAMA_BASE_URL=http://localhost:11434 diff --git a/README.md b/README.md index 64b9ebf..eddca8e 100644 --- a/README.md +++ b/README.md @@ -1,80 +1,582 @@ # MetonaAI Desktop -生产级通用 AI Agent 智能体桌面应用。 +> 生产级通用 AI Agent 智能体桌面应用 + +[](./package.json) +[](./LICENSE) +[](https://www.electronjs.org/) +[](https://react.dev/) +[](https://www.typescriptlang.org/) + +Metona 是一款基于 Electron 的生产级 AI Agent 桌面应用,内置 ReAct 状态机驱动的智能体循环、27 个内置工具、三层记忆系统、四层安全防线与完整的可观测性链路。支持 DeepSeek、Agnes AI、MiMo(小米)、Ollama 四种 LLM Provider,兼容 MCP 协议扩展。 + +--- + +## 目录 + +- [技术栈](#技术栈) +- [快速开始](#快速开始) +- [核心特性](#核心特性) +- [项目架构](#项目架构) +- [内置工具](#内置工具) +- [LLM 适配器](#llm-适配器) +- [记忆系统](#记忆系统) +- [安全机制](#安全机制) +- [配置说明](#配置说明) +- [项目结构](#项目结构) +- [开发命令](#开发命令) +- [许可证](#许可证) + +--- ## 技术栈 -- **运行时**: Electron 35 + React 19 + TypeScript 5.8 -- **状态管理**: Zustand 5 -- **数据库**: better-sqlite3 -- **LLM**: DeepSeek / Agnes AI / Ollama -- **协议**: MCP (Model Context Protocol) -- **构建**: electron-vite + Vite 6 +| 层级 | 技术 | 版本 | +|------|------|------| +| 运行时 | Electron | 35 | +| 前端框架 | React | 19 | +| 类型系统 | TypeScript | 5.8 | +| UI 组件库 | Material UI (MUI) | 9 | +| 状态管理 | Zustand | 5 | +| 数据库 | better-sqlite3 | 11 | +| 构建工具 | electron-vite + Vite | 3 / 6 | +| LLM 协议 | MCP SDK | 1.12 | +| 样式辅助 | Tailwind CSS | 4 | +| Markdown | react-markdown + remark-gfm | 10 / 4 | +| UUID | nanoid | 5 | +| 校验 | Zod | 3 | +| 缓存 | lru-cache | 11 | +| 日志 | electron-log | 5 | +| 配置存储 | electron-store | 10 | + +--- ## 快速开始 +### 环境要求 + +- Node.js >= 18 +- npm >= 9 +- Windows / macOS / Linux + +### 安装与运行 + ```bash # 安装依赖 npm install -# 开发模式 +# 开发模式(启动 Electron + Vite 热重载) npm run dev -# 构建 +# 类型检查 +npm run typecheck + +# 构建生产包(Windows 输出 NSIS 安装包 + 便携版) npm run build ``` -## 配置 +### 配置 LLM Provider -复制 `.env.example` 为 `.env`,填入 API Key: +1. 复制 `.env.example` 为 `.env`,填入 API Key: ```bash cp .env.example .env ``` -或在应用设置界面中配置 LLM Provider。 +```env +# DeepSeek API +DEEPSEEK_API_KEY=your_key +DEEPSEEK_BASE_URL=https://api.deepseek.com + +# Agnes AI API +AGNES_API_KEY=your_key +AGNES_BASE_URL=https://apihub.agnes-ai.com/v1 + +# Ollama(本地运行,无需 Key) +OLLAMA_BASE_URL=http://localhost:11434 +``` + +2. 或在应用启动后,通过 **设置 → LLM 配置** 界面可视化配置 Provider、API Key、模型、上下文窗口等参数。 + +--- + +## 核心特性 + +### 智能体引擎 + +- **ReAct 状态机**:8 状态闭环(INIT → THINKING → PARSING → EXECUTING → OBSERVING → REFLECTING → COMPRESSING → TERMINATED) +- **流式对话**:SSE(DeepSeek/Agnes)+ NDJSON(Ollama)双协议流式响应 +- **Thinking 模式**:支持 deepseek-v4-pro / agnes-2.0-flash / qwen3 等模型的推理模式 +- **死循环检测**:连续 3 轮相同工具调用签名自动终止 +- **上下文压缩**:80% 阈值触发 LLM 摘要压缩,保留最近 10 条消息 +- **错误重试**:指数退避(1s/2s/4s,上限 30s)+ ±20% jitter +- **可配置迭代**:最大迭代次数(默认 20)、总超时(默认 600s)、工具执行超时(默认 120s) + +### 工具与执行 + +- **27 个内置工具**:覆盖文件系统、代码搜索、网络搜索、浏览器自动化、Git、开发工具、记忆、任务管理等 +- **MCP 协议支持**:动态加载外部 MCP Server 工具 +- **子任务委派**:TaskOrchestrator 支持最大 3 层深度的 SubAgent 编排 +- **策略引擎**:三级权限(READ/WRITE/EXTERNAL_ACTION)+ 滑动窗口频率限制 +- **确认机制**:HIGH/CRITICAL 风险工具需用户确认,支持会话内同类免确认与持久化自动执行 + +### 记忆与上下文 + +- **三层记忆系统**:情节记忆(episodic)、语义记忆(semantic)、工作记忆(working) +- **TF-IDF 语义检索**:中英文分词 + 时间衰减(30 天半衰期)+ IDF 缓存 +- **自动记忆固化**:会话结束时 LLM 提取重要信息写入 MEMORY.md +- **System Prompt 分区构建**:SOUL.md + AGENTS.md + USERS.md + MEMORY.md + 安全准则 + +### 安全防线(四层纵深防御) + +1. **路径安全**:工作空间边界校验 + realpathSync 符号链接逃逸检测 + 根目录 MEMORY.md 保护 +2. **命令安全**:SandboxManager 28 模式扫描 + shell-quote 双层防御 + 受保护文件检查 +3. **权限控制**:PolicyEngine 三级权限 + 频率限制(20 次/分钟)+ 用户确认钩子 +4. **内容安全**:PromptInjectionDefender(30+ 正则 + 语义检测)+ OutputValidator(幻觉检测) + +### 可观测性 + +- **全链路追踪**:TraceViewer 可视化 ReAct 每轮迭代 +- **会话录制**:9 种事件录制到 JSONL 文件 +- **审计日志**:SQLite 链式哈希防篡改(INSERT-ONLY 触发器) +- **Token 统计**:输入/输出/推理 Token 用量追踪 + +### 桌面体验 + +- **三栏布局**:Sidebar + Chat + DetailPanel,支持专注模式 +- **系统托盘**:4 状态指示(idle/thinking/executing/error) +- **全局快捷键**:Cmd/Ctrl+Shift+M 唤起应用 +- **14 个应用内快捷键**:会话管理、布局切换、主题切换等 +- **暗色/亮色主题**:跟随系统 + 手动切换 +- **首次使用引导**:5 步 Onboarding 向导 +- **命令面板**:Cmd/Ctrl+K 快速搜索 +- **多平台构建**:Windows(NSIS + 便携版)、macOS(DMG + ZIP)、Linux(AppImage + DEB) + +--- + +## 项目架构 + +### 四层 Harness 架构 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ L1 推理与编排层 │ +│ AgentLoopEngine (ReAct 状态机) · TaskOrchestrator (子任务) │ +│ MetonaRequest / MetonaResponse / MetonaStreamEvent │ +├─────────────────────────────────────────────────────────────┤ +│ L2 上下文与记忆层 │ +│ ContextBuilder · MemoryManager · MemoryConsolidator │ +│ MetonaContext / MetonaMemoryItem │ +├─────────────────────────────────────────────────────────────┤ +│ L3 工具与安全执行层 │ +│ ToolRegistry · SandboxManager · PolicyEngine · MCPAdapter │ +│ PromptInjectionDefender · OutputValidator · ConfirmationHook │ +│ MetonaToolDef / MetonaToolCall / MetonaToolResult │ +├─────────────────────────────────────────────────────────────┤ +│ L4 支撑与基础架构层 │ +│ ConfigService · DatabaseService · AuditService │ +│ SessionService · SessionRecorder · WindowManager │ +│ TrayManager · MCPManager · WorkspaceService │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 进程模型 + +| 进程 | 运行时 | 职责 | +|------|--------|------| +| Main Process | Node.js | Agent 引擎、工具调度、数据库、MCP 管理、配置 | +| Preload Script | 沙箱 | contextBridge 安全暴露 14 个 API 命名空间 | +| Renderer | Chromium | React 19 + MUI 9 界面渲染 | + +### 数据流 + +``` +用户输入 → ChatInput → agent-store.sendMessage + → IPC: agent:sendMessage → handlers.ts + → reloadAdapter (热重载,配置签名比对) + → 保存用户消息到 SQLite + → 加载历史消息 + 注入相关记忆 + → ContextBuilder.buildSystemPrompt (SOUL+AGENTS+USERS+MEMORY+安全准则) + → PromptInjectionDefender.detect (riskScore>=7 阻断) + → AgentLoopEngine.runStream + → Adapter.sendStream (SSE/NDJSON 流式) + → 流式事件 → webContents.send('agent:streamEvent') + → 工具调用 → PreToolHooks (权限+频率+确认) + → ToolRegistry.execute → PostToolHooks (审计+记忆触发) + → 80% 阈值触发上下文压缩 + → 死循环检测 (3 轮相同签名) + → OutputValidator.validate (幻觉检测) + → 保存 assistant 消息 + tool 结果消息 + → MemoryConsolidator.consolidate (异步提取记忆) + → AuditService.logSessionEnd + ← useAgentStream Hook 监听事件 → Zustand Store → React 重渲染 +``` + +--- + +## 内置工具 + +Metona 内置 27 个工具,按功能分类如下: + +### 文件系统(5 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `read_file` | SAFE | 否 | 读取文本文件,二进制检测,offset/limit 分页 | +| `write_file` | MEDIUM | 是 | 原子写入(tmp+rename),支持 overwrite/append | +| `list_directory` | SAFE | 否 | 列出目录,depth(max 5)/glob/include_hidden | +| `search_files` | SAFE | 否 | 按模式搜索,content/files 模式,context_lines | +| `delete_file` | HIGH | 是 | 删除文件,禁止删除工作空间根目录和 MEMORY.md | + +### 编辑与搜索(3 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `file_editor` | MEDIUM | 是 | 精准编辑,replace/insert/delete/regex + dry_run | +| `code_search` | SAFE | 否 | 基于 ripgrep 高速搜索,回退 JS | +| `diff_viewer` | SAFE | 否 | unified diff 格式,LCS 算法 | + +### 网络与浏览器(4 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `web_search` | LOW | 否 | 双模式(SearXNG / 内置四引擎),智能排序,自动抓取 | +| `web_fetch` | LOW | 否 | 三阶段回退(HTTP + 反爬 + 浏览器渲染),10MB 限制 | +| `web_browser` | HIGH | 是 | 浏览器自动化,9 个 action(open/screenshot/extract 等) | +| `http_request` | LOW | 否 | HTTP/REST API 请求,6 种 method | + +### 记忆(2 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `memory_store` | MEDIUM | 否 | 存储记忆到三层(episodic/semantic/working) | +| `memory_search` | SAFE | 否 | TF-IDF 检索记忆,时间衰减 | + +### 命令与开发(5 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `run_command` | HIGH | 是 | 沙箱执行 Shell 命令,双重校验 + shell-quote 防御 | +| `lint_code` | SAFE | 否 | TypeScript tsc 或 ESLint 检查 | +| `run_tests` | LOW | 否 | 运行测试套件,filter 字符白名单防注入 | +| `project_info` | SAFE | 否 | 项目结构分析,4 种 detail | +| `delegate_task` | MEDIUM | 否 | 子任务委派给独立 SubAgent | + +### Git(4 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `git_status` | SAFE | 否 | 工作树状态,porcelain v1 解析 | +| `git_diff` | SAFE | 否 | diff 输出,50KB 截断,5MB maxBuffer | +| `git_log` | SAFE | 否 | 提交历史,jest/vitest/mocha 格式解析 | +| `git_commit` | MEDIUM | 是 | 暂存+提交,校验 file 在 workspace 内 | + +### 任务与辅助(4 个) + +| 工具 | 风险 | 需确认 | 功能 | +|------|------|--------|------| +| `task_manager` | LOW | 否 | 持久化任务 CRUD,支持父子关系 | +| `todo_write` | SAFE | 否 | 会话级 TODO,LRU 淘汰(max 50 sessions) | +| `think` | SAFE | 否 | 结构化思考空间,无副作用 | +| `view_image` | SAFE | 否 | 读取图片返回 base64,5MB 限制,7 种格式 | + +--- + +## LLM 适配器 + +| 适配器 | Provider ID | 模型 | 上下文窗口 | 流式格式 | Thinking | 多模态 | +|--------|-------------|------|-----------|----------|----------|--------| +| DeepSeekAdapter | deepseek | deepseek-v4-pro / deepseek-v4-flash | 1M(可配) | SSE | thinking + reasoning_effort | 否 | +| AgnesAdapter | agnes | agnes-2.0-flash | 1M(可配) | SSE | chat_template_kwargs | 是(URL) | +| MimoAdapter | mimo | mimo-v2.5-pro / mimo-v2.5 | 131072(可配) | SSE | thinking.type | 是(URL) | +| OllamaAdapter | ollama | qwen3 / gemma3 / deepseek-r1 | 4096(可配 num_ctx) | NDJSON | think 参数 | 是(Base64) | + +### 上下文窗口配置 + +- **DeepSeek / Agnes / MiMo**:`contextWindow` 配置项影响本地压缩判断和 UI 显示(最小 4096) +- **Ollama**:`num_ctx` 配置项直接影响 API 请求参数 +- 切换 Provider 时自动清空 API Key,防止使用不兼容的密钥 +- Engine 上下文窗口与 Adapter 配置值自动同步 + +--- + +## 记忆系统 + +### 三层记忆架构 + +| 层级 | 类型 | 存储表 | 用途 | 检索方式 | +|------|------|--------|------|----------| +| L2 | 情节记忆 (episodic) | episodic_memories | 会话事件、用户交互 | TF-IDF + 时间衰减 | +| L3 | 语义记忆 (semantic) | semantic_memories | 知识、偏好、事实 | 精确 + 模糊匹配 | +| L1 | 工作记忆 (working) | working_memories | 当前任务临时状态 | 精确键值查找 | + +### 记忆生命周期 + +``` +新记忆写入 → 重要性评分 (0-1) + ├── 高 (>0.8) → 永久保存 + ├── 中 (0.4-0.8) → 定期回顾,逐渐衰减 + └── 低 (<0.4) → 短期保留,自然遗忘 +会话结束 → MemoryConsolidator 提取重要信息 → 写入 MEMORY.md +``` + +### 磁盘文件(工作空间) + +| 文件 | 用途 | 是否必需 | +|------|------|----------| +| SOUL.md | AI 角色定义(灵魂) | 是 | +| AGENTS.md | AI 行为规则 | 是 | +| MEMORY.md | 动态记忆存储 | 是(仅根目录受保护) | +| USERS.md | 用户信息画像 | 是 | + +--- + +## 安全机制 + +### 四层纵深防御 + +``` +第 1 层:路径安全 + └─ isPathWithinWorkspace + realpathSync + MEMORY.md 保护 + +第 2 层:命令安全 + └─ SandboxManager (28 模式扫描) + shell-quote 双层防御 + +第 3 层:权限控制 + └─ PolicyEngine (三级权限) + 频率限制 (20/min) + ConfirmationHook + +第 4 层:内容安全 + └─ PromptInjectionDefender (30+ 正则 + 语义检测) + OutputValidator (幻觉检测) +``` + +### 风险分级 + +| 风险等级 | 示例工具 | 确认要求 | +|----------|----------|----------| +| SAFE | read_file, list_directory, code_search | 无需确认 | +| LOW | web_search, web_fetch, http_request | 无需确认 | +| MEDIUM | write_file, file_editor, memory_store | 可配置自动执行 | +| HIGH | delete_file, run_command, web_browser, git_commit | 强制确认 | +| CRITICAL | (预留) | 强制确认 + 双人复核 | + +--- + +## 配置说明 + +### 环境变量(.env) + +```env +# DeepSeek API +DEEPSEEK_API_KEY=your_deepseek_api_key_here +DEEPSEEK_BASE_URL=https://api.deepseek.com + +# Agnes AI API +AGNES_API_KEY=your_agnes_api_key_here +AGNES_BASE_URL=https://apihub.agnes-ai.com/v1 + +# Xiaomi MiMo API +MIMO_API_KEY=your_mimo_api_key_here +MIMO_BASE_URL=https://api.xiaomimimo.com/v1 + +# Ollama API (local) +OLLAMA_BASE_URL=http://localhost:11434 + +# App +VITE_APP_TITLE=MetonaAI Desktop +``` + +### 应用配置(app_config 表) + +关键配置项及默认值: + +| 配置项 | 默认值 | 说明 | +|--------|--------|------| +| `llm.provider` | deepseek | LLM Provider | +| `llm.model` | deepseek-v4-pro | 模型名称 | +| `agent.maxIterations` | 20 | 最大迭代次数 | +| `agent.totalTimeoutMs` | 600000 | 总超时(ms) | +| `agent.thinkingEnabled` | true | Thinking 模式 | +| `agent.thinkingEffort` | high | 推理强度 | +| `agent.confirmationTimeoutMs` | 120000 | 确认超时(30s~600s) | +| `deepseek.contextWindow` | 1000000 | DeepSeek 上下文窗口 | +| `agnes.contextWindow` | 1000000 | Agnes 上下文窗口 | +| `mimo.contextWindow` | 131072 | MiMo 上下文窗口 | +| `ollama.numCtx` | 4096 | Ollama 上下文窗口 | + +### SearXNG 配置(可选) + +启用 SearXNG 元搜索引擎替代内置四引擎搜索,支持 12 项配置(URL、引擎列表、认证方式等),详见设置界面。 + +--- ## 项目结构 ``` MetonaAI-Desktop/ -├── electron/ # Electron 主进程 -│ ├── main.ts # 应用入口 -│ ├── preload.ts # 安全桥接脚本 -│ ├── ipc/ # IPC 通道处理 -│ ├── services/ # 业务服务(数据库、会话、记忆等) -│ └── harness/ # Agent 核心引擎 -│ ├── agent-loop/ # ReAct 状态机 -│ ├── adapters/ # LLM Provider 适配器 -│ ├── tools/ # 工具注册与内置工具 -│ ├── memory/ # 记忆系统 -│ ├── prompts/ # System Prompt 构建 -│ └── types/ # Metona IR 类型定义 -├── src/ # React 渲染进程 -│ ├── components/ # UI 组件 -│ ├── hooks/ # React Hooks -│ ├── stores/ # Zustand 状态管理 -│ ├── styles/ # 全局样式 -│ └── types/ # 类型声明 -├── docs/ # 设计文档 -├── standard/ # 开发规范 -└── apis/ # API 文档 +├── electron/ # Electron 主进程 +│ ├── main.ts # 应用入口(538 行) +│ ├── preload.ts # 安全桥接(14 个 API 命名空间) +│ ├── ipc/ +│ │ └── handlers.ts # IPC 通道处理(50+ 通道) +│ ├── services/ # 业务服务层 +│ │ ├── audit.service.ts # 审计日志(链式哈希防篡改) +│ │ ├── config.service.ts # 配置管理 +│ │ ├── database.service.ts # SQLite 数据库(9 张表) +│ │ ├── mcp-manager.service.ts # MCP Server 管理 +│ │ ├── session-recorder.service.ts # 会话录制 +│ │ ├── session.service.ts # 会话 CRUD +│ │ ├── tray-manager.service.ts # 系统托盘 +│ │ ├── update.service.ts # 自动更新 +│ │ ├── window-manager.service.ts # 窗口管理 +│ │ └── workspace.service.ts # 工作空间管理 +│ └── harness/ # Agent 核心引擎 +│ ├── agent-loop/ # ReAct 状态机 +│ │ ├── engine.ts # 循环引擎(8 状态) +│ │ └── types.ts # 状态枚举 +│ ├── adapters/ # LLM Provider 适配器 +│ │ ├── base-adapter.ts # 抽象基类 +│ │ ├── deepseek.adapter.ts # DeepSeek(SSE) +│ │ ├── agnes-ai.adapter.ts # Agnes AI(SSE) +│ │ ├── mimo.adapter.ts # MiMo 小米(SSE) +│ │ ├── ollama.adapter.ts # Ollama(NDJSON) +│ │ └── shared/ # 共享模块 +│ │ ├── openai-format.ts # OpenAI 兼容格式 +│ │ └── sse-stream.ts # SSE 流解析 +│ ├── tools/ # 工具系统 +│ │ ├── registry.ts # 工具注册 + PolicyEngine +│ │ └── built-in/ # 27 个内置工具 +│ │ ├── filesystem.ts # 文件系统(5 工具) +│ │ ├── file-editor.ts # 编辑器 +│ │ ├── code-search.ts # 代码搜索 +│ │ ├── diff-viewer.ts # 差异查看 +│ │ ├── web-search.ts # 网络搜索 +│ │ ├── web-fetch.ts # 网页抓取 +│ │ ├── browser.ts # 浏览器工具 +│ │ ├── browser-window-manager.ts # 浏览器窗口管理 +│ │ ├── network.ts # 网络工具入口 +│ │ ├── network-utils.ts # 网络工具函数 +│ │ ├── http-request.ts # HTTP 请求 +│ │ ├── memory.ts # 记忆工具 +│ │ ├── command.ts # 命令执行 +│ │ ├── git.ts # Git 工具(4 个) +│ │ ├── dev-tools.ts # 开发工具(3 个) +│ │ ├── task-manager.ts # 任务管理 +│ │ ├── delegate-task.ts # 子任务委派 +│ │ ├── todo.ts # TODO 工具 +│ │ ├── think.ts # 思考工具 +│ │ ├── view-image.ts # 图片查看 +│ │ └── file-guard.ts # 文件保护 +│ ├── types/ # Metona IR 类型定义 +│ │ ├── metona-request.ts # 请求类型 +│ │ ├── metona-response.ts # 响应类型 +│ │ ├── metona-tool.ts # 工具类型 +│ │ ├── metona-context.ts # 上下文类型 +│ │ └── metona-adapter.ts # 适配器接口 +│ ├── sandbox/ # 沙箱安全 +│ │ ├── sandbox.ts # SandboxManager +│ │ └── permissions.ts # PolicyEngine +│ ├── security/ # 安全防御 +│ │ └── prompt-injection-defense.ts +│ ├── memory/ # 记忆系统 +│ │ ├── manager.ts # MemoryManager +│ │ └── consolidator.ts # MemoryConsolidator +│ ├── orchestration/ # 编排 +│ │ └── orchestrator.ts # TaskOrchestrator +│ ├── prompts/ # 提示词构建 +│ │ └── context-builder.ts # ContextBuilder +│ ├── hooks/ # 钩子 +│ │ ├── pre-tool.ts # 工具前钩子 +│ │ ├── post-tool.ts # 工具后钩子 +│ │ └── confirmation-hook.ts # 确认钩子 +│ ├── verification/ # 验证 +│ │ └── output-validator.ts # OutputValidator +│ └── utils/ # 工具函数 +│ └── token-estimator.ts # Token 估算 +├── src/ # React 渲染进程 +│ ├── main.tsx # React 入口 +│ ├── App.tsx # 应用根组件 +│ ├── components/ # UI 组件(25 个) +│ │ ├── chat/ # 聊天组件(11 个) +│ │ ├── layout/ # 布局组件(5 个) +│ │ ├── settings/ # 设置面板 +│ │ ├── memory/ # 记忆查看器 +│ │ ├── tasks/ # 任务列表 +│ │ ├── trace/ # 追踪查看器(3 个) +│ │ ├── workspace/ # 工作空间查看器 +│ │ ├── onboarding/ # 引导向导 +│ │ └── common/ # 通用组件 +│ ├── hooks/ # React Hooks +│ │ ├── useAgentStream.ts # Agent 流式事件 +│ │ ├── useKeyboardShortcuts.ts # 键盘快捷键 +│ │ └── useTheme.ts # 主题管理 +│ ├── stores/ # Zustand 状态管理 +│ │ ├── agent-store.ts # Agent 状态 +│ │ ├── session-store.ts # 会话状态 +│ │ └── ui-store.ts # UI 状态 +│ ├── lib/ # 工具库 +│ │ ├── constants.ts # 常量定义 +│ │ ├── formatters.ts # 格式化函数 +│ │ ├── theme.ts # MUI 主题 +│ │ └── cn.ts # className 合并 +│ ├── styles/ +│ │ └── globals.css # 全局样式 +│ └── types/ +│ └── global.d.ts # window.metona 类型声明 +├── docs/ # 设计文档 +├── standard/ # 开发规范 +├── apis/ # LLM API 文档 +├── assets/ # 应用图标 +├── .env.example # 环境变量示例 +├── electron-builder.yml # 构建配置 +├── electron.vite.config.ts # Vite 配置 +├── package.json # 依赖与脚本 +├── tsconfig.json # TypeScript 配置 +├── tsconfig.node.json # Node 端配置 +├── tsconfig.web.json # Web 端配置 +└── LICENSE # MIT 许可证 ``` -## 功能 +--- -- ✅ 三栏布局(Sidebar + Chat + DetailPanel) -- ✅ 流式对话(DeepSeek / Agnes / Ollama) -- ✅ 9 个内置工具(文件系统、网络、记忆、命令行) -- ✅ MCP 协议支持 -- ✅ 会话持久化(SQLite) -- ✅ 三层记忆系统(情节/语义/工作) -- ✅ 全链路追踪(Trace Viewer) -- ✅ 审计日志(防篡改) -- ✅ 系统托盘 + 全局快捷键 -- ✅ 暗色/亮色主题 -- ✅ 14 个键盘快捷键 +## 开发命令 + +```bash +# 开发 +npm run dev # 启动开发模式 +npm run typecheck # 全量类型检查 +npm run typecheck:node # Node 端类型检查 +npm run lint # ESLint 检查 +npm run lint:fix # ESLint 自动修复 +npm run format # Prettier 格式化 + +# 测试 +npm test # 运行单元测试 (Vitest) +npm run test:watch # 测试监听模式 +npm run test:e2e # E2E 测试 (Playwright) + +# 构建 +npm run build # 构建生产包 +npm run build:renderer # 仅构建渲染进程 +npm run build:electron # 仅构建主进程 +npm run preview # 预览构建产物 +``` + +### 数据库 Schema(9 张表) + +| 表名 | 用途 | +|------|------| +| sessions | 会话管理 | +| messages | 消息持久化 | +| app_config | 应用配置(键值对) | +| audit_logs | 审计日志(链式哈希防篡改) | +| mcp_servers | MCP Server 配置 | +| episodic_memories | 情节记忆 | +| semantic_memories | 语义记忆 | +| working_memories | 工作记忆 | +| tasks | 持久化任务 | + +--- ## 许可证 -MIT +[MIT](./LICENSE) diff --git a/apis/mimo-api-docs-20260715.html b/apis/mimo-api-docs-20260715.html new file mode 100644 index 0000000..14b5f3a --- /dev/null +++ b/apis/mimo-api-docs-20260715.html @@ -0,0 +1,793 @@ + + +
+ + +Xiaomi MiMo V2.5 系列 OpenAI 兼容对话补全接口完整文档。支持多轮对话、深度思考、工具调用、联网搜索、语音合成、图像/视频输入等全功能。
+MiMo Chat Completions API 是小米大语言模型提供的 OpenAI 兼容对话补全接口,支持 RESTful HTTP 协议,所有请求与响应均使用 JSON 格式。流式响应采用 SSE(Server-Sent Events)。
+ +| 项目 | 值 |
|---|---|
| Base URL | https://api.xiaomimimo.com/v1/chat/completions |
| 协议 | HTTPS (POST) |
| 认证方式 | api-key Header 或 Authorization Bearer |
| 内容类型 | application/json |
| SDK 兼容 | OpenAI Python / Node.js SDK(修改 base_url 即可) |
| 文档日期 | 2026-07-15 |
| 更新时间 | 2026-06-29(官方) |
支持 system/user/assistant/developer/tool 多角色消息
思维链推理,返回 reasoning_content
Function Calling + Web Search 工具
自动联网检索并返回引用注释
支持图像、音频、视频输入
TTS / Voice Design / Voice Clone
流式输出,降低首字延迟
获取 API Key 后即可开始调用。支持 OpenAI SDK 兼容格式,也可直接使用 HTTP 请求。
+ +bashcurl --location --request POST 'https://api.xiaomimimo.com/v1/chat/completions' \
+--header "api-key: $MIMO_API_KEY" \
+--header "Content-Type: application/json" \
+--data-raw '{
+ "model": "mimo-v2.5-pro",
+ "messages": [
+ {
+ "role": "system",
+ "content": "You are MiMo, an AI assistant developed by Xiaomi."
+ },
+ {
+ "role": "user",
+ "content": "你好,请介绍一下自己"
+ }
+ ],
+ "max_completion_tokens": 1024,
+ "temperature": 1.0,
+ "top_p": 0.95,
+ "stream": false,
+ "thinking": {
+ "type": "disabled"
+ }
+}'
+ pythonfrom openai import OpenAI
+
+client = OpenAI(
+ api_key="$MIMO_API_KEY",
+ base_url="https://api.xiaomimimo.com/v1"
+)
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[
+ {"role": "system", "content": "You are MiMo, an AI assistant developed by Xiaomi."},
+ {"role": "user", "content": "你好,请介绍一下自己"}
+ ],
+ max_completion_tokens=1024,
+ temperature=1.0,
+ thinking={"type": "disabled"}
+)
+
+print(response.choices[0].message.content)
+ | 模型 ID | 类型 | 默认 max_tokens | 深度思考 | 工具调用 | 语音合成 | 联网搜索 |
|---|---|---|---|---|---|---|
mimo-v2.5-pro | 旗舰文本 | 131072 | ✅ 支持 | ✅ 支持 | ❌ | ✅ 支持 |
mimo-v2.5 | 标准文本 | 32768 | ✅ 支持 | ✅ 支持 | ❌ | ✅ 支持 |
mimo-v2.5-tts | 语音合成 | 8192 | ❌ | ❌ | ✅ 预置音色 | ❌ |
mimo-v2.5-tts-voicedesign | 音色设计 | 8192 | ❌ | ❌ | ✅ 音色设计 | ❌ |
mimo-v2.5-tts-voiceclone | 声音克隆 | 8192 | ❌ | ❌ | ✅ 声音克隆 | ❌ |
1.0;TTS 系列默认 0.6
+ 接口支持以下两种认证方式,选择其中一种添加到请求头中:
+ +httpapi-key: $MIMO_API_KEY
+Content-Type: application/json
+
+ httpAuthorization: Bearer $MIMO_API_KEY
+Content-Type: application/json
+| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
model | string | 必选 | 模型 ID。可选值:mimo-v2.5-pro, mimo-v2.5, mimo-v2.5-tts, mimo-v2.5-tts-voicedesign, mimo-v2.5-tts-voiceclone |
messages | array | 必选 | 对话消息列表。支持 role: system / user / assistant / developer / tool |
messages[].role | string | 必选 | 角色:system / user / assistant / developer / tool |
messages[].content | string | array | 必选 | 消息内容。支持纯文本或多模态 content parts 数组 |
messages[].name | string | 可选 | 参与者名称,用于区分相同角色的不同参与者 |
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
max_completion_tokens | integer | null | 可选 | 生成 token 上限(含推理 token)。pro 默认 131072;标准版 32768;TTS 系列 8192。范围 [1, 131072] |
temperature | number | 可选 | 采样温度 [0, 1.5]。pro/标准默认 1.0;TTS 默认 0.6。思考模式下不可自定义 |
top_p | number | 可选 | 核采样概率 [0.01, 1.0],默认 0.95。建议仅与 temperature 二选一。思考模式下不可自定义 |
frequency_penalty | number | null | 可选 | 频率惩罚 [-2.0, 2.0],默认 0 |
presence_penalty | number | null | 可选 | 存在惩罚 [-2.0, 2.0],默认 0 |
stop | string | array | null | 可选 | 停止序列(最多 4 个)。TTS 系列不支持 |
stream | boolean | null | 可选 | 是否 SSE 流式传输,默认 false |
response_format | object | 可选 | 指定输出格式。TTS 系列不支持 |
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
thinking | object | 可选 | 思维链控制。TTS 系列不支持 |
thinking.type | string | 可选 | "enabled"(默认)或 "disabled" |
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
tools | array | 可选 | 工具列表。支持 function 和 web_search 两种类型。TTS 系列不支持 |
tools[].type | string | 必选 | 工具类型:"function" 或 "web_search" |
tools[].function.name | string | 必选 | 函数名(a-z, A-Z, 0-9, _, -),最大 64 字符 |
tools[].function.description | string | 可选 | 功能描述 |
tools[].function.parameters | object | 可选 | JSON Schema 格式的参数定义 |
tools[].function.strict | boolean | 可选 | 是否严格遵循 schema,默认 false |
tool_choice | string | 可选 | 仅支持 "auto"。传入其他值会被后端移除。TTS 系列不支持 |
| 参数名 | 类型 | 必填 | 描述 |
|---|---|---|---|
audio | object | 可选 | 音频输出参数。仅 TTS 系列模型支持 |
audio.format | string | 可选 | 输出格式:wav(默认) / mp3 / pcm / pcm16。stream:true 时默认 pcm |
audio.voice | string | 可选 | 预置音色 ID 或 base64 音频样本。TTS 预置:mimo_default, 冰糖, 茉莉, 苏打, 白桦, Mia, Chloe, Milo, Dean |
audio.optimize_text_preview | boolean | 可选 | 智能润色播报文本,默认 false。仅 voicedesign 模型支持 |
role: "assistant" 的消息指定合成文本。使用 voicedesign + optimize_text_preview=true 时可省略 assistant 消息。
+ 当 stream: false 时,API 返回完整的 chat.completion 对象。
| 字段名 | 类型 | 描述 |
|---|---|---|
id | string | 响应的唯一标识符 |
object | string | 固定值 "chat.completion" |
created | integer | Unix 时间戳(秒) |
model | string | 实际使用的模型 ID |
| 字段名 | 类型 | 描述 |
|---|---|---|
choices[].index | integer | 选项索引 |
choices[].finish_reason | string | 停止原因:stop / length / tool_calls / content_filter / repetition_truncation |
choices[].message.content | string | 回复内容 |
choices[].message.reasoning_content | string | 思维链推理内容(思考模式) |
choices[].message.role | string | 固定为 "assistant" |
choices[].message.tool_calls | array | 工具调用列表(如有) |
choices[].message.tool_calls[].id | string | 工具调用 ID |
choices[].message.tool_calls[].type | string | 固定为 "function" |
choices[].message.tool_calls[].function.name | string | 被调用的函数名 |
choices[].message.tool_calls[].function.arguments | string | JSON 格式的调用参数 |
choices[].message.annotations | array | 联网搜索引用注释(如有) |
choices[].message.audio | object | 音频响应数据(TTS 请求时) |
choices[].message.audio.id | string | 音频唯一标识 |
choices[].message.audio.data | string | Base64 编码的音频数据 |
choices[].final_text_preview | string | 优化后的播报文本(optimize_text_preview 时返回) |
| 字段名 | 类型 | 描述 |
|---|---|---|
usage.prompt_tokens | integer | 提示词 token 数 |
usage.completion_tokens | integer | 输出 token 数 |
usage.total_tokens | integer | 总 token 数 |
usage.completion_tokens_details.reasoning_tokens | integer | 推理 token 数 |
usage.prompt_tokens_details.cached_tokens | integer | 缓存命中的 token 数 |
usage.prompt_tokens_details.audio_tokens | integer | 音频输入 token 数 |
usage.prompt_tokens_details.image_tokens | integer | 图像输入 token 数 |
usage.prompt_tokens_details.video_tokens | integer | 视频输入 token 数 |
usage.web_search_usage.tool_usage | integer | 联网搜索 API 调用次数 |
usage.web_search_usage.page_usage | integer | 联网搜索返回网页数 |
json{
+ "id": "8b51f9e0515949cb8207fbd35ea6ea5c",
+ "object": "chat.completion",
+ "created": 1776848906,
+ "model": "mimo-v2.5-pro",
+ "choices": [
+ {
+ "finish_reason": "stop",
+ "index": 0,
+ "message": {
+ "content": "Hello! I'm MiMo, Xiaomi's AI assistant created by the Xiaomi LLM-Core team...",
+ "role": "assistant",
+ "tool_calls": null
+ }
+ }
+ ],
+ "usage": {
+ "completion_tokens": 72,
+ "prompt_tokens": 57,
+ "total_tokens": 129,
+ "completion_tokens_details": {
+ "reasoning_tokens": 0
+ },
+ "prompt_tokens_details": null
+ }
+}
+当 stream: true 时,API 通过 SSE 以 chat.completion.chunk 格式增量返回数据。
data: {...} 行发送,结束标记为 data: [DONE]。
+ | 字段名 | 类型 | 描述 |
|---|---|---|
object | string | 固定值 "chat.completion.chunk" |
choices[].delta | object | 增量数据(替代 message) |
choices[].delta.content | string | 本 chunk 的文本增量 |
choices[].delta.reasoning_content | string | 本 chunk 的推理增量 |
choices[].delta.role | string | 首个 chunk 中的角色(通常为 "assistant") |
choices[].delta.tool_calls | array | 增量工具调用(含 index 定位) |
choices[].delta.tool_calls[].index | integer | 工具调用在列表中的索引(从 0 开始) |
choices[].delta.audio | object | null | 音频增量数据 |
choices[].finish_reason | string | null | 最后一个 chunk 的停止原因 |
其余字段(id, created, model, usage, annotations 等)与非流式相同,通常仅在最后一个 chunk 中返回 usage。
+MiMo V2.5 Pro 和标准版支持思维链(Chain-of-Thought)推理,让模型在回答前进行深度推理。适用于数学、逻辑、编程、复杂分析等场景。
+ +| 参数名 | 类型 | 描述 |
|---|---|---|
thinking.type | string | "enabled"(默认)启用 / "disabled" 关闭 |
reasoning_content 字段包含模型的推理过程,content 为最终回答temperature 强制为 1.0,top_p 强制为 0.95,自定义无效tool_calls 和 reasoning_contentMiMo 支持 Function Calling,允许模型调用外部函数获取信息或执行操作。同时内置 Web Search 联网搜索工具。
+ +| 特性 | 描述 |
|---|---|
| 工具类型 | function(函数工具)+ web_search(联网搜索) |
| tool_choice | 仅支持 "auto"。传入其他值会被后端移除 |
| strict 模式 | 支持 strict: true,严格遵循 JSON Schema(子集) |
| 思考模式兼容 | V2.5 Pro/标准版支持思考模式下的工具调用 |
json{
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的当前天气信息",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": { "type": "string", "description": "城市名称" }
+ },
+ "required": ["location"]
+ },
+ "strict": false
+ }
+}
+
+ MiMo 内置 Web Search 工具,模型可自动联网检索最新信息并在回答中引用来源。
+ +在 tools 数组中添加 web search 类型的工具:
json{
+ "tools": [
+ { "type": "web_search" }
+ ]
+}
+
+ | 字段名 | 类型 | 描述 |
|---|---|---|
annotations[].title | string | 引用页面标题 |
annotations[].url | string | 引用网址 |
annotations[].site_name | string | 网站名称 |
annotations[].summary | string | 内容摘要 |
annotations[].publish_time | string | 发布时间 |
annotations[].logo_url | string | 网站 Logo 地址 |
annotations[].type | string | 类型 |
error_message | string | 联网搜索错误信息(如有) |
MiMo 提供三种 TTS 能力,通过不同的模型和 audio 参数组合实现。
+ +| 能力 | 模型 | audio.voice | 特点 |
|---|---|---|---|
| 预置音色 TTS | mimo-v2.5-tts | 可选,预置音色名 | 9 种预置音色,默认 mimo_default |
| 音色设计 | mimo-v2.5-tts-voicedesign | 不支持 | 通过文字描述设计音色 |
| 声音克隆 | mimo-v2.5-tts-voiceclone | 必填,base64 音频 | 上传 3~10 秒音频样本克隆声音 |
| 音色 ID | 说明 |
|---|---|
mimo_default | 默认音色 |
冰糖 | 甜美女声 |
茉莉 | 温柔女声 |
苏打 | 清爽男声 |
白桦 | 沉稳男声 |
Mia | 英文女声 |
Chloe | 英文女声 |
Milo | 英文男声 |
Dean | 英文男声 |
| format 值 | 说明 |
|---|---|
wav | WAV 格式(默认) |
mp3 | MP3 格式 |
pcm / pcm16 | PCM16 格式(stream 模式下默认) |
pythonfrom openai import OpenAI
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[
+ {"role": "system", "content": "You are MiMo, an AI assistant developed by Xiaomi."},
+ {"role": "user", "content": "你好,请介绍一下自己"}
+ ],
+ max_completion_tokens=1024,
+ temperature=1.0,
+ thinking={"type": "disabled"}
+)
+
+print(response.choices[0].message.content)
+print(f"输入: {response.usage.prompt_tokens}, 输出: {response.usage.completion_tokens}")
+ bashcurl --location --request POST 'https://api.xiaomimimo.com/v1/chat/completions' \
+--header "api-key: $MIMO_API_KEY" \
+--header "Content-Type: application/json" \
+--data-raw '{"model":"mimo-v2.5-pro","messages":[{"role":"system","content":"You are MiMo."},{"role":"user","content":"你好"}],"max_completion_tokens":1024,"thinking":{"type":"disabled"}}'
+ pythonfrom openai import OpenAI
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[
+ {"role": "system", "content": "你是一个专业的编程助手。"},
+ {"role": "user", "content": "解释 JavaScript 的事件循环机制"}
+ ],
+ stream=True
+)
+
+full_reply = ""
+for chunk in response:
+ content = chunk.choices[0].delta.content
+ if content:
+ full_reply += content
+ print(content, end="", flush=True)
+
+# 继续对话
+messages.append({"role": "assistant", "content": full_reply})
+messages.append({"role": "user", "content": "能给一个 async/await 的代码示例吗?"})
+ javascriptconst response = await fetch('https://api.xiaomimimo.com/v1/chat/completions', {
+ method: 'POST',
+ headers: {
+ 'api-key': MIMO_API_KEY,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ model: 'mimo-v2.5-pro',
+ messages: [
+ { role: 'system', content: '你是一个专业的编程助手。' },
+ { role: 'user', content: '解释 JavaScript 的事件循环机制' }
+ ],
+ stream: true
+ })
+});
+
+const reader = response.body.getReader();
+const decoder = new TextDecoder();
+let buffer = '';
+
+while (true) {
+ const { done, value } = await reader.read();
+ if (done) break;
+ buffer += decoder.decode(value, { stream: true });
+ const lines = buffer.split('\n');
+ buffer = lines.pop();
+ for (const line of lines) {
+ if (!line.startsWith('data: ') || line === 'data: [DONE]') continue;
+ const chunk = JSON.parse(line.slice(6));
+ const content = chunk.choices[0]?.delta?.content;
+ if (content) process.stdout.write(content);
+ }
+}
+ pythonfrom openai import OpenAI
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[{"role": "user", "content": "9.11 和 9.8 哪个更大?"}],
+ extra_body={"thinking": {"type": "enabled"}}
+)
+
+msg = response.choices[0].message
+print(f"[思考过程]\n{msg.reasoning_content}")
+print(f"\n[最终回答]\n{msg.content}")
+
+ pythonfrom openai import OpenAI
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[{"role": "user", "content": "杭州今天天气怎么样?"}],
+ tools=[{
+ "type": "function",
+ "function": {
+ "name": "get_weather",
+ "description": "获取指定城市的当前天气信息",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {"type": "string", "description": "城市名称"}
+ },
+ "required": ["location"]
+ }
+ }
+ }]
+)
+
+tool_calls = response.choices[0].message.tool_calls
+print("工具调用:", tool_calls)
+
+ pythonfrom openai import OpenAI
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-pro",
+ messages=[{"role": "user", "content": "今天有什么科技新闻?"}],
+ tools=[{"type": "web_search"}]
+)
+
+msg = response.choices[0].message
+print("回答:", msg.content)
+if msg.annotations:
+ print("\n引用来源:")
+ for ann in msg.annotations:
+ print(f" - [{ann.title}]({ann.url})")
+
+ pythonfrom openai import OpenAI
+import base64
+
+client = OpenAI(api_key="$MIMO_API_KEY", base_url="https://api.xiaomimimo.com/v1")
+
+response = client.chat.completions.create(
+ model="mimo-v2.5-tts",
+ messages=[
+ {"role": "user", "content": "用甜美的声音为大家念一首诗"},
+ {"role": "assistant", "content": "床前明月光,疑是地上霜。举头望明月,低头思故乡。"}
+ ],
+ audio={
+ "format": "wav",
+ "voice": "茉莉"
+ }
+)
+
+audio_data = response.choices[0].message.audio.data
+audio_bytes = base64.b64decode(audio_data)
+with output("output.wav", "wb") as f:
+ f.write(audio_bytes)
+print("音频已保存到 output.wav")
+| 错误码 | HTTP 状态 | 描述 |
|---|---|---|
invalid_api_key | 401 | API Key 无效或未提供 |
rate_limit_exceeded | 429 | 请求频率超限,请稍后重试 |
invalid_request | 400 | 请求参数错误(如缺少必填字段、模型不存在等) |
context_length_exceeded | 400 | 输入内容超出模型上下文长度限制 |
content_filter | 400 | 内容触发安全过滤策略 |
server_error | 500 | 服务器内部错误 |
model_not_found | 404 | 请求的模型不存在或已下线 |
stop — 自然结束 · length — 达到最大 token · tool_calls — 模型调用了工具content_filter — 内容被过滤 · repetition_truncation — 检测到复读截断
+ 🎨 MetonaAI Desktop UI/UX 设计集成方案
研究来源: Fuselab Creative · Ant Design X · Google A2UI · Hermes Agent · Siyu's Newsletter
-集成组件: MetonaToast v2.0.0 · 版本 v1.0.0 · 2026-06-26
+集成组件: MetonaToast v2.0.0 · 版本 v1.0.0 · 2026-07-15
@@ -1000,13 +1000,13 @@
📜 Metona 内部 API 请求与响应标准 —— 项目端到端类型安全的基础
-版本: v1.0.0 · 生效日期: 2026-06-25
+版本: v1.0.0 · 生效日期: 2026-07-15
所属项目: Metona (AI Agent Desktop) · 技术栈: TypeScript + React + SQLite + Electron