v0.16.18: 网络超时 30s→900s + 流式超时动态计算修复 + 预存编译错误修复

This commit is contained in:
2026-08-01 14:13:04 +08:00
parent 794f94ab89
commit e140e735de
10 changed files with 126 additions and 126 deletions
+108 -108
View File
@@ -5,7 +5,7 @@
<h1 align="center">Metona Ollama Desktop</h1> <h1 align="center">Metona Ollama Desktop</h1>
<p align="center"> <p align="center">
<strong>🤖 本地 AI 桌面客户端 · Local AI Desktop Client</strong> <strong>🤖 本地 AI 桌é¢å®¢æˆ·ç«?· Local AI Desktop Client</strong>
</p> </p>
<p align="center"> <p align="center">
@@ -14,7 +14,7 @@
</p> </p>
<p align="center"> <p align="center">
<img src="https://img.shields.io/badge/version-v0.16.17-E8734A?style=flat-square" alt="version"> <img src="https://img.shields.io/badge/version-v0.16.18-E8734A?style=flat-square" alt="version">
<img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron"> <img src="https://img.shields.io/badge/electron-33+-47848F?style=flat-square&logo=electron" alt="electron">
<img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript"> <img src="https://img.shields.io/badge/typescript-5.7+-3178C6?style=flat-square&logo=typescript" alt="typescript">
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license"> <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
@@ -22,65 +22,65 @@
</p> </p>
<p align="center"> <p align="center">
<em>所有 AI 推理在本地完成,数据不离开本机。</em><br> <em>所æœ?AI 推ç†åœ¨æœ¬åœ°å®Œæˆï¼Œæ•°æ®ä¸ç¦»å¼€æœ¬æœºã€?/em><br>
<em>All AI inference runs locally data never leaves your machine.</em> <em>All AI inference runs locally �data never leaves your machine.</em>
</p> </p>
--- ---
# 🇨🇳 中文 # 🇨🇳 中文
## ✨ 特性 ## âœ?特æ€?
| | 功能 | 说明 | | | 功能 | 说明 |
|:---:|:---|:---| |:---:|:---|:---|
| 🤖 | **ReAct Agent Loop** | 始终开启的唯一对话模式。8 状态机(INITTHINKINGPARSINGEXECUTINGOBSERVINGREFLECTINGCOMPRESSINGTERMINATED),最大 85 轮(可配置),智能重试(永久错误立即返回、瞬态错误指数退避),工具去重,智能路径依赖串行化,看门狗超时保护 | | 🤖 | **ReAct Agent Loop** | 始终开å¯çš„å”¯ä¸€å¯¹è¯æ¨¡å¼ã€? çŠ¶æ€æœºï¼ˆINIT→THINKING→PARSING→EXECUTING→OBSERVING→REFLECTING→COMPRESSING→TERMINATED),最å¤?85 轮(å¯é…置),智能é‡è¯•(永久错误立å³è¿”回ã€çž¬æ€é”™è¯¯æŒ‡æ•°é€€é¿ï¼‰ï¼Œå·¥å…·åŽ»é‡ï¼Œæ™ºèƒ½è·¯å¾„ä¾èµ–ä¸²è¡ŒåŒ–ï¼Œçœ‹é—¨ç‹—è¶…æ—¶ä¿æŠ?|
| 🛡️ | **提示词加固** | 参考数据标记(<<<REFERENCE_DATA_START>>>+ 工具结果仅为数据非指令的安全规则注入 | | 🛡ï¸?| **æç¤ºè¯åŠ å›?* | å‚è€ƒæ•°æ®æ ‡è®°ï¼ˆ<<<REFERENCE_DATA_START>>>ï¼? 工具结果仅为数æ®éžæŒ‡ä»¤çš„安全规则注入 |
| 📋 | **Plan Mode** | 开关切换,AI 首先生成执行计划(Markdown 渲染确认弹窗),批准后按步骤追踪执行,plan_track 工具标记完成状态,**支持断点续传**(中止后可恢复未完成计划) | | 📋 | **Plan Mode** | 开关切æ¢ï¼ŒAI é¦–å…ˆç”Ÿæˆæ‰§è¡Œè®¡åˆ’(Markdown æ¸²æŸ“ç¡®è®¤å¼¹çª—ï¼‰ï¼Œæ‰¹å‡†åŽæŒ‰æ­¥éª¤è¿½è¸ªæ‰§è¡Œï¼Œplan_track 工具标记完æˆçжæ€ï¼Œ**æ”¯æŒæ–­ç‚¹ç»­ä¼ **(中止åŽå¯æ¢å¤æœªå®Œæˆè®¡åˆ’ï¼?|
| 🔧 | **32 个内置工具** | 文件系统(13个) · 命令执行 · 联网搜索 · 浏览器控制(9个) · Git · 记忆 · 会话 · 子代理 · 系统工具 · Plan Mode 追踪 | | 🔧 | **32 个内置工å…?* | 文件系统ï¼?3个) · 命令执行 · è”网æœç´¢ · æµè§ˆå™¨æŽ§åˆ¶ï¼ˆ9个) · Git · 记忆 · ä¼šè¯ Â· å­ä»£ç?· 系统工具 · Plan Mode 追踪 |
| 🧠 | **智能记忆系统** | 三类记忆(fact / preference / rule),存储于工作空间 MEMORY.md 文件,受路径保护仅 memory 工具可访问,写入前安全扫描,容量 500 条,对话结束自动提取,严格格式校验 | | 🧠 | **智能记忆系统** | 三类记忆(fact / preference / rule),存储于工作空é—?MEMORY.md 文件,å—è·¯å¾„ä¿æŠ¤ä»?memory 工具å¯è®¿é—®ï¼Œå†™å…¥å‰å®‰å…¨æ‰«æï¼Œå®¹é‡ 500 æ¡ï¼Œå¯¹è¯ç»“æŸè‡ªåЍæå–ï¼Œä¸¥æ ¼æ ¼å¼æ ¡éª?|
| 📋 | **自定义文件** | SOUL.md(人格,不可压缩)+ AGENT.md(行为准则,内置 fallback+ USER.md(用户画像,仅工作空间读取,不存在则不注入) | | 📋 | **自定义文ä»?* | SOUL.md(人格,ä¸å¯åŽ‹ç¼©ï¼? AGENT.md(行为准则,内置 fallbackï¼? USER.md(用户画åƒï¼Œä»…工作空间读å–,ä¸å­˜åœ¨åˆ™ä¸æ³¨å…¥ï¼‰ |
| 🌠| **MCP å议扩展** | JSON-RPC 2.0 over stdio,动æ€å·¥å…·å‘现,Shadowing 防护 | | 🌠| **MCP å议扩展** | JSON-RPC 2.0 over stdio,动æ€å·¥å…·å‘现,Shadowing 防护 |
| 🔍 | **联网搜索(双模式)** | SearXNG 元搜索引擎 JSON API70+引擎聚合)/ 四引擎 HTML 解析(Bing+百度+搜狗+360),双模式可切换;web_fetch 支持反爬+UA切换+浏览器回退 | | 🔠| **è”网æœç´¢ï¼ˆåŒæ¨¡å¼ï¼?* | SearXNG å…ƒæœç´¢å¼•æ“?JSON APIï¼?0+引擎èšåˆï¼? 四引æ“?HTML è§£æžï¼ˆBing+百度+æœç‹—+360ï¼‰ï¼ŒåŒæ¨¡å¼å¯åˆ‡æ¢ï¼›web_fetch 支æŒå爬+UA切æ¢+æµè§ˆå™¨å›žé€€ |
| 🌏 | **浏览器控制** | 打开网页 · 截图 · 执行 JS · 提取内容 · 点击 · 输入 · 滚动 · 关闭 | | 🌠| **æµè§ˆå™¨æŽ§åˆ?* | 打开网页 · 截图 · 执行 JS · æå–内容 · 点击 · 输入 · 滚动 · 关闭 |
| 🖥️ | **工作空间面板** | 终端(增量流式输出)+ 文件浏览器,命令安全检查 | | 🖥ï¸?| **å·¥ä½œç©ºé—´é¢æ¿** | ç»ˆç«¯ï¼ˆå¢žé‡æµå¼è¾“出)+ 文件æµè§ˆå™¨ï¼Œå‘½ä»¤å®‰å…¨æ£€æŸ?|
| 🔢 | **上下文长度手动控制** | 设置面板下拉选择(128K / 256K / 512K / 1M),默认 128K,模型栏显示当前配置值,下拉框中显示每个模型自身的上下文长度 | | 🔢 | **上下文长度手动控åˆ?* | è®¾ç½®é¢æ¿ä¸‹æ‹‰é€‰æ‹©ï¼?28K / 256K / 512K / 1M),默认 128Kï¼Œæ¨¡åž‹æ æ˜¾ç¤ºå½“å‰é…置值,下拉框中显示æ¯ä¸ªæ¨¡åž‹è‡ªèº«çš„上下文长度 |
| 🗜️ | **智能上下文管理** | 滑动窗口 + Token 自动校准 + 消息重要性评分 + LLM 结构化 JSON 压缩,智能触发(120 条增量压缩 + 300 条硬上限) | | 🗜ï¸?| **智能上下文管ç?* | æ»‘åŠ¨çª—å£ + Token 自动校准 + 消æ¯é‡è¦æ€§è¯„åˆ?+ LLM 结构åŒ?JSON 压缩,智能触å‘(120 æ¡å¢žé‡åŽ‹ç¼?+ 300 æ¡ç¡¬ä¸Šé™ï¼?|
| ⏱️ | **智能超时保护** | Agent Loop 看门狗(可配,默认 30min)+ 流式总超时(可配,默认 300s)+ 工具 HTTP/MCP 超时可配 | | â±ï¸ | **æ™ºèƒ½è¶…æ—¶ä¿æŠ¤** | Agent Loop 看门狗(å¯é…,默è®?30minï¼? æµå¼æ€»è¶…时(å¯é…,默è®?300sï¼? 工具 HTTP/MCP è¶…æ—¶å¯é… |
| 🪝 | **Hook 系统** | 4 阶段生命周期钩子(pre_tool / post_tool / post_iteration / pre_completion),内置安全检查、文件去重、自动计划追踪、变更审计、结果校验 | | 🪠| **Hook 系统** | 4 阶段生命周期钩å­ï¼ˆpre_tool / post_tool / post_iteration / pre_completionï¼‰ï¼Œå†…ç½®å®‰å…¨æ£€æŸ¥ã€æ–‡ä»¶åŽ»é‡ã€è‡ªåŠ¨è®¡åˆ’è¿½è¸ªã€å˜æ›´å®¡è®¡ã€ç»“果校éª?|
| 👥 | **子代理委派** | spawn_task 工具,独立上下文 + 超时保护 | | 👥 | **å­ä»£ç†å§”æ´?* | spawn_task 工具,独立上下文 + è¶…æ—¶ä¿æŠ¤ |
| 📈 | **Token 仪表盘** | 全局 + 会话统计,消耗趋势柱状图,2 秒刷新,输入/输出分色 | | 📈 | **Token 仪表ç›?* | 全局 + 会è¯ç»Ÿè®¡ï¼Œæ¶ˆè€—趋势柱状图ï¼? 秒刷新,输入/输出分色 |
| 📋 | **系统提示词卡片** | 每条 AI 回复顶部折叠卡片,点击查看实际发送给模型的完整上下文 | | 📋 | **系统æç¤ºè¯å¡ç‰?* | æ¯æ¡ AI 回å¤é¡¶éƒ¨æŠ˜å å¡ç‰‡ï¼Œç‚¹å‡»æŸ¥çœ‹å®žé™…å‘é€ç»™æ¨¡åž‹çš„完整上下文 |
| 🎨 | **暖色调 UI** | 奶白 `#FAF7F2` + 珊瑚橙 `#E8734A`,长时间使用不疲劳,流式渲染优化 | | 🎨 | **暖色è°?UI** | 奶白 `#FAF7F2` + çŠç‘šæ©?`#E8734A`,长时间使用ä¸ç–²åŠ³ï¼Œæµå¼æ¸²æŸ“优化 |
| 🔔 | **系统托盘** | åŽŸç”Ÿæ‰˜ç›˜é›†æˆ | | 🔔 | **系统托盘** | åŽŸç”Ÿæ‰˜ç›˜é›†æˆ |
| 🔠| **AES-256-GCM** | æ•°æ®åŠ å¯†æ”¯æŒ | | 🔠| **AES-256-GCM** | æ•°æ®åŠ å¯†æ”¯æŒ |
| 🧪 | **可观测性** | 执行轨迹缓冲批量写入 SQLite + Agent Metrics JSON/Prometheus 双格式导出 | | 🧪 | **å¯è§‚测æ€?* | 执行轨迹缓冲批é‡å†™å…¥ SQLite + Agent Metrics JSON/Prometheus åŒæ ¼å¼å¯¼å‡?|
## 🔧 工具清å ## 🔧 工具清å
<details> <details>
<summary><strong>📁 文件系统(13 个)</strong></summary> <summary><strong>📠文件系统ï¼?3 个)</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
| `read_file` | 读取文件(文本/binary,2000行默认) | | `read_file` | è¯»å–æ–‡ä»¶ï¼ˆæ–‡æœ?binaryï¼?000行默认) |
| `write_file` | 写入/追加文件(支æŒbase64二进制) | | `write_file` | 写入/追加文件(支æŒbase64二进制) |
| `list_directory` | 列出目录内容 | | `list_directory` | 列出目录内容 |
| `search_files` | 搜索文件(正则/通配符) | | `search_files` | æœç´¢æ–‡ä»¶ï¼ˆæ­£åˆ?通é…符) |
| `create_directory` | 创建目录 | | `create_directory` | 创建目录 |
| `delete_file` | 删除文件/目录(返回大å°ï¼‰ | | `delete_file` | 删除文件/目录(返回大å°ï¼‰ |
| `move_file` | 移动/重命名文件 | | `move_file` | 移动/é‡å‘½åæ–‡ä»?|
| `copy_file` | å¤åˆ¶æ–‡ä»¶ | | `copy_file` | å¤åˆ¶æ–‡ä»¶ |
| `edit_file` | ç¼–è¾‘æ–‡ä»¶ï¼ˆæ”¯æŒæ­£åˆ™æ›¿æ¢ï¼‰ | | `edit_file` | ç¼–è¾‘æ–‡ä»¶ï¼ˆæ”¯æŒæ­£åˆ™æ›¿æ¢ï¼‰ |
| `tree` | 目录树结构(默认5层深度) | | `tree` | 目录树结构(默认5层深度) |
| `download_file` | 下载文件 | | `download_file` | 下载文件 |
| `read_multiple_files` | 批量读取(50文件/10KB | | `read_multiple_files` | 批é‡è¯»å–ï¼?0文件/10KBï¼?|
| `compress` | 压缩文件/目录 | | `compress` | 压缩文件/目录 |
</details> </details>
<details> <details>
<summary><strong>⚡ 命令执行(1 个)</strong></summary> <summary><strong>âš?命令执行ï¼? 个)</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
@@ -89,11 +89,11 @@
</details> </details>
<details> <details>
<summary><strong>🔍 联网搜索(2 个)</strong></summary> <summary><strong>🔠è”网æœç´¢ï¼? 个)</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
| `web_search` | SearXNG JSON API / 四引擎并行,默认 30 条结果 | | `web_search` | SearXNG JSON API / 四引擎并行,默认 30 æ¡ç»“æž?|
| `web_fetch` | 网页内容抓å–,自动é‡è¯•(指数退é¿ï¼‰ï¼Œç§»åŠ¨ç«¯UA切æ¢ï¼ŒSPA页é¢è‡ªåЍå‡çº§åˆ°æµè§ˆå™¨æ¸²æŸ“ | | `web_fetch` | 网页内容抓å–,自动é‡è¯•(指数退é¿ï¼‰ï¼Œç§»åŠ¨ç«¯UA切æ¢ï¼ŒSPA页é¢è‡ªåЍå‡çº§åˆ°æµè§ˆå™¨æ¸²æŸ“ |
</details> </details>
@@ -111,27 +111,27 @@
| `browser_type` | 输入文本 | | `browser_type` | 输入文本 |
| `browser_scroll` | 页颿»šåЍ | | `browser_scroll` | 页颿»šåЍ |
| `browser_wait` | 等待元素/延时 | | `browser_wait` | 等待元素/延时 |
| `browser_close` | 关闭浏览器 | | `browser_close` | 关闭æµè§ˆå™?|
</details> </details>
<details> <details>
<summary><strong>📦 Git1 个,17 个子命令)</strong></summary> <summary><strong>📦 Gitï¼? 个,17 个å­å‘½ä»¤ï¼?/strong></summary>
| 子命令 | 功能 | | å­å‘½ä»?| 功能 |
|--------|------| |--------|------|
| `init` `clone` `add` `commit` `push` `pull` | 基础æ“作 | | `init` `clone` `add` `commit` `push` `pull` | 基础æ“作 |
| `diff` `log` `status` `branch` `checkout` | 查看与切换 | | `diff` `log` `status` `branch` `checkout` | 查看与切æ?|
| `merge` `stash` `reset` `tag` `remote` | 高级æ“作 | | `merge` `stash` `reset` `tag` `remote` | 高级æ“作 |
</details> </details>
<details> <details>
<summary><strong>🧠 记忆管理(1 个)</strong></summary> <summary><strong>🧠 记忆管ç†ï¼? 个)</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
| `memory` | 统一记忆管理(5 个 actionsearch 搜索 / add 添加 / replace 替换 / remove 删除 / read_all 读取全部)。工作空间 MEMORY.md 受路径保护,仅此工具可访问 | | `memory` | 统一记忆管ç†ï¼? ä¸?action:search æœç´¢ / add 添加 / replace æ›¿æ¢ / remove 删除 / read_all 读å–全部)。工作空é—?MEMORY.md å—è·¯å¾„ä¿æŠ¤ï¼Œä»…æ­¤å·¥å…·å¯è®¿é—?|
</details> </details>
@@ -142,21 +142,21 @@
|------|------| |------|------|
| `session_list` | 列出历å²ä¼šè¯ | | `session_list` | 列出历å²ä¼šè¯ |
| `session_read` | 读å–会è¯å†…容 | | `session_read` | 读å–会è¯å†…容 |
| `spawn_task` | 委派子代理(独立上下文 + 超时保护) | | `spawn_task` | 委派å­ä»£ç†ï¼ˆç‹¬ç«‹ä¸Šä¸‹æ–?+ è¶…æ—¶ä¿æŠ¤ï¼?|
</details> </details>
<details> <details>
<summary><strong>🕐 系统工具(1 个)</strong></summary> <summary><strong>🕠系统工具ï¼? 个)</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
| `calculator` | 安全数学计算(+ - * / ** % (),递归下降解析器) | | `calculator` | 安全数学计算ï¼? - * / ** % (),递归下é™è§£æžå™¨ï¼‰ |
</details> </details>
<details> <details>
<summary><strong>📋 Plan Mode1 个,仅 Plan 模式激活)</strong></summary> <summary><strong>📋 Plan Modeï¼? 个,ä»?Plan æ¨¡å¼æ¿€æ´»ï¼‰</strong></summary>
| 工具 | 功能 | | 工具 | 功能 |
|------|------| |------|------|
@@ -164,51 +164,51 @@
</details> </details>
## 🏗️ 架构 ## ðŸ—ï¸?æž¶æž„
``` ```
用户消息 → 扫描工作空间 SOUL.md(不可压缩层)→ AGENT.md USER.md(工作空间,不存在则跳过) ç”¨æˆ·æ¶ˆæ¯ â†?扫æå·¥ä½œç©ºé—´ SOUL.md(ä¸å¯åŽ‹ç¼©å±‚ï¼‰â†’ AGENT.md â†?USER.md(工作空间,ä¸å­˜åœ¨åˆ™è·³è¿‡ï¼?
�
记忆检索 (MEMORY.md 关键词搜索) → 上下文注入 记忆检ç´?(MEMORY.md å…³é”®è¯æœç´? â†?上下文注å…?
�
Agent Engine (8 状态机 ReAct Loop, ≤85 轮, 智能重试, 路径依赖串行化, 看门狗+分级超时) Agent Engine (8 çŠ¶æ€æœº ReAct Loop, â‰?5 è½? 智能é‡è¯•, 路径ä¾èµ–串行åŒ? 看门ç‹?分级超时)
�
提示词加固(参考数据标记 + 工具结果安全规则) æç¤ºè¯åŠ å›ºï¼ˆå‚è€ƒæ•°æ®æ ‡è®?+ 工具结果安全规则ï¼?
�
Ollama API (æµå¼å“应,num_ctx 用户å¯é… 128K/256K/512K/1M) Ollama API (æµå¼å“应,num_ctx 用户å¯é… 128K/256K/512K/1M)
�
Tool Registry (32 内置 + MCP 动态 + Plan Mode plan_track) Tool Registry (32 内置 + MCP 动æ€?+ Plan Mode plan_track)
�
Hook 系统 (pre/post tool/iteration/completion) → 观察结果 → 反思 → 循环 / 最终回答 Hook 系统 (pre/post tool/iteration/completion) â†?观察结果 â†?忀?â†?循环 / 最终回ç­?
``` ```
### 🧩 UI 组件(原生 DOM ### 🧩 UI 组件(原ç”?DOMï¼?
``` ```
main.ts (å…¥å£) main.ts (å…¥å£)
├── header.ts # 顶部导航栏 ├── header.ts # 顶部导航æ ?
├── model-bar.ts # 模型选择栏 ├── model-bar.ts # 模型选择æ ?
├── chat-area.ts # èŠå¤©æ¶ˆæ¯åŒºåŸŸ ├── chat-area.ts # èŠå¤©æ¶ˆæ¯åŒºåŸŸ
├── input-area.ts # 输入框 + 文件上传 + Plan Mode 开关 ├── input-area.ts # 输入æ¡?+ 文件上传 + Plan Mode å¼€å…?
├── workspace-panel.ts # 终端 + 文件浏览器 + 工具卡片 ├── workspace-panel.ts # 终端 + 文件æµè§ˆå™?+ 工具å¡ç‰‡
├── settings-modal.ts # è®¾ç½®é¢æ¿ï¼ˆå«çœ‹é—¨ç‹—è¶…æ—¶é…置) ├── settings-modal.ts # è®¾ç½®é¢æ¿ï¼ˆå«çœ‹é—¨ç‹—è¶…æ—¶é…置)
├── history-modal.ts # 会è¯åŽ†å² â”œâ”€â”€ history-modal.ts # 会è¯åކå²
├── memory-modal.ts # 记忆管ç ├── memory-modal.ts # 记忆管ç
├── tools-modal.ts # 工具列表 ├── tools-modal.ts # 工具列表
├── token-dashboard.ts # Token 消耗仪表盘 ├── token-dashboard.ts # Token 消耗仪表盘
├── tool-confirm-modal.ts # 工具执行确认 ├── tool-confirm-modal.ts # 工具执行确认
├── prompt-modal.ts # 系统提示词查看 + Plan 确认弹窗 ├── prompt-modal.ts # 系统æç¤ºè¯æŸ¥çœ?+ Plan 确认弹窗
├── toast.ts # Toast 通知 ├── toast.ts # Toast 通知
└── lightbox.ts # 图片ç¯ç®± └── lightbox.ts # 图片ç¯ç®±
``` ```
### 🗄️ 数据库 ### 🗄ï¸?æ•°æ®åº?
SQLite (sql.js WASM)5 张表,WAL 模式: SQLite (sql.js WASM)ï¼? 张表,WAL 模å¼ï¼?
| 表 | 用途 | | è¡?| 用é€?|
|---|---| |---|---|
| `sessions` | 会话(parent_id 父子关系) | | `sessions` | 会è¯ï¼ˆparent_id 父å­å…³ç³»ï¼?|
| `messages` | 消æ¯ï¼ˆå¤–键级è”删除) | | `messages` | 消æ¯ï¼ˆå¤–键级è”删除) |
| `tool_calls` | 工具调用记录 | | `tool_calls` | 工具调用记录 |
| `settings` | 设置(JSON åºåˆ—化) | | `settings` | 设置(JSON åºåˆ—化) |
@@ -218,17 +218,17 @@ SQLite (sql.js WASM)5 张表,WAL 模式:
| 层级 | 措施 | | 层级 | 措施 |
|------|------| |------|------|
| 📁 文件系统 | `checkPathAllowed()` — 路径黑名单(33 个系统/敏感目录,含 Linux + Windows | | 📠文件系统 | `checkPathAllowed()` â€?路径黑åå•(33 个系ç»?æ•æ„Ÿç›®å½•ï¼Œå« Linux + Windowsï¼?|
| ⚡ 命令执行 | `checkCommandAllowed()` — 命令黑名单(30 条危险命令,含 POSIX + Windows+ 三种模式 | | âš?命令执行 | `checkCommandAllowed()` â€?命令黑åå•(30 æ¡å±é™©å‘½ä»¤ï¼Œå?POSIX + Windowsï¼? ä¸‰ç§æ¨¡å¼ |
| 🖥️ 前端渲染 | HTML 净化器(白名单标签 + URI 协议检查) | | 🖥ï¸?å‰ç«¯æ¸²æŸ“ | HTML 净化器(白å啿 ‡ç­¾ + URI å议检查) |
| 🔒 Electron | `contextIsolation: true` + IPC 白名单 + IPC fs 路径验证 | | 🔒 Electron | `contextIsolation: true` + IPC 白åå?+ IPC fs è·¯å¾„éªŒè¯ |
| 🔠数æ®åР坆 | AES-256-GCM | | 🔠数æ®åР坆 | AES-256-GCM |
| 🧠 记忆安全 | 写入前 Prompt Injection / 敏感信息检测,多层级去重过滤 | | 🧠 记忆安全 | 写入å‰?Prompt Injection / æ•æ„Ÿä¿¡æ¯æ£€æµ‹ï¼Œå¤šå±‚级去é‡è¿‡æ»?|
| 🌐 MCP 安全 | Shadowing 防护 + 双下划线分隔防歧义 | | 🌠MCP 安全 | Shadowing 防护 + åŒä¸‹åˆ’线分隔防歧ä¹?|
| 🌐 网络安全 | `web_fetch` 流式体积限制(10MB+ 无 content-length 时防 OOM | | 🌠网络安全 | `web_fetch` æµå¼ä½“积é™åˆ¶ï¼?0MBï¼? æ—?content-length 时防 OOM |
| ⚡ 进程安全 | Windows `taskkill` 强制终止 + 工作空间路径大小写不敏感校验 | | âš?进程安全 | Windows `taskkill` 强制终止 + 工作空间路径大å°å†™ä¸æ•感校验 |
## 🚀 快速开始 ## 🚀 快速开å§?
```bash ```bash
git clone https://gitee.com/thzxx/metona-ollama-desktop.git git clone https://gitee.com/thzxx/metona-ollama-desktop.git
@@ -238,32 +238,32 @@ npm install
npm start npm start
``` ```
## 📦 构建 Windows 安装包 ## 📦 构建 Windows 安装åŒ?
```bash ```bash
# 环境:Ubuntu 24.04 + Node.js v22 + Wine 9.0+ # 环境:Ubuntu 24.04 + Node.js v22 + Wine 9.0+
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
``` ```
产出:`release/Metona Ollama Setup v0.16.17.exe` 产出:`release/Metona Ollama Setup v0.16.18.exe`
## 🛠️ 常用命令 ## 🛠ï¸?常用命令
```bash ```bash
npm start # 构建并运行 npm start # 构建并è¿è¡?
npm run dev:renderer # Vite watch(渲染进程) npm run dev:renderer # Vite watch(渲染进程)
npm run dev:main # tsc watch(主进程) npm run dev:main # tsc watch(主进程ï¼?
npm run build # 完整构建 npm run build # 完整构建
npm run dist # 构建 Windows 安装包 npm run dist # 构建 Windows 安装åŒ?
``` ```
## 💻 ç³»ç»Ÿè¦æ±‚ ## 💻 ç³»ç»Ÿè¦æ±‚
- 🖥️ Windows 10/1164 位) - 🖥ï¸?Windows 10/11ï¼?4 ä½ï¼‰
- 🤖 Ollama 本地运行中(默认 `http://localhost:11434` - 🤖 Ollama 本地è¿è¡Œä¸­ï¼ˆé»˜è®¤ `http://localhost:11434`ï¼?
- 💾 建议 8GB+ 内存 - 💾 建议 8GB+ 内存
## 📄 许可证 ## 📄 许å¯è¯?
[MIT](LICENSE) [MIT](LICENSE)
@@ -271,27 +271,27 @@ npm run dist # 构建 Windows 安装包
# 🇬🇧 English # 🇬🇧 English
## Features ## �Features
| | Feature | Description | | | Feature | Description |
|:---:|:---|:---| |:---:|:---|:---|
| 🤖 | **ReAct Agent Loop** | Always-on, only chat mode. 8-state machine, up to 85 iterations (configurable), smart retry (permanent errors return immediately, transient errors use exponential backoff), tool dedup, path-aware dependency serialization, watchdog + tiered timeout protection | | 🤖 | **ReAct Agent Loop** | Always-on, only chat mode. 8-state machine, up to 85 iterations (configurable), smart retry (permanent errors return immediately, transient errors use exponential backoff), tool dedup, path-aware dependency serialization, watchdog + tiered timeout protection |
| 🛡️ | **Prompt Hardening** | Reference data markers (<<<REFERENCE_DATA_START>>>) + tool results are data-not-instructions safety rules | | 🛡ï¸?| **Prompt Hardening** | Reference data markers (<<<REFERENCE_DATA_START>>>) + tool results are data-not-instructions safety rules |
| 📋 | **Plan Mode** | Toggle switch. AI first generates an execution plan (Markdown-rendered confirmation dialog), then tracks step-by-step execution, **supports resume** (interrupted plans restore on next session) | | 📋 | **Plan Mode** | Toggle switch. AI first generates an execution plan (Markdown-rendered confirmation dialog), then tracks step-by-step execution, **supports resume** (interrupted plans restore on next session) |
| 🔧 | **32 Built-in Tools** | File system · Command · Web search · Browser · Git · Memory · Sessions · Sub-agent · System · Plan Mode tracking | | 🔧 | **32 Built-in Tools** | File system · Command · Web search · Browser · Git · Memory · Sessions · Sub-agent · System · Plan Mode tracking |
| 🧠 | **Smart Memory System** | Three types (fact / preference / rule), stored in workspace MEMORY.md file, path-protected only the memory tool can access it, pre-write security scan, 500 capacity, auto-extract on conversation end, strict format validation | | 🧠 | **Smart Memory System** | Three types (fact / preference / rule), stored in workspace MEMORY.md file, path-protected â€?only the memory tool can access it, pre-write security scan, 500 capacity, auto-extract on conversation end, strict format validation |
| 📋 | **Custom Files** | SOUL.md (persona, never compressed) + AGENT.md (behavior rules, built-in fallback) + USER.md (user profile, workspace only, skipped if absent) | | 📋 | **Custom Files** | SOUL.md (persona, never compressed) + AGENT.md (behavior rules, built-in fallback) + USER.md (user profile, workspace only, skipped if absent) |
| 🌠| **MCP Protocol Extension** | JSON-RPC 2.0 over stdio, dynamic tool discovery, Shadowing protection | | 🌠| **MCP Protocol Extension** | JSON-RPC 2.0 over stdio, dynamic tool discovery, Shadowing protection |
| 🔠| **Web Search (dual-mode)** | SearXNG meta-search JSON API (70+ engines) / quad-engine HTML parsing (Bing+Baidu+Sogou+360), switchable; web_fetch with auto-retry+mobile UA+SPA browser fallback | | 🔠| **Web Search (dual-mode)** | SearXNG meta-search JSON API (70+ engines) / quad-engine HTML parsing (Bing+Baidu+Sogou+360), switchable; web_fetch with auto-retry+mobile UA+SPA browser fallback |
| 🌠| **Browser Control** | Open pages · Screenshot · JS execution · Content extraction · Click · Type · Scroll · Close | | 🌠| **Browser Control** | Open pages · Screenshot · JS execution · Content extraction · Click · Type · Scroll · Close |
| 🖥️ | **Workspace Panel** | Terminal (incremental streaming) + file browser, command security checks | | 🖥ï¸?| **Workspace Panel** | Terminal (incremental streaming) + file browser, command security checks |
| 🔢 | **Manual Context Length** | Settings dropdown (128K / 256K / 512K / 1M), default 128K. Model bar shows configured value, dropdown shows per-model context length | | 🔢 | **Manual Context Length** | Settings dropdown (128K / 256K / 512K / 1M), default 128K. Model bar shows configured value, dropdown shows per-model context length |
| 🗜️ | **Smart Context Manager** | Sliding window + Token auto-calibration + message importance scoring + LLM structured JSON compression, smart triggers (120 msg incremental + 300 msg hard limit) | | 🗜ï¸?| **Smart Context Manager** | Sliding window + Token auto-calibration + message importance scoring + LLM structured JSON compression, smart triggers (120 msg incremental + 300 msg hard limit) |
| â±ï¸ | **Smart Timeout Protection** | Agent Loop watchdog (configurable, default 30min) + stream total timeout (configurable, default 300s) + configurable HTTP/MCP timeouts | | â±ï¸ | **Smart Timeout Protection** | Agent Loop watchdog (configurable, default 30min) + stream total timeout (configurable, default 300s) + configurable HTTP/MCP timeouts |
| 🪠| **Hook System** | 4-phase lifecycle hooks (pre_tool / post_tool / post_iteration / pre_completion), built-in security check, file dedup, auto plan tracking, change audit, result validation | | 🪠| **Hook System** | 4-phase lifecycle hooks (pre_tool / post_tool / post_iteration / pre_completion), built-in security check, file dedup, auto plan tracking, change audit, result validation |
| 👥 | **Sub-agent Delegation** | spawn_task tool, isolated context + timeout protection | | 👥 | **Sub-agent Delegation** | spawn_task tool, isolated context + timeout protection |
| 📈 | **Token Dashboard** | Global + session stats, consumption trend bar chart, 2s refresh, input/output color-coded | | 📈 | **Token Dashboard** | Global + session stats, consumption trend bar chart, 2s refresh, input/output color-coded |
| 📋 | **System Prompt Card** | Collapsible card atop each AI reply click to inspect the full context sent to the model | | 📋 | **System Prompt Card** | Collapsible card atop each AI reply â€?click to inspect the full context sent to the model |
| 🎨 | **Warm-tone UI** | Cream `#FAF7F2` + coral `#E8734A`, fatigue-free for extended use, streaming render optimized | | 🎨 | **Warm-tone UI** | Cream `#FAF7F2` + coral `#E8734A`, fatigue-free for extended use, streaming render optimized |
| 🔔 | **System Tray** | Native tray integration | | 🔔 | **System Tray** | Native tray integration |
| 🔠| **AES-256-GCM** | Data encryption support | | 🔠| **AES-256-GCM** | Data encryption support |
@@ -321,7 +321,7 @@ npm run dist # 构建 Windows 安装包
</details> </details>
<details> <details>
<summary><strong>Command Execution (1)</strong></summary> <summary><strong>âš?Command Execution (1)</strong></summary>
| Tool | Function | | Tool | Function |
|------|------| |------|------|
@@ -404,22 +404,22 @@ npm run dist # 构建 Windows 安装包
</details> </details>
## 🏗️ Architecture ## ðŸ—ï¸?Architecture
``` ```
User message workspace SOUL.md (never compressed) AGENT.md USER.md (workspace, skipped if absent) User message �workspace SOUL.md (never compressed) �AGENT.md �USER.md (workspace, skipped if absent)
�
Memory Retrieval (MEMORY.md keyword search) Context Injection Memory Retrieval (MEMORY.md keyword search) �Context Injection
�
Agent Engine (8-state ReAct Loop, ≤85 iter, smart retry, path-aware serialization, watchdog+tiered timeout) Agent Engine (8-state ReAct Loop, â‰?5 iter, smart retry, path-aware serialization, watchdog+tiered timeout)
�
Prompt Hardening (reference data markers + tool result safety rules) Prompt Hardening (reference data markers + tool result safety rules)
�
Ollama API (Streaming Response, num_ctx user-configurable 128K/256K/512K/1M) Ollama API (Streaming Response, num_ctx user-configurable 128K/256K/512K/1M)
�
Tool Registry (32 Built-in + MCP Dynamic + Plan Mode plan_track) Tool Registry (32 Built-in + MCP Dynamic + Plan Mode plan_track)
�
Hook System (pre/post tool/iteration/completion) Observation Reflection Loop / Final Answer Hook System (pre/post tool/iteration/completion) �Observation �Reflection �Loop / Final Answer
``` ```
### 🧩 UI Components (Native DOM) ### 🧩 UI Components (Native DOM)
@@ -442,7 +442,7 @@ main.ts (Entry)
└── lightbox.ts # Image lightbox └── lightbox.ts # Image lightbox
``` ```
### 🗄️ Database ### 🗄ï¸?Database
SQLite (sql.js WASM), 5 tables, WAL mode: SQLite (sql.js WASM), 5 tables, WAL mode:
@@ -458,15 +458,15 @@ SQLite (sql.js WASM), 5 tables, WAL mode:
| Layer | Measure | | Layer | Measure |
|------|------| |------|------|
| 📁 File System | `checkPathAllowed()` path blacklist (33 system/sensitive dirs, Linux + Windows) | | 📠File System | `checkPathAllowed()` â€?path blacklist (33 system/sensitive dirs, Linux + Windows) |
| Command Execution | `checkCommandAllowed()` command blacklist (30 dangerous commands, POSIX + Windows) + three modes | | �Command Execution | `checkCommandAllowed()` �command blacklist (30 dangerous commands, POSIX + Windows) + three modes |
| 🖥️ Frontend Rendering | HTML sanitizer (whitelist tags + URI protocol check) | | 🖥ï¸?Frontend Rendering | HTML sanitizer (whitelist tags + URI protocol check) |
| 🔒 Electron | `contextIsolation: true` + IPC whitelist + IPC fs path validation | | 🔒 Electron | `contextIsolation: true` + IPC whitelist + IPC fs path validation |
| 🔠Data Encryption | AES-256-GCM | | 🔠Data Encryption | AES-256-GCM |
| 🧠 Memory Security | Pre-write prompt injection / sensitive info detection, multi-layer dedup filtering | | 🧠 Memory Security | Pre-write prompt injection / sensitive info detection, multi-layer dedup filtering |
| 🌠MCP Security | Shadowing protection + double-underscore delimiter disambiguation | | 🌠MCP Security | Shadowing protection + double-underscore delimiter disambiguation |
| 🌠Network Security | `web_fetch` streaming size limit (10MB) + OOM prevention without content-length | | 🌠Network Security | `web_fetch` streaming size limit (10MB) + OOM prevention without content-length |
| Process Security | Windows `taskkill` forced termination + case-insensitive workspace path validation | | âš?Process Security | Windows `taskkill` forced termination + case-insensitive workspace path validation |
## 🚀 Quick Start ## 🚀 Quick Start
@@ -485,9 +485,9 @@ npm start
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ npm run dist
``` ```
Output: `release/Metona Ollama Setup v0.16.17.exe` Output: `release/Metona Ollama Setup v0.16.18.exe`
## 🛠️ Common Commands ## 🛠ï¸?Common Commands
```bash ```bash
npm start # Build and run npm start # Build and run
@@ -499,7 +499,7 @@ npm run dist # Build Windows installer
## 💻 System Requirements ## 💻 System Requirements
- 🖥️ Windows 10/11 (64-bit) - 🖥ï¸?Windows 10/11 (64-bit)
- 🤖 Ollama running locally (default `http://localhost:11434`) - 🤖 Ollama running locally (default `http://localhost:11434`)
- 💾 8GB+ RAM recommended - 💾 8GB+ RAM recommended
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "metona-ollama-desktop", "name": "metona-ollama-desktop",
"version": "0.16.17", "version": "0.16.18",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "metona-ollama-desktop", "name": "metona-ollama-desktop",
"version": "0.16.17", "version": "0.16.18",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ffmpeg-static": "^5.2.0", "ffmpeg-static": "^5.2.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "metona-ollama-desktop", "name": "metona-ollama-desktop",
"version": "0.16.17", "version": "0.16.18",
"description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端", "description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端",
"main": "dist/main/main.js", "main": "dist/main/main.js",
"author": "thzxx", "author": "thzxx",
+1 -1
View File
@@ -101,7 +101,7 @@ export function createMenu(): void {
dialog.showMessageBox(mainWindow!, { dialog.showMessageBox(mainWindow!, {
type: 'info', type: 'info',
title: '关于 Metona Ollama', title: '关于 Metona Ollama',
message: 'Metona Ollama Desktop v0.16.17', message: 'Metona Ollama Desktop v0.16.18',
detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama', detail: 'TypeScript + Electron Ollama AI 聊天客户端\n\nhttps://gitee.com/thzxx/metona-ollama',
icon: getIconPath() icon: getIconPath()
}); });
+3 -3
View File
@@ -124,8 +124,8 @@ export function killToolProcess(): boolean {
/** HTTP 请求超时(毫秒),默认 30s,可通过 IPC 设置 */ /** HTTP 请求超时(毫秒),默认 900s,可通过 IPC 设置 */
let HTTP_TIMEOUT = 30_000; let HTTP_TIMEOUT = 900_000;
/** 设置 HTTP 请求超时(毫秒),0=禁用超时 */ /** 设置 HTTP 请求超时(毫秒),0=禁用超时 */
export function setHTTPTimeout(ms: number): void { export function setHTTPTimeout(ms: number): void {
@@ -576,7 +576,7 @@ export async function handleWebFetch(params: { url: string; max_chars?: number;
} catch (err) { } catch (err) {
const errMsg = (err as Error).message; const errMsg = (err as Error).message;
if (errMsg.includes('abort') && attempt < maxAttempts - 1) { if (errMsg.includes('abort') && attempt < maxAttempts - 1) {
lastError = `请求超时 (${HTTP_TIMEOUT > 0 ? HTTP_TIMEOUT / 1000 : '∞'}s)(将重试)`; lastError = `请求超时 (${HTTP_TIMEOUT > 0 ? HTTP_TIMEOUT / 1000 : '∞'}s)(将重试)`; // 900s 默认,大页面/慢服务器需要更长时间
continue; continue;
} }
if (errMsg.includes('abort')) { if (errMsg.includes('abort')) {
+1 -1
View File
@@ -129,7 +129,7 @@ function renderMetricsDashboard(): void {
suggestionsEl.innerHTML = suggestions.map(s => ` suggestionsEl.innerHTML = suggestions.map(s => `
<div class="md-suggestion"> <div class="md-suggestion">
<span class="md-suggestion-severity md-severity-${s.severity}">${s.severity}</span> <span class="md-suggestion-severity md-severity-${s.severity}">${s.severity}</span>
<span class="md-suggestion-msg">${s.message}</span> <span class="md-suggestion-msg">${s.suggestion}</span>
</div> </div>
`).join(''); `).join('');
} }
+4 -4
View File
@@ -106,22 +106,22 @@ export function initSettingsModal(): void {
const saveHttpTimeout = debounce(async () => { const saveHttpTimeout = debounce(async () => {
const db = state.get<ChatDB | null>(KEYS.DB); const db = state.get<ChatDB | null>(KEYS.DB);
const sec = parseSec(inputHttpTimeout.value.trim()); const sec = parseSec(inputHttpTimeout.value.trim());
const ms = sec >= 0 ? sec * 1000 : 30_000; const ms = sec >= 0 ? sec * 1000 : 900_000;
if (db) await db.saveSetting('httpTimeout', sec); if (db) await db.saveSetting('httpTimeout', sec);
const bridge = window.metonaDesktop; const bridge = window.metonaDesktop;
if (bridge?.tool?.setTimeouts) { if (bridge?.tool?.setTimeouts) {
await bridge.tool.setTimeouts({ http: ms }); await bridge.tool.setTimeouts({ http: ms });
} }
logSetting('HTTP 超时', sec >= 0 ? (sec === 0 ? '已禁用' : `${sec}s`) : '默认(30s)'); logSetting('HTTP 超时', sec >= 0 ? (sec === 0 ? '已禁用' : `${sec}s`) : '默认(900s)');
}, 500); }, 500);
const saveStreamTimeout = debounce(async () => { const saveStreamTimeout = debounce(async () => {
const db = state.get<ChatDB | null>(KEYS.DB); const db = state.get<ChatDB | null>(KEYS.DB);
const sec = parseSec(inputStreamTimeout.value.trim()); const sec = parseSec(inputStreamTimeout.value.trim());
const ms = sec >= 0 ? sec * 1000 : 300_000; const ms = sec >= 0 ? sec * 1000 : -1;
state.set('streamTimeout', ms); state.set('streamTimeout', ms);
if (db) await db.saveSetting('streamTimeout', sec); if (db) await db.saveSetting('streamTimeout', sec);
logSetting('流式超时', sec >= 0 ? (sec === 0 ? '已禁用' : `${sec}s`) : '默认(300s)'); logSetting('流式超时', sec >= 0 ? (sec === 0 ? '已禁用' : `${sec}s`) : '默认(动态)');
}, 500); }, 500);
const saveMCPTimeout = debounce(async () => { const saveMCPTimeout = debounce(async () => {
+2 -2
View File
@@ -28,7 +28,7 @@
<div class="header-left"> <div class="header-left">
<img class="logo" src="./assets/icons/llama.png" alt="logo" /> <img class="logo" src="./assets/icons/llama.png" alt="logo" />
<span class="app-title">Metona Ollama</span> <span class="app-title">Metona Ollama</span>
<span class="app-version">v0.16.17</span> <span class="app-version">v0.16.18</span>
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助"> <button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/> <circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
@@ -344,7 +344,7 @@
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
<div> <div>
<label style="font-size:12px;color:var(--text-secondary);" for="inputHttpTimeout">🌐 HTTP 请求超时(秒)</label> <label style="font-size:12px;color:var(--text-secondary);" for="inputHttpTimeout">🌐 HTTP 请求超时(秒)</label>
<input class="setting-input" id="inputHttpTimeout" type="number" min="0" step="5" placeholder="30" style="margin-bottom:0;"> <input class="setting-input" id="inputHttpTimeout" type="number" min="0" step="5" placeholder="900" style="margin-bottom:0;">
<p class="text-muted" style="font-size:10px;">web_search / web_fetch 等 HTTP 请求的超时</p> <p class="text-muted" style="font-size:10px;">web_search / web_fetch 等 HTTP 请求的超时</p>
</div> </div>
<div> <div>
+3 -3
View File
@@ -459,13 +459,13 @@ async function init(): Promise<void> {
} }
// 应用流式超时到 stateagent-engine 读取,0=禁用) // 应用流式超时到 stateagent-engine 读取,0=禁用)
state.set('streamTimeout', streamTimeout >= 0 ? streamTimeout * 1000 : 300_000); state.set('streamTimeout', streamTimeout >= 0 ? streamTimeout * 1000 : -1);
// 应用 HTTP 和 MCP 超时到主进程 // 应用 HTTP 和 MCP 超时到主进程
const bridge = window.metonaDesktop; const bridge = window.metonaDesktop;
if (bridge?.tool?.setTimeouts) { if (bridge?.tool?.setTimeouts) {
await bridge.tool.setTimeouts({ await bridge.tool.setTimeouts({
http: httpTimeout >= 0 ? httpTimeout * 1000 : 30_000, http: httpTimeout >= 0 ? httpTimeout * 1000 : 900_000,
mcp: mcpTimeout >= 0 ? mcpTimeout * 1000 : 60_000, mcp: mcpTimeout >= 0 ? mcpTimeout * 1000 : 60_000,
}); });
} }
@@ -474,7 +474,7 @@ async function init(): Promise<void> {
(document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout >= 0 ? String(httpTimeout) : ''; (document.querySelector('#inputHttpTimeout') as HTMLInputElement).value = httpTimeout >= 0 ? String(httpTimeout) : '';
(document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout >= 0 ? String(streamTimeout) : ''; (document.querySelector('#inputStreamTimeout') as HTMLInputElement).value = streamTimeout >= 0 ? String(streamTimeout) : '';
(document.querySelector('#inputMCPTimeout') as HTMLInputElement).value = mcpTimeout >= 0 ? String(mcpTimeout) : ''; (document.querySelector('#inputMCPTimeout') as HTMLInputElement).value = mcpTimeout >= 0 ? String(mcpTimeout) : '';
logInit(`超时设置: HTTP=${httpTimeout>=0?httpTimeout:30}s 流式=${streamTimeout>=0?streamTimeout:300}s MCP=${mcpTimeout>=0?mcpTimeout:60}s`); logInit(`超时设置: HTTP=${httpTimeout>=0?httpTimeout:900}s 流式=${streamTimeout>=0?streamTimeout:'动态'}s MCP=${mcpTimeout>=0?mcpTimeout:60}s`);
// ── 子代理参数 ── // ── 子代理参数 ──
let subAgentMaxLoops = await db.getSetting<number>('subAgentMaxLoops', 10); let subAgentMaxLoops = await db.getSetting<number>('subAgentMaxLoops', 10);
+1 -1
View File
@@ -215,7 +215,7 @@ export async function executeSubAgent(
if (chunk.message?.content) content += chunk.message.content; if (chunk.message?.content) content += chunk.message.content;
if (chunk.message?.tool_calls?.length) { if (chunk.message?.tool_calls?.length) {
for (const tc of chunk.message.tool_calls) { for (const tc of chunk.message.tool_calls) {
if (tc.function?.name && SUB_AGENT_TOOL_WHITELIST.has(tc.function.name)) { if (tc.function?.name && toolWhitelist.has(tc.function.name)) {
toolCalls.push({ name: tc.function.name, arguments: tc.function.arguments || {} }); toolCalls.push({ name: tc.function.name, arguments: tc.function.arguments || {} });
} }
} }