Files
goodbuddy/docs/features/assistant-workbar/runtime-process-reuse-technical-design.md
T
mesalogo b90ff50f2a fix: reduce supervisor stalls and preserve task delivery
Load Supervisor graphs only when opened, preserve source details on demand, reuse indexed story digests and window selection lists without losing keyboard or focus behavior. Route heavy UI reads through the existing worker, batch scoped queries and construct each publication snapshot once.

Keep remote cancellation responsive during model-route cleanup, remove late routes and retain reported usage after response-cap cancellation. Preserve Telegram pending replies through polling conflicts, show delivery errors and honor the final rate-limit cooldown.

Schema 62 adds lookup indexes without rewriting user content; older clients cannot open upgraded data. Large review publication still blocks Main and remains documented follow-up work. Record the future storage-service direction without performing the architecture migration.

Validation: exact staged code passed isolated full tests (6212 passed, 87 skipped), typecheck and lint. Three-round source performance comparisons, SQLite migration equivalence, native Electron interaction checks and current-source Linux x64 Host validation completed; eight external text-model requests.

Release note: Supervisor opens reviews without loading the entire graph, keeps long selection lists responsive and preserves details and keyboard navigation. Remote cancellation and Telegram reply recovery are more reliable; remote fixes require an Agent build containing this change.
2026-10-05 14:18:33 +08:00

35 KiB
Raw Blame History

Runtime 进程复用技术设计

1. 状态与结论

项目 内容
状态 已接入本机与 Agent 生产源码,Windows / Linux x64 验证结果及边界已记录,未发布
日期 2026-09-15
调研源码 de14a6157a6c34f1e3ef22619eca374a50a83706;相关 Runtime 与 Desktop 0.13.2 一致
需求 工作栏 PRD §14.1,FR-RR1–FR-RR6
行为规则 Runtime 资源生命周期
验证事实 实施与验证记录,原始调研记录保留在同页

修复对象是进程所有权过细,不是工具太多,也不是历史记录应该删除。 本机 OpenCode 和 DeepSeek Harness 应在兼容启动配置内共享重型进程,工作区与会话上下文仍各自独立。 远端 OpenCode 必须同时调整 Agent 进程所有权、ACP 连接和模型桥,不能把桌面修复当作远端 修复。Continue 的锁定版本是单会话 Host,不做未经验证的常驻进程池;直连模型没有独立 模型进程,应检查对象、历史和工具资源的生命周期。

“一个进程”指一组兼容启动配置对应一个 Runtime Server/Host,不是把不同 Runtime、 不同 SSH 账号、不同插件组合强行塞入一个进程。正常工具命令产生的短期子进程不属于重复 Server,也不能通过关闭 Shell、子代理或 MCP 来达成进程数指标。

2. 修复前证据与缺陷

2.1 已测现象和解释边界

Windows 已安装 0.13.2 的只读采样发现两个属于同一 App 的 OpenCode Server:一个原生 数据库为 0 Session / 0 Message,约 527 MiB Private Commit;另一个已有会话并执行请求。 两个 Server 的启动工作区不同。源码能解释“清单查询也可启动按工作区缓存的 Runtime”, 但没有取得能独立证明空 Server 最初由哪一个 UI 操作启动的调用链记录。

该缺陷不等于整个 App 内存的唯一来源。五分钟活跃采样的 App 相关进程 Private Commit 约 3.15–3.78 GiB,CPU 平均占整机约 3.15%;后续一分钟包含新任务,不是空闲回收试验。 数据库五分钟增长约 2.72 MiB,新增子代理负载约 1.49 MiB,重复工具 upsert 为 0。 schema 35 的存储修复与本方案独立,不能回退或删历史来改善指标。

同次源数据检查还发现最近 100 个会话的消息 metadata 合计约 107.75 MiB, listConversations() 会读入这些会话的全部消息详情。它是 Renderer 大对象加载的明确 检查方向,不是堆快照已经证明的泄漏。进程复用不能代替历史按需加载的独立性能工作。

2.2 调研基线的源码归属

