DeepSeek Harness Hub
← 返回列表

launchmaniac/dsh-media-tools

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

图像、视频和语音生成,作为 deepseek-harness 工具,由 OpenRouter 提供支持。以树外…

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/24 · 已提供中文文档

OpenRouter 图像、视频和语音生成作为 deepseek-harness 工具——一个树外配置文件包,无需 fork

综合分
28.1
GitHub 分
28.1
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add launchmaniac/dsh-media-tools
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-attachment@deepseek-ai/dsh-credentials@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm@deepseek-ai/dsh-settings@deepseek-ai/dsh-tools@deepseek-ai/schemastery
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-media-tools

图像、视频和语音生成,作为 deepseek-harness 工具,由 OpenRouter 提供支持。以树外 profile 包的形式发布——无需 fork harness,无需修改核心。

它注册了什么

| 工具 | 后端端点 | 结果以何种形式到达模型 |
|---|---|---|
| generate_image | POST /images | 图像本身——提交到附件存储,以图像块的形式返回。同时写入 outputDir,以便人工打开。 |
| generate_video | POST /videos + 轮询 | 一个文件路径 |
| generate_speech | POST /audio/speech | 一个文件路径,外加一个播放链接 |
| transcribe_audio | POST /audio/transcriptions | 转录文本——这里唯一一个向内运行的工具 |

这种划分就是整个设计的核心,而且并非随意为之。harness 的内容词汇表(ContentBlockMap)包含 text、reasoning、image、tool-call 和 tool-result——没有视频,没有音频——而模型路由可能只声明 text 和 image 输入。因此,生成的图像可以重新进入模型上下文,而生成的视频则不能。添加视频或音频块需要修改 harness 本身及其适配器、UI 和压缩消费者,这是任何树外包都无法做到的。

实际后果是:模型永远看不到视频,也听不到音频。 它只知道路径和字节数。正因如此,渲染出的工具结果严格保持事实性——模型无法核实任何关于产物外观或声音的说法。

生成的图像确实会内联显示在 Web UI 中,其实现路径值得你在依赖它之前了解清楚。没有任何 harness 界面会渲染工具结果中的图像——卡片显示的是持久引用,而非像素——并且客户端的 markdown 渲染器只接受来自 http(s) 的图像,拒绝 data: URI 和 file:// 路径。因此,本包会在 harness Web 服务器上,用一个不可猜测的进程本地令牌来提供每张写入的图像,工具结果则将该 URL 交给模型,并指示其将 URL 包含在回复中。

最后一步正是需要注意的地方:显示取决于模型是否遵循该指令。 如果模型忽略它,你只会得到文件路径而没有图片。因此,每张图像也会以真实扩展名写入 outputDir,并且 revealImages: true 会在每张图像生成时在你的桌面查看器中打开它——这两条路径不依赖模型行为。

安装

dsh plugin --profile  add @launchmaniac/dsh-media-tools
dsh --profile  --dump-config   # verify the layer without booting

这是推荐的方式:npm tarball 已经附带构建好的 lib/,因此安装时你的机器上不会执行任何内容,也不涉及构建许可。

改为从 GitHub 安装

git 安装获取的是源代码,而非构建产物,因此 pnpm 会运行本包的 prepare 脚本来构建 lib/。pnpm ≥10 拒绝运行 git
依赖的构建脚本,直到你允许它为止,所以第一次 add 会失败,并给出它想要的包键。把它加到你的 profile 的 pnpm-workspace.yaml 中:

allowBuilds:
"@launchmaniac/dsh-media-tools": true

然后重新运行 add。

npm v12 将 git 依赖与构建脚本分开管控——安装一个还需要 --allow-git,而远程 URL 依赖需要 --allow-remote。npm approve-scripts --allow-scripts-pending 会审查正在等待的内容。这是优先选择上面那种 npm 安装方式的另一个原因:它是一个普通的 registry 依赖,不会触发这些问题中的任何一个。

把这项许可当作它本来的样子:允许在安装时在你的机器上执行这个包的代码,在 agent 运行所在的任何沙箱之外。先阅读源码,并固定一个 commit,这样后续的推送就无法悄悄改变运行的内容:

