lukaiwuyi/dsh-frontend-tools--packages-client ↗★ 0
dsh-frontend-tools-client
Frontend tools client SDK: register an application's tools with the DeepSeek Harness frontend-tools bridge over WebSocket (browser, Electron, Tauri, Node)
安装
此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗
说明文档
阅读完整 README ↗dsh-frontend-tools-client
English | 中文
前端工具桥的应用侧:把一个应用(浏览器渲染进程、Web 应用或 Node 进程)连接到 dsh-frontend-tools-bridge 的 WebSocket 服务,并把应用私有的工具暴露给模型。应用保留带完整权限的真实实现——本 SDK 只单向携带注册、反向携带转发调用。
功能
createFrontendToolsClient({ url, key }) 返回一个客户端,持有一条连接和一个工具注册表。凭证归应用自己掌管:用 generateClientKey() 生成一次 DSH KEY 并持久化(例如存入 localStorage),展示给用户——buildClientKeyClipboardText({ namespace, key, appName }) 生成推荐的复制文本——由用户在对话中经 frontend_tools_register_client 管理工具把它登记到应用的命名空间。KEY 就是客户端的全部身份:握手只呈交 KEY,服务端在 welcome 中回显绑定的命名空间——connect() 落定后可从 client.namespace 读取。registerTools(tools) 发送一个 register 批次,并按注册顺序以桥注册出的模型侧公开名(__)落定;unregisterTools(names) 按原始名移除工具,并以桥实际移除的原始名落定(未知名被忽略)。传入的 call 帧按原始名称分发到对应工具的 execute;落定结果——值,或结构化的 { code, message } 失败——作为一条 callResult 回传。服务端的 ping 存活探测由 SDK 自动以 pong 应答。
抛出的 FrontendToolsError 保留其 code 与 message(模型应当读到的权限拒绝用 code: 'denied',例如"未登录");其他抛出的错误以 internal 连同错误文本呈现。未知工具名应答 unknown_tool。
运行时要求
除平台 WebSocket(浏览器与 Node 22+ 都内置)外没有运行时依赖。可透过 socket 注入构造函数用于测试或替代传输。连接呈现四种状态——connecting、connected、disconnected、reconnecting——经 onStateChange 监听器广播。已建立的会话断开后按指数退避自动重试(1 秒起倍增至 30 秒),恢复后自动重注册客户端仍持有的全部工具,模型侧视图无需应用代码即自行恢复;一次性脚本可传 reconnect: false 快速失败。连接断开或超时会让待定的 registerTools / unregisterTools 调用以 disconnected 错误落定。显式 disconnect() 后客户端即终结——重连需新建客户端。
最小示例
import { createFrontendToolsClient, generateClientKey } from 'dsh-frontend-tools-client'
// Generate once, persist (localStorage or similar), and show the DSH KEY to
// the user — they register it with the dsh bridge through a conversation.
const key = localStorage.getItem('dsh-key') ?? generateClientKey()
localStorage.setItem('dsh-key', key)
const client = createFrontendToolsClient({ url: 'ws://127.0.0.1:31870', key })
await client.connect()
console.log(client.namespace) // the namespace the bridge bound to this key
const names = await client.registerTools([{
name: 'echo',
description: 'Echo the provided message back.',
parametersSchema: { type: 'object', properties: { message: { type: 'string' } }, required: ['message'] },
async execute(args: unknown) { return { echoed: (args as { message?: unknown }).message } },
}])