位置 已确认行为 修复含义
SelectedRuntimeManager 缓存键包含原始 selection 与 execution-space identity;默认 8 个缓存、16 个保留实例;只在容量压力下淘汰 轻量工作区适配器和重型进程不能继续按同一键、同一数量计费
AgentRuntimeController canRetire 同时要求无请求、无 owned conversation;普通完成不移除会话所有权 不能把“已完成请求”和“已释放原生会话”混为一谈
本机 OpenCode 对象私有 Server/client/初始化 Promise;已有多会话映射;多个入口使用固定 defaultWorkspace 仅删除 manager 的 workspace 键会把后续操作送进错误目录
DeepSeek Runtime 每对象一个 Utility Host;getStatus() 调用 getState() 启动 Host manager 的临时状态实例会额外启动、探测并销毁 Host
Harness Host、控制面 根 Provider 有 cwd 默认值;控制面拒绝与 Host workspace 不同的 newSession.cwd 限制主要在 GoodBuddy 创建入口,不是原生工具缺少会话 cwd
Continue Host Adapter 每次 run 启动临时 Host,最终 /exit 与进程树回收;准备结果已在 adapter 内缓存 不重复添加已有缓存;研究跨 adapter 重复准备,不直接共享活动 Host
直连模型 Main 内 HTTP;历史 Map 按 50 个会话限制,其他归属及工具资源依赖 release/dispose 没有可合并的常驻模型子进程,按对象和资源检查
远端 ACP、Agent backend 会话取得 binding/channel;backend 按 binding 拥有进程并拒绝跨 binding 复用 process identity 必须拆开会话绑定与进程所有权
Agent-owned Prompt、模型桥 owner 一个 ACP connection/session/当前 operation;helper 固定模型和工作模式并串行 dispatch 共享进程还要求会话路由、请求归属和取消隔离

原始 selection 的 auto、默认 profile 和显式 profile 可能解析为同一有效配置。当前 已确认“先按原始 selection 建键、后解析配置”的顺序,但尚未证明全部 UI 调用会实际生成 等价重复实例。实施时从 runtime-selection 和调用者验证,不把可能性记为另一次生产复现。

2.3 锁定依赖与协议基础

以仓库 lock 和本机已安装代码为准,不用最新网页替代锁定版本:

依赖 基线 本次核验
OpenCode binary / SDK / plugin 1.18.29 HTTP API 接受 directory;ACP 接受多个 Session;chat.headers 有 sessionID
ACP SDK 0.25.1 一条连接关联多个 request ID,session notification/permission 带 sessionId
DeepSeek Harness 包族 0.1.2-rc.1 Agent factory/scoped context、Session header.cwd、真实文件与 Shell 工具
Cordis 4.0.2 Host 根组件与 Agent scope 的生命周期
Continue CLI 1.5.47 实际受管补丁入口的单 M.session、QuizService 和权限状态

本表保留进程复用探针执行时的版本。2026-09-26 DS 已升级为 0.1.7-rc.2, Cordis 为 4.0.4;当前依赖及升级回归见 DS 实现进度。

已通过的三个隔离探针:

  1. OpenCode HTTP:调用当前生产 Server launcher,只有一次 spawn;同一个 SDK client 在两个目录创建四个 Session,读取各自的同名文件;删除一个 Session 后其余三个仍可取回。 没有调用 Runtime.run、模型或活动取消。
  2. DeepSeek 工具:当前 Host composition 和真实 Agent factory 在同一 Node 测试进程中 创建两个不同 cwd 的原生 Agent;并行执行真正的 read、write 和 PowerShell, 同名相对路径各自命中正确目录。另确认生产控制面仍拒绝第二工作区。没有启动 Electron Utility、ACP Prompt 或模型流,不能据此声称生产多工作区已经可用。
  3. 原生 ACP 与模型归属:Windows 上一个 1.18.29 opencode acp 进程、一条 ACP connection、两个工作区 Session;分别选模型并发出并行 Prompt。本机确定性 HTTP 服务收到两次请求,原生 chat.headers 插件传来的 sessionID 分别匹配两个 Session。 不经过已发布 Agent backend/helper,没有测试真实工具、子代理、Linux 或断线恢复。

三个探针真实模型调用均为 0,其中第三个有 2 次本机合成提供方请求。 它们证明方案有原生基础,不替代后文的真实开发任务验收。

特别纠正:dsh-tool-fs 将 exec.agent.session.header.cwd 传给 fs.resolve; dsh-tool-bash / dsh-tool-pwsh 也从 Session cwd 补全相对 workdir。 dsh-fs-local / 本地 Shell 的根 cwd 是非会话调用的默认值,不是工作区隔离边界。 不需要为这个已具备的能力新建一套“每工作区 Filesystem/Shell Provider”。

官方背景资料:OpenCode Server、 DeepSeek Harness、 Continue CLI。 网页只用于核对产品入口;上述版本结论来自本地锁定代码和探针。

