ChatGPTClaudeGrok / X / CursorGemini

DSH plugin 怎么写 Typert 远程调用?lookup、descriptor 与 Gateway 边界

插件开发发布于 2026-10-21作者: DeepSeek Plugin 插件市场
DSH pluginDeepSeek HarnessTypertAPI Gateway远程调用
Typert 远程调用分三层:LookupMap 声明 Host 对象与 wire identity,InvocationDescriptor 描述参数与结果 codec,Gateway 按 principal 与资源做访问控制。取消走带外 signal,不进 args。

Typert 远程调用不是“把方法名和参数 JSON 化”,而是一套三层的类型契约:声明层定义哪些 Host 对象可被寻址,描述符层定义参数与结果怎么编码,Gateway 层定义谁能调用、能碰哪些资源。 三层混在一起写,最容易出现“本地能调、远程报 lookups 不可用”或“参数里有取消信号导致 codec 失败”。

DeepSeek Harness:声明层:哪些对象能被远程寻址

远程调用不能传对象引用,必须给对象一个 wire identity;LookupMap 与 ContextMap 就是这份声明。 两个 map:(来源)

  1. TypertLookupMap — 把一种 Host 对象类型关联到 wire identity。预期:参数可以被识别为 lookup,而不是普通业务对象。
  2. TypertContextMap — 把一种作用域上下文类别关联到 wire identity。预期:方法可以选择上下文接收器。
  3. 声明合并 — 业务对象包扩展空 map,生成的 descriptor 引用这些 key。预期:Host 与 Client 构建看到同一份声明。

lookup 的 resolver 卸载后,注册表仍保留 wire 声明。SRC 发现过程会继续把该参数归类为 lookup,并因不可用而失败,而不会把 wire 值当普通对象接受。这是“宁可失败,也不误收”的设计。

DeepSeek Harness:描述符层:参数与结果怎么编码

InvocationDescriptor 是本地反射信息,不是 wire message;请求只发 endpoint 与具名 args。 关键字段:(来源)

字段作用
service / namespace / method定位要调用的方法
parameters有序业务参数,含 wire 名与 codec
invocationdirect 或 context 接收器
scope可选的上下文投影
uplink流式调用中 Client 回传项的 codec
cancellation带外 signal 的保留参数
result一元结果或每个流项的 codec

strict codec 携带生成的 schema factory;SRC codec 只强制输入是 JSON 安全值,不恢复结构类型。一元结果 codec 可以提供 encode() 处理含字节的子树,并用 decode() 递归校验原生字节;纯 JSON 结果不需要字节识别。

取消通过带外 carrier signal 表达,在业务参数之后注入,绝不进入 args。不要把 signal 当成普通参数写进 descriptor 的 parameters。

DeepSeek Harness:调用层:方法、流与取消

createTypertRemoteInfo 返回惰性类实例,方法索引引用 descriptor;调用方拿到的不是裸函数,而是带 input/invoke 的远程方法。 三层能力:(来源)

  1. 一元调用 — mode 缺省,invoke 发起一次请求并返回结果。预期:参数按 descriptor 编码。
  2. 流式调用 — mode: 'stream',Host 返回 RemoteStream<Out, In>。预期:Client 拿到 RemoteStreamHandle,可 send、end、dispose。
  3. 上下文接收器 — 方法只用 Context 接收器时,仍保留在 descriptor 与作用域声明中。预期:不需要额外业务参数。

method.input(options?) 只接受 strict?: boolean,返回缓存的 TypertRemoteValue;它不改变 Host 分发或 result。读取元数据或 schema 不会发起网络调用。

DeepSeek Harness:权限与资源

Typert 的访问控制不在方法内部,而在 Gateway 与资源策略层。 要点:(来源)

  • principal 固定 — PeerScope 的 principal 在创建时由进程内 Host 代码固定,没有 wire 字段能设置它。预期:调用方不能自报身份。
  • 资源声明 — @Remote({ resources }) 或 @RemoteScope(key, { resources }) 读取资源身份;其次看 lookup 参数或作用域 Context,再次看 typert.resources 默认字段。
  • global 资源 — 不指向任何资源的调用访问内置 global。预期:无身份资源也要有策略。
  • 非 owner 才校验 — 只有非 owner 调用才需要 policy 在每个资源上绑定 role。

如果方法能改数据,先把资源种类声明清楚,再谈 role;否则 Gateway 只能把它当 global。

DeepSeek Harness:三种接入方式

直连方法、上下文接收器、远程流,复杂度依次上升。 三种:(来源)

  1. direct 一元方法 — 最简单,适合 CRUD 与查询。预期:参数与结果都是 JSON 或已声明 lookup。
  2. context 接收器 — 方法需要作用域上下文时使用。预期:接收器从 Context 派生,不注入业务参数。
  3. 远程流 — 需要持续推送或双向通信时使用。预期:Client 持有 handle,负责 end 或 dispose。

流式调用要特别注意:一个既不迭代也不 dispose 的 handle 会让 Host 流一直活着;载体断开时迭代会失败,handle 也随之结束。

