6.8 KiB
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。