3. 选定的结构

3.1 两层对象,不建立通用进程池框架

SelectedRuntimeManager
  -> 轻量 Runtime adapter(有效 selection + execution space)
       -> OpenCode process owner / Harness Host owner(兼容启动配置)
            -> Session binding(execution space + conversationId)
                 -> 当前 requestId / 原生 sessionId / 工作目录
  • 保留 Main 已解析、校验的 execution space;adapter 每次将其显式交给共享 owner。 目录不是 Renderer 新增的任意启动参数,也不依赖 process.chdir 或进程级可变 cwd。
  • owner 持有唯一启动 Promise、client/connection、子进程、会话映射与关闭逻辑。两个 工作区同时冷启动时复用同一 Promise;一个调用者取消等待不取消其他使用者的启动。
  • adapter 的 dispose 只释放其引用,不直接关闭同组进程。会话映射由 owner 持有,避免 adapter 缓存淘汰丢掉原生续接。会话操作通过 binding 查目录,不从“当前选中项目”反查。
  • 设置重建沿用现有 reset/drain:新请求取得新配置,旧请求持有启动时的配置直到结算。 旧配置不再有在途使用者后释放旧绑定和进程,不能被历史会话 ID 永久钉住。 IPC 的 Runtime 设置、定制及能力更新不再主动取消全部请求或清空审批;controller 退役仍允许回答其已拥有的问题,但拒绝新请求和未知问题。 既有专家调度器仍在配置替换时取消专家子任务,团队父请求一起停止,防止用新模型 汇总旧 generation 的部分结果;不为该单独生命周期新建通用退役框架。
  • 8/16 的旧上限不应继续限制轻量项目 adapter 数量。若保留重型 owner 的容量保护, 应统计实际进程配置组及退役进程;不靠提高常数掩盖“一项目一进程”。
  • 只用进程内 Map、现有 controller、Promise 和普通定时器。会话历史仍以现有 SQLite / Agent transcript 为准,不增加数据库表、迁移、持久化池快照、恢复日志或新配额。

3.2 兼容键与上下文

先通过 applyRuntimeSelection 等现有解析取得有效配置,再生成进程键;公开的 selection 仍按现有语义保存,不能把“跟随默认”永久改写成某个显式 profile。

范围 参与进程兼容性 留在会话/请求
本机 OpenCode 本机账号、二进制身份、有效模型连接/配置、启动环境、原生配置和插件组合 目录、conversation/session、Prompt、模式、当前权限和问答、请求级 MCP/知识 token
本机 Harness Host/依赖版本、有效模型连接、图片能力、凭据引用、启动环境、启用插件及配置、启动 Skill 集合 cwd、conversation/session、请求模式、Main Web/MCP 代理与用量归属
SSH OpenCode 已有 Host/SSH 身份、Agent/Runtime installation identity、模型协议/连接、原生插件与启动配置 Workspace、binding/session、operation、请求凭据和账本归属

第一轮只合并同一有效模型连接及等价默认选择,不顺便支持任意不同模型连接共享: 本机 OpenCode 配置使用固定 provider ID,Harness 用量也读取 Host config,跨 profile 混用会引入另一项真实风险。不同 profile ID 不通过比较或序列化明文 API Key 来合并; 密钥、Header 和插件配置更新通过现有设置失效路径使旧 owner 退役。

调研基线的 SSH launch profile 曾把 workMode 写入原生启动配置。当前源码已从启动、 Session 和 Prompt 路由删除产品模式,按实际能力和请求归属接入工具,详见 §6.1; 不向用户增加逐工具审批。

4. 本机 OpenCode

在 opencode-runtime.ts 中抽出重型 owner, 由 create-runtime 的 Main composition 复用。 保留工作区 adapter,逐项替换隐式 options.defaultWorkspace:

  1. create/get/delete Session、Prompt、历史初始化和压缩。
  2. 原生能力、工具、文件、Skill、MCP 查询的 directory。
  3. SSE 订阅、父子 Session 归属、待答 question 的 directory 与原生 ID。
  4. 权限更新、abort、问题答复/拒绝、MCP 临时注册及最终清理。