dsh plugin --profile  add github:launchmaniac/dsh-media-tools#

如果你不想授予构建许可,可以从一个 checkout 用 pnpm pack 打包成 tarball,然后 dsh plugin --profile  add ./launchmaniac-dsh-media-tools-0.1.0.tgz——已预构建,因此不涉及构建权限。

设置你的密钥:

export OPENROUTER_API_KEY=sk-or-...

当挂载了 harness 凭据接缝(ctx.credentials)时,密钥会通过它读取,否则回退到进程环境。它是按调用解析的,从不缓存,因此轮换后的密钥会在下一次工具调用时生效。

配置

三个地方,优先级递增。

1. 每次调用,在对话中。 generate_image 接受一个可选的 model,所以你可以说“用 recraft/recraft-v4-vector 生成一个 logo”,它只对该次调用生效。

2. $DSH_HOME/settings.yaml 中的 media-tools 键下。这是实时生效的那个——更改会在下一次工具调用时生效,无需重启:

media-tools:
imageModel: black-forest-labs/flux.2-pro

Settings 对话框的 Open configuration file 按钮可以打开这个文件。该 bundle 通过 installSettingsSection 注册其 schema,因此值在写入时会经过校验。它尚未作为卡片出现在 Settings → Plugins 中:那需要一个用 dsh.client 声明的浏览器端部分,而客户端 bundle 的构建预设并未在 harness monorepo 之外发布。

3. 你的 profile 的 cordis.patch.yml —— 其他所有配置都叠加其上的部署默认值:

- id: media-tools
name: "@launchmaniac/dsh-media-tools"
config:
imageModel: bytedance-seed/seedream-4.5
videoModel: bytedance/seedance-2.5
A voice-requiring model must be given one, or every call 400s.
speechModel: google/gemini-3.1-flash-tts-preview
speechVoice: Kore
outputDir: ./media
videoTimeoutMs: 900000

| 键 | 默认值 | 含义 |
|---|---|---|
| apiKeyEnv | OPENROUTER_API_KEY | 保存密钥的环境变量 |
| baseURL | https://openrouter.ai/api/v1 | API 根地址 |
| attributionTitle | deepseek-harness | 作为 X-Title 发送 |
| attributionUrl | — | 作为 HTTP-Referer 发送 |
| imageModel | bytedance-seed/seedream-4.5 | 由 generate_image 使用 |
| videoModel | bytedance/seedance-2.5 | 由 generate_video 使用 |
| speechModel | fish-audio/s2.1-pro | 由 generate_speech 使用 |
| speechVoice | — | 默认语音,可在每次调用时覆盖 |
| transcribeModel | openai/whisper-1 | 由 transcribe_audio 使用;deepgram/nova-3 和 openai/gpt-4o-transcribe 也可用 |
| maxTranscribeBytes | 26214400 | 发送用于转录的最大音频文件 |
| outputDir | ./media | 产物写入的位置。相对路径会相对于会话的工作目录解析,因此每个工作区保留各自的目录;绝对路径则将所有内容汇集到一处 |
| revealImages | false | 在桌面查看器中打开每张生成的图像 |
| requestTimeoutMs | 120000 | 每个 HTTP 请求的预算 |
| videoPollIntervalMs | 5000 | 视频任务轮询之间的延迟 |
| videoTimeoutMs | 900000 | 单个视频任务的总等待时间 |

补丁会替换某一行的整个 config 值,而不是合并键,因此覆盖时必须重新声明它所需的每一个键。

要求与拒绝

generate_image 在两种情况下会拒绝,而不是降级:

- 未挂载附件存储。 该工具注册在 ctx.inject(['attachments'], …) 内部,因此没有附件存储时它不存在。@deepseek-ai/dsh-attachment-local 随 @deepseek-ai/dsh-base 一起提供,因此正常配置文件中会有它。
- 调用模型未声明 image 输入。 生成当前路由无法承载的图像,会把一个块放入持久会话历史中,而该路由无法重放它。拒绝信息会指明模型并提示你切换。

