fix: complete runtime and workspace workflows

Restore Ask workspace reads and output paging without granting write access,
and let programming Subagents reuse their parent's browser page. Allocate
browser resources only when used, keep Agent pages aligned with workbar tabs,
recover released bindings, and remove unused automatic screenshot work.

Preserve inherited Runtime selections during remote usage persistence and
manual compression. Keep viable channel model fallbacks, display the actual
scheduled-task mode and Harness model source, and avoid rediscovery delays
when calling healthy MCP tools. Fix directory/history refresh, case-only
renames, rename-aware commit diffs, and FastGPT probe success reporting.

Add regression coverage and align feature documentation. The Agent-side
connection timeout fix requires deploying an updated Agent; existing Ask
read-only and Execute authorization boundaries remain unchanged.

Final validation: 3839 tests passed, 66 skipped; typecheck, lint, development
build, and diff checks passed. Isolated Electron UI/MCP workflows passed with
a loopback model fixture. Current-source Linux x64 Host checks passed with
three successful real model requests. Chromium loadURL rejection was not
reproduced in the UI; released-binding recovery has automated coverage.

Release note: 修复 Ask 读取项目文件、浏览器页面显示与恢复、文件管理及模型配置跟随中的不一致,并减少无用截图和 MCP 等待。定时任务显示实际工作模式,远程会话可正常保存继承 Runtime 的用量;远端连接超时修复需更新 Agent 后生效。
This commit is contained in:
mesalogo
2026-09-10 12:48:30 +08:00
parent 020a9ad0dc
commit c037d7fb20
62 changed files with 2637 additions and 521 deletions
@@ -76,6 +76,9 @@ Record<ConversationId, Record<BrowserTabId, BrowserLiveState>>
非活动 Browser Tab 保持页面和状态,但隐藏 `WebContentsView` 并停止非必要画面采集。工作栏
收起、切换主页面和窗口隐藏时采用相同规则,不销毁 Tab。
普通导航、快照与页面操作只同步轻量导航状态,不自动截图、等待画面或传输 JPEG;只有显式
`browser_screenshot` 调用生成图片。侧栏内终端关闭确认显示期间,同样隐藏原生浏览器视图,
确认或取消后恢复当前实例,避免原生子视图遮挡 HTML 确认按钮。
浏览器应用声明 `visibleAcrossContextSwitches: true`,打开的 Tab 跨项目、会话切换继续显示。
切换活动 Conversation 不改变当前选中的浏览器或其 `targetRef.conversationId`;用户在会话 B
@@ -84,6 +87,11 @@ Record<ConversationId, Record<BrowserTabId, BrowserLiveState>>
Tab 的跨会话可见性与 MCP 授权分开处理。B 的请求不能选择属于 A 的可见 Tab;A 已取得的
capability 在用户切到 B 后仍固定路由至 A 的原 Tab,使用租约也继续阻止关闭该 Tab。
内部点击实例只同步应用类型,不再次按当前 Conversation 改选实例。Main 状态携带对应的
`workbarInstanceId`,Renderer 据此绑定请求创建的同一 Tab,而不是另建空白页。收到 `stopped`
后清除该实例的旧 Tab 绑定,下一次使用通过原逻辑实例重新创建,保留地址草稿与错误反馈。
请求创建的实例也遵守现有 32 个工作栏页签上限;满额时保留 Main 页面及其状态,并就地提示
关闭一个可关闭页签。释放位置后再绑定该页面,不写入超限布局或丢弃 Agent 页面。
## 5. IPC 与服务接口
@@ -116,7 +124,12 @@ Browser Tab。
1. 当前可见且绑定该 Conversation 的 Browser Tab。
2. 该 Conversation 的 `primaryTabId`。
3. 新建一个 primary Browser Tab。
3. 预留 primary Browser Tab 身份,首次实际浏览器操作时才创建页面与 Conversation Context。
未使用浏览器的请求只持有随请求释放的内存预留,不创建 Chromium 资源、不触发浏览器 UI、
也不占用活动浏览器会话名额。物化后使用同一 Tab 身份和工作栏实例归属;取消、能力撤销及
服务关闭释放未使用的预留,不保存到磁盘。编程 Subagent 继承父请求的 Browser Tab 与浏览器
Conversation 归属,不新建租约或把页面重新归属到子级对话。
直连模型上下文和请求级 MCP capability 同时保存 `conversationId` 与
`boundBrowserTabId`。请求执行期间,用户切换、创建或关闭其他工作栏 Tab 不改变工具目标;
+4 -1
View File
@@ -403,6 +403,7 @@ Renderer 不接收任意系统 PID 控制能力。控制动作引用 Main 签发
支持方向键、Home、End 和 Escape,Escape 或选定操作后焦点返回触发按钮,删除入口独立分隔。
菜单提供重命名、移动、删除、属性、复制路径和本机默认应用打开;删除须明确确认对象
与不可恢复性。操作失败保留输入与上下文。本机和远程均支持文件管理,系统默认打开仅本机可用。
重命名允许仅修改同一目录项的名称大小写,不得覆盖另一个已存在的文件、目录或硬链接目录项。
移动通过与创建项目相同的目录选择流程指定目标:本机打开系统目录选择器,远程浏览当前
SSH Host 的目录。选择目录后保留原名,确认后执行;取消不移动文件。目标限于当前工作区,
选择外部目录时在弹窗内说明限制,不切换项目或工作区范围。取消按钮使用共享次按钮样式,
@@ -416,6 +417,8 @@ Renderer 不接收任意系统 PID 控制能力。控制动作引用 Main 签发
- FR-W6:Git 工作区底部提供默认收起的提交历史区,独立滚动,可调整高度。按当前分支
分页读取提交,展示摘要、作者、时间、短 OID 和 refs。选中提交显示该次修改文件,
再选文件进入内联提交 Diff;逐层返回保留分支、分页、选择、滚动位置与焦点。
提交 Diff 保留重命名前后路径和实际内容修改;后台工作区刷新不得使正在加载的历史或详情
永久停留在忙碌状态。
历史展开入口使用带方向箭头的紧凑列表行;提交行沿用文件列表的表面、悬停和焦点样式,
摘要与元信息左对齐分行展示,长内容省略并提供完整提示,不撑宽侧栏。
- Git 错误和无更改提示只在 Git 工作区显示,不阻断文件浏览。
@@ -429,7 +432,7 @@ Renderer 不接收任意系统 PID 控制能力。控制动作引用 Main 签发
- 文件预览提供复制项目相对路径、刷新,以及仅本机项目可用的“使用默认应用打开”。
刷新失败保留此前内容并显示错误;Markdown 默认渲染预览,可切换源码。
- Diff 提供刷新、复制项目相对路径和“查看当前文件”;删除项不显示查看当前文件入口。
- 手动刷新或任务结束更新 Git 状态时,同步重读根目录和已展开目录,保留目录展开状态,
- 手动刷新或任务结束更新 Git 状态时,同步重读根目录、当前浏览目录和已展开目录并去重,保留目录展开状态,
刷新失败保留已有目录列表;重新展开目录时重读。目录读取错误在对应目录旁显示,
可就地重试。正在查看的单文件 Diff 同时重读,旧请求不得覆盖新结果。
无首次提交的仓库也应显示新增和暂存文件。
@@ -1,5 +1,47 @@
# 工作栏实现与验证进度
## 2026-09-10 提交审查修复
- [FR-W3、FR-W6](./prd.md#76-工作区):同一目录项可仅修改大小写,仍拒绝覆盖其他文件、
目录和硬链接目录项;提交 Diff 同时使用重命名前后路径;分支后台刷新不再使历史请求
遗留 busy;自动目录刷新包含当前浏览目录并去重。
- 浏览器请求仅预留目标身份,首次导航才创建实际资源;Main 状态携带工作栏实例身份,
Renderer 直接绑定同一页面,停止或回收后清除旧绑定。跨会话显式选择不会被应用类型
同步覆盖,终端关闭确认期间释放原生浏览器 viewport。规则以
[浏览器多实例技术设计](./browser-tabs-technical-design.md) 为准。
- 删除普通浏览器操作的自动截图、固定等待、重试及 JPEG 状态缓存/IPC 字段,保留显式截图。
- 整合复核补齐现有 32 页签容量处理与 Harness 代理的已发现工具复用。新增容量回归验证
满额时布局仍有效、页面保留,关闭一项后显示原页面;Harness 回归验证发现接口后续失败时
已知工具调用不再触发发现。相关三文件 66 项通过,最新 typecheck 与 lint 通过。
- 工作区聚焦测试 43 项通过、2 项需大小写敏感文件系统而跳过;IPC 与 Sidebar 聚焦回归
132 项通过。随后新增的 Ask 指令、继承 Runtime 用量持久化及计划模式 App 场景,3 项通过。
- 扩展真实 Electron/MCP E2E 在独立临时 profile 通过:四个未使用的请求预留不创建会话、
WebContents 或 UI 事件;首次 MCP 导航物化相同 Tab/工作栏身份,恢复不额外创建页面,
并验证独立页面、共享 Cookie、请求租约关闭保护和清理。
- 当前源码的共享 Linux x64 Host 验证已通过,覆盖工作区目标保护和重命名/Git Diff,
并通过桌面托管 ACP → 隔离 Agent → OpenCode 完成 Ask/Execute 和继承 Runtime 指标持久化;
该组共 3 次真实模型调用,清理后无所属进程残留。完整记录见
[远程 Host 开发验证](../remote-host/technical-design.md#agent-开发期间的真实-host-验证)。
- 最终整库 `npm test` 为 341 个文件通过、9 个文件跳过,3839 项通过、66 项按平台或手动
条件跳过、0 失败;`npm run typecheck`、`npm run lint`、开发期 `npm run build` 和
`git diff --check` 通过,19 份修改 Markdown 的相对链接目标检查通过。
先前整合中的一轮为 3823 项通过、6 项失败、66 项跳过,另有被移动的测试路径加载失败,
不作为最终结果;源码稳定后完整重跑得到上述全绿结果。
- 原文档解析焦点回归改为等待 Modal 的焦点效果,保留焦点与背景隔离断言,没有改动产品逻辑。
- Windows 独立 Electron profile 的完整 App → Preload → Main UI 验证通过;最终复测使用
本轮最终开发构建。启用浏览器后普通 Execute 没有创建原生浏览器视图,工具导航只创建
一张同时显示在工作栏的页面,跨会话选择保留原页面与 viewport。
- 实际终端连通后,从浏览器关闭该终端可正常显示确认并操作按钮;原生视图可见性按
可见 → 确认时隐藏 → 取消后可见变化,终端关闭清理完成。无效地址 `http://` 被拒绝后,
原控件可重试有效地址并关闭页面;关闭端口返回了过滤代理错误页,因此该 UI 场景不作为
Chromium `loadURL` 拒绝的实机证据。服务与 Renderer 释放绑定回归另有自动测试覆盖。
- 桌面使用确定性 loopback 模型服务驱动真实生产路径,共 24 次本地 completion 请求,
未发出外部模型请求;可选真实 Provider 探针没有找到已加密保存的 OpenAI 兼容文本连接,
未据此宣称桌面真实模型验收通过。Ask 与编程 Subagent 的桌面结果见
[直连模型验收记录](../direct-model-agent/progress.md#2026-09-10-提交审查后的桌面-ui-验收)。
测试应用与具名浏览器会话已退出,所属 Electron/Node 进程及 fixture 监听端口均为 0;
临时截图和隔离 profile 保留在本机测试目录,不进入仓库。
## 2026-09-10 固定基础页签与浏览器多实例
- 工作栏注册表已分别声明实例策略、默认上下文、默认打开、必须存在、可关闭和排序属性。
+5 -8
View File
@@ -92,14 +92,11 @@ Linux x64 和 Linux arm64。
### P0:右侧没有浏览器实时画面,已修复
浏览器窗口默认使用 `show: false`,但 BrowserService 现在从模型实际操作的同一
会话捕获页面帧,并通过受限 IPC 发送状态、当前 URL 和约 220KB 的 JPEG 画面。右侧工作栏
新增“浏览器”页签;活动对话启动浏览器时会自动打开该页签,并显示创建中、
加载中、操作中、用户交互中、就绪、失败和已停止状态。用户可点击“交互”打开
同一会话的子窗口辅助 Agent;交互时主窗口暂时禁用,关闭时先刷新最终画面再将
浏览器窗口最小化,页面和会话继续保留。用户也可明确关闭当前对话的浏览器会话。
当前实现按导航、快照、点击、输入、选择、返回和截图操作刷新画面,而不是创建
第二个预览浏览器,因此显示内容与模型受控页面一致。
早期版本通过同一浏览器会话的 JPEG 帧提供预览。当前工作栏直接嵌入 Agent 操作的原生
`WebContentsView`,不再自动截图或传输预览帧,也不再用独立交互窗口阻塞主界面。
页面显示、标签页归属、失败重试和显式截图的当前规则统一见
[浏览器多实例技术设计](../assistant-workbar/browser-tabs-technical-design.md);
该路径的最新验证证据见[工作栏进度](../assistant-workbar/progress.md)。
### 已实现:浏览器工具栏
@@ -381,6 +381,9 @@ GoodBuddy conversationId -> Harness sessionId + process generation
- 工作区不是 containment 边界;绝对路径和命令可访问当前用户本来有权访问的主机资源。
- 已启用插件注册的工具与内置工具使用同一分发路径;GoodBuddy 不增加插件权限矩阵或逐工具确认。
- Main 代理的 MCP 工具继续执行分配、schema、活动请求、模式和 RuntimeAuthorizer 校验。
`goodbuddy/tools/list` 按 Session 保存本次发现的工具定义;`goodbuddy/tools/call` 复用该定义
校验参数与授权,不因调用健康工具而重新等待故障 MCP 的发现。发现重试留在清单刷新,
Session 释放及 Runtime dispose 清除内存定义,不持久化第二份能力状态。
- 所有工具调用仍作为活动事件记录;Ask 和 delegation 路径继续固定拒绝。
### 10.4 Runtime OS 沙箱
@@ -446,8 +449,17 @@ DeepSeek Harness 首版只使用符合下列边界的 GoodBuddy 模型连接:
任意 Body 配置入口,因此 DeepSeek Harness 不接收自定义 Body。完整支持矩阵和合并规则
见[模型连接请求定制](../model-connections/technical-design.md)。
- API Key 继续保存在 GoodBuddy 加密设置中。
- 启动环境提供的部署连接只由 Main 自动解析,不在 Renderer 中显示为可选来源。
- 未显式指定 Harness 模型且没有可用的管理员预置连接时,Main 优先使用当前默认的兼容 GoodBuddy 模型连接;默认连接不兼容时使用首个兼容连接。只有不存在任何兼容连接时才提示用户前往模型或 Runtime 设置。
- `platform` 在设置页显示为“管理员环境优先,回退 GoodBuddy 兼容连接”,不是 Harness
自有配置文件。Main 优先读取完整的 `GOODBUDDY_MODEL_BASE_URL`、
`GOODBUDDY_MODEL_NAME` 和 `GOODBUDDY_MODEL_API_KEY` 环境预置;不完整时使用
当前默认兼容 GoodBuddy 连接,再回退首个兼容连接。
- `default` 只跟随 GoodBuddy 默认兼容连接或首个兼容连接,跳过独立管理员预置;
`profile` 使用指定的兼容连接。没有兼容连接时,仍允许选择 `platform`,因为完整
管理员预置不依赖已保存连接的协议;运行时缺少实际连接才报告不可用。
- Renderer 通过 Main 的只读平台来源投影展示实际管理员模型或兼容回退,不读取环境
或密钥,也不根据 `credentialSource` 猜测。投影直接复用本节所述的生产 resolver,
字段、非持久化与草稿展示边界见
[Harness 平台来源公开投影](../model-connections/technical-design.md#9-harness-平台来源公开投影)。
不允许选择 Harness 自有的用户配置文件或自定义 Host。Runtime 始终使用随当前 GoodBuddy 版本发布的内置 Host,并通过完整内部能力握手。
@@ -55,6 +55,9 @@
工具清单隐藏不是最终授权边界。`callTool` 仍须重新验证 Runtime、工作模式、执行空间和父请求
是否活动,以拒绝旧快照或伪造调用。
FR-4 / FR-12 / US-B0:Ask 工作区搜索和读取不依赖知识库、联网搜索或委派开关,不需要
切到 Execute 或额外批准。MCP 服务器失败也不改变本机只读工具的可用性。
`output_read` 在直连模型拥有进程或 Subagent 服务时提供,Ask/Execute 均可用,不取决于
本轮 Shell 可用性、是否允许再次委派或委派深度。读取只接受当前会话的句柄;其他 Runtime
不注册该工具,调用边界同样拒绝。
@@ -148,6 +151,8 @@ type SubagentDelegateResult = {
- 子级不能请求更高模式。
- 子级使用父请求开始时的工具与能力快照;运行中设置变化不重写快照。
- 子级调用 MCP、浏览器或知识能力时继续经过这些能力已有的作用域和生命周期边界。
- FR-5 / FR-7 / US-C1:Execute 子级使用父请求的浏览器标签页,不另开标签页或改变所有权;
子级结束后父模型仍可继续操作该页,父请求继续负责其使用租约。
- Execute 子级不弹出额外的“Subagent 执行授权”,也不获得父级没有的 MCP 分配。
## 9. 并发和顺序
+34 -1
View File
@@ -18,7 +18,20 @@ DeepSeek Harness 和托管 SSH 路径不注入这些工具。既有功能的 Win
全量项目验证已通过;本次分页验证记录见下方 2026-09-10 条目。macOS 与 Linux 真机验证
仍需由对应平台完成。
## 已确认的当前基线
## 2026-09-10 提交审查后的桌面 UI 验收
- Windows 隔离配置使用本轮最终开发构建,通过普通输入框发送触发完整
App → Preload → Main → ModelAgentRuntime → ModelToolProvider 路径。
- Ask 在已保存 `toolApproval: policy` 下完成实际 `workspace_read_text` 与 `workspace_rg`,
读取同一专用哨兵,24 字节测试文件与校验值保持不变。未放开 Ask 写工具。
- 父请求调用实际编程 Subagent;子级在父浏览器归属下完成导航和快照,子级页面显示在
父级工作栏 Tab,没有额外空白原生页面。
- 本组使用确定性 loopback 模型服务,不声称执行了桌面真实 Provider 推理。
请求计数、浏览器/终端 UI 场景、明确覆盖边界及清理结果统一记录在
[工作栏验收进度](../assistant-workbar/progress.md#2026-09-10-提交审查修复)。
- 最终整库回归与静态检查结果同见该记录;测试进程已退出,不改变用户安装版或工作区。
## 设计前基线(历史)
- [x] 直连模型当前内置工作区读、目录列表和文本写入,但没有进程工具。
- [x] 内置 MCP 当前没有 Shell;自定义 MCP 不能替代开箱即用的进程能力。
@@ -203,6 +216,26 @@ DeepSeek Harness 和托管 SSH 路径不注入这些工具。既有功能的 Win
- 本目录中文文档已按 `deai-writing` 审校,扫描阻断项为 0;保留技术枚举、权限限制和历史
验证记录中的明确边界。本次未运行全量测试或生产构建,也不作为其他平台真机验收。
## 2026-09-10 直连工具接线回归修复
- FR-4 / FR-12 / US-B0:普通 Ask 不再依赖可选能力才进入工具循环;明确允许工作区搜索、
文本读取和当前会话输出续读绕过 Ask 默认拒绝 authorizer,保留写入、补丁、进程和浏览器
的 Ask 拒绝。内部无工具摘要路径不变。
- FR-5 / FR-7 / US-C1:编程 Subagent 继承父浏览器标签页及所属 Conversation;子级历史和
输出仍独立,浏览器资源不转移所有权。回归通过真实 Runtime、Provider 和 Subagent 服务,
浏览器使用校验父 Conversation/标签页身份的测试替身,并确认子级结束后父级可继续调用。
- MCP 已发现工具调用不再触发其他失败服务器的发现重试;覆盖连接失败、清单失败、动态
刷新失效、健康调用、配置替换与 dispose 清空。发现重试仍只发生在下一次 `listTools`。
- 验证命令:`npm test -- --run src/main/agent/model-tool-provider.test.ts src/main/agent/model-runtime.test.ts`。
最终结果为 `122 passed, 1 skipped`(Provider 36;Runtime 86 通过、1 跳过)。
Ask 回归实际执行随包 ripgrep、工作区分页读取和真实本机输出续读;模型响应均为测试夹具。
- 本次真实模型调用精确为 0,没有外部网络或远端 Host 操作;未运行全量测试、类型检查、
Lint 或构建。桌面 IPC 提示词、浏览器租约生产入口和最小真实模型验收由集成工作继续验证,
以上聚焦测试不作为真实浏览器、真实模型或整条桌面路径验收。
- 源码检查:GoodBuddy Agent 不导入这两个 Runtime/Provider;本机 DeepSeek Harness 的
MCP 代理复用 Provider 发现快照规则,托管 SSH Runtime 不经过该本机构造路径。本次未
修改远端 Agent、桥接或启动器。
## 进度维护要求
- 只有真实生产路径完成并验证后才能勾选实施项。
@@ -280,6 +280,10 @@ type DirectModelSubagentContext = {
- 子级复用父 Provider;Main 写入的 `delegationDepth=1` 同时在清单和调用边界过滤
`subagent_delegate`。
- Ask 子级使用 Ask 清单;Execute 子级使用 Execute 清单。
- Execute 子级经 `ModelSubagentRequestContext` 继承父 `browserTabId` 和浏览器所属
`browserConversationId`。后者只在 Main 内部请求与工具上下文中传递:浏览器操作使用父
Conversation,历史与分页输出仍使用子 Conversation。子级不新建标签页或申请使用租约,
结束时只释放自己的临时会话,父标签页和租约仍由父请求生命周期管理。
### 7.3 调度和结果
@@ -327,6 +331,25 @@ type ModelToolCallContext = {
- `releaseConversation` 取消并释放该会话拥有的浏览器、Subagent 和进程。
- `dispose` 等待有界清理,不因模型或子进程不响应而阻塞应用退出。
### 8.1 Ask 工具循环
普通 Ask 请求进入工具循环,不再依赖知识、联网搜索或 Subagent 是否启用。Runtime 对
`workspace_rg`、`workspace_read_text`、`output_read` 三个明确只读工具免去 Ask authorizer
调用,避免生产 authorizer 的默认拒绝使已列出的只读工具无法执行。Execute 仍沿用既有
authorizer;补丁、进程和其他写入不因此获准。Provider 按清单和调用边界继续校验模式,
浏览器工具不加入 Ask 免审批集合。内部上下文摘要使用 `noModelTools`,保留无工具问答路径。
### 8.2 MCP 发现与调用
`listTools` 发现 MCP 并保存当前绑定快照;已知工具调用只查该快照,不在每次调用前重试
其他失败服务器。未知名称直接失败。失败服务器只在下一次发现入口重试,动态清单刷新失败
时从新快照中移除该服务器工具,下一次发现再刷新;健康连接继续复用。
绑定只在 Provider 内存中存在,`dispose` 与连接缓存一起清空。MCP 配置保存通过
`refreshCapabilities → onRuntimeSettingsChanged → reconfigureRuntimes` 替换 Runtime,
`SelectedRuntimeManager.reset` 使后续请求创建新 Provider;退役 Runtime 按原有会话生命周期
清理。没有新增持久缓存、失败重试日志或配置兼容层。
DeepSeek Harness 的 Main 工具代理必须使用仅包含分配 MCP 和 Web 的 Provider 视图,不能因为
共享 `ModelToolProvider` 类而自动看到直连模型编程工具。
@@ -88,6 +88,7 @@ Given 直连模型在 TLS 建连、网络传输或单次请求超时时失败且
Given 用户在 Ask 或 Execute 中处理本机项目,When 模型需要定位代码或读取大文件,Then
它可以使用随包 ripgrep 搜索内容或列出文件,并按行分页读取命中位置,不要求用户预装 `rg`。
Given Ask 未启用知识库、联网搜索或编程委派,Then 工作区搜索和读取仍可使用,不要求额外批准。
### US-B1 修改后运行验证
@@ -126,6 +127,8 @@ Given 用户选择 Ask,Then 补丁工具不出现在清单中且伪造调用
Given 父直连模型正在处理复杂请求,When 它调用 `subagent_delegate` 并给出独立任务,
Then 子级使用同一项目、模型连接和 Execute 能力完成工作,And 最终结果返回父模型综合。
Given 父请求已有浏览器标签页,When 委派任务需要浏览器,Then 子级使用同一页;子级完成后,
父模型仍可继续操作该页,不因子会话清理而关闭父页。
### US-C2 Ask 中只读委派
@@ -621,6 +621,15 @@ node scripts/external-knowledge-probe.mjs --extended --output=<report.json>
Rerank、RAGFlow GraphRAG 和 Knowledge Compilation 检索。脚本只有固定 GET/POST 读取与
检索端点,不实现或调用远端创建、更新、上传和删除。
FastGPT 报告将请求成功与命中数量分开:HTTP 必须成功、业务 `code` 必须为 `200`,
且 `data` 或 `data.list` 必须是数组,才记录 `success: true` 和 `count`。成功的空数组
记录 `count: 0`;HTTP、业务、响应结构、JSON 解析或网络失败记录 `success: false` 与
固定失败类别,不用零命中代替失败。目录失败时不继续调用详情和检索。
`features.searchModes` 只包含基础检索实际成功的模式;`rerankProbed` 表示实际尝试,
`rerankSucceeded` 单独表示成功。历史基线保留原始证据,不追填未观测的成功字段。
`tests/external-knowledge-probe-fastgpt.test.ts` 使用内存 fetch fixture 运行真实 CLI,
覆盖错误、成功零命中和非空结果,不连接外部知识服务。
### 14.7 CRUD 验收边界
| 对象 | Create | Read | Update | Delete | 验收方式 |
@@ -12,6 +12,10 @@ Provider 要求的附加元数据;GoodBuddy 只在直连链路或 Runtime 明
| [技术设计](./technical-design.md) | 契约、持久化、合并优先级、Runtime 支持矩阵和验证 |
| [功能进度](./progress.md) | 已验证实现、剩余工作和验证证据 |
模型连接选择准确性也在本目录维护:技术设计第 8 节定义通道直连回退修复,
UI 设计末节定义 Harness 来源标签和公开设置展示;Harness 的实际解析顺序由其
[技术设计](../deepseek-harness/technical-design.md#121-配置来源)唯一维护。
本次改动是现有模型连接的有界扩展,不新增独立业务对象或工作流,因此不单独建立 PRD、
User Stories 和逻辑设计;本页定义产品边界,技术设计定义唯一的请求合并规则。
@@ -1,5 +1,23 @@
# 模型连接请求定制进度
## 2026-09-10:配置准确性修复
- 通道直连回退修复已按[技术设计第 8 节](./technical-design.md#8-通道直连模型选择修复)
实现;测试把修复结果交给现有 Main resolver,不仅断言返回对象。
- Harness 设置使用专用来源标签、关联帮助及 Main 直接从生产 resolver 派生的只读
`deepseekHarnessPlatformModel` 投影;准确区分完整管理员预置、兼容回退和无连接,
不再从通用环境凭据状态推断。投影不含地址、密钥或请求定制,也不写入设置文件。
- 无兼容连接时管理员来源仍可选择;未保存候选与实际已保存来源分别展示。UI 验证涵盖
中英文、兼容默认、首个兼容回退、管理员覆盖、部分环境回退、无连接、草稿预览和保存动作。
- 聚焦命令 `npx vitest run src/main/agent/runtime-selection-contracts.test.ts src/renderer/src/SettingsPanel.test.tsx`
对应的两个文件在本次五文件联合运行中全部通过,共 96 项。真实模型调用 0 次;
本次未运行全量测试、typecheck、lint 或真实 Harness 请求。
通道修复集成测试随后归入 Main 测试目录,避免 Shared/Web 类型项目导入主进程实现。
- 后续聚焦验证 `npx vitest run src/main/runtime-settings-store.test.ts src/renderer/src/SettingsPanel.test.tsx`
全部通过:2 文件、181 项。Store 覆盖完整、部分与旧环境变量、默认/首个兼容回退、
无连接、精确字段白名单、非持久化以及不改变所选来源。真实模型/Host 调用均为 0;
未运行全量测试、构建、typecheck 或 lint。
## 2026-09-03
### 已完成
@@ -85,3 +85,33 @@ JSON 对象,标准认证 Header 也由 schema 拒绝。
Utility 启动配置和 Pi-AI Provider 配置。
- 远程:Main/Agent 网关合并、认证优先级、摘要绑定、大小限制和不重放。
- UI:默认值、保存、无效 JSON 保留和 Runtime 支持说明。
## 8. 通道直连模型选择修复
`repairChannelRuntimeSelection` 只在默认连接可用于文本通道时保留动态
`{ provider: 'model' }`。默认连接为图像生成、API Key 认证但明确缺少凭据,或默认 ID
已不存在时,若找到可用文本连接,修复结果必须携带该连接的 `profileId`,使后续
`applyRuntimeSelection` 使用已验证回退,而不是重新解析到不可用的全局默认值。
已有可用显式引用保持不变;没有可用连接时不虚构 ID 或声称可运行。
共享回归测试将修复结果直接传入 Main 的生产 resolver,验证动态默认、显式固定、
图像默认、缺少凭据和失效默认 ID。该修复不改变 OpenCode、Continue 或托管 SSH 的
Runtime 选择路径。
## 9. Harness 平台来源公开投影
`RuntimeSettings.deepseekHarnessPlatformModel` 是可选只读元数据,描述 `platform`
选项在当前已保存模型设置与管理员环境下的实际解析结果:
- `{ source: 'environment', name, modelName }`:使用完整管理员预置。
- `{ source: 'profile', profileId, name, modelName }`:使用兼容 GoodBuddy 连接回退。
- `{ source: 'unavailable' }`:没有可解析的连接。
Main 的 `toPublicSettings` 复用 `resolveDeepSeekHarnessModelProfile`,只在调用中将来源
设为 `platform`,不改变用户已保存的 `default`、`profile` 或 `platform` 选择。投影逐字段
构造,不包含地址、API Key、自定义 Header/Body 或凭据状态,不写入设置文件、迁移或新状态。
公开契约保持可选,缺失时 UI 明确来源信息不可用,不从通用模型或环境凭据猜测。
`source: 'profile'` 描述来源分支,不代表凭据来源:仅环境密钥或旧环境变量可能仍影响该
GoodBuddy 连接,但不会被误报为完整管理员预置。连接解析不代替真实模型请求或可用性测试。
UI 的未保存兼容候选只作草稿预览,保存后继续以 Main 返回的投影为准。
@@ -36,3 +36,20 @@ OpenCode 与 DeepSeek Harness 不使用该值。
- 无效状态不能只依赖颜色,必须同时提供错误文字和 `aria-invalid`。
- 文本域遵循标准键盘编辑、选择、复制和粘贴行为;保存继续使用设置页唯一的主保存操作。
- 焦点边框、字体、间距、颜色和深浅主题全部复用全局语义令牌。
## Harness 模型来源展示
DeepSeek Harness 的 `platform` 选项命名为“管理员环境优先,回退 GoodBuddy 兼容连接”,
不能沿用 OpenCode/Continue 的“Runtime 自有配置”标签。来源规则以
[Harness 模型配置](../deepseek-harness/technical-design.md#121-配置来源)为准。
帮助文字与选择器通过 `aria-describedby` 关联,并明确此选项不加载用户 profile 或
配置文件;无兼容 GoodBuddy 连接时仍可选择管理员环境来源。
概览使用 Main 提供的[平台来源投影](./technical-design.md#9-harness-平台来源公开投影),
明确显示实际管理员预置模型,或“未配置完整的管理员预置”及已保存兼容回退的名称与模型;
没有可解析连接时显示明确空状态,但保留 `platform` 选项。不得从通用模型名称或
`credentialSource` 猜测管理员来源,也不得显示密钥或读取 Main 环境。
没有管理员覆盖且草稿兼容候选发生变化时,额外显示“草稿兼容候选(未保存)”,保留实际
已保存来源;草稿失去兼容连接时也明确说明。管理员覆盖生效时不把草稿回退显示为实际模型。
保存完成后以 Main 重新解析的投影刷新概览。
@@ -302,6 +302,10 @@ Execute 直接启动已签名 Runtime:
时提交 Task 终态;事务成功后生成器才继续并向 Agent ACK。断电发生在同一 sequence
中间时会重读该 sequence,已写事件按 `(binding, operation, sequence, eventIndex)` 去重,
未写事件继续归并,不会重复 Provider 或工具执行。
- 远程 context metrics 与对话级压缩后的估算值按本次请求实际使用的 Runtime 选择写入
`context_state_json`。实时接收与恢复入口都传入请求的选择;数据库在未传入时按对话、
项目、auto 顺序解析。继承项目设置的对话保持 `runtime_selection_json = NULL`,
不为接收 usage 固定对话 Runtime;去重和消息/指标写入仍在同一 SQLite 事务中完成。
- ACK 后 Agent 删除已确认事件,只保留小型操作终态与游标用于幂等核对;未 ACK 输出继续
保留。Main 按 transcript page 的最高连续 sequence ACK,终态仍立即 ACK。单事件、单页、
单 Prompt 总字节和事件数都有上限;Agent 始终为唯一终态预留一个事件和最大事件字节,
@@ -360,12 +364,28 @@ Execute 直接启动已签名 Runtime:
- Unix socket 接收端按 `readableLength` 中已经缓冲的字节增量排空一个声明长度的帧,
不会在部分大响应到达时反复请求尚未缓冲的完整剩余长度;短读、连接结束、错误和取消
都会使当前交换失败。原生 Linux 回归覆盖至少 256 KiB 的 broker 响应。
- Unix broker 的请求超时 `0` 表示不设置请求总时限,不等于零毫秒连接等待。
连接仍有独立的默认 5 秒超时;只有显式正数请求时限才与连接时限取较小值,
用户取消仍关闭连接并中止 dispatch。
- Renderer 把相邻 text/reasoning delta 合并为消息 block 时始终替换最后一个 block,
不修改既有 React state 对象。这样开发环境 StrictMode 重复调用 state updater 时,
block metadata 与 canonical 消息正文保持一致。
## Agent 开发期间的真实 Host 验证
本轮 `020a9ad` 工作树修复使用当前源码在共享 Linux x64 Host 验证:默认 Unix broker
完成 256 KiB 响应并传递取消;生产 AssistantDatabase 在临时库中写入继承项目的指标,
重开后去重重放,未固定对话选择。当前 Workspace 协议的目标存在/同名/硬链接重命名
保护、字面路径 diff、重命名 diff 和 merge commit diff 均通过,Git 使用 Host 已配置身份。
当前 Desktop `createManagedRemoteAcpRuntime` 经真实 SSH attach、隔离 Agent、OpenCode
和 Agent gateway 完成 Ask 与 Execute,均得到两字符回答和 done。Execute 的真实
model-usage 转换为指标后通过生产数据库持久化与去重,继承设置保持未固定。
共 3 次真实 Provider 调用(2 次 Ask、1 次 Execute),均 HTTP 200、completed 且已交付;
前两次运行在模型完成后被测试 harness 的 usage 元数据/事件名断言拦截,并非产品失败。
未修改产品来适配 harness:构建时直接解析 ACP SDK 的 ESM 入口,凭据只通过既有
safeStorage 与模型控制协议使用。各次隔离 Agent 停止后剩余所属进程数为 0,测试目录和
上传文件均已回收,原 Host registry 与已安装组件未改变。此次不覆盖 UI 点击或安装升级。
2026-09-10 已发布模型桥兼容修复:从 `agent-v0.11.22` 读取的源码与当前源码分别在共享
Linux x64 Host 启动隔离 Agent daemon。当前 Main 的 `createManagedRemoteAcpRuntime`
经真实 SSH attach、Agent protocol、OpenCode 和 Agent gateway,在两版 Agent 上各完成
@@ -160,6 +160,10 @@ GoodBuddy Desktop · 项目工作目录
已保存计划中的旧工作模式和 Runtime 字段不再控制执行;用户在关联会话或项目中调整配置。
会话任务详情中的模式与执行来源保持一致:从未运行的计划显示关联会话当前有效模式;
已开始或已结束的 Task 显示该次执行记录的实际模式,不被计划旧字段或会话后续切换覆盖。
缺少实际模式记录时明确显示不可用,不从旧计划字段推断。
### 6.3 审批
- 使用普通会话的授权和提问流程。Agent Runtime 的 Execute 工具调用无需通用 GoodBuddy 审批,工具活动仍显示在会话中。
@@ -116,6 +116,9 @@ Task 行只显示聚合后的用户状态,不要求用户理解内部 Job/Run
选择 Task 后显示名称、模式、聚合状态、计划、下次执行、最近结果和 Task 级操作。工具、审批、
错误和成果通过 Task 关联显示,但不暴露 Job/Run 层级。
模式来源遵循[Scheduled Task 的执行时配置](./scheduled-task-prd.md#62-执行时配置):
未运行计划跟随会话当前有效模式,已执行 Task 保留实际模式;计划旧值不得覆盖展示。
## 8. 删除关系
- 删除 Schedule 只停止后续触发,不删除 Task、Conversation 或历史。