会话绑定记录规范化绝对目录及原生 sessionId。同一 conversation 的请求继续串行, 不同 conversation 并行,不引入覆盖整个 Server 的 Prompt 队列。 取消或失败时,每次请求只发送一次会话级 abort,并在该调用结束后才释放会话锁,避免 迟到的 abort 中断下一条请求。abort 使用既有控制请求超时;失败或超时后移除对应绑定, 下一条请求创建新 Session。这也适用于配置外部 OpenCode HTTP Server 的路径;托管 SSH 使用独立的 ACP 取消路径。 现有 snapshot: false 必须保留。

提交 Prompt 的 Promise 与 SSE 消费同时运行。提交返回错误、抛错或控制请求超时后, 立即中止本请求的 SSE 订阅并保留提交错误;不能等待服务端为未接受的 Prompt 发送 session.idle。回收仍先 abort 订阅再结束迭代器,随后完成该 Session 的有界取消, 不关闭其他会话的订阅或共享 Server。生产运行不增加整个 Prompt 的默认总时限。

mcpMutationTail 目前属于 Runtime 对象;共享后同一原生目录的变更必须由同一 owner 串行协调。注册名称、工具可见性、knowledge token 和清理仍按请求区分,不能用一个全局 “当前 MCP 列表”覆盖同目录或跨目录的其他请求。探针未覆盖动态 MCP,这是实施验收项。

第一轮保留现有按请求消费事件流和结束清理的方式,扩展目录及 Session 过滤即可。 只有测出重复 SSE 消费是瓶颈时才另做 owner 级事件分发,不同时引入第二套事件总线。 健康检查也读取 owner 的总 activeRequests,不能从一个空闲 adapter 判断整个 Server 无任务后重启。异常退出使该 owner 的全部绑定失效,明确结算受影响请求,不重放已执行工具。

4.1 本地 MCP 初始化失败恢复

桌面 HTTP 工具网关保持监听,MCP 注册和授权仍按请求创建、清理。本地 OpenCode 的内置 工具和自定义 MCP 共用连接逻辑:仅对明确的连接拒绝、连接重置、断管或传输超时,在 一秒内成功断开失败连接后重试一次。SDK 返回的无 HTTP response 网络错误和抛出的网络 错误采用同一判定;HTTP/API 错误、鉴权或协议错误、未知失败不自动重试。 取消立即终止后续尝试。Prompt 和工具调用不重放。

自定义 MCP 上游发现由 KnowledgeMcpGateway.getCustomMcpBindings 按服务隔离失败。 某个服务连接、列举或校验工具失败时,记录脱敏诊断并跳过该服务,保留正常服务的连接; 全部失败时返回空的自定义工具列表,Continue 和内置 OpenCode 仍可开始回复。 首次发现的结果在当前授权内复用,初次失败的服务在下一次请求创建授权时重试。 动态刷新失败会清空该服务的工具列表,下次发现时再刷新,不阻断其他服务。 请求取消和授权撤销仍终止操作,工具总数和名称冲突检查保留。发现仍等待连接尝试结束, 因此连接超时可能延迟首个回复;失败隔离不等于后台加载。

OpenCode 1.18.x 的 mcp.add 在服务端独立执行:客户端超时或取消不会中止初始化, disconnect 也只清理当时已登记的连接。晚到的初始化完成后会按名称写入状态,并关闭同名 的现有连接。因此,mcp.add 未得到 HTTP 响应(抛错、超时、取消或无 response 的网络错误), 或断开未确认成功时,该名称即作废;同一槽位之后改用本客户端内唯一的替代名称 (前缀加 8 位 base-36 序号,仍为 12 个字符)。槽位随请求结束释放,不因断开失败而长期占用。 已得到响应的正常失败继续复用原名称。

界面显示有界、脱敏的失败详情。runtime.mcp.failed 诊断记录连接或断开阶段、失败类别、 耗时、尝试次数、内置或自定义类型及可用的 HTTP 状态;通过本轮令牌的 SHA-256 摘要与 网关鉴权、初始化和工具发现失败记录关联。日志不保存令牌、地址、请求正文或原始错误。 网关初始化抛错时也清理未完成会话,防止失败会话累积。

此恢复逻辑属于本地 OpenCodeRuntime。远程 Agent 使用 RuntimeAcpBackend 和 AgentImageToolMcp,不经过本地 MCP 注册或网关 HTTP 处理;本节不代表远程恢复能力。 远程 Story Graph 通过网关的独立绑定调用,不经过上述自定义 MCP 发现方法。

5. DeepSeek Harness

