嵌入现有应用
@tool-bridge/sdk 把 tool-bridge 作为库嵌入你的应用。你可以注册本地 Tool/Context,把 fetch 接到现有 HTTP 宿主,或通过 connect() 把本地能力反向挂到远程网关。
它适合已有 Node 22+ 应用、需要调用进程内函数或自定义存储的开发者。它不适合希望”安装后自动获得完整托管 gateway”的场景:SDK 不会自动替你提供持久数据库、对象存储、Search、设备网关通道或完整内置 Plugin catalog。
包的根入口以 Node 22 为目标,并直接依赖 node:os、Node ws 和 process.env。HTTP 表面使用标准 Request / Response,但根入口仍是 Node 宿主 API;标准自托管服务使用 Node / PG / S3。
另有一个 runtime-neutral / Hermes-safe 子入口 @tool-bridge/sdk/device,面向 React Native / Hermes 运行时。它是实时设备客户端与显式 Mailbox processor(把本地 tool/context 反向挂到远程网关),不含 createToolBridge,不是完整网关;webSocketFactory 必填,凭证由 credentialProvider 提供(SDK 不存 SK),shell/文件执行器只在 CLI tb connect 里。详见接入本地设备与服务。
- Node.js 22+;
- 熟悉
Request/ResponseFetch API; - 一套生产 StateStore 方案;
- Admin SK 与可选 SecretStore 加密密钥;
- 如果对外暴露 HTTP,准备 TLS、域名和宿主生命周期管理。
下面的 Node 示例使用 Hono 的 Node server adapter:
npm install @tool-bridge/sdk @hono/node-server2. 创建实例并注册本地工具
Section titled “2. 创建实例并注册本地工具”import { serve } from '@hono/node-server'import { createToolBridge, MemoryObjectStore, MemoryStateStore,} from '@tool-bridge/sdk'
const adminSk = process.env.TB_BOOTSTRAP_ADMIN_SKif (!adminSk) throw new Error('TB_BOOTSTRAP_ADMIN_SK is required')
const tb = createToolBridge({ state: new MemoryStateStore(), objects: new MemoryObjectStore(), adminSk, encryptionKey: process.env.TB_SECRET_ENCRYPTION_KEY,})
tb.registerTool( 'tools/echo', { List: () => [ { name: 'echo', description: '原样返回 text', inputSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'], additionalProperties: false, }, }, ], Call: (_name, args) => ({ content: { echoed: args.text } }), }, { description: '本地 echo 工具' },)
serve({ fetch: (request) => tb.fetch(request), port: 8787,})registerTool 的 List 是运行时 ~help 与 JSON Schema 的来源;Call 执行实际工具。也可以传入 OperationRegistry,通过 Zod 统一生成 schema 与校验。
3. 验证 HTTP 表面
Section titled “3. 验证 HTTP 表面”在另一个终端先读取节点级工具索引:
curl \ -H "Authorization: Bearer $TB_BOOTSTRAP_ADMIN_SK" \ -H "Accept: application/json" \ http://127.0.0.1:8787/tools/echo/~help这一层默认是索引,会列出 echo,但不含完整 schema。加查询参数 ?schemas=1 可让节点级一次返回该节点所有工具的 schema;只看单个工具时,直接下钻工具级帮助更省上下文:
curl \ -H "Authorization: Bearer $TB_BOOTSTRAP_ADMIN_SK" \ -H "Accept: application/json" \ http://127.0.0.1:8787/tools/echo/echo/~help再原样调用命令级路径,body 直接发送 arguments:
curl -X POST \ -H "Authorization: Bearer $TB_BOOTSTRAP_ADMIN_SK" \ -H "Content-Type: application/json" \ -d '{"text":"hello"}' \ http://127.0.0.1:8787/tools/echo/echo- 节点级
~help默认返回echo索引(加?schemas=1可一次取回整节点 schema),工具级~help返回含outputSchema的完整契约; - 合法调用返回
{ "echoed": "hello" }对应内容; - 缺少
text或加入未知字段时按 schema 被拒绝; - 未携带有效 SK 时无法访问受保护路径。
完成示例后应签发受限 SK,并用它重复 help/call。不要让业务调用长期使用 bootstrap Admin SK。
4. 显式装配宿主依赖
Section titled “4. 显式装配宿主依赖”createToolBridge 不读取环境变量来补齐 adminSk 或 encryptionKey。示例中的 process.env 是你的应用显式取值,再传给 SDK;它与标准服务的受保护安装不是同一入口。
| 配置 | 责任 |
|---|---|
state |
必填,树、SK、manifest 的持久权威 |
objects |
必填,字节服务;示例 MemoryObjectStore 仅适合易失开发 |
adminSk |
首次 bootstrap 显式身份 |
encryptionKey / secrets |
显式加密根或 SecretStore;缺配置时相关能力 fail closed |
storeRepository / storeBackends |
Store 领域事务与后端解析 |
mailboxRepository |
Mailbox 领域事务,另需加密根 |
remoteAllowlist / maxHops |
Federation 范围与跳数 |
pluginBindings / pluginCatalog |
同源的进程内代码与 descriptor |
providerOAuthFetch |
宿主显式提供的受控 OAuth 出站,不回退全局 fetch |
单独提供 objects 不等于 Store / Mailbox 已完整可用;生产不能用普通 KV CAS 或内存锁替代领域事务。需要开箱即用的持久化、安装、配置、后端与维护管理时,使用标准 Node 服务。
如果只给 pluginBindings 不给 catalog,运行时代码存在但无法按 export 解析;只给 catalog 不给 binding,则能选择却不能调用。标准宿主从 @tool-bridge/plugins 同源装配两者,自定义宿主也应保持这个不变量。
当前公开 ToolBridgeConfig 没有 SearchIndex 注入字段,因此 SDK 实例不提供 ~search。需要 Search 时使用标准 Node server,并以根 ~describe 验收;不要向 SDK 传入一个类型未声明、运行时也不会装配的 search 字段。
5. 注册 Context
Section titled “5. 注册 Context”使用 registerContext(path, provider, meta) 注册本地 Context。Provider 至少实现读取所需动词;是否有 Put、Patch、Delete、Search 或 Subscribe 取决于你提供的方法。
客户端应从 Context 路径的 ~help 读取实际命令和 schema,从同一路径的 ~describe 读取可选 capability。公共文档不应静态宣称某个自定义 Context 可写或可搜索。
如果 Context 返回大型内容,可以配合 ObjectStore 和短期 $ref;签名、有效期与访问边界由宿主实现负责。
6. 反向连接远程网关
Section titled “6. 反向连接远程网关”本地实例可以把已经注册的 Tool/Context 上报到远程 tool-bridge:
const connection = tb.connect( 'https://tb.example.com', process.env.TB_DEVICE_SK!, { deviceId: 'my-service-01' },)
const mountPath = await connection.readyconsole.log(`mounted at ${mountPath}`)
// 应用退出时:connection.close()await connection.closed长驻服务必须显式使用稳定 deviceId,否则断线重连无法可靠恢复同一个 online 节点。远端 SK 需要 register scope 和相应 registerPaths,详见接入本地设备与服务与权限、SK 与可见性。
SDK 的 connect() 上报注册节点,不内置 CLI 的 shell/fs 执行器。需要暴露 shell 或文件时使用 tb connect,并配置显式白名单。
7. 显式接入 Device Mailbox
Section titled “7. 显式接入 Device Mailbox”工具的运行时 metadata 可以把某条命令声明为 delivery: 'mailbox' | 'both',但 connect() 只负责 WebSocket 注册与实时调用,不会自动消费 durable operation。需要离线投递时,从 runtime-neutral 子入口创建 processor:
import { createDeviceMailboxProcessor } from '@tool-bridge/sdk/device'createDeviceMailboxProcessor 需要同一份 live expose、同一 handler、每次请求现取凭证的 credentialProvider,以及 installation-local 的 durable journal。它只提供 pullOnce() / drain(),不会自行启动 timer 或监听连接状态。宿主必须:
- 在初次 WebSocket
ready和每次重连ready后触发一次drain(); - 停止、suspend 或进程退出时 abort 当前 drain;
- 让 realtime 与 Mailbox 复用同一份命令表和 handler;
- 保证 journal
put()在 resolve 前真正持久化,并按 entryexpiresAt回收; - 把非 abort 错误进入宿主日志/事件面,不能把失败当成“已消费”。
journal 是防止重启后重复副作用的执行屏障。handler 开始后崩溃而无法恢复结果时,processor 会提交 result_unknown,不会盲目重跑。内存 Map 不满足这一契约;标准 CLI 使用带权限限制、fsync 与 atomic rename 的本地文件 journal。
完整 delivery 策略、operation 状态与部署前提见Device 离线投递与 Mailbox。
为客户端选择正确子入口
Section titled “为客户端选择正确子入口”| 入口 | 用途 |
|---|---|
@tool-bridge/sdk |
Node 22+ 嵌入网关、注册本地函数、Node 反向连接 |
@tool-bridge/sdk/client |
Web 标准 HTTP 客户端、固定控制面与运行时解析 |
@tool-bridge/sdk/store |
Store 客户端、上传与读取流程 |
@tool-bridge/sdk/device |
实时设备 supervisor、上传助手、显式 Mailbox processor |
三个子入口不反向依赖 Node 根入口。它们是客户端能力,不等于部署了一个完整网关。移动端设备需要宿主提供 WebSocket factory、凭证来源和生命周期;Mailbox 还必须有真正 durable journal。
第一次请求时报缺 Admin SK
Section titled “第一次请求时报缺 Admin SK”SDK 在首次 fetch/connect 前执行 bootstrap。显式传 adminSk;不要在共享环境随机生成并打印最高权限凭证。
secret set 返回 unavailable
Section titled “secret set 返回 unavailable”没有自定义 secrets,也没有提供合法 encryption key。显式传 encryptionKey 后重新启动并验证;已有密文还需要原加密根。
Mailbox 入队返回 unavailable
Section titled “Mailbox 入队返回 unavailable”确认 SDK 宿主显式提供 mailboxRepository 与合法 encryptionKey,设备侧接入 durable journal 与 processor。只有命令 metadata 声明 delivery,并不代表自定义宿主已经交付离线消费闭环。
本地工具能调用,远程连接后找不到
Section titled “本地工具能调用,远程连接后找不到”确保在 connect() 前调用 registerTool/registerContext,设备 SK 的 registerPaths 覆盖目标 mountPath,并等待 connection.ready。远程身份看到的最终路径和工具仍以远程 ~help 为准。
以为 SDK 自动包含所有 integration
Section titled “以为 SDK 自动包含所有 integration”SDK 默认不装配完整 built-in catalog。需要自行同源提供 pluginCatalog 和 pluginBindings,或改用标准 Node 宿主。
- 用受限 SK替代业务 Admin 调用;
- 阅读从
~help到调用验证自定义 schema; - 对外运行前完成生产上线检查清单;
- 需要反向连接时进入接入本地设备与服务。
- 需要离线投递时进入Device 离线投递与 Mailbox。