两项检查都在任何 HTTP 请求之前运行,因此拒绝绝不会消耗一次调用。

音频输入:转录

transcribe_audio 是唯一向内运行的工具。没有聊天路由接受音频
输入——ModelModality 仅支持文本和图像——因此转录是录制的
语音到达模型的唯一方式。将它指向一个文件,模型就会读取所说的内容。

提供三种模型:openai/whisper-1(默认)、deepgram/nova-3 和
openai/gpt-4o-transcribe。它们都不出现在普通的 /models 列表中,
就像 TTS 模型一样。

这是基于轮次的,而不是对话。与智能体实时交谈需要在浏览器中进行
麦克风采集,而插件无法触及这一点——那是测试框架侧的改动。

文本转语音:语音与容器

在配置 TTS 之前,有两件事值得了解,它们都是通过运行端点而不是
阅读其文档学到的:

- 大多数提供商要求显式的 voice,而语音名称不可
移植。 Gemini TTS 会拒绝无语音的请求,并接受像
Kore 或 Puck 这样的名称(alloy 返回 500)。Deepgram 接受 flux-*-en 名称
并在其错误中列出有效集合。fish-audio/s2.1-pro 在完全没有语音的情况下
进行合成,这就是它成为随附默认值的原因——该工具可以正常工作
开箱即用,并且你有意选择了一个需要语音的模型。
- 原始 PCM 会被重新封装为 WAV。 两个已验证的提供方都会返回
audio/pcm,采样率只出现在媒体类型参数中。按原样写入这些字节是无法播放的,
因此 generate_speech 会前置一个 RIFF/WAVE 头(16 位小端序,采样率和声道数取自媒体类型),
并写入 .wav。非 PCM 音频则原样透传。

选择模型

GET https://openrouter.ai/api/v1/images/models 和 .../videos/models 会列出每个端点当前可用的内容。默认的 /api/v1/models 列表只返回文本输出模型,这就是生成模型不出现在其中的原因。

已知限制

- 视频和音频写入绕过了 ctx.fs 接缝。 产物使用 node:fs 直接写入 outputDir,因此它们不受会话文件系统沙箱或观察策略的约束。这受限于目标是一个由部署配置的单一目录,且绝不是模型提供的路径,但这确实是一个真实的缺口——参见 src/output.ts 中的 FIXME。
- 不支持流式传输。 图像和语音调用会在写入之前将整个产物缓冲在内存中。
- 假定 PCM 为 16 位。 audio/pcm 媒体类型携带采样率和声道数,但不携带采样位宽。观察到的每个提供方都输出有符号 16 位小端序;如果有提供方输出 24 位或 32 位,生成的 WAV 会以错误的速度播放,而不是直接失败。参见 src/output.ts 中的 PCM_BITS_PER_SAMPLE。
- 视频内容过滤器会基于音轨进行拒绝。 即使视觉提示词无害,generate_audio: true 请求也可能因版权拒绝而失败。如果你一直遇到这种情况,请传入 generate_audio: false。
- 视频任务的生命周期会超过其超时时间。 当 videoTimeoutMs 到期时,该工具会报告超时并指明任务 id;任务会在服务端继续运行,且该 id 仍可轮询。
- 配置在加载时读取,而非实时读取。 该插件只读取其配置节一次。如果你想要实时编辑,请接入来自 @deepseek-ai/dsh-settings 的 installSettingsSection。
- 不生成声明文件。 prepare 必须在 git 安装环境中工作,此时 peer 依赖可能无法解析,因此 tsdown 以 dts: false 运行。在已安装 peer 依赖的检出中运行 pnpm typecheck 以获得真实的类型信号。

开发

pnpm install
pnpm check       # 对纯辅助函数进行自检;不需要密钥,也不需要 peer 依赖
pnpm typecheck   # 真实的类型信号;需要安装 peer 依赖
pnpm build

pnpm check 会测试唯一没有请求覆盖的分支逻辑——扩展名选择、文件命名,以及可重放安全的呈现器收窄。它可以独立运行,因为 src/output.ts 没有运行时 peer 导入。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群