5.1 共享 Host 的最小改法

  • 将 HarnessState、Utility 启动 Promise、ACP connection 和事件路由提升到兼容配置 owner;Runtime adapter 保留请求工作区。
  • 每个新 Session 在 Main 解析 realpath,Host 校验绝对路径格式, 不再要求它等于 Host 启动工作区;meta.cwd 传入已有 Agent factory。 不依赖 Windows 大小写字符串猜测,也不取消路径存在性校验。
  • 保留一个本地 Filesystem、Subprocess 和平台 Shell Provider。Session 使用原生 cwd 路由;非 Session 的清单查询显式传入查询工作区,不能回退到第一个项目。
  • 保留 setup(agentCtx) 注册 Skill 和工具视图、每 Session 的请求归属校验、 sessionId + requestId 准备及事件路由。Main 的 Web/MCP callback 按对应请求找 ToolProvider,不挂到某个最先创建的 adapter 上。
  • 第一轮保持同 profile、图片能力和插件组合共享,queueUsage 的模型配置因此仍一致。 给用量加跨会话断言,不借本次改造扩大跨模型 Host 能力。

第三方插件的初始化可能依赖配置中的路径,不能因为内置工具支持 cwd 就声称所有插件 天然多工作区安全。已启用插件组合属于进程配置;对实际产品支持的插件验证它使用 Agent scope/Session cwd。若某插件确实有项目级初始化状态,将该状态显式作为不兼容 启动配置,不默认给所有工作区各起一套 Provider 或禁用工具。

5.2 状态与取消

被动 getStatus 改为已有 owner 快照或本地配置/Host 资源检查,不调用 getState()。 没有启动过时不能写“握手已验证”,可表示资源已安装、尚未连接。 状态检查不取得执行引用,也不清除或重置无会话 owner 的空闲计时;owner 已回收时, 临时配置检查对象用完即释放,不将其登记成新的执行 owner。 用户显式连接测试与原生清单可启动共享 owner;已有 owner 时只做有界控制检查,最终 释放的是检查引用,不能在 finally dispose 掉仍服务其他会话的 Host。

当前取消超时会 terminate 整个 Utility。共享后先取消并释放目标 Session 的 Agent / 工具资源,不因一个请求结算较慢就杀掉仍健康服务其他 Session 的 Host。若真实控制面 已失去响应,保留整个 Host 的有界终止,向受影响会话分别报告中断;不得把它说成 “取消完全不影响其他任务”。同步插件卡死的进程级故障无法在同一 JS 进程中强行隔离, 不为此新增通用恢复框架。普通长工具取消与整 Host 故障必须分开测试。

6. SSH OpenCode 与 Agent

本节定义当前源码的共享进程改造;当前已发布版本仍见 远程技术设计。不能删除或绕过其持久 binding、 operation、transcript、ACK 和模型 dispatch 结果不确定性规则。

6.1 连接与所有权

将 RuntimeAcpBackend 的进程 owner 与 binding 分开:

Agent 当前 Runtime installation + 兼容配置
  -> 一个 process owner / 一条 ACP ClientSideConnection
       -> sessionId -> binding -> 当前 operation / 原始 Prompt Promise
  • 一条 stdio 流只交给一套 ACP decoder/connection,不能让几个 ClientSideConnection 竞争读取同一 stdout。消息和 permission 按 sessionId 分派给 binding 的当前 operation。
  • AgentAcpConnection 统一连接级握手、stdio 解码与退出监听,Prompt 生命周期仍留在 binding。同一 Session 串行,其他 Session 不等待它完成。
  • closeAcpChannel、取消和 release 只释放所属 binding/Session;以活动 operation 判断共享进程是否空闲,最后一个任务结束即回收,不因历史 binding 保留进程。 待答问题仍占用活动 operation。关闭 Session 时等待原生 closeSession 和原始 Prompt 结算,不等待排在 backend 控制队列后面的完成回调。只有原生控制面不响应时才有界 终止共享进程,并向其余请求报告中断,不声称这类故障可以逐 Session 隔离。
  • terminal 与物理进程状态分开:取消/失败的 Session 也可返回 processTree: running,表示进程继续服务其他 Session,不能伪报进程树为空。 Desktop 与 Agent 须使用配套的新契约;原始字节透传 binding 仍保留独占进程规则。
  • 共享 stdio owner 不使用单 Prompt 的累积输入和墙钟期限管理整进程;单次写入、 待写队列、输出背压继续有界,Prompt 输入与截止时间由 binding 管理。
  • SSH attach 仍不拥有活动 Prompt,断线不能取消或重发 Agent 已接受的工作。 历史 binding 的语义和原生 sessionId 保留;内存进程索引从当前安装和已有绑定得出, 不增加第二份持久进程恢复账本。
  • 同一 PID 的多个 binding 不代表同一权限或同一 operation。Host/installation identity 变化仍使用已有失效和退役规则,不把不同 Host、账号或 Runtime generation 合并。

