deepseek-harness/.agents/notes/implemented/architecture/2026-08-10-unary-apiproxy-remote-migration.zh.md

6.8 KiB
Raw Blame History

Agent Note: 将一元浏览器操作放到所属 Remote 服务

Status: implemented

English | 中文

问题

Host API Proxy 曾在业务 Service、API Proxy interface、Zod schema、路由表、Client stub 与 Client 调用方之间重复定义简单一元操作。Typert Remote 调用已经允许业务包持有这类调用,但如果迁移 endpoint 时没有一并保留生命周期与投影策略,就会改变可观察行为。

与 Agent 绑定的调用需要格外谨慎。共享 lookup 策略会复用 live Agent、用记录的 preset 恢复普通冷 Session、对并发恢复去重,并拒绝由 subagent 持有的 identity。skill 列表则必须检查 Session 而不激活 Agent。Settings 与 preset 操作不会把 Host 持有的文档路径放进浏览器请求;Session 文件链接保留由调用方解析路径的行为。

决策

简单一元操作归属其自然的业务 Remote owner。业务包持有 Remote 签名与 Host 适配;@deepseek-ai/dsh-api-remotes/client 选择其生成贡献;Client 包持有呈现联接。Connection 持有传输 envelope 与精确 Fetch 路由注册表,不再存在 API Proxy 服务。

原 API Proxy 操作 目标 Owner 与保留行为
session.rename sessionTitle/rename SessionTitleService 通过共享 lookup 策略解析 Session,并返回标题事件序号。
command.list、command.execute commands/list、commands/execute CommandRuntime 保留 Agent lookup、未匹配命令与调用方取消。
llm.providers llm/listProviders、llm/listConfigurableProviders LlmRuntime 持有 provider 事实;Client 联接 live 与 configurable 行。
llm.discoverModels llm/discoverModels LlmRuntime 保留 provider 发现、取消与净化后的失败。
llm.models session/modelCatalog SessionController 持有 Host generation 的目录、默认选择与隔离后的 provider 失败。
credentials.describe、credentials.set、credentials.unset credentials/describe、credentials/set、credentials/unset CredentialsController 保留引用校验、字段投影、provider 诊断与拒绝映射。
settings.describe、settings.update、settings.replace、settings.mutate 对应的 settings/* 方法 SettingsController 保留脱敏、mutation 语义、revision 校验与 provider 失败。
settings.openDocument settings/openSettingsDocument SettingsController 准备 provider 持有的文档,并按文本编辑器意图打开。
agentPreset.read、agentPreset.copy、agentPreset.remove 对应的 agentPresets/* 方法 AgentPresetService 持有文档读取、复制与删除。
agentPreset.openDocument settings/openAgentPresetDirectory SettingsController 解析 preset 目录,并在原生打开不可用时返回其路径。
subagent.interrupt subagents/interruptByParent subagent 服务保留 parent 权限,且不激活任何一方的 Agent。
workspace.list、workspace.insertSessionBefore、workspace.archiveSession 对应的 workspace/* 方法 Workspace registry 持有脱离可变对象的 snapshot 与串行 mutation。
skill.list skills/list SessionSkillCatalog 观察 Session 及其记录的 preset,仅在 live Agent 已存在时使用它,列表查询绝不激活 Agent。
fileReferences/list fileReferences/list SessionFileReferences 向 provider 提供 Session Controller 的既有 Agent lookup;冷 lookup 行为保持不变。
host.openPath session/openWorkspacePath Session-aware Client 先基于已知 workspace 解析相对路径,再由 SessionController 交给原生打开器。
host.describe $events ready frame 与 capability 查询 API Remotes 随 generation readiness 发送 Host home;Settings 与 Session controller 在对应页面显示时报告各自的原生打开能力。不发送无人使用的进程元数据。
session.export GET/HEAD /api/session.export session-log-export 注册精确的 Connection Fetch 路由,并在没有 JSON Remote envelope 的情况下流式传输 ZIP。

共享 Agent 与 Session resolver 仍是接收这些对象的 endpoint 的权威。它提供与旧 API Proxy 调用相同的 live 复用、冷恢复、并发去重、preset setup、持久化失败与 subagent ownership fence。TypertLookupFailure 保留 resolver 持有的 RPC error,而不把它们归并为 internal。

原生路径实现在 @deepseek-ai/dsh-native-command 中。Settings controller 选择 Host 持有的目标,Session-aware Client 则在调用 SessionController 前解析 workspace 路径;该工具仅负责平台探测、WSL 转换、浏览器偏好、文本编辑器意图与无 shell 命令执行。

浏览器认证

Connection 在选择 Typert endpoint 或精确 Fetch 路由前认证完整的 /api 请求。因此 Remote 调用与 Session 日志下载要求相同的浏览器会话和 Host/Origin 校验。

验证

聚焦的 Host 与 Client 测试覆盖 Remote 调用、lookup 与不激活策略、原生打开、错误投影和 legacy 路由移除。仓库构建会先生成并消费所选 Remote contribution,再构建 Web 应用。

考虑过的替代方案

将简单调用留在 API Proxy。 否决,因为业务 owner 已存在后,这仍会保留重复的 interface、schema、路由行、stub 与结果投影。

保留 host.describe。 否决,因为一次 bootstrap 调用会把 Connection readiness 与互不相关的进程和业务事实耦合起来。generation-ready frame 只携带立即需要的生命周期事实,各 capability owner 页面在显示时查询自己的当前能力。

在 generation-ready frame 中发布所有业务 capability。 否决,因为这些值没有共同的更新生命周期。只有稳定的 Host home 属于 Connection;各业务 owner 回答自己的当前 capability。

把 Session export 表示为 Remote。 否决,因为浏览器下载管理器消费流式 HTTP 响应,而不是 JSON 结果。精确注册的 Fetch 路由让功能包持有该行为,同时不引入第二个 gateway。

把原生打开操作放入某个 controller。 否决,因为 Session 与 Settings 选择不同的授权目标。Host 工具可以避免 controller 间导入,同时不让浏览器成为文件系统目标的权威。

后果

业务 owner 与 Client consumer 各自定义一元操作的一侧,而 Connection 持有认证、传输、响应 envelope、精确 Fetch 路由与 generation 状态。删除 legacy Client timeout 是已接受的可观察传输变化;业务结果、取消、生命周期策略、过滤与原生路径权限仍由既有领域持有。

每当 Remote 签名或所选包发生变化,都必须更新生成的 Remote 产物和显式 API Remotes assembly。