v0.16.12: 删除 8 个非必要工具 — get_file_info/diff_files/replace_in_files/random/uuid/json_format/hash/datetime
This commit is contained in:
@@ -21,7 +21,7 @@ const MODE_NAMES: Record<string, string> = {
|
||||
const MANAGED_TOOLS = [
|
||||
'run_command',
|
||||
'write_file', 'create_directory', 'delete_file',
|
||||
'edit_file', 'replace_in_files', 'move_file', 'copy_file',
|
||||
'edit_file', 'move_file', 'copy_file',
|
||||
'download_file', 'compress',
|
||||
];
|
||||
|
||||
|
||||
@@ -996,8 +996,8 @@ function getToolDisplayName(name: string): string {
|
||||
read_file: '读取文件', write_file: '写入文件', list_directory: '列出目录',
|
||||
search_files: '搜索文件', create_directory: '创建目录', delete_file: '删除文件', run_command: '执行命令',
|
||||
move_file: '移动文件', copy_file: '复制文件', web_fetch: '网页抓取',
|
||||
edit_file: '编辑文件', get_file_info: '文件信息', tree: '目录树', download_file: '下载文件',
|
||||
diff_files: '文件对比', replace_in_files: '批量替换', read_multiple_files: '批量读取',
|
||||
edit_file: '编辑文件', tree: '目录树', download_file: '下载文件',
|
||||
read_multiple_files: '批量读取',
|
||||
git: 'Git 操作', compress: '压缩/解压', web_search: '联网搜索',
|
||||
memory: '记忆管理',
|
||||
|
||||
@@ -1013,8 +1013,8 @@ function getToolIcon(name: string): string {
|
||||
read_file: '📄', write_file: '✏️', list_directory: '📁',
|
||||
search_files: '🔍', create_directory: '📂', delete_file: '🗑️', run_command: '💻',
|
||||
move_file: '📦', copy_file: '📋', web_fetch: '🌐',
|
||||
edit_file: '✂️', get_file_info: 'ℹ️', tree: '🌳', download_file: '⬇️',
|
||||
diff_files: '🔀', replace_in_files: '🔄', read_multiple_files: '📚',
|
||||
edit_file: '✂️', tree: '🌳', download_file: '⬇️',
|
||||
read_multiple_files: '📚',
|
||||
git: '🔖', compress: '🗜️', web_search: '🔍',
|
||||
memory: '🧠',
|
||||
|
||||
|
||||
+2
-34
@@ -28,7 +28,7 @@
|
||||
<div class="header-left">
|
||||
<img class="logo" src="./assets/icons/llama.png" alt="logo" />
|
||||
<span class="app-title">Metona Ollama</span>
|
||||
<span class="app-version">v0.16.11</span>
|
||||
<span class="app-version">v0.16.12</span>
|
||||
<button class="icon-btn help-btn" id="btnHelp" title="使用帮助">
|
||||
<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"/>
|
||||
@@ -438,7 +438,7 @@
|
||||
<div class="modal-body">
|
||||
<div class="help-section"><h4>🚀 快速开始</h4><ol><li>确保 Ollama 已启动(默认 <code>http://127.0.0.1:11434</code>,可在设置中修改)</li><li>顶部模型栏选择一个模型,右侧会显示模型能力徽章(🧠 Think / 👁️ Vision / 🔧 Tools)</li><li>输入消息,按 <kbd>Enter</kbd> 发送,<kbd>Shift+Enter</kbd> 换行</li></ol></div>
|
||||
<div class="help-section"><h4>💬 聊天功能</h4><ul><li><strong>流式回复</strong> — 实时打字效果,随时点 ■ 停止</li><li><strong>Think 推理</strong> — 下方 Think 按钮切换,让模型展示深度思考过程(需模型支持,如 Qwen3)</li><li><strong>上下文长度手动控制</strong> — 设置面板下拉选择(128K / 256K / 512K / 1M),默认 128K。模型栏显示当前配置值,下拉框中每个模型旁显示其自身的上下文长度</li><li><strong>Qwen3 兼容</strong> — 自动保证 system 消息唯一且位于首位,避免 Qwen3 等模型 400 错误</li><li><strong>多模态</strong> — 上传图片或视频(≤10MB),模型需支持 Vision。图片自动压缩,视频 1fps 提取帧序列带时序标注</li><li><strong>文件分析</strong> — 支持 50+ 种文本/代码格式,单文件 ≤500KB,自动剥离注释并按上下文预算智能截断</li><li><strong>AI 回复顶部</strong> — 每条 AI 回复上方展示 📋 系统提示词折叠卡片,可点击查看实际发送给模型的完整上下文</li></ul></div>
|
||||
<div class="help-section"><h4>🔧 Tool Calling(始终开启)</h4><ul><li>所有消息均通过 <strong>Agent Loop 自主调用本地工具</strong>,像一个本地 Agent,无普通聊天模式</li><li><strong>40+1 个工具</strong>,分为 9 类:<ul><li><strong>文件系统</strong>(16 个):read_file / write_file / list_directory / search_files / create_directory / delete_file / move_file / copy_file / edit_file / get_file_info / tree / download_file / diff_files / replace_in_files / read_multiple_files / compress</li><li><strong>命令执行</strong>(1 个):run_command(实时流式输出,支持自动/需确认/禁用三种模式,可配置超时)</li><li><strong>联网搜索</strong>(2 个):web_search(支持 SearXNG 元搜索引擎 JSON API / 四引擎 HTML 解析,双模式可切换)/ web_fetch(反爬headers+UA自动切换+自动回退浏览器渲染)</li><li><strong>Git</strong>(1 个):git(17 个子操作,push/pull/clone 内置60-120s超时保护)</li><li><strong>浏览器控制</strong>(9 个):browser_open / browser_screenshot / browser_evaluate / browser_extract / browser_click / browser_type / browser_scroll / browser_wait / browser_close</li><li><strong>记忆 & 会话</strong>(5 个):memory(统一记忆管理,5 个 action)/ session_list / session_read / spawn_task / plan_track</li><li><strong>系统工具</strong>(6 个):datetime / calculator / random / uuid / json_format / hash</li></ul></li><li>read_file 支持 binary模式读取/base64解码/字节分页/2000行默认+截断hint自动续读</li><li>write_file 支持 base64写二进制文件/mode(overwrite+append)合并append_file功能/10MB</li><li>edit_file 支持 use_regex 正则替换</li><li>search_files 支持正则表达式搜索(use_regex=true)</li><li>browser_screenshot 支持全页面截图+元素截图</li><li>browser_extract 支持CSS选择器提取特定区域</li><li>new browser_wait 等待元素出现或定时等待</li><li>所有写操作工具均支持三档开关:自动/需确认/禁用(浏览器工具始终自动执行)</li><li>危险命令(<code>rm -rf</code>、<code>mkfs</code>、反弹 shell 等)和系统路径(<code>/etc</code>、<code>~/.ssh</code> 等)被自动拦截</li><li>工具调用以<strong>可视化卡片</strong>展示状态(pending → running → success/error),在工作空间🔧工具页签中显示</li><li>默认最大 <strong>85 轮</strong>工具调用循环(设置面板可调),上下文使用率>80%时自动缩减到3轮</li><li>独立工具自动<strong>并行执行</strong>(16个只读工具加入并行白名单),有依赖关系的工具串行执行</li></ul></div>
|
||||
<div class="help-section"><h4>🔧 Tool Calling(始终开启)</h4><ul><li>所有消息均通过 <strong>Agent Loop 自主调用本地工具</strong>,像一个本地 Agent,无普通聊天模式</li><li><strong>32 个工具</strong>,分为 9 类:<ul><li><strong>文件系统</strong>(13 个):read_file / write_file / list_directory / search_files / create_directory / delete_file / move_file / copy_file / edit_file / tree / download_file / read_multiple_files / compress</li><li><strong>命令执行</strong>(1 个):run_command(实时流式输出,支持自动/需确认/禁用三种模式,可配置超时)</li><li><strong>联网搜索</strong>(2 个):web_search(支持 SearXNG 元搜索引擎 JSON API / 四引擎 HTML 解析,双模式可切换)/ web_fetch(反爬headers+UA自动切换+自动回退浏览器渲染)</li><li><strong>Git</strong>(1 个):git(17 个子操作,push/pull/clone 内置60-120s超时保护)</li><li><strong>浏览器控制</strong>(9 个):browser_open / browser_screenshot / browser_evaluate / browser_extract / browser_click / browser_type / browser_scroll / browser_wait / browser_close</li><li><strong>记忆 & 会话</strong>(5 个):memory(统一记忆管理,5 个 action)/ session_list / session_read / spawn_task / plan_track</li><li><strong>系统工具</strong>(1 个):calculator</li></ul></li><li>read_file 支持 binary模式读取/base64解码/字节分页/2000行默认+截断hint自动续读</li><li>write_file 支持 base64写二进制文件/mode(overwrite+append)合并append_file功能/10MB</li><li>edit_file 支持 use_regex 正则替换</li><li>search_files 支持正则表达式搜索(use_regex=true)</li><li>browser_screenshot 支持全页面截图+元素截图</li><li>browser_extract 支持CSS选择器提取特定区域</li><li>new browser_wait 等待元素出现或定时等待</li><li>所有写操作工具均支持三档开关:自动/需确认/禁用(浏览器工具始终自动执行)</li><li>危险命令(<code>rm -rf</code>、<code>mkfs</code>、反弹 shell 等)和系统路径(<code>/etc</code>、<code>~/.ssh</code> 等)被自动拦截</li><li>工具调用以<strong>可视化卡片</strong>展示状态(pending → running → success/error),在工作空间🔧工具页签中显示</li><li>默认最大 <strong>85 轮</strong>工具调用循环(设置面板可调),上下文使用率>80%时自动缩减到3轮</li><li>独立工具自动<strong>并行执行</strong>(11个只读工具加入并行白名单),有依赖关系的工具串行执行</li></ul></div>
|
||||
<div class="help-section"><h4>🧠 Agent 记忆系统</h4><ul><li>记忆存储在工作空间 <strong>MEMORY.md</strong> 文件,受严格路径保护,仅 <code>memory</code> 工具可读写</li><li>新对话时自动检索相关记忆注入 AI 上下文,让 AI "记住"你</li><li>对话结束时 AI 自动提取有价值的用户信息保存(多层质量过滤,宁缺毋滥)</li><li><strong>memory 工具</strong>(5 个 action):search(关键词搜索)/ add(添加)/ replace(替换)/ remove(删除)/ read_all(读取全部)</li><li>点击顶部 🧠 按钮打开记忆面板:查看、添加、删除记忆条目</li><li><strong>记忆容量上限 500 条</strong>,超限时自动清理低价值条目(规则类型受保护)</li><li>写入前自动安全扫描(prompt injection / 敏感信息 / 不可见字符检测)</li><li>应用启动时自动校验 MEMORY.md 格式,格式错误自动备份重建</li></ul></div>
|
||||
<div class="help-section"><h4>📋 Plan Mode(计划模式)</h4><ul><li>点击输入框上方 📋 按钮开启 <strong>Plan Mode</strong>(开关式)</li><li>开启后,AI <strong>先生成执行计划</strong>(Markdown 渲染弹窗),用户批准后才开始执行</li><li>计划批准后自动初始化追踪器,每个步骤完成后调用 <code>plan_track</code> 工具标记进度</li><li>系统提示词自动注入当前进度状态,AI 始终知道还剩多少步未完成</li><li><strong>多步骤任务防遗忘</strong>:自动检测用户请求中的动作动词,对比已完成步骤,注入提醒</li><li>关闭 Plan Mode 后恢复正常 Agent Loop 模式</li><li><strong>仅 Plan 模式</strong> 下 plan_track 工具可见,避免污染普通模式的工具列表</li></ul></div>
|
||||
<div class="help-section"><h4>🛡️ 抗幻觉 & 稳定性</h4><ul><li><strong>5 层防御体系</strong>:系统提示词加固 → 任务感知 → 中途幻觉检测(中英双语规则覆盖全部工具类别)→ 进度锚点 → 完成闸门(6 项检查,幻觉/注入 → 阻断,质量/效率 → 咨询)</li><li><strong>完成闸门</strong>:对话结束前自动审查 AI 回复,检测工具幻觉和 prompt injection,阻断有问题的回复</li><li><strong>中英双语检测规则</strong>:覆盖中英文模型输出,防止 AI 声称执行了未调用的工具</li><li><strong>智能重试机制</strong>:永久错误(文件不存在/权限拒绝)立即返回,瞬态错误(网络/超时)指数退避最多重试 2 次</li><li><strong>看门狗超时</strong>:设置面板可配置全局超时(默认 30 分钟),AI 卡死或无限循环时自动中止</li><li><strong>流式总超时</strong>:可配置超时(默认 300s),Ollama 卡死不再永久阻塞</li><li><strong>中止保护</strong>:所有状态处理器 + 重试循环均检查中止信号,点击 ■ 按钮立即生效</li><li><strong>上下文硬上限</strong>:200 条消息强制压缩 + 120 条增量压缩,防止 OOM</li></ul></div>
|
||||
@@ -524,10 +524,6 @@
|
||||
<div class="tool-card-header"><span class="tool-card-icon">💻</span><span class="tool-card-name">run_command</span><span class="tool-card-badge confirm">需确认</span></div>
|
||||
<div class="tool-card-desc">执行 shell 命令,支持超时配置</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">ℹ️</span><span class="tool-card-name">get_file_info</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">获取文件/目录详细信息:大小、日期、权限</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🌳</span><span class="tool-card-name">tree</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">以树形结构展示目录内容</div>
|
||||
@@ -536,14 +532,6 @@
|
||||
<div class="tool-card-header"><span class="tool-card-icon">⬇️</span><span class="tool-card-name">download_file</span><span class="tool-card-badge confirm">需确认</span></div>
|
||||
<div class="tool-card-desc">从 URL 下载文件到本地</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🔀</span><span class="tool-card-name">diff_files</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">对比两个文件,显示差异</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🔄</span><span class="tool-card-name">replace_in_files</span><span class="tool-card-badge confirm">需确认</span></div>
|
||||
<div class="tool-card-desc">按 glob 模式批量查找替换多个文件</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">📚</span><span class="tool-card-name">read_multiple_files</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">并行读取最多50个文件,每文件10KB</div>
|
||||
@@ -612,30 +600,10 @@
|
||||
<div class="tool-card-header"><span class="tool-card-icon">❌</span><span class="tool-card-name">browser_close</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">关闭 Agent 浏览器并释放资源</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🕐</span><span class="tool-card-name">datetime</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">获取系统精确时间(ISO/Unix/日期/时间/完整)</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🔢</span><span class="tool-card-name">calculator</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">安全数学计算(+ - * / ** % (),递归下降解析器)</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🎲</span><span class="tool-card-name">random</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">随机数/随机选择(整数/浮点/抽取/字符串)</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🆔</span><span class="tool-card-name">uuid</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">生成 UUID v4 唯一标识符(批量最多20个)</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">📋</span><span class="tool-card-name">json_format</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">JSON 格式化 + 语法验证 + 键排序</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">🔐</span><span class="tool-card-name">hash</span><span class="tool-card-badge auto">自动</span></div>
|
||||
<div class="tool-card-desc">哈希计算(MD5/SHA1/SHA256/SHA384/SHA512)</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">📋</span><span class="tool-card-name">plan_track</span><span class="tool-card-badge confirm" id="badge_plan_track">需确认</span></div>
|
||||
<div class="tool-card-desc">Plan 模式专属:追踪执行进度,标记/查看步骤完成状态</div>
|
||||
|
||||
@@ -458,7 +458,7 @@ async function init(): Promise<void> {
|
||||
// 如果旧 toolModes 中所有被管理工具都是 auto,则迁移为 auto;否则 confirm
|
||||
const allAuto = [
|
||||
'run_command', 'write_file', 'create_directory', 'delete_file',
|
||||
'edit_file', 'replace_in_files', 'move_file', 'copy_file',
|
||||
'edit_file', 'move_file', 'copy_file',
|
||||
'download_file', 'compress',
|
||||
].every(t => savedModes[t] === 'auto');
|
||||
globalMode = allAuto ? 'auto' : 'confirm';
|
||||
|
||||
@@ -159,18 +159,16 @@ function getOSEnvironment() {
|
||||
|
||||
/** 始终可并行的只读/独立工具 */
|
||||
const ALWAYS_PARALLEL = new Set([
|
||||
'read_file', 'list_directory', 'search_files', 'get_file_info', 'tree',
|
||||
'read_file', 'list_directory', 'search_files', 'tree',
|
||||
'web_search', 'browser_screenshot', 'browser_extract',
|
||||
'memory', 'session_list', 'session_read',
|
||||
'diff_files',
|
||||
'datetime', 'calculator',
|
||||
'random', 'uuid', 'json_format', 'hash',
|
||||
'calculator',
|
||||
]);
|
||||
|
||||
/** D4: 有副作用的工具 — 同轮次去重时不返回缓存,需实际执行 */
|
||||
const SIDE_EFFECT_TOOLS = new Set([
|
||||
'write_file', 'edit_file', 'create_directory', 'delete_file',
|
||||
'move_file', 'copy_file', 'replace_in_files', 'download_file',
|
||||
'move_file', 'copy_file', 'download_file',
|
||||
'run_command', 'git', 'compress',
|
||||
'browser_open', 'browser_click', 'browser_type', 'browser_close',
|
||||
]);
|
||||
@@ -190,17 +188,11 @@ const _pendingMemoryTimers: ReturnType<typeof setTimeout>[] = [];
|
||||
/** R3/R108: 工具超时配置(基础超时 + 动态调整) */
|
||||
const TOOL_TIMEOUT_MAP: Record<string, { base: number; grade: 'fast' | 'medium' | 'slow' | 'long'; description: string }> = {
|
||||
// fast (<5秒)
|
||||
datetime: { base: 1_000, grade: 'fast', description: '时间查询' },
|
||||
random: { base: 1_000, grade: 'fast', description: '随机数' },
|
||||
uuid: { base: 1_000, grade: 'fast', description: 'UUID' },
|
||||
calculator: { base: 3_000, grade: 'fast', description: '计算器' },
|
||||
json_format: { base: 3_000, grade: 'fast', description: 'JSON 格式化' },
|
||||
hash: { base: 3_000, grade: 'fast', description: '哈希计算' },
|
||||
create_directory: { base: 5_000, grade: 'fast', description: '创建目录' },
|
||||
get_file_info: { base: 5_000, grade: 'fast', description: '获取文件信息' },
|
||||
memory: { base: 5_000, grade: 'fast', description: '记忆操作' },
|
||||
session_list: { base: 5_000, grade: 'fast', description: '会话列表' },
|
||||
|
||||
|
||||
// medium (5-15秒)
|
||||
list_directory: { base: 10_000, grade: 'medium', description: '列目录' },
|
||||
delete_file: { base: 10_000, grade: 'medium', description: '删除文件' },
|
||||
@@ -208,15 +200,13 @@ const TOOL_TIMEOUT_MAP: Record<string, { base: number; grade: 'fast' | 'medium'
|
||||
edit_file: { base: 15_000, grade: 'medium', description: '编辑文件' },
|
||||
move_file: { base: 15_000, grade: 'medium', description: '移动文件' },
|
||||
tree: { base: 15_000, grade: 'medium', description: '目录树' },
|
||||
diff_files: { base: 15_000, grade: 'medium', description: '文件差异' },
|
||||
session_read: { base: 10_000, grade: 'medium', description: '会话读取' },
|
||||
web_search: { base: 30_000, grade: 'medium', description: '网页搜索' },
|
||||
git: { base: 30_000, grade: 'medium', description: 'Git 操作' },
|
||||
|
||||
|
||||
// slow (15-60秒)
|
||||
read_file: { base: 30_000, grade: 'slow', description: '读取文件' },
|
||||
copy_file: { base: 30_000, grade: 'slow', description: '复制文件' },
|
||||
replace_in_files: { base: 30_000, grade: 'slow', description: '批量替换' },
|
||||
search_files: { base: 60_000, grade: 'slow', description: '搜索文件' },
|
||||
read_multiple_files: { base: 60_000, grade: 'slow', description: '批量读取' },
|
||||
web_fetch: { base: 60_000, grade: 'slow', description: '网页抓取' },
|
||||
@@ -375,9 +365,7 @@ function extractReadPath(call: ToolCall): string | null {
|
||||
case 'read_file': return String(args.path || '');
|
||||
case 'list_directory': return String(args.path || '');
|
||||
case 'search_files': return String(args.path || '');
|
||||
case 'get_file_info': return String(args.path || '');
|
||||
case 'tree': return String(args.path || '');
|
||||
case 'diff_files': return String(args.file1 || args.file2 || '');
|
||||
case 'read_multiple_files': return null; // 多文件,难以精确判断
|
||||
default: return null;
|
||||
}
|
||||
@@ -412,10 +400,7 @@ function extractAffectedPath(call: ToolCall): string | null {
|
||||
case 'create_directory': return String(args.path || '');
|
||||
case 'move_file': return String(args.source || '');
|
||||
case 'copy_file': return String(args.source || '');
|
||||
case 'get_file_info': return String(args.path || '');
|
||||
case 'tree': return String(args.path || '');
|
||||
case 'diff_files': return String(args.file1 || args.file2 || '');
|
||||
case 'replace_in_files': return String(args.path || '');
|
||||
case 'read_multiple_files': return null; // 多文件,难以精确判断
|
||||
case 'download_file': return null; // 下载不依赖本地文件
|
||||
case 'compress': return String(args.path || '');
|
||||
@@ -444,7 +429,6 @@ function validateToolArgs(toolName: string, args: Record<string, unknown>): stri
|
||||
case 'write_file':
|
||||
case 'delete_file':
|
||||
case 'create_directory':
|
||||
case 'get_file_info':
|
||||
case 'tree':
|
||||
case 'compress':
|
||||
if (!getString('path')) return `${toolName} 缺少有效的 path 参数`;
|
||||
@@ -478,10 +462,6 @@ function validateToolArgs(toolName: string, args: Record<string, unknown>): stri
|
||||
if (args.new_text === undefined || args.new_text === null)
|
||||
return 'edit_file 缺少 new_text 参数';
|
||||
break;
|
||||
case 'diff_files':
|
||||
if (!getString('file1')) return 'diff_files 缺少 file1 参数';
|
||||
if (!getString('file2')) return 'diff_files 缺少 file2 参数';
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -490,11 +470,10 @@ function validateToolArgs(toolName: string, args: Record<string, unknown>): stri
|
||||
const VALID_TOOL_NAMES = new Set([
|
||||
'read_file', 'write_file', 'list_directory', 'search_files', 'create_directory',
|
||||
'delete_file', 'run_command', 'move_file', 'copy_file', 'web_fetch', 'web_search',
|
||||
'edit_file', 'get_file_info', 'tree', 'download_file', 'diff_files',
|
||||
'replace_in_files', 'read_multiple_files', 'git', 'compress',
|
||||
'edit_file', 'tree', 'download_file',
|
||||
'read_multiple_files', 'git', 'compress',
|
||||
'memory', 'session_list', 'session_read',
|
||||
'datetime', 'calculator',
|
||||
'random', 'uuid', 'json_format', 'hash'
|
||||
'calculator'
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -684,13 +663,10 @@ const CACHE_TTL_MAP: Record<string, number> = {
|
||||
search_files: 2 * 60_000,
|
||||
browser_screenshot: 60_000,
|
||||
browser_extract: 5 * 60_000,
|
||||
get_file_info: 2 * 60_000,
|
||||
tree: 2 * 60_000,
|
||||
git: 30_000, // git status 30s 过期
|
||||
datetime: 5_000, // 时间 5s 过期
|
||||
session_list: 60_000,
|
||||
session_read: 60_000,
|
||||
diff_files: 2 * 60_000,
|
||||
memory: 10_000, // M2: 记忆搜索 10s 过期(短TTL,避免 add 后搜索过期)
|
||||
default: 60_000, // 默认 60s,不再永久缓存
|
||||
};
|
||||
@@ -961,18 +937,6 @@ export function formatToolResultForModel(toolName: string, result: ToolResult):
|
||||
});
|
||||
}
|
||||
|
||||
case 'get_file_info': {
|
||||
return JSON.stringify({
|
||||
success: true,
|
||||
message: `${(result as any).type === 'directory' ? '目录' : '文件'}:${result.path}`,
|
||||
path: result.path,
|
||||
type: (result as any).type,
|
||||
size: (result as any).size,
|
||||
modified: (result as any).modified,
|
||||
created: (result as any).created,
|
||||
});
|
||||
}
|
||||
|
||||
case 'tree': {
|
||||
return JSON.stringify({
|
||||
success: true,
|
||||
@@ -1887,8 +1851,8 @@ async function handleExecuting(
|
||||
// R79: 路径沙箱验证 — 确保文件操作不超出工作空间边界
|
||||
const FILE_PATH_TOOLS = new Set([
|
||||
'read_file', 'write_file', 'edit_file', 'delete_file', 'create_directory',
|
||||
'list_directory', 'search_files', 'get_file_info', 'tree', 'compress',
|
||||
'move_file', 'copy_file', 'replace_in_files', 'download_file',
|
||||
'list_directory', 'search_files', 'tree', 'compress',
|
||||
'move_file', 'copy_file', 'download_file',
|
||||
]);
|
||||
if (FILE_PATH_TOOLS.has(call.function.name)) {
|
||||
const workspaceDir = getWorkspaceDirPath();
|
||||
|
||||
@@ -319,10 +319,6 @@ export function scoreMessageImportance(msg: OllamaMessage): number {
|
||||
if (/read_file|list_directory|tree/.test(msg.tool_name)) {
|
||||
score += 1;
|
||||
}
|
||||
// 时间/计算类工具结果:低价值(时效性强,很快过期)
|
||||
if (/datetime|random|uuid|hash/.test(msg.tool_name)) {
|
||||
score -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// 长度加分:长消息通常包含更多信息
|
||||
|
||||
@@ -196,20 +196,6 @@ export const TOOL_DEFINITIONS: ToolDefinition[] = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'get_file_info',
|
||||
description: 'Get detailed file or directory information: size, dates, permissions, type.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['path'],
|
||||
properties: {
|
||||
path: { type: 'string', description: 'File or directory path.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
@@ -241,39 +227,6 @@ export const TOOL_DEFINITIONS: ToolDefinition[] = [
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'diff_files',
|
||||
description: 'Compare two files and show differences. Returns a unified diff.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['file1', 'file2'],
|
||||
properties: {
|
||||
file1: { type: 'string', description: 'First file path.' },
|
||||
file2: { type: 'string', description: 'Second file path.' },
|
||||
context_lines: { type: 'integer', description: 'Context lines around changes. Default: 3.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'replace_in_files',
|
||||
description: 'Find and replace text across multiple files matching a glob pattern. Requires user confirmation.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['path', 'glob', 'old_text', 'new_text'],
|
||||
properties: {
|
||||
path: { type: 'string', description: 'Root directory.' },
|
||||
glob: { type: 'string', description: 'File pattern, e.g. "*.ts", "**/*.js".' },
|
||||
old_text: { type: 'string', description: 'Text to find.' },
|
||||
new_text: { type: 'string', description: 'Replacement text.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
@@ -590,17 +543,269 @@ TIP: Use remove_batch when deleting multiple entries — it's much more efficien
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'datetime',
|
||||
description: 'Get the precise current system time. Returns ISO timestamp, Unix time (seconds and milliseconds), locale-formatted date/time, timezone, and individual components (year/month/day/hour/minute/second/millisecond/day_of_week). Use format parameter to request specific output: "iso" / "unix" / "date" / "time" / "full" (default: full).',
|
||||
name: 'calculator',
|
||||
description: 'Safely evaluate a mathematical expression. Supports + - * / ** % () and floating-point numbers. Uses a pure JS recursive descent parser — no eval(), CSP-safe. Returns the numeric result.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['expression'],
|
||||
properties: {
|
||||
expression: { type: 'string', description: 'The mathematical expression to evaluate (e.g., "(3 + 5) * 2 ** 3"). Max 500 characters.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'web_search',
|
||||
description: 'Search the web with auto-fetch. Always use this when the user asks for information, news, facts, or current data. Never rely on training data or past conversation results — call this tool every time the user asks to search. Set fetch_top to auto-fetch full page content from the top N results.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['query', 'fetch_top'],
|
||||
properties: {
|
||||
query: { type: 'string', description: 'The search query. Be specific and concise for best results.' },
|
||||
max_results: { type: 'integer', description: 'Maximum number of results to return. Default: 30, max: 30.' },
|
||||
time_range: { type: 'string', enum: ['day', 'week', 'month', 'year'], description: 'Filter results by time. Supported by Bing and Google. Use for recent news, latest version, etc.' },
|
||||
enhance_snippets: { type: 'boolean', description: 'Auto-fetch detailed snippet for results with too-short descriptions. Default: true.' },
|
||||
fetch_top: { type: 'integer', description: 'Number of top results to auto-fetch full content for. Min: 3. Results shorter than this are useless — snippets lack detail.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ══════════════════════════════════════════════
|
||||
// 记忆工具(统一入口,读写工作空间 MEMORY.md)
|
||||
// ══════════════════════════════════════════════
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'memory',
|
||||
description: `Manage agent memories stored in MEMORY.md. Usage by action:
|
||||
- search: {"action":"search","query":"keywords","limit":8}
|
||||
- add: {"action":"add","type":"fact","content":"the memory content","importance":8,"tags":["tag1","tag2"]} ← type and content are REQUIRED for add!
|
||||
- replace: {"action":"replace","old_text":"unique substring","new_content":"replacement"}
|
||||
- remove: {"action":"remove","old_text":"unique substring"}
|
||||
- remove_batch: {"action":"remove_batch","old_texts":["substring1","substring2","substring3"]} ← Batch delete multiple entries in one call
|
||||
- read_all: {"action":"read_all"}
|
||||
|
||||
CRITICAL: For add action, you MUST include both "type" (fact/preference/rule) and "content" fields. If you omit them, the call will fail.
|
||||
TIP: Use remove_batch when deleting multiple entries — it's much more efficient than calling remove repeatedly.`,
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['action'],
|
||||
properties: {
|
||||
action: { type: 'string', enum: ['search', 'add', 'replace', 'remove', 'remove_batch', 'read_all'], description: 'Which operation to perform. Note: "add" requires "type"+"content", "replace" requires "old_text"+"new_content", "remove" requires "old_text", "remove_batch" requires "old_texts" (array), "search" requires "query".' },
|
||||
query: { type: 'string', description: '[search REQUIRED] Keywords to search for.' },
|
||||
limit: { type: 'integer', description: '[search] Max results. Default: 8.' },
|
||||
type: { type: 'string', enum: ['fact', 'preference', 'rule'], description: '[add REQUIRED] Memory type. fact=user info, preference=user preference, rule=behavior rule.' },
|
||||
content: { type: 'string', description: '[add REQUIRED, replace] Memory text. Keep it concise (8-100 chars).' },
|
||||
importance: { type: 'integer', description: '[add] Priority 1-10. Default: 5. Use 8+ for critical info.' },
|
||||
tags: { type: 'array', items: { type: 'string' }, description: '[add] 2-5 keywords for search matching.' },
|
||||
old_text: { type: 'string', description: '[replace, remove REQUIRED] Unique substring to identify the entry. Must be ≥5 chars. Use exact text from read_all for best results.' },
|
||||
old_texts: { type: 'array', items: { type: 'string' }, description: '[remove_batch REQUIRED] Array of substrings to identify multiple entries for batch deletion. Each must be ≥5 chars.' },
|
||||
new_content: { type: 'string', description: '[replace REQUIRED] New text to replace with.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ══════════════════════════════════════════════
|
||||
// 会话管理工具
|
||||
// ══════════════════════════════════════════════
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'session_list',
|
||||
description: 'List previous chat sessions with their titles and timestamps. Useful for referencing past conversations.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
format: { type: 'string', enum: ['full', 'iso', 'unix', 'date', 'time'], description: 'Output format. Default: full (all fields).' },
|
||||
timezone: { type: 'string', description: 'IANA timezone name (e.g., "Asia/Shanghai", "America/New_York"). Default: system timezone.' }
|
||||
limit: { type: 'integer', description: 'Max sessions to return. Default: 20.' },
|
||||
search: { type: 'string', description: 'Filter sessions by title keyword.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'session_read',
|
||||
description: 'Read the messages from a previous chat session. Use when the user references something from a past conversation.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['session_id'],
|
||||
properties: {
|
||||
session_id: { type: 'string', description: 'The session ID to read.' },
|
||||
max_messages: { type: 'integer', description: 'Max messages to return. Default: 50.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ══════════════════════════════════════════════
|
||||
// v4.3 新增工具:子代理委派
|
||||
// ══════════════════════════════════════════════
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'spawn_task',
|
||||
description: 'Spawn a sub-agent to independently execute a task using read-only tools (file reading, web search, browser viewing, memory/session queries). Use this to parallelize independent research or analysis sub-tasks. The model is configured in Settings and cannot be overridden per call.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['task'],
|
||||
properties: {
|
||||
task: { type: 'string', description: 'The task description for the sub-agent to execute.' },
|
||||
context: { type: 'string', description: 'Optional additional context or reference data for the sub-agent.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ══════════════════════════════════════════════
|
||||
// 新增工具:Plan Mode 执行追踪
|
||||
// ══════════════════════════════════════════════
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'plan_track',
|
||||
description: 'Manage Plan Mode execution progress. Use this to mark plan steps as completed so you always know what remains. REQUIRED in Plan Mode — call plan_track after completing each step.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['action'],
|
||||
properties: {
|
||||
action: { type: 'string', enum: ['status', 'mark_done', 'mark_undone', 'mark_all_done'], description: 'status=查看当前进度, mark_done=标记步骤完成, mark_undone=撤销步骤完成标记, mark_all_done=全部完成' },
|
||||
step_index: { type: 'integer', description: 'Step number (1-indexed) to mark as done. Required for mark_done.' },
|
||||
step_label: { type: 'string', description: 'Optional: description of what was completed, for logging.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// ══════════════════════════════════════════════
|
||||
// v5.0 新增工具:浏览器控制
|
||||
// ══════════════════════════════════════════════
|
||||
// v5.1 Browser 控制工具(增强版)
|
||||
// ══════════════════════════════════════════════
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_open',
|
||||
description: 'Open a URL in the agent browser. Waits for page load. Use wait_selector to wait for a specific element (useful for SPA pages). Returns page title and URL.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['url'],
|
||||
properties: {
|
||||
url: { type: 'string', description: 'The URL to open (http/https).' },
|
||||
wait_selector: { type: 'string', description: 'CSS selector to wait for after page load. Useful for SPA/dynamic pages. Default: none.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_screenshot',
|
||||
description: 'Take a screenshot of the current page. Supports viewport (default), full_page (entire scrollable page), or selector (specific element only). Returns base64 PNG.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
full_page: { type: 'boolean', description: 'Capture the entire scrollable page. Default: false.' },
|
||||
selector: { type: 'string', description: 'CSS selector of element to capture. Overrides full_page.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_evaluate',
|
||||
description: 'Execute JavaScript in the browser page. Returns the result as JSON string. Use to read DOM, extract data, or interact programmatically.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['js'],
|
||||
properties: {
|
||||
js: { type: 'string', description: 'JavaScript code to execute in the page context.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_extract',
|
||||
description: 'Extract text and links from the current page. Use selector to extract only from a specific element (e.g. "main", "#content", "article"). Without selector, extracts full page. Returns title, text, and up to 50 links.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
selector: { type: 'string', description: 'CSS selector to extract from. Default: entire body.' },
|
||||
max_chars: { type: 'integer', description: 'Max characters to return. Default: 15000.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_click',
|
||||
description: 'Click an element by CSS selector. Use wait=true to wait up to 10s for the element to appear first (useful after page navigation). Scrolls element into view before clicking.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['selector'],
|
||||
properties: {
|
||||
selector: { type: 'string', description: 'CSS selector for the element to click.' },
|
||||
wait: { type: 'boolean', description: 'Wait for element to appear before clicking (max 10s). Default: false.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_type',
|
||||
description: 'Type text into an input field. Use clear=false to append instead of replacing. Use submit=true to press Enter or submit the parent form after typing.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['selector', 'text'],
|
||||
properties: {
|
||||
selector: { type: 'string', description: 'CSS selector for the input element.' },
|
||||
text: { type: 'string', description: 'Text to type into the input.' },
|
||||
clear: { type: 'boolean', description: 'Clear existing text first. Default: true.' },
|
||||
submit: { type: 'boolean', description: 'Submit the form or press Enter after typing. Default: false.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_scroll',
|
||||
description: 'Scroll the page. Use direction for up/down/top/bottom, or selector to scroll a specific element into view.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
direction: { type: 'string', enum: ['down', 'up', 'top', 'bottom'], description: 'Scroll direction. Default: down.' },
|
||||
selector: { type: 'string', description: 'CSS selector to scroll into view (overrides direction).' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_wait',
|
||||
description: 'Wait for a condition. Use selector to wait for an element to appear, or time_ms for a fixed delay. Default: 1 second.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
selector: { type: 'string', description: 'CSS selector to wait for. Returns found: true/false.' },
|
||||
time_ms: { type: 'integer', description: 'Fixed wait time in milliseconds. Default: 1000.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'browser_close',
|
||||
description: 'Close the agent browser and free resources.',
|
||||
parameters: { type: 'object', properties: {} }
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
@@ -614,68 +819,6 @@ TIP: Use remove_batch when deleting multiple entries — it's much more efficien
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'random',
|
||||
description: 'Generate random numbers or pick random items. Supports: int (integer range, default 0-100), float (decimal, default 0-1), pick (select from array of items), string (random alphanumeric, default length 8). Use count for multiple values.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
type: { type: 'string', enum: ['int', 'float', 'pick', 'string'], description: 'Random type. Default: int.' },
|
||||
min: { type: 'number', description: 'Minimum value (int/float). Default: 0.' },
|
||||
max: { type: 'number', description: 'Maximum value (int/float). Default: 100 (int) or 1 (float).' },
|
||||
count: { type: 'integer', description: 'Number of results. Max 100. Default: 1.' },
|
||||
items: { type: 'array', items: { type: 'string' }, description: 'Item pool for pick type.' },
|
||||
length: { type: 'integer', description: 'String length for string type. Max 256. Default: 8.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'uuid',
|
||||
description: 'Generate cryptographically random UUID v4 (e.g., "550e8400-e29b-41d4-a716-446655440000"). Uses Node.js crypto.randomUUID(). Supports batch generation up to 20.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
count: { type: 'integer', description: 'Number of UUIDs. Max 20. Default: 1.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'json_format',
|
||||
description: 'Format and validate a JSON string. Returns pretty-printed JSON with configurable indentation. Optionally sort object keys alphabetically. Also works as a JSON syntax validator — returns error details on invalid input.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['json'],
|
||||
properties: {
|
||||
json: { type: 'string', description: 'The JSON string to format/validate.' },
|
||||
indent: { type: 'integer', description: 'Indentation spaces. Default: 2.' },
|
||||
sort_keys: { type: 'boolean', description: 'Sort object keys alphabetically. Default: false.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'hash',
|
||||
description: 'Compute cryptographic hash of text. Supports MD5, SHA-1, SHA-256, SHA-384, SHA-512. Default: SHA-256. Returns hex-encoded digest.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
required: ['text'],
|
||||
properties: {
|
||||
text: { type: 'string', description: 'The text to hash.' },
|
||||
algorithm: { type: 'string', enum: ['md5', 'sha1', 'sha256', 'sha384', 'sha512'], description: 'Hash algorithm. Default: sha256.' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -684,7 +827,7 @@ TIP: Use remove_batch when deleting multiple entries — it's much more efficien
|
||||
const MODE_TOOLS = [
|
||||
'run_command',
|
||||
'write_file', 'create_directory', 'delete_file',
|
||||
'edit_file', 'replace_in_files', 'move_file', 'copy_file',
|
||||
'edit_file', 'move_file', 'copy_file',
|
||||
'download_file', 'compress',
|
||||
];
|
||||
|
||||
@@ -730,14 +873,13 @@ let enabledTools: Set<string> = new Set([
|
||||
'write_file', 'create_directory', 'delete_file',
|
||||
'run_command',
|
||||
'move_file', 'copy_file', 'web_fetch', 'web_search', 'edit_file',
|
||||
'get_file_info', 'tree', 'download_file', 'diff_files', 'replace_in_files',
|
||||
'tree', 'download_file',
|
||||
'read_multiple_files', 'git', 'compress',
|
||||
'memory',
|
||||
'session_list', 'session_read', 'spawn_task',
|
||||
'browser_open', 'browser_screenshot', 'browser_evaluate', 'browser_extract',
|
||||
'browser_click', 'browser_type', 'browser_scroll', 'browser_wait', 'browser_close',
|
||||
'datetime', 'calculator',
|
||||
'random', 'uuid', 'json_format', 'hash'
|
||||
'calculator'
|
||||
]);
|
||||
|
||||
export function setToolEnabled(toolName: string, enabled: boolean): void {
|
||||
@@ -784,11 +926,8 @@ const TOOL_KEYWORDS: Record<string, string[]> = {
|
||||
web_fetch: ['fetch', 'url', '网页', '抓取', '获取'],
|
||||
web_search: ['search', 'web', '搜索', '联网', '查', 'google', 'bing'],
|
||||
edit_file: ['edit', 'replace', '编辑', '替换', '修改'],
|
||||
get_file_info: ['info', 'stat', '信息', '属性', '详情'],
|
||||
tree: ['tree', '结构', '树', '目录结构'],
|
||||
download_file: ['download', '下载'],
|
||||
diff_files: ['diff', 'compare', '对比', '差异'],
|
||||
replace_in_files: ['replace', 'batch', '批量替换'],
|
||||
read_multiple_files: ['read', 'multiple', '批量读取'],
|
||||
git: ['git', 'commit', 'push', 'pull', 'branch', '仓库'],
|
||||
compress: ['compress', 'zip', 'tar', '压缩', '解压', 'extract'],
|
||||
@@ -806,12 +945,7 @@ const TOOL_KEYWORDS: Record<string, string[]> = {
|
||||
browser_scroll: ['scroll', '滚动'],
|
||||
browser_wait: ['wait', '等待'],
|
||||
browser_close: ['close', '关闭浏览器'],
|
||||
datetime: ['time', 'date', '时间', '日期'],
|
||||
calculator: ['calculate', 'math', '计算', '算'],
|
||||
random: ['random', '随机'],
|
||||
uuid: ['uuid', 'guid', '唯一'],
|
||||
json_format: ['json', 'format', '格式化'],
|
||||
hash: ['hash', 'sha', 'md5', '哈希'],
|
||||
};
|
||||
|
||||
/** R55: 根据用户查询语义过滤工具定义,减少 token 占用 */
|
||||
@@ -1611,8 +1745,8 @@ export function getToolIcon(name: string): string {
|
||||
read_file: '📄', write_file: '✏️', list_directory: '📁',
|
||||
search_files: '🔍', create_directory: '📂', delete_file: '🗑️', run_command: '💻',
|
||||
move_file: '📦', copy_file: '📋', web_fetch: '🌐',
|
||||
edit_file: '✂️', get_file_info: 'ℹ️', tree: '🌳', download_file: '⬇️',
|
||||
diff_files: '🔀', replace_in_files: '🔄', read_multiple_files: '📚',
|
||||
edit_file: '✂️', tree: '🌳', download_file: '⬇️',
|
||||
read_multiple_files: '📚',
|
||||
git: '🔖', compress: '🗜️', web_search: '🔍',
|
||||
memory: '🧠',
|
||||
session_list: '📋', session_read: '📖', spawn_task: '🤖',
|
||||
@@ -1620,7 +1754,7 @@ export function getToolIcon(name: string): string {
|
||||
browser_open: '🌐', browser_screenshot: '📸', browser_evaluate: '⚡', browser_extract: '📰',
|
||||
browser_click: '👆', browser_type: '⌨️', browser_scroll: '↕️', browser_close: '❌',
|
||||
browser_wait: '⏳',
|
||||
datetime: '🕐', calculator: '🔢', random: '🎲', uuid: '🔑', json_format: '📝', hash: '#️⃣'
|
||||
calculator: '🔢'
|
||||
};
|
||||
return icons[name] || '🔧';
|
||||
}
|
||||
@@ -1691,8 +1825,8 @@ export function formatToolName(name: string): string {
|
||||
search_files: '搜索文件', create_directory: '创建目录', delete_file: '删除文件',
|
||||
run_command: '执行命令', move_file: '移动文件', copy_file: '复制文件',
|
||||
web_fetch: '网页抓取', edit_file: '编辑文件',
|
||||
get_file_info: '文件信息', tree: '目录树', download_file: '下载文件',
|
||||
diff_files: '文件对比', replace_in_files: '批量替换', read_multiple_files: '批量读取',
|
||||
tree: '目录树', download_file: '下载文件',
|
||||
read_multiple_files: '批量读取',
|
||||
git: 'Git 操作', compress: '压缩/解压', web_search: '联网搜索',
|
||||
memory: '记忆管理',
|
||||
session_list: '会话列表', session_read: '读取会话', spawn_task: '子代理委派',
|
||||
@@ -1700,7 +1834,7 @@ export function formatToolName(name: string): string {
|
||||
browser_open: '打开网页', browser_screenshot: '浏览器截图', browser_evaluate: '执行JS', browser_extract: '提取内容',
|
||||
browser_click: '点击元素', browser_type: '输入文本', browser_scroll: '滚动页面', browser_close: '关闭浏览器',
|
||||
browser_wait: '等待',
|
||||
datetime: '日期时间', calculator: '计算器', random: '随机数', uuid: '生成UUID', json_format: 'JSON格式化', hash: '哈希计算'
|
||||
calculator: '计算器'
|
||||
};
|
||||
return names[name] || name;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user