主对话工具调用
主对话的 run.start 经 Host Runtime 创建会话独立 Agent,向配置的模型发送当前可用工具 schema。DeepSeek adapter 聚合 SSE 工具参数及调用 ID;Host 顺序执行每批调用、逐项回填结果,再继续请求模型。任务默认最多 8 轮,取消或预算耗尽时停止。
文件工具包括 files_list、files_read、files_write、files_search、files_replace、files_mkdir、files_move、files_trash。只有明确授权工作目录或继承可信项目目录的会话才提供这些工具。路径和写入内容在审批前校验,执行时再次检查目录边界。写入仍须批准完整参数;一次审批不能重复使用。内置文件工具不提供任意 shell 或全盘访问。可选的托管技能脚本执行是独立高权限模式,不受项目文件沙箱约束,默认关闭且每次审批。
未知工具、错误参数和执行错误作为带调用 ID 的错误结果回传模型;取消不会当作可继续的工具错误。模型能调整请求,但依然受相同步数预算限制。多个工具串行执行,避免副作用顺序不确定。已请求写入或浏览器工具的失败任务不能自动重试;用户必须检查结果并发送新指令。重启将未完成任务标为中断,不重放工具。
私有模型续传(含 DeepSeek reasoning)仅保存在 Host 私有会话数据中;事件日志与 Renderer 不接收原始推理。界面按调用 ID 显示工具状态,详情可查看参数和结果,成功读写的文件可通过原有授权预览接口打开。
浏览器预览并非 Agent 浏览器控制。用户自行添加并激活的 本地 MCP 服务可提供额外工具,全部逐次审批;Wisp 不内置浏览器自动化服务。
本地验证
pnpm web:simulate 启动明确标识的开发模拟模式,使用真实 DeepSeek adapter、Host 和文件工具,不调用外部模型。详情见现有模拟开发说明。新增协议场景:[demo:multi](双工具)、[demo:escape](路径越权)、[demo:invalid](错误写入参数)、[demo:loop](预算耗尽)。这些脚本场景只属于开发模拟服务,正式 provider 不匹配提示词来伪造执行。
pnpm test 中的 simulation 测试经受限本地 HTTP 接口覆盖读取、批准写入、拒绝无副作用、工具结果续答、取消、模型请求重试不重复写入、会话切换/重启和上述新增场景。项目与路径隔离由 projects/runtime 测试覆盖;adapter 测试覆盖交错 SSE、私有续传及错误边界。
qa.html 的工作台是明确标记的组件样例,审批只更新内存;不能替代真实 Host 或 Electron 实机验证。真实 DeepSeek API 未进行收费验证。
执行层级与网页展示
一条用户请求对应一个 run。模型记录的 step 将过程划分为轮次,工具以调用 ID 关联参数、审批和结果。成功过程默认折叠,最终无工具回复保持主内容;待审批操作不在折叠层内。旧日志可沿用此前模型事件的明确 step,没有轮次证据则标为历史工具过程,不补造思考内容。
open_webpage 是展示工具,不是抓取或浏览器自动化。模型提交完整 HTTP/HTTPS URL,Host 校验并要求用户批准后,向界面发送会话绑定的一次性票据。界面领取票据、复用右侧网页标签并确认接收。工具结果 open_request_accepted 仅代表界面已接收打开请求,不代表加载成功;网页内容和原生/iframe 加载错误仍由现有预览区处理,iframe 可能因站点策略无法显示。
未确认、超时、取消、跨会话和重复票据不会重放打开。票据仅存在内存,不写进恢复快照;应用重启后不自动打开历史工具结果。已接收的网页展示不承诺因随后取消而回滚。
模拟服务新增 [demo:openweb]。QA 工作台顶部的“切换打开网页工具样例”提供独立的 example.com 审批场景;批准才请求展示网页,拒绝不打开,不读写真实文件或调用模型。该样例不是模型执行证明。
搜索、定点修改与目录管理
files_search:path+query+mode: name | content。纯文本、不执行正则或 shell。最多检查 2000 项 / 8 层,单文件 256 KB、总读取 8 MB、输出 100 项 / 24000 字符。默认排除隐藏、符号链接、硬链接、私有目录、二进制及 node_modules/dist/build/coverage/vendor/target。结果含路径、内容匹配行号与片段、truncated/skipped;被跳过的内容不是“没有匹配”。内容搜索结果可在授权文件标签中预览。files_replace:path、oldText、newText和可选sha256。旧段必须唯一匹配,UTF-8 文件与输出最多 200000 字节(片段各最多 50000 字符)。审批展示旧段、新段和摘要。Host 保存原始内容摘要与文件身份;批准后重新校验,过期即拒绝。通过同目录临时文件 + rename 原子替换,保留 UTF-8 BOM。它不支持自动合并或批量多处替换。files_mkdir:创建一个目录,父目录须已存在,不递归扩建、不覆盖。files_move:移动/重命名文件或目录,源/目标均在授权根内且目标不存在。审批绑定整个目录树的元数据指纹(最多 2000 项 / 20 层),含隐藏/链接/私有后代的目录拒绝移动。文件用独占硬链接目标 + 移除源名称,不覆盖目标;目录逐项转移,不是全树原子事务。开始前检查所有源条目与目标父目录的设备号,含空目录或嵌套挂载的跨磁盘移动均拒绝;实际 link 若返回 EXDEV 也不降级复制。失败/取消可能留下部分转移或两侧文件,结果要求人工检查,不自动重试。未完成目录只尝试移除已空源目录,不递归永久删除。files_trash:审批后通过私有 Host IPC 调用 Electronshell.trashItem。桌面端再次校验授权路径和树指纹;当前仅启用 macOS/Windows,Web/Linux 明确不支持。绝不以 rm/unlink 代替废纸篓。用户在系统废纸篓恢复;系统调用开始后无法保证取消或回滚。
Wisp 自身所有文件变更串行执行,防止两个会话同时批准覆盖同一版本。重验覆盖审批等待期间与已检测到的文件变动;Node 的路径式文件 API 不是跨进程文件锁或内核条件替换,不能保证抵御其他本机进程在最后检查与系统调用之间恶意替换路径。不要在敌对进程可同时修改的目录授权这些操作。普通 files_write 仍是明确批准完整内容的覆盖操作,不具备定点替换的内容版本条件。
读取右侧网页
先调用 list_preview_tabs {},再调用 read_webpage(必填 tabId)仅桌面原生网页支持。两个工具均为只读,无需用户审批,不显示确认框。执行时验证当前会话标签身份与导航版本后立即读取。读取票据只驻留内存、5 分钟失效、一次消费,绑定会话、标签与导航版本;导航/切会话/关闭/加载失败/取消均拒绝或丢弃结果。不能读取其他会话的网页。返回不含 URL 查询或片段的链接及不透明标签 ID。
主进程在现有隔离 WebContents 的隔离世界执行固定 DOM 提取函数;沿用该标签自己的登录状态,不访问 cookies、存储、其他标签或任意脚本参数。优先 article/main,退回 body,可见文本最多 24000 字符,最多 60 链接、遍历 20000 文本节点;排除表单、可编辑区域、输入控件、隐藏元素、script/style 和 iframe。非通用阅读器,不能保证抽取所有文章,也不读取跨域子框架。可见正文可能含私人资料;调用此只读工具会将正文送入当前模型续答。正文标记为 untrusted_webpage,模型应当作来源材料而非指令;提取结果与工具历史一样留在本机会话记录,且会用于模型续答。
接口依据:Electron webContents、Electron shell.trashItem。没有给远程网页新增 Node、preload、IPC、权限或证书豁免。
新工具验证与限制
开发模拟服务提供 [demo:search]、[demo:replace]、[demo:mkdir]、[demo:move]、[demo:trash]、[demo:readpage]。前三项和移动走真实临时目录;模拟 Web 的后两项会准确报告桌面能力不支持。集成测试通过注入假桌面服务验证真实 DeepSeek SSE adapter → Host → 审批 → 工具结果 → 模型续答,Electron 提取/导航票据和废纸篓边界另以测试替身验证。它们不是实际 macOS 页面读取或废纸篓验收,也未调用真实模型 API。
qa.html → 对话工作台 → “工具交互样例”可选择替换、建目录、移动、废纸篓和正文读取。文件变更审批延迟约 1.8 秒,支持批准/拒绝;网页只读工具直接执行,无审批卡;所有内容和变化明确是内存样例,不调用 Host、模型或系统废纸篓。搜索样例有可点的内存文件预览。桌面真实页面与系统行为仍需实机验证。
先列标签,再读取指定网页
list_preview_tabs {} 通过实时、一次性 UI 票据获取当前会话右侧所有标签(包括收起的工作区),按 UI 顺序返回 tabId、kind(web/file/new/workspace)、title、active、网页 url 或授权范围内文件相对 path。不返回文件正文、cookies、输入框或其他会话标签;URL 去掉查询参数/片段,内部含路径或 URL 的 UI ID 不交给模型。文件路径再次经过 Host 授权校验。现有 Web 验证入口和 Electron 都实现了列表;Web 不是生产目标,此处仅记录已有行为,不要求后续工具适配纯 Web。
read_webpage {"tabId":"列表返回的网页ID"} 必须明确选择一个网页,可读取非 active 标签。未列出、跨会话、文件/新标签、关闭或过期 ID 拒绝。列表有效期五分钟;工具在执行时再次查询 UI,桌面按原生网页身份及导航版本匹配,身份绑定后的导航/重载/关闭/切换会话也使读取失效。需要重新列出再读取,不会默认回退到当前网页。ID 在同一 Host 生命周期内的连续列表中稳定,重启不恢复票据或自动读取。右侧标签按会话隔离;当前尚不跨应用重启保存原生网页导航历史。
Web 可列出标签,但读取明确返回不支持,绝不绕过跨域 iframe。开发 [demo:readpage] 会先列出再选择一个非 active 网页(若有),无需审批直接读取并把结果送回真实适配器续答;没有网页时只返回列表结果。qa.html 的“读取网页正文”场景先自行打开标签,点击“获取当前标签列表(内存测试)”,再选择网页请求模拟正文读取(无需审批);该场景实时列出真实 UI 标签,正文仅固定测试材料,不代表 Electron 页面提取已实机验证。
工具自省
tool_introspect 只接受空对象 {},无需审批,返回 JSON 数组;每项只有 name、description、inputSchema、requiresApproval。包含工具自身,不读取文件、网页、凭据、环境变量或会话内容。第三方工具的描述和 schema 仍是不可信元数据。
Agent 在 run 开始时获取一次完整工具集合,深拷贝 schema;自省 JSON 与每轮模型请求定义来自同一份元数据。运行中注册表或原对象变化不会更新该快照。没有目录授权时不注入文件工具;网页工具仍会注入,但实际操作须满足对应桌面/标签条件,清单并非环境可用性检查。
新激活或刷新后的 MCP 工具从下一次用户请求生效。已禁用或变化的 MCP 连接仍由原执行校验拒绝调用,快照不授予权限。历史记录只保存普通工具结果,不用于重建或执行新 run 的工具;每个 run 重新捕获快照。
指定标签操作
read_webpage {"tabId":"…"} 保持原有读取契约与免审批策略。新增统一的 preview_tab_action {"tabId":"…","action":"reload|back|forward|close"},先从 list_preview_tabs 获取目标 ID,直接执行,无需工具审批(requiresApproval: false);这不表示动作只读。open_webpage 仍需审批。执行准备绑定当时的标签类型、当前目录/网址和导航版本;实际执行时再次校验,变化即拒绝,需重新列出。未保存内容确认和 beforeunload 不属于工具审批,仍保留。新工具也来自 run 的固定工具快照。
- 网页支持四种动作,前进/后退使用原生历史,无历史返回错误;不会切换到目标标签。
navigation_requested仅表示请求已发送,加载状态和错误见标签,不能作为读取或加载成功证明。 - 文件与目录支持刷新、关闭。刷新在 Host 重新校验当前目录授权,重新读取文件或当前子目录,在同一标签回填;内容不会通过动作结果发给模型。编辑中、加载中或保存中的面板拒绝工具操作,避免丢弃草稿。
- 空白新标签只支持关闭,没有内容可刷新。关闭活动标签正常选取邻页,关闭后台标签不改变选择。
- 网页关闭先显示原生未保存内容确认,默认保留;随后调用
webContents.close({waitForBeforeUnload:true}),不自动接受页面的卸载请求。由于嵌入视图的 unload 行为有版本差异,保留这层明确原生确认;取消返回cancelled,不假称关闭成功。当前手动关闭与窗口退出的旧路径未在本轮重构。 - 票据仅驻留内存,一次领取、一次执行;取消、超时、切会话、历史恢复不能自动重放。已经发送的导航或关闭不可回滚;失去界面回执时报告状态未知,不自动重试。过期/已关闭 ID 要重新列出,不会按标题找另一个标签代替。
Electron 是生产目标。原生导航、关闭确认和 beforeunload 的真实表现仍需 Electron 实机验收;协议/模拟 Electron 测试不是实机证明。纯 Web 不提供这些工具的生产降级。
UI 验证:qa.html → 对话工作台样例 → 工具交互样例 →「标签操作(内存模拟)」。在工作区打开文件/目录/新标签,获取列表,选目标与动作,发起后直接执行,无审批卡。文件刷新回填明确的内存文本;关闭使用真实标签 reducer。Web 网页导航会明确报不支持,不伪造历史/加载成功;原生关闭确认不在 Web 样例模拟。