DeepSeek Harness:codec 怎么选

纯 JSON、含字节、需要严格结构,三种情况对应不同 codec。 三种:(来源)

  1. 纯 JSON — 不需要字节识别或 Client 解码,直接用普通 codec。预期:参数与结果都是无损 JSON。
  2. 含字节子树 — 一元结果用 encode() 把字节投影成附件,用 decode() 递归校验原生字节。预期:Uint8Array 不会在传输中变成普通对象。
  3. 需要严格结构 — 用 strict codec 携带生成的 schema factory。预期:接收端能按声明的结构校验。

SRC codec 只强制输入是 JSON 安全值,不恢复结构类型;需要类型保证时,别只依赖 SRC。

如果方法同时有 JSON 与 lookup 参数,逐个参数声明 codec,不要用一个统一 codec 兜底;否则 SRC 会把 lookup 也当普通 JSON。

声明与 descriptor 的最小例子

先声明 lookup,再让生成的 descriptor 引用它;不要手写 wire 字段。 结构大致是:

ts
declare module '@deepseek-ai/dsh-typert-protocol' {
  interface TypertLookupMap {
    'my-service/session': Session
  }
}

生成器会产出 TypertLookupDefinition,包含 key、parameter、wire 与 host/wire 类型符号;运行时提供方负责把 wire 值解析回活对象。方法侧只暴露具名 args,取消信号在业务参数之后注入,不进入 args。

如果 lookup 的 resolver 卸载,注册表仍保留 wire 声明;后续调用会因不可用而失败,而不是把 wire 值当普通对象放过去。

DeepSeek Harness 常见问题

Q:为什么本地调用正常,远程却报 lookup 不可用? 远程调用只能按 wire identity 找对象;resolver 卸载或未注册时,SRC 会拒绝把 wire 值当普通对象。先确认 lookup 声明与运行时解析器都在。

Q:能不能在参数里直接传 Uint8Array? 需要 codec 支持字节子树:一元结果可用 encode()/decode() 处理;纯 JSON 结果不要假设字节会自动保留。

Q:流式调用的 uplink 会进参数列表吗? 不会。uplink 通过 RemoteInvocation.uplink() 读取,descriptor 单独声明其 codec。

一句话收束: Typert 的关键是“声明、描述、授权”三层各自成立;把取消或对象引用塞进参数,只会在某一层失败。

ChatGPTClaudeGrok / X / CursorGemini

常见问题

Typert 的 LookupMap 和 ContextMap 分别解决什么问题?

DeepSeek Harness 里,LookupMap 把一种 Host 对象类型关联到 wire identity,让远程调用能按身份找到活对象;ContextMap 把一种作用域上下文类别关联到 wire identity,让调用能选择接收上下文。两者都通过声明合并扩展。

Typert 的 descriptor 是 wire message 吗?

DeepSeek Harness 里,不是。InvocationDescriptor 是本地反射信息,Host 与消费方构建会生成彼此对应的 descriptor;请求只发送 endpoint 与具名 args,不发送 descriptor 本身。

Typert 调用怎么取消,在 DeepSeek Harness 中如何处理?

DeepSeek Harness 里,取消通过带外 carrier signal 表达,在业务参数之后注入,绝不进入 args。这样业务参数保持纯净,取消也不会被误当成一个普通输入。

lookup 的 resolver 卸载后,已有调用会怎样?

DeepSeek Harness 里,注册表会保留 wire 声明。SRC 发现过程仍把该参数归类为 lookup,并因不可用而失败,而不会把 wire 值当作普通业务对象接受。

Typert 的访问控制在哪里做,在 DeepSeek Harness 中如何处理?

DeepSeek Harness 里,在 dsh-api-remote-access:非 owner 调用只有在 principal 种类的 policy 于每个被访问资源上绑定包含该端点 action 的 role 时才放行。Gateway 从 @Remote 的 resources 或默认 typert.resources 读取资源身份。

相关术语

TypertLookupMap
TypertLookupMap 是可通过声明合并扩展的映射,把一种 Host 对象类型关联到其 wire identity;生成的 descriptor 引用这些 key,运行时提供方负责解析活对象。— DeepSeek Harness 官方参考 - Typert 远程调用
InvocationDescriptor
InvocationDescriptor 是一次导出方法调用的本地反射描述,包含 id、service、method、参数、codec、结果 codec 与可选的 uplink/取消信息,不是 wire message。— DeepSeek Harness 官方参考 - Typert 远程调用
RemoteStream
RemoteStream 是 Host 方法返回的一条远程流,Host 侧按 AsyncIterable<Out> 迭代,In 标记 Client 可回传的 uplink 类型;Client 侧拿到 RemoteStreamHandle。— DeepSeek Harness 官方参考 - Typert 远程调用
PeerScope
PeerScope 表示一个 Peer 在本 Host 上的会话,含 id、连接生命周期上下文、固定 principal、取消 signal 与交互能力;Remote 流会随 Peer 结束而结束。— DeepSeek Harness 官方参考 - Typert 远程调用

来源