runtime/startPrompt 校验及 owner 登记经过 backend 控制队列,原生握手、Session 创建/恢复和模型路由准备在队列外等待。协议接收端也不等待该 RPC 的最终响应才分派 后续帧;未完成的响应继续占用已有 request channel,沿用连接通道容量限制及 FIFO 写入。其他方法的分派顺序保持不变,Prompt 终态仍经 backend 控制队列提交。 同一 binding 的相同启动请求共用 Promise,内容不同的并发启动返回冲突。

启动等待属于 Session owner,可以被取消、启动 watchdog 或关闭中断。取消后不得 发送 Prompt;原生调用迟到返回的 Session 只关闭自身,不能回收仍服务其他 binding 的共享进程。原生握手本身仍由进程 owner 共享,一个等待者退出不取消其他等待者。

模型路由撤销不等待原生 HTTP 响应后才释放 backend 控制队列;broker 关闭、凭据释放 及 terminal 提交仍按原顺序执行。启动准备保存原 transport 和取消 signal,安装完成时 若已取消,按原 Session/operation 再撤销一次,避免早先清理被迟到安装覆盖。撤销沿用 helper 的 operation 匹配检查,不删除同 Session 的其他 operation。HTTP 沿用 10 秒 超时,进程退出或 transport dispose 中止未完成请求;无需新的持久状态或协议阶段。

原生 chat.message 在模型请求前设置该 Session 的工具与模型路由,不再按产品模式 过滤 Shell、编辑或写入;请求级端点与子会话归属仍独立。 OpenCode 1.18.29 的 ACP 不转发未注册子 Session 的权限请求,且原生子代理只继承父 Session 的拒绝规则、不继承允许规则,因此子 Session 也按根 Prompt 设置规则,再 保留原生子代理的显式限制。不能只把进程启动配置统一设成 ask,否则子代理工具会等待。

6.2 模型桥归属

选用锁定 OpenCode 已有的 chat.headers 会话标记,扩展当前受管 原生插件,不靠解析正文、猜测 “当前最新 Prompt”或重写用户模型名来路由:

  1. 现有 Agent prepare/start 顺序在 helper 的进程内登记 Session/根 Session 与 binding、operation;插件从原生 sessionID 及已建立的父子关系取得精确归属。
  2. 在请求生成时固定所属 operation,将有界内部归属 Header 加到 loopback 模型请求。 归属必须覆盖原生子代理、自动/手动压缩,不能等 HTTP 到达后才绑定“目前活动的请求”。
  3. helper 检查它是否仍属于已登记的 Prompt,选择对应现有 Agent gateway/凭据上下文。 转发真实提供方前剥离内部 Header;不将其当作密钥或新增认证体系。
  4. 当前 helper 的单 socket/全局 dispatchBusy 改成按 operation 隔离的派发状态; 每个 operation 的现有轮次、顺序、字节和结果不确定性规则不变,取消 A 只关闭 A 的 提供方流,不关闭 B 的 socket、response 或待处理请求。
  5. Prompt 终态撤销对应映射及凭据;迟到请求不能借用下一轮 operation。保留 snapshot: false、关闭不消费的 title 请求和现有父子问题转交。

普通 ACP 双 Session 的 Header 路由已有探针证据;子代理、压缩和终态竞态的实际 验证结果以进度记录为准。若锁定版本某条实际调用路径不触发 hook,先定位那条原生路径, 不得悄悄用全局串行 Prompt 或一个共享凭据槽冒充并行复用。 内部桥字段如需调整,按既有受管 Agent/Runtime 版本配套交付,不移动发布标签,不给 旧 Agent 宣称具备新行为。

