ST-bridge 是本机持久会话桥接,供柏宝绘、玉子手机、数据库等酒馆插件调用:
33.6/100
综合分
5
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add wuhehen176/ST-bridge该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · other
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 0 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 95 处,展示前 78 条)
- 写入剪贴板client.js:554
onClick: () => { if (form.snapshotMarker) void navigator.clipboard?.writeText(`<<<STB-${form.snapshotMarker}:B>>> ... <<<STB-${form.snapshotMarker}:E> - 写入剪贴板client.js:629
try { await navigator.clipboard.writeText(address); setNotice('地址已复制;新增或修改接入后请先保存,再用于插件。') } - 读取本地文件lib/build-info.js:9
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) - 读取本地文件lib/build-info.js:25
if (lstatSync(cursor).isSymbolicLink()) throw new Error(`包文件包含链接: ${name}`) - 读取本地文件lib/build-info.js:28
const stat = lstatSync(path) - 读取本地文件lib/build-info.js:30
for (const child of readdirSync(path).sort()) visit(join(rel, child)) - 读取本地文件lib/build-info.js:32
files.set(rel.replaceAll('\\', '/'), readFileSync(path)) - 读取本地文件lib/log.js:18
if (!existsSync(file)) return - 读取本地文件lib/log.js:19
if (statSync(file).size < MAX_BYTES) return - 写入本地文件lib/log.js:20
renameSync(file, `${file}.1`) - 写入本地文件lib/log.js:30
appendFileSync(file, line, { encoding: 'utf8', mode: 0o600 }) - 读取本地文件lib/panel.js:296
const text = readFileSync(file, 'utf8') - 读取本地文件lib/pairing.js:78
if (!existsSync(this.file)) return - 读取本地文件lib/pairing.js:80
const parsed = JSON.parse(readFileSync(this.file, 'utf8')) - 写入本地文件lib/pairing.js:99
mkdirSync(dirname(this.file), { recursive: true }) - 写入本地文件lib/pairing.js:102
writeFileSync(temporary, json) - 写入本地文件lib/pairing.js:104
renameSync(temporary, this.file) - 写入本地文件lib/pairing.js:108
writeFileSync(this.file, json) - 删除本地文件lib/pairing.js:109
try { unlinkSync(temporary) } catch {} - 读取本地文件lib/store.js:36
if (!existsSync(this.file)) return - 写入本地文件lib/store.js:39
copyFileSync(this.file, backup) - 写入本地文件lib/util.js:18
mkdirSync(dir, { recursive: true }) - 读取本地文件lib/util.js:23
return JSON.parse(readFileSync(file, 'utf8')) - 写入本地文件lib/util.js:34
writeFileSync(tmp, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 }) - 写入本地文件lib/util.js:35
renameSync(tmp, file) - 写入本地文件lib/context-policy.js:22
if (existsSync(this.file)) copyFileSync(this.file, `${this.file}.bak-${Date.now()}-${randomUUID().slice(0, 8)}`) - 读取本地文件lib/context-policy.js:22
if (existsSync(this.file)) copyFileSync(this.file, `${this.file}.bak-${Date.now()}-${randomUUID().slice(0, 8)}`) - 读取本地文件lib/preset-policy.js:121
if (existsSync(this.file)) { - 写入本地文件lib/preset-policy.js:122
copyFileSync(this.file, `${this.file}.bak-${Date.now()}-${randomUUID().slice(0, 8)}`) - 读取本地文件deploy.mjs:23
if (existsSync(cursor) && lstatSync(cursor).isSymbolicLink()) throw new Error(`目标文件包含链接: ${name}`) - 读取本地文件deploy.mjs:23
if (existsSync(cursor) && lstatSync(cursor).isSymbolicLink()) throw new Error(`目标文件包含链接: ${name}`) - 读取本地文件deploy.mjs:26
if (existsSync(path) && !lstatSync(path).isFile()) throw new Error(`目标不是普通文件: ${name}`) - 读取本地文件deploy.mjs:26
if (existsSync(path) && !lstatSync(path).isFile()) throw new Error(`目标不是普通文件: ${name}`) - 读取本地文件deploy.mjs:37
if (existsSync(vendor)) roots.push(realpathSync(vendor)) - 读取本地文件deploy.mjs:44
const before = existsSync(path) ? readFileSync(path) : null - 执行外部命令固定命令deploy.mjs:65
const running = execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', - 执行外部命令来自配置/变量deploy.mjs:75
if (/ (?:js|mjs)$/.test(name)) execFileSync(process.execPath, ['--input-type=module', '--check'], { input: bytes, windowsHide: true, stdio: ['pipe', - 写入本地文件deploy.mjs:80
mkdirSync(backup, { recursive: true }) - 写入本地文件deploy.mjs:84
mkdirSync(dirname(path), { recursive: true }) - 写入本地文件deploy.mjs:85
writeFileSync(path, change.before) - 写入本地文件deploy.mjs:87
writeFileSync(join(backup, 'manifest.json'), JSON.stringify({ source: plan.source, build: plan.build, files: changes.map(c => ({ target: c.root, file: - 删除本地文件deploy.mjs:99
if (c.after === null) unlinkSync(c.path) - 写入本地文件deploy.mjs:100
else { mkdirSync(dirname(c.path), { recursive: true }); write(c.path, c.after) } - 删除本地文件deploy.mjs:112
if (c.before === null) { if (existsSync(c.path)) unlinkSync(c.path) } - 写入本地文件deploy.mjs:113
else { mkdirSync(dirname(c.path), { recursive: true }); writeFileSync(c.path, c.before) } - 发起网络请求deploy.mjs:122
const response = await fetch(`http://127.0.0.1:${port}/health`, { headers: authToken ? { authorization: `Bearer ${authToken}` } : {}, redirect: 'error - 读取本地文件install-tavern.mjs:11
if (existsSync(target) && lstatSync(target).isSymbolicLink()) throw new Error('目标为链接,停止安装') - 读取本地文件install-tavern.mjs:11
if (existsSync(target) && lstatSync(target).isSymbolicLink()) throw new Error('目标为链接,停止安装') - 读取本地文件install-tavern.mjs:15
if (existsSync(path) && (!lstatSync(path).isFile() || lstatSync(path).isSymbolicLink())) throw new Error(`目标不是普通文件: ${path}`) - 读取本地文件install-tavern.mjs:15
if (existsSync(path) && (!lstatSync(path).isFile() || lstatSync(path).isSymbolicLink())) throw new Error(`目标不是普通文件: ${path}`) - 读取本地文件install-tavern.mjs:16
return { name, path, before: existsSync(path) ? readFileSync(path) : null, after: readFileSync(join(source, name)) } - 读取本地文件install-tavern.mjs:16
return { name, path, before: existsSync(path) ? readFileSync(path) : null, after: readFileSync(join(source, name)) } - 写入本地文件install-tavern.mjs:23
mkdirSync(backup, { recursive: true }) - 写入本地文件install-tavern.mjs:24
for (const file of files) if (file.before) copyFileSync(file.path, join(backup, file.name)) - 写入本地文件install-tavern.mjs:25
mkdirSync(target, { recursive: true }) - 写入本地文件install-tavern.mjs:30
writeFileSync(file.path, file.after) - 写入本地文件install-tavern.mjs:35
if (file.before) writeFileSync(file.path, file.before) - 删除本地文件install-tavern.mjs:36
else if (existsSync(file.path)) unlinkSync(file.path) - 读取本地文件install.mjs:66
const persona = readFileSync(join(PROJECT, 'assets', 'preset-persona.txt'), 'utf8').trimEnd() - 读取本地文件install.mjs:109
if (!existsSync(file)) return - 写入本地文件install.mjs:111
copyFileSync(file, `${file}.bak-st-bridge-${stamp}`) - 写入本地文件install.mjs:117
mkdirSync(modules, { recursive: true }) - 读取本地文件install.mjs:118
if (existsSync(target)) { - 读取本地文件install.mjs:119
const stat = lstatSync(target) - 读取本地文件install.mjs:133
if (!existsSync(target)) return - 读取本地文件install.mjs:134
const stat = lstatSync(target) - 删除本地文件install.mjs:145
unlinkSync(target) - 删除本地文件install.mjs:147
try { rmdirSync(target) } catch { rmSync(target, { recursive: false, force: true }) } - 删除本地文件install.mjs:147
try { rmdirSync(target) } catch { rmSync(target, { recursive: false, force: true }) } - 写入本地文件install.mjs:185
writeFileSync(patchFile, next, 'utf8') - 写入本地文件install.mjs:197
writeFileSync(patchFile, next, 'utf8') - 发起网络请求tavern-extension/index.js:35
const response = await window.fetch(`${base}/bridge/capabilities`, { - 发起网络请求tavern-extension/index.js:129
const response = await window.fetch(`${serviceBase()}/bridge/context/${path}`, { - 发起网络请求tavern-extension/index.js:286
const response = await fetch(`${origin}/health`, { cache: 'no-store', headers }) - 发起网络请求tavern-extension/index.js:290
const response = await fetch(`${base}/bridge/selftest`, { - 发起网络请求tavern-extension/index.js:300
const response = await fetch(`${base}/bridge/selftest/stream`, { - 发起网络请求tavern-extension/index.js:328
const response = await fetch(`${pairState.base}/bridge/pair/status`, { - 写入剪贴板tavern-extension/index.js:527
try { await navigator.clipboard.writeText(text); status('已复制脱敏发送副本;其中仍含聊天私密内容。') }
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 持久化智能体会话桥接,供 Tavern 插件使用
README
由 DeepSeek 最新模型翻译生成ST-bridge
ST-bridge 是本机持久会话桥接,供柏宝绘、玉子手机、数据库等酒馆插件调用: http://127.0.0.1:43121/v1。
仓库:<https://github.com/wuhehen176/ST-bridge>
两个可安装部分分别发布:
| 部分 | 安装源 |
| DSH Host 插件 | <https://github.com/wuhehen176/ST-bridge> |
| 酒馆 / TauriTavern 扩展 | <https://github.com/wuhehen176/ST-bridge-tavern> |
酒馆扩展使用独立仓库,因为酒馆要求仓库根目录直接包含 manifest.json。
本机跨插件的来源预览与手动规则档位见 上下文适配第一版。
默认所有材料保留,仅处理显式配置的本机桥接请求。
玉子手机、数据库等插件建议使用各自的 /clients/插件ID/v1 地址,避免没有来源标识的请求共用一个 Agent。电脑设置页的「插件接入」可登记、停用和复制地址;配置步骤见 插件专属地址与聊天隔离。
更新本项目代码后,需要完全退出并重启 DSH Desktop才能加载新版本。
DSH Host 插件不会热替换已经加载的代码。
展开完整文档(README 剩余 1 节)
ST-bridge
ST-bridge 是本机持久会话桥接,供柏宝绘、玉子手机、数据库等酒馆插件调用: http://127.0.0.1:43121/v1。
仓库:<https://github.com/wuhehen176/ST-bridge>
两个可安装部分分别发布:
| 部分 | 安装源 |
| DSH Host 插件 | <https://github.com/wuhehen176/ST-bridge> |
| 酒馆 / TauriTavern 扩展 | <https://github.com/wuhehen176/ST-bridge-tavern> |
酒馆扩展使用独立仓库,因为酒馆要求仓库根目录直接包含 manifest.json。
本机跨插件的来源预览与手动规则档位见 上下文适配第一版。
默认所有材料保留,仅处理显式配置的本机桥接请求。
玉子手机、数据库等插件建议使用各自的 /clients/插件ID/v1 地址,避免没有来源标识的请求共用一个 Agent。电脑设置页的「插件接入」可登记、停用和复制地址;配置步骤见 插件专属地址与聊天隔离。
更新本项目代码后,需要完全退出并重启 DSH Desktop才能加载新版本。
DSH Host 插件不会热替换已经加载的代码。vendor 和 node_modules 可能是两份独立副本;仅复制 vendor 或仅比较版本号,不能证明运行进程已更新。
请用下方部署检查脚本核对解析入口、磁盘副本和进程加载指纹。
这不是一个直接转发模型 API 的代理,而是一个 DSH Host 插件。每个酒馆 chat_id 绑定一个真实的 DSH Agent 会话;会话通过 ctx.agents 创建,因此会出现在 DSH 界面中,可以手工打开、继续交流、查看历史。桥接只负责:
- 支持 dsh_session v1:固定组/动态组、generate/sync_rules/reset;
- 按 client_id + chat_id + task_id 隔离插件、聊天和子任务会话;
- 把首次完整上下文送进新会话;
- 后续只追加新增正文和本轮要求;
- 用 request_id 做幂等,避免网络重试重复追加;
- 同一 chat_id 的生成请求串行执行;
- 重写旧楼层、swipe、回退剧情时重建分支会话;
- 等 Agent 回合结束,只把最终正文放进 choices[0].message.content。
0.12.0 起支持客户端原生函数工具的往返:Agent 返回 tool_calls,由客户端执行,回传 role: "tool" 后继续同一个 Agent 回合。第一版支持范围和验收方式见外部工具接入。
桥接不解析、不包裹、不增加代码围栏,所以柏宝绘的 images/changes JSON 会原样返回。
目录
| 文件 | 作用 |
| index.js | DSH 插件入口,读取配置、启动 43121 端口 |
| lib/engine.js | 会话创建/恢复、上下文分类、发送、等待、分支、幂等 |
| lib/context.js | 消息规范化、前缀 diff、首次/追加/重建提示词 |
| lib/session-protocol.js | dsh_session 校验、固定规则格式化、稳定 session ID、采样参数 |
| lib/turn.js | 从 DSH 事件日志提取最终回答与 usage |
| lib/store.js | chat_id -> session_id 映射和 request_id 记录的持久化 |
| lib/server.js | OpenAI 兼容 HTTP/SSE 层 |
| lib/external-tools.js | 客户端工具注册、异步等待回填、会话隔离与幂等 |
| lib/panel.js | DSH 设置页 Host RPC、设置持久化、scope/规则/危险操作 |
| client.js | DSH 设置页浏览器半边 |
| install.mjs | 安装到当前 DSH profile |
| deploy.mjs | 更新前检查、备份同步与重启后的运行指纹检查 |
| lib/build-info.js | 捕获本次进程加载的版本、入口与 SHA-256 指纹 |
| cordis.patch.yml | npm/bundle 安装时使用的插件包 patch |
| cordis.patch.snippet.yml | 手工安装片段 |
| assets/preset-persona.txt | 桥接专用最小系统提示词 |
安装
要求:DSH Desktop 已正常运行,Node.js 22.19+。
cd D:\AIGC\MOSS\ST-bridge
node install.mjs --cwd D:\AIGC\MOSS --port 43121
脚本会:
1. 在 <profile>/node_modules/ST-bridge 创建指向本目录的链接;
2. 备份并修改 <profile>/cordis.patch.yml,追加一个受管配置块;
3. 注册一个只含文本系统提示词的 Agent 预设 st-bridge,不加载 DSH 工具、技能、酒馆人格或运行时上下文。
安装后必须 完全退出 DSH Desktop(托盘退出,不是只关窗口),再重新启动。
然后验证:
curl http://127.0.0.1:43121/health
curl http://127.0.0.1:43121/v1/models
预期:
{"object":"list","data":[{"id":"dsh-default","object":"model"}]}
卸载:
node install.mjs --uninstall
手工安装可参考 cordis.patch.snippet.yml。配置块也可以直接写进 ~/.dsh/profiles/desktop/cordis.patch.yml 末尾。
更新与部署检查
在准备发布的源码目录执行,Node.js 22.19+,无需额外依赖:
node deploy.mjs --check
默认是只读检查。脚本通过 Node 的模块解析确定 profile 实际加载的 ST-bridge 入口,并检查现存 vendor 副本。发现待同步文件时退出码为 1;磁盘一致时为 0。这里检查的是磁盘,尚不能证明运行进程已更新。
确认当前没有生成任务,从托盘完全退出 DSH Desktop,再执行:
node deploy.mjs --apply
脚本会检查 DSH 进程和本机桥接端口均已停止,再对发布包里的 JS 做语法检查。
它备份待修改文件到 <profile>/.st-bridge-backups/<时间与随机编号>/,同步实际安装副本和 vendor,移除旧发布清单中的过时代码,并逐文件比对内容。
复制或校验失败时回滚本次修改,备份保留。若检查期间目标文件被其他程序改动,脚本停止,要求重新检查。它不会改 profile 配置、设置、会话数据,也不会安装依赖或自动启动、退出 DSH。源码链接安装会跳过自我复制。
手动启动 DSH 后执行:
node deploy.mjs --verify-running
只有磁盘副本一致,且 /health 报告的加载时指纹与入口都与本次源码及所选 profile 对应,才返回成功。版本号相同、未重启的旧进程、旧版没有指纹,都不能通过。启动日志同时记录 [build] version=... sha256=... entry=...。
指纹在模块加载时捕获,之后覆盖磁盘文件不会改变该进程报告的值。
默认 profile 是 ~/.dsh/profiles/desktop,默认从 ~/.dsh/st-bridge/settings.json 读取桥接端口与令牌(令牌不会打印)。可指定:
node deploy.mjs --check --profile C:\path\to\profile
node deploy.mjs --verify-running --port 43121 --settings C:\path\to\settings.json
需要同时指定 profile 与 settings 时,将两个选项一起传入。若认证仅写在 Cordis 配置而未保存到本地设置,先通过 DSH 桥接设置页保存,或指定含当前令牌的本地 settings 文件。运行检查只连接 127.0.0.1,不跟随重定向。
自动部署的进程检查目前支持 Windows;--check 可跨平台使用。
DSH 设置面板
重启后,DSH「设置」里会出现「ST-bridge」页,包含:
- 服务:启停、host/port、Bearer token、CORS、allowLegacyPlain、请求超时、请求体上限。host/port 修改后点「保存并重启」。
- 模型:provider/model(留空跟随 DSH 当前默认;要填就同时填)、Agent 预设、 cwd、默认 max_tokens。修改只影响新创建/重新恢复的会话。reasoning_effort 只在模型支持该档位时传递;不支持会自动忽略,不会让整个回合报错。
- 客户端:按 client_id + chat_id + task_id 列出绑定,支持筛选、允许 client_id 列表、查看当前固定规则、清除规则、重置绑定。重置不删除 DSH 会话历史。
- 诊断:运行状态、scope/会话数、capabilities、日志路径与最近日志。
- 危险操作:停止/启动/重启桥接、清空全部绑定。清空需要输入 RESET;停止前会二次确认。
- 高级:直接编辑 settings.json 对应的 JSON;不展示真实 token。
设置保存到 ~/.dsh/st-bridge/settings.json(权限 0600)。界面里的 token 输入框留空表示保持现有 token;点「清除」才会移除。
从 baobaohui-bridge 升级
旧名 baobaohui-bridge 已改为 ST-bridge:
- profile 依赖/bundle 改为 ST-bridge;
- 状态目录改为 ~/.dsh/st-bridge,旧目录保留为备份;
- 旧的 session-bbh- 会话仍可通过本地绑定恢复;
- 新会话使用 session-st- 前缀;
- API 地址、client_id、chat_id、task_id 协议不变。
分发与其他电脑
这是一个 DSH Host + Client 插件,不是脱离 DSH 的独立服务。换电脑时整目录复制,目标机器必须有兼容的 DSH Desktop/Host、Node.js 22.19+、已配置的模型账号。
安装有两种方式,二选一:
1. 本地链接安装(当前 install.mjs):创建 <profile>/node_modules/ST-bridge 链接,并把 preset/plugin 行写进 <profile>/cordis.patch.yml。
2. 包/bundle 安装:把本包加入 profile 的 dsh.profile.bundles,或通过 dsh plugin --profile <name> add <本包> 安装;package.json 已声明 dsh.bundle.patch,cordis.patch.yml 会插入同样的 preset/plugin 行。
两种方式不要同时做,否则会出现重复的 st-bridge 行。
install.mjs 检测到 profile 已把本包列为 dependency/bundle 时会直接停止,避免重复插入。
换机器时:
cd <本目录>
node install.mjs --cwd <目标工作区> --port 43121 --profile desktop
- Windows 用 junction,macOS/Linux 用符号链接。
- 目标机器需重新配置模型通道/API Key;本仓库不携带任何密钥或聊天内容。
- state.json 是本机 chat_id -> session_id 映射,不建议跨机直接复用;新机器首次请求会返回 410 并重新初始化。
- 默认只监听 127.0.0.1。其他电脑要调用,需要在面板开启 allowRemote、设置 token、放行防火墙,并把客户端 Base URL 改成目标机地址。
- 当前按 DSH 0.2.1-rc.2 的 service/slot API 实现;DSH 大版本升级后若 settings.section、connection.rpc 等改名,需要适配。
柏宝绘 dsh_session v1(推荐)
请求仍是普通 OpenAI 非流式 JSON,额外在顶层带一个 dsh_session 对象。
DSH 用 fixed_message_count / fixed_message_types 把 messages 切成「固定组」和「动态组」,固定组按用途保存为该会话的最新规则。
{
"model": "dsh-default",
"stream": false,
"temperature": 0.6,
"max_tokens": 8192,
"messages": [
{"role":"system","content":"固定前缀"}, {"role":"system","content":"生图提示词规范及版式清单"},
{"role":"system","content":"宿主输出协议"}, {"role":"system","content":"输出前检查指导"},
{"role":"user","content":"本次角色库、上下文、目标正文与任务"} ],
"dsh_session": {
"protocol_version": 1,
"client_id": "baibai-image",
"chat_id": "opaque-plugin-chat-identity",
"task_id": "default",
"request_id": "9d55d2dfce15d5210fd95890c973c039a",
"action": "generate",
"fixed_message_count": 4,
"fixed_message_types": ["prefix","spec","contract","check"],
"target": {"floor":12,"swipe_id":0,"revision":"opaque-target-revision"}
}
}
字段
| 字段 | 含义 |
| protocol_version | 固定整数 1 |
| client_id | 可选插件身份,例如 baibai-image、yuzi-phone、shujuku;缺省按旧柏宝绘处理 |
| chat_id | 插件生成的不透明聊天标识;不能只用角色显示名 |
| task_id | 可选子任务标识,缺省 default;不是每轮随机 ID |
| session_id | 首次没有;后续由桥接返回并携带 |
| request_id | 单次操作 ID;网络重试必须复用,桥接做幂等 |
| action | generate / sync_rules / reset |
| fixed_message_count | messages 开头多少条属于固定组 |
| fixed_message_types | 与固定组逐条对应:prefix、spec、contract、check |
| target | 仅生成时携带的元数据;桥接只记录,不放进正文 |
如果客户端只能填静态 YAML body、无法生成 request_id,可以省略它;桥接会用 chat_id + action + messages 的 SHA-256 自动生成 auto-...。相同 body 重试仍然幂等,适合数据库这类固定预设:
dsh_session:
protocol_version: 1
client_id: shujuku
chat_id: shujuku-db
task_id: database
action: generate
fixed_message_count: 0
fixed_message_types: []
注意:chat_id 写死意味着所有数据库调用共用一个持久会话。需要按酒馆聊天隔离时,必须让客户端把 chat_id 换成动态值,而不是写死。
同一 chat_id 的后续请求即使不传 session_id,也会复用已绑定的会话;只有固定组内容变化,或旧会话返回 410 时,才会重建。这样静态 YAML 预设不会每次调用都新开一个 DSH 聊天。
client_id / task_id 也可放在顶层 body.client_id / body.task_id 或 x-client-id / x-task-id 头;chat_id / request_id 仍支持顶层与请求头兼容写法。
fixed_message_count 可以为 0;未配置某类规则时,固定组可以少于四条, fixed_message_types 必须与固定组一一对应。动态组可以包含多条 system (角色卡、世界书)和多条 user(角色库、记忆、上下文、目标正文)。
多插件与子任务隔离
会话索引是 (client_id, chat_id, task_id) 的组合(服务端用 SHA-256 规范化,不把组合键截断后当唯一身份)。不同插件或不同 task_id 即使 chat_id 相同,也会得到不同 DSH 会话;generate / sync_rules / reset 都只作用于当前范围。
- client_id 缺省:按旧柏宝绘的 chat_id 绑定查找,旧 session_id 继续有效。
- 显式 client_id: "baibai-image" + task_id: "default":同样复用旧绑定。
- 其它 client_id 或非默认 task_id:使用独立的新范围,不会静默迁移旧会话。
- 界面标题使用可读插件名(柏宝绘 / 玉子手机 / 数据库)与聊天名;非默认 task_id 也会出现在标题里。
已知客户端标识:baibai-image、yuzi-phone、shujuku;其它稳定标识也接受。
chat_id / task_id 只作为不透明数据,不作为磁盘路径。
客户端接入要点:
- 柏宝绘:client_id: "baibai-image",继续使用固定组;旧请求不带 client_id 时仍命中旧绑定。
- 玉子手机:client_id: "yuzi-phone",建议用 task_id 区分 QQ 私聊/ 群聊/主动周期;手动与主动请求都要带同一个聊天身份。
- 数据库:client_id: "shujuku",数据库自身身份独立。
- 玉子手机借用数据库 callAI:出口仍须保持 yuzi-phone,不能到 transport 再改身份。
- 新插件:使用稳定 client_id;无法判断固定规则用途时用 fixed_message_count: 0,每轮发送完整任务材料。
- 浏览器侧需通过酒馆 custom source 的 custom_include_body 透传 dsh_session;普通 openai source 可能在代理层丢掉扩展字段。
三种 action
generate(首次)
没有 session_id:创建独立、可在 DSH 中查看的 Agent 会话,保存固定组,并用本次动态组执行一次生成。返回 dsh_session.session_id。
generate(后续)
携带 session_id,fixed_message_count: 0、fixed_message_types: [], messages 只有动态组。桥接在同一会话内继续执行,固定规则由该会话的系统段自动注入,不需要插件重复传输。
固定组不会作为可见 user 消息重复塞进会话;DSH 把它保存为当前会话的「最新确认版固定规则」系统段,每次生成自动带上。这样既减少重复传输,也保证后续轮次继续生效。
动态组开头的 system 消息(角色卡、世界书等)同样作为「本轮动态系统资料」注入 system 段,不挤进 user 正文;动态组其余消息保持原顺序和 role 标记。
sync_rules
messages 只有固定组,fixed_message_count === messages.length。
有 session_id 就更新该会话;没有就创建并绑定一个空会话。
该操作不执行模型生成,返回 choices: [],也不发回上一轮图片规划。
固定规则按 type 整组替换,不会让旧规范和新规范并列生效。
reset
messages 为空,fixed_message_count: 0,fixed_message_types: []。
创建新的空 Agent 会话并返回新的 session_id;旧会话保留在 DSH 历史中。
下次 generate 携带固定组和动态组重新初始化。
响应
生成成功:
{
"id":"chatcmpl-example",
"object":"chat.completion",
"choices":[{"index":0,"message":{"role":"assistant","content":"Agent 最终回复字符串"},"finish_reason":"stop"}],
"dsh_session":{
"client_id":"baibai-image",
"chat_id":"stable-tavern-chat-identity",
"task_id":"default",
"session_id":"session-st-..."
},
"bridge":{"client_id":"baibai-image","chat_id":"stable-tavern-chat-identity","task_id":"default","session_id":"session-st-..."},
"usage":{"prompt_tokens":10000,"completion_tokens":1200,"prompt_tokens_details":{"cached_tokens":8000}}
}
控制操作成功:
{
"choices":[],
"dsh_session":{"client_id":"baibai-image","chat_id":"...","task_id":"default","session_id":"session-st-..."}
}
sync_rules 和 reset 只有在会话状态真正落实后才返回成功。usage 只在真实模型调用产生时出现;控制操作没有 usage。
文本能力与工具模式
纯文本、JSON 字符串和填表文本指令保留原有行为。桥接 0.12.0 与酒馆扩展 0.4.4 增加客户端 tools: [{type:"function",function:{...}}]、assistant.tool_calls 和 role:"tool" 的原生往返,参见 外部工具接入。
需要 stream:false,tool_choice 省略或为 auto,parallel_tool_calls 省略或为 false;旧 functions/function_call、强制工具选择、strict:true、并行和工具流式仍明确拒绝,不会静默降级成普通正文。
response_format: {"type":"json_schema",...} 这种严格结构约束返回
400 unsupported_response_format;json_object 可以按普通文本处理,但桥接不承诺严格 schema 采样。DSH Agent 内部自用工具与调用端 OpenAI 工具协议不是同一件事。
能力探测
GET /v1/bridge/capabilities
返回协议版本、范围键、控制操作、文本/工具/严格 JSON/流式能力,不创建会话。
连接测试不应调用 generate,避免留下正式任务会话。
{
"object": "bridge.capabilities",
"protocol_versions": [1],
"scope_keys": ["client_id", "chat_id", "task_id"],
"control_actions": ["generate", "sync_rules", "reset"],
"input_modes": ["text", "json", "form_text"],
"tool_calls": true,
"external_tools": {"streaming":false,"execution":"caller","tool_choice":["auto"],"parallel_execution":false},
"strict_json": false,
"streaming": false
}
重试、隔离与 410
- 同一范围下的同一 request_id 只执行或追加一次;重复请求返回同一结果。
- 首次生成、sync_rules 创建、reset 使用由 client_id + chat_id + task_id + request_id 派生的稳定 session ID;进程崩溃后重试会续用同一会话,而不是再建一个。
- 不同范围(插件 / 聊天 / 子任务)严格隔离;session_id 不属于当前范围时返回 410 session_gone。
- 未知或失效的 session_id 也返回 410;插件清除本地绑定后重新发送固定组。
- 同一范围的请求串行处理;跨标签页并发也会排队。
- 普通文本的 stream: true 在本协议下被忽略;外部工具模式要求 stream:false。
- target 只作为元数据保存,不作为正文、画面内容或提示词注入。
普通 OpenAI 兼容模式(旧版/备用,默认关闭)
不传 dsh_session 时,默认返回 400 persistent_protocol_required,避免一次健康检查或测试请求在 DSH 里创建一个正式持久会话。确实需要旧模式时,在桥接配置中显式设置 allowLegacyPlain: true;启用后按普通 OpenAI 消息模式处理,每次生成请求必须带两个稳定标识:
| 字段 | 含义 | 可放位置 |
| chat_id | 酒馆聊天 ID,稳定不变 | body.chat_id、body.chatId、body.metadata.chat_id、x-chat-id |
| request_id | 本轮请求 ID,重试时不变 | body.request_id、body.requestId、body.metadata.request_id、x-request-id、Idempotency-Key |
同一 chat_id 的请求会串行处理。不同 chat_id 可以并行,互不串台。
首次请求
把完整规范、角色资料、世界书、已有上下文和目标正文按顺序放进 messages:
curl -s http://127.0.0.1:43121/v1/chat/completions \
-H 'content-type: application/json' \
-d '{
"model": "dsh-default",
"chat_id": "tavern-chat-001",
"request_id": "turn-0001",
"messages": [
{"role": "system", "content": "完整规范/世界书/角色资料"}, {"role": "user", "content": "已有剧情上下文"}, {"role": "assistant", "content": "上一段正文"}, {"role": "user", "content": "本轮目标正文"} ], "temperature": 0.6, "max_tokens": 8192, "stream": false }'
桥接会创建 DSH 会话,发送完整上下文,并在成功后把最终回答写入
choices[0].message.content。
后续请求
推荐继续发送 完整 messages 历史(OpenAI 常见做法),桥接会自动只追加上次已发送内容之后的新增部分:
{
"chat_id": "tavern-chat-001",
"request_id": "turn-0002",
"messages": [
{"role": "system", "content": "完整规范/世界书/角色资料"}, {"role": "user", "content": "已有剧情上下文"}, {"role": "assistant", "content": "上一段正文"}, {"role": "user", "content": "本轮目标正文"}, {"role": "assistant", "content": "桥接上一轮返回的正文"}, {"role": "user", "content": "本轮新增正文"} ] }
也可以只发送新增内容,桥接会把无 system 的 messages 当作增量:
{
"chat_id": "tavern-chat-001",
"request_id": "turn-0003",
"messages": [{"role": "user", "content": "只发本轮新增正文"}]
}
如果只发增量,建议显式加 "context_mode": "delta",避免客户端某些特殊格式被误判。
调参
- temperature、top_p 等采样参数当前版本不会透传到 DSH Agent(安全忽略)。
- max_tokens 会作为 agentOptions.maxTokens 传给新会话或恢复的会话。
- stream: true 会返回 OpenAI 风格 SSE,但内容在 Agent 完成整轮后一次性发出;不是逐 token 流。
- 其他未知字段安全忽略。
API
GET /v1/models
固定返回:
{
"object": "list",
"data": [{"id": "dsh-default", "object": "model"}]
}
dsh-default 映射到 DSH 当前选择的模型通道;如果桥接配置里写了 provider/model,则使用配置值。
POST /v1/chat/completions
请求体:
{
"model": "dsh-default",
"chat_id": "tavern-chat-001",
"request_id": "turn-0001",
"messages": [
{"role": "system", "content": "..."},
{"role": "user", "content": "..."}
],
"context_mode": "auto",
"max_tokens": 8192,
"stream": false
}
context_mode:
| 值 | 行为 |
| auto(默认) | 用完整历史做前缀 diff;不带 system 的列表优先按增量处理 |
| full | 强制按完整历史 diff;重写或回退会触发重建 |
| delta | 强制把 messages 全部当新增内容追加 |
| branch | 强制重建分支会话,用本次 messages 作为新分支的完整上下文 |
成功响应:
{
"id": "chatcmpl-turn-0001",
"object": "chat.completion",
"created": 1793054822,
"model": "dsh-default",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "最终正文或 images/changes JSON"},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1234,
"completion_tokens": 567,
"prompt_cache_hit_tokens": 100
},
"bridge": {
"chat_id": "tavern-chat-001",
"session_id": "session-...",
"turn": 12,
"idempotent": false,
"branch": false
}
}
usage 只在 DSH 或上游真实提供时出现。缺失的字段直接省略,不伪造成 0。
缓存命中可能是 prompt_cache_hit_tokens,也可能是 prompt_tokens_details.cached_tokens,两者都按上游原样透传。
新请求还会在 usage.diagnostics 中记录诊断;usage 字段结构和跨事件累加方式保持兼容,原生 DSH 输入口径按下述账目规则纠正:
- usageEventCount 是带 usage 的消息事件数,maxUsageEventPromptTokens 是事件最大输入,二者不等同于模型调用数和单次上下文。
- 每个事件有明确的 data.callId 或合法的 turn:step 时才提供 modelCallCount,消息 ID 不作替代。同一步重复记录时不猜测 token 去重方式。
- 只有调用 ID 全部唯一且每条均有输入计数时,才提供 sumPromptTokens 和 maxPromptTokens。重复调用 ID 的 usage 是快照还是增量无法确认时,保留未知。
- cacheReporting 标记是否提供缓存数据,cacheCoverage 为 complete/partial/none。完整且独立的调用才提供诊断缓存合计;缺失值不补零。
- usageRecords 保留调用标识、识别到的数值 usage,以及原始 DSH 数值字段 adapterUsage,不复制正文、请求头或任意上游元数据。两种缓存字段若同时存在,不相加;诊断合计优先使用 prompt_cache_hit_tokens。
DSH 的 cacheReadTokens 映射到 prompt_tokens_details.cached_tokens。若原生字段满足 totalTokens = inputTokens + cacheReadTokens + cacheWriteTokens + outputTokens,则按已核对的账目将缓存部分计入 OpenAI 格式的 prompt_tokens;已有显式 prompt_tokens 不再加一次缓存。方程无法验证时保留原输入值,不能只因缓存读取大于该值就断言数据累计或上下文截断。旧版本保存的 prompt_tokens 可能只含未缓存部分,不能直接与新版本比较。
只读账本(不会调用模型、修改状态或压缩历史):
node tools/ctx-audit.mjs --state /path/to/state.json
node tools/ctx-audit.mjs --state /path/to/state.json --json /path/to/report.json
调用数与事件数分列;历史无诊断时显示未知。--prompt /path/to/payload.json 可提供按正则分类的估算,仅用于观察方向,不能当作准确来源归因。固定规则的字符体积来自当前保存版本,token 数为估算,不代表旧请求的最终模型输入。源仓库更新后,需在没有生成任务时另行同步 vendor 并重启;旧记录不会自动补齐。
流式响应:
curl -N http://127.0.0.1:43121/v1/chat/completions \
-H 'content-type: application/json' \
-d '{
"chat_id": "c1",
"request_id": "r1",
"stream": true,
"messages": [{"role": "user", "content": "hello"}]
}'
返回标准 data: {...} 分片,最后 data: [DONE]。若 stream_options.include_usage 为 true,会在结束前发一个 usage 分片。
POST /v1/bridge/reset
重置某个聊天的绑定。旧 DSH 会话保留在历史里,不会被删除;下一次请求创建新会话。
curl -s http://127.0.0.1:43121/v1/bridge/reset \
-H 'content-type: application/json' \
-d '{"chat_id":"tavern-chat-001"}'
当前聊天还有请求未结束时返回 409 chat_busy。
GET /v1/bridge/status?chat_id=...
查看绑定、会话 ID、模型、预设、已记录消息数、历史分支。
GET /health
健康检查,返回服务名、版本、端口、启动时长。
普通请求兼容模式
有些插件(例如玉子手机的 API 预设)只能填 URL / Key / 模型,无法发送 dsh_session。桥接默认拒绝这类请求;如果在设置面板显式开启兼容模式,可以把它们归入一个固定的本机 scope:
plainCompat.enabled = true
plainCompat.clientId = yuzi-phone
plainCompat.chatId = yuzi-phone
plainCompat.taskId = default
行为:
- 只对不带 dsh_session 的 POST /v1/chat/completions 生效;
- 自动补 protocol_version:1、action:generate、fixed_message_count:0,并按 chat_id + messages 生成稳定的 request_id;
- 所有普通请求共用这一个持久会话;
- stream: true 会返回 SSE,其余返回普通 JSON;
- 显式带 dsh_session 的请求不受影响。
这是全局开关,同一时间只适合一个不会发 dsh_session 的插件。数据库有能力发 dsh_session(用固定组),不要和玉子共用兼容模式。
行为细节
首次 vs 后续
- 首次请求:messages 全部进入新会话。最后一条是 user 时,它被放到 <st_bridge_current_request>;其他消息按原顺序放进 <st_bridge_context>。
- 后续请求:如果完整历史是已记录历史的严格扩展,只把新增的 user/system 消息发进同一会话;已发送过的内容不会重复追加。
- 单条新增 user 消息会原样发送,不加包装,尽量保持柏宝绘的原文和格式。
request_id 幂等
- 同一 chat_id + 同一 request_id + 相同 messages:直接返回上一次结果,不新增消息、不重复调用模型。
- 同一 request_id 但 messages 不同:409 request_id_conflict。
- 同一 request_id 正在处理:等待同一个 Promise;跨进程重启用会话日志尝试恢复。
- 失败请求会缓存错误;如需重试,请换新的 request_id。
分支/重建
以下情况会创建 新的 DSH 会话,旧会话保留:
- 旧楼层被改写(messages 与已记录历史在中间分叉);
- 回退剧情(messages 变短);
- swipe/重新生成(相同或截断的上下文,没有新增用户内容);
- 固定规范、世界书、角色资料变化;
- 原会话无法恢复且本次带完整上下文。
新会话会重新接收完整上下文,避免旧场景污染新分支。分支关系记录在 previous_sessions 中。当前版本采用「重建」而不是 DSH 原生 fork;这满足「从对应位置分支或重建会话」的要求,也最容易保证干净。
串行
同一 chat_id 的请求进入单条 Promise 队列;上一轮完成后才开始下一轮。
不同 chat_id 各自独立队列。
最终回答
只取本轮最后一条不含 tool-call 的 assistant/message。工具调用步骤、进度提示、内部思考不会混进最终回答。回答原样返回,不解析 JSON,不加代码围栏。
DSH 界面继续交流
会话是普通 DSH 会话,会挂到 cwd 对应的 MOSS 工作区。你可以在 DSH 里打开它继续聊天。桥接的增量 diff 只跟踪柏宝绘发来的消息,不跟踪你在 DSH 界面手工输入的消息;但那些消息已经在同一个会话里,后续桥接追加时 Agent 仍能看到它们。只有在触发分支/重建时,才会只使用柏宝绘提供的上下文。
配置
安装脚本写入的配置块:
- id: st-bridge
name: ST-bridge
config:
host: '127.0.0.1'
port: 43121
cwd: 'D:\AIGC\MOSS'
agentPreset: st-bridge
requestTimeoutMs: 1800000
maxBodyBytes: 33554432
可选字段:
| 字段 | 默认 | 说明 |
| provider / model | 空 | 空表示使用 DSH 当前默认模型选择 |
| maxTokens | 空 | 默认输出上限;请求里的 max_tokens 优先 |
| agentPreset | st-bridge | Agent 预设 ID |
| authToken | 空 | 设置后要求 Authorization: Bearer 或 x-api-key |
| corsOrigins | 未设置 | 额外允许的 Origin;默认允许本机与浏览器扩展 |
| allowRemote | false | 允许绑定非 127.0.0.1 地址,不建议 |
| allowLegacyPlain | false | 允许不带 dsh_session 的旧式普通补全;会创建持久会话 |
| allowedClientIds | [] | 非空时只允许列表中的 client_id;留空允许所有 |
| stateDir | ~/.dsh/st-bridge | 映射和日志目录 |
状态文件:~/.dsh/st-bridge/state.json。日志: ~/.dsh/st-bridge/bridge.log。
错误
所有错误都是:
{"error":{"message":"具体原因"}}
| HTTP | code | 含义 |
| 400 | missing_chat_id / missing_request_id | 缺少稳定标识 |
| 400 | model_not_found | 只支持 dsh-default(或配置的模型 ID) |
| 400 | unsupported_content | 消息含非文本片段,拒绝静默丢弃 |
| 400 | persistent_protocol_required | 未带 dsh_session 且未开启旧模式 |
| 400 | invalid_client_id / invalid_task_id | 插件身份或子任务标识不合法 |
| 400 | unsupported_tool_mode | 调用了原生工具协议 |
| 400 | unsupported_response_format | 请求了严格 JSON schema 约束 |
| 400 | unsupported_reasoning_effort | 模型不支持该思考强度;桥接会按模型能力过滤 |
| 400 | invalid_fixed_count / fixed_types_mismatch / invalid_fixed_type | 固定组字段不合法 |
| 400 | reset_messages_not_empty / empty_dynamic_group / missing_user_message | action 与 messages 不匹配 |
| 401 | unauthorized | 配置了 token,但请求没带或带错 |
| 403 | origin_forbidden | 浏览器 Origin 不在白名单 |
| 403 | client_not_allowed | client_id 不在面板允许列表中 |
| 409 | request_id_conflict | 同一 ID 对应不同请求内容 |
| 409 | request_in_progress | 该 ID 仍在处理,且无法从日志恢复 |
| 409 | duplicate_context | 没有新增内容 |
| 409 | session_unavailable | 会话恢复失败,且本次只有增量 |
| 410 | session_gone | 会话未知、失效或不属于该 chat_id;插件应清绑定并重新初始化 |
| 413 | context_length_exceeded | 上下文超出模型限制 |
| 413 | body_too_large | 请求体超过上限 |
| 502 | agent_turn_error | Agent 回合失败 |
| 502 | upstream_account_error | 账号/额度异常 |
| 502 | empty_answer | 回合结束但没有最终正文 |
| 504 | timeout | 超过 requestTimeoutMs |
安全
- 默认只绑定 127.0.0.1。
- 默认允许本机页面和浏览器扩展 Origin;其他网页 Origin 返回 403。
- 如果本机还有其他用户或不可信页面,请设置 authToken。
- 桥接会让本机调用方使用你的 DSH 模型账号,可能产生费用。
发布到 GitHub
本目录已经初始化为本地 Git 仓库,当前分支 main,未配置 remote,也没有执行推送。
创建好 GitHub 仓库后:
git remote add origin https://github.com/<你的账号>/<仓库名>.git
git push -u origin main
git push --tags
提交作者由本机 Git 身份决定。后续提交如需使用自己的身份:
git config user.name "Your Name"
git config user.email "you@example.com"
仓库里不要提交 settings.json、state.json、*.log;.gitignore 已排除。
blocked 与归档会话
桥接会在恢复会话时检查 DSH 的归档状态。已归档会话返回 HTTP 409、error.code=session_archived;恢复旧会话,或明确清除绑定新建后再提交。桥接不会自动解除归档,也不会绕过归档新建会话。
DSH 在模型调用前拒绝请求时,日志可能只有 inbox 领取记录和 turn/end: blocked,没有 user/message。桥接会按确切 request ID 回查被领取的 inbox 消息,将该请求标记为 error 并返回 agent_turn_blocked,不再等待整个超时时间。重启后重试旧 pending 请求时也使用同一恢复逻辑;不匹配的、尚未领取的和取消的消息不会被当成本请求的结果。
HTTP 400 persistent_protocol_required 是另一类入口错误:请求未携带 dsh_session,尚未进入 Agent 回合。应修正调用方的协议配置;它不等于 blocked。
测试
cd D:\AIGC\MOSS\ST-bridge
npm test
测试覆盖:dsh_session 的 generate/sync_rules/reset、固定组注入、多插件/子任务 scope 隔离、旧绑定兼容、工具模式拒绝、capabilities、410、request_id 幂等、串行、usage 透传;设置面板的设置校验、持久化、token 不回显、危险操作确认;以及旧模式的 messages 顺序、多 system、前缀 diff、增量/分支/回退、SSE、工具调用过滤。
柏宝绘专属模式(可选)
柏宝绘可使用插件级稳定 chat_id,并发送 session_mode: "dedicated" 和 source_chat_id。
普通模式保持原样。专属模式的 sync_rules/reset 成功响应在验证原生 surface API 后返回 dedicated-v1 能力确认。
每次生成前,桥接分别替换受保护的系统头和历史会话尾部,旧事件仍留在不可变日志中;新生成只投影本轮动态快照和当前有效固定规则。
快照差量裁剪在该模式下停用。相同 request_id 继续幂等,来源聊天改变会触发请求冲突。
会话标题稳定为「柏宝绘专属会话 · 输出格式」,不跟随正文变化。
skill_id 是预留字段;当前版本不加载技能,非空值返回 skill_binding_unavailable。不要将外部工具续接与专属快照模式混用。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
wuhehen176/ST-bridge
ST-bridge 是本机持久会话桥接,供柏宝绘、玉子手机、数据库等酒馆插件调用:
相关插件 · 其他
模型破甲清洗YuJunZhiXue/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 16,148已汉化DeepSeek 客户端
73
女娲蒸馏alchaincyf/nuwa-skill
输入名人名字,提炼其思维模型与决策方式供你调用
★ 37,308已汉化DSH
72
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 888已汉化DSH
71.6
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,266已汉化DSH
70.7
这是你的仓库?认领条目