6.3 恢复与终态投影

  • Agent-owned 语义 Prompt 不一定产生原始 ACP journal 行。binary replay 仍校验现有 cursor 边界,但不存在 raw cursor 时不向 journal ACK 0;不虚建记录来满足 replay。
  • 同一 Agent 断线恢复后,保留的 Session binding 使用新 transport generation, Runtime 可以同时接纳新 Session。安装身份已经更换的 attach-only 请求明确失败, 不能无限重试阻塞项目,也不能借此重发旧 Prompt。
  • Desktop 重启时,同项目的可恢复任务并行附加,不能等待一个待答 Prompt 结束才附加 第二个。live question/question-resolved 不属于有 provenance 的 transcript, 使用既有 pending Map,清除时只影响对应 request/question。
  • conversations.list 将恢复租约的 request/message ID 和待答列表投影为可选 activeRequest,Renderer 合并表单并使 Stop 指向真实请求。保存 header/消息时不保存 这个实时字段。回答/跳过成功由 Main 按 task → assistant message 归属更新既有 answeredQuestions,不写另一份问题日志,不覆盖流式正文、已完成或失败状态。
  • 明确确认的取消使用现有消息/任务终态事务一并结算,避免 Task cancelled 而消息仍 streaming。仍无法确认的 Stop 保持可恢复;连接中断本身不是已取消或已失败的证据。

7. Continue、直连模型与相邻内存问题

7.1 Continue

保留每请求 Host 的隔离和最终清理。1.5.47 的单 Session、QuizService/权限队列意味着 “一个 HTTP Server”不等于可安全承载多会话;这一例外有锁定源码依据。

getPreparedHost() 已缓存本 adapter 的准备 Promise,磁盘也有按内容确认的补丁产物。 先分别测量读取/哈希/补丁准备、Utility 启动、HTTP ready、首个提供方请求和退出耗时。 若确认跨 adapter 重复准备明显,再将只读准备结果与启动 Promise 按已验证的 CLI identity/补丁版本放到 Main composition 复用;失败仍允许重试。不得复用临时 config、 token、global dir、活动 Session 或权限/问题队列。设置替换及窗口状态刷新也纳入测量。

不在本次给 Continue 加多 Session 补丁或常驻池。将来只有锁定版本真正支持多 Session 且生产桥验证通过,才替换这一实现。

7.2 直连模型及历史详情

  • 不新增模型 Utility 或进程池。检查 conversations、knownConversationIds、 summary、ToolProvider 与 DirectModelProcessService 的实际引用与 release 调用链。
  • 活动请求、会话可续读的有界输出和数据库历史是不同资源。请求结束回收临时闭包/ callback;会话释放才结束其可续读输出和工具资源,不在工具刚完成时删掉用户可查看结果。
  • 当前 50 个会话的 history 限制不是字节上限。先采堆与 retained size,再决定可从 SQLite 重建的历史缓存是否使用字节约束和 LRU,不能先增加一套持久历史副本。
  • Renderer 整包 metadata 加载是独立于进程复用的性能工作。现有实现改为列表摘要、 打开会话时读取完整历史,不截断已保存消息;搜索、复制、续聊、后台活动和缓存释放 规则见会话列表读取与前端保留。 不将这项后续修改的收益计入原进程复用对照结果。
  • 旧 Runtime 磁盘缓存可单独评估版本清理策略,不在本次研究或进程 idle 时删除安装、 用户工作区、数据库、备份或历史。

8. 内部实施顺序

阶段 具体工作 必须产出的证据
P0 固化本次原生探针为聚焦回归;补有效 selection/进程计数和状态启动计数 修复前能复现重复启动,失败原因不依赖真实用户配置
P1 Main composition、兼容键、owner 与 adapter 生命周期;本机 OpenCode 全入口目录化 真实 UI 两项目四会话同一 Server,文件/工具/问答/取消不串线
P2 DeepSeek 共享 Utility、会话 cwd、被动状态、请求级代理及取消收敛 实际 Utility/ACP 两项目四会话,原生工具与插件验证,状态刷新无额外 Host
P3 Agent process/session owner、ACP 单连接路由、Header 模型桥、权限和终态清理 开发中的真实 Linux x64 Host,含多会话工具、断线/重连和结果不确定性
P4 全 Runtime 资源回归;Continue 冷启动分解与有证据的准备复用;直连对象释放检查 相同输入的前后进程/内存/CPU/磁盘/延迟报告;没有残留测试进程

这是依赖顺序,不是发布一半实现的许可。涉及的正常生产 UI 路径、远端专用修复和下节 验收全部完成后,才能称为 Runtime 复用修复。Continue 测量若没有显示重复准备成本, 明确记录不改;不要为凑齐阶段增加代码。历史 UI 分页是后续独立工作。

9. 验收与性能比较

9.1 必测场景

编号 对应需求 场景与通过条件
V1 FR-RR1、FR-RR2 全新 profile 仅查看状态、切换设置,OpenCode/DSH 重型启动次数为 0;已有 Host 时刷新不新建;清单与首个真实请求并发只有一次初始化
V2 FR-RR1、FR-RR3 同一有效模型连接,两个独立项目各两会话同时自然开发,OpenCode/DSH 各一重型进程;各项目同名不同内容文件、命令 cwd、Git/测试结果都正确
V3 FR-RR3 第二轮复用同一批会话;不同能力分配不串用,无产品模式或一般审批;Skill、MCP、图片能力、用量和业务问答不串归属
V4 FR-RR3、FR-RR4 一会话取消真实长工具/子代理时另外三会话完成并通过独立项目测试;分别检查请求 abort、SSE、问题映射和工具句柄释放
V5 FR-RR4 关闭面板不取消工作;释放一个会话不关闭共享进程;无会话 owner 空闲后退出;App 退出后本机受管进程无残留,远端按已有 detach 规则保留 Agent-owned 工作
V6 FR-RR1、FR-RR4 等价默认/显式选择复用;不同实际连接/插件配置不串用;配置更新期间旧请求完成,旧 generation 不永久积累;超过八个项目不因轻量 adapter 报重型容量满
V7 FR-RR5 当前源码 Desktop → SSH → 当前开发 Agent → 原生 Runtime,两个项目/四会话;断线、重连、取消、重复 ACK/事件、迟到模型请求不重复调用或跨 operation 归账
V8 FR-RR6 Continue 并发请求仍各自正确清理;直连 HTTP 不生出额外模型进程;会话 release 后工具/分页输出资源释放;性能采样不靠删除历史或禁用工具达标

V2/V4 必须是正常开发任务,模型可自然调用读写、Shell、测试和已支持的原生子代理; 不是要求模型“不用工具”后回复一行。验证产出应用本身可运行、独立测试通过,模型口头 说完成不算完成。每个 Runtime 只验证它已经支持的能力,不伪造 DSH/Continue 子代理。

9.2 采样口径

  • 使用同一源码变更前后、同一机器、隔离 profile 与等规模历史副本;不改写用户运行库。 覆盖至少三次冷启动、五次热请求,以及三轮多项目任务和至少十分钟确无新任务的 空闲观察。分别记录中位数、范围与实际样本数,不从一次采样推断泄漏已消失。
  • 记录 Main、Renderer、Runtime 和工具子进程的 Private Commit、工作集/RSS、堆、 CPU、PID/启动次数、会话数、活动请求、SSE/ACP 订阅与残留句柄。Windows 工作集求和 会重复计算共享页,Private Commit 也不等于独占物理 RAM。
  • 同时报首轮准备、HTTP/ACP ready、首个模型请求、首次可见输出和总耗时。降低进程数 但把不同会话全局串行化,不能通过验收。
  • 数据库/WAL 字节与新增事件负载分开;进程 I/O 包含管道,不能称为物理磁盘读写。 继续检查未变化工具 upsert 为 0,旧历史读取/搜索/展开正常。
  • 核心硬指标是每个兼容组一重型进程、无额外被动启动、无跨会话错误、无结束后持续 增加的活动句柄、无重复提供方 dispatch。没有证据前不承诺“固定省 527 MiB”或 “整个 App 降到某个 RAM 上限”;原生 Session 仍保留时必须单独说明其常驻成本。

9.3 源码与平台验证

定向覆盖 manager/controller、各 Runtime lifecycle、Harness Host/control plane、 ACP backend/owner、模型桥与插件,随后执行仓库要求的 npm test、npm run typecheck、 npm run lint;生产构建改动在开发阶段按仓库规则构建验证。

凡改变 Agent 或桌面到 Agent 路径,必须在开发期间按 真实 Host 验证规则 使用当前源码的共享 Linux x64 Host 验证。Windows 原生 ACP 探针、旧版本 Host、mock、 CI 和将来发布测试都不能替代它。Windows PowerShell 与 Linux Bash 的工作目录及取消 分别验证;macOS/Linux arm64 生命周期与原生依赖由可用原生平台和 CI 补齐并明确报告。

当前源码的真实 Linux Host、完整生产 UI 和最终整仓门禁结果均保留在进度记录; 各次失败、修正、模型调用数及未测平台也一并记录,不以本机单测或原生协议探针 替代完整产品验收。完整 App 性能样本保留用户要求的按钮位置调整,属于包含该 UI 差异的实测对照,不是纯 Runtime 单变量实验。