fix(openrouter): normalize stt mime parsing · openclaw/openclaw@f756b9a
remdev
·
2026-05-12
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -922,6 +922,7 @@ Docs: https://docs.openclaw.ai
|
922 | 922 | - Discord/status: add degraded Discord transport and gateway event-loop starvation signals to `openclaw channels status`, `openclaw status --deep`, and fetch-timeout logs so intermittent socket resets do not look like a healthy running channel. (#76327) Thanks @joshavant. |
923 | 923 | - Providers/OpenRouter: add opt-in response caching params that send OpenRouter's `X-OpenRouter-Cache`, `X-OpenRouter-Cache-TTL`, and cache-clear headers only on verified OpenRouter routes. Thanks @vincentkoc. |
924 | 924 | - Providers/OpenRouter: expand app-attribution categories so OpenClaw advertises coding, programming, writing, chat, and personal-agent usage on verified OpenRouter routes. Thanks @vincentkoc. |
| 925 | +- Providers/OpenRouter: add inbound audio STT support to media-understanding via OpenRouter's JSON `/audio/transcriptions` contract, including default audio model metadata and auto-selection priority. (#77490) Thanks @remdev. |
925 | 926 | - Plugins/update: make package upgrades swap pnpm/npm-prefix installs cleanly, keep legacy plugin install runtime chunks working, and on the beta channel fall back default-line npm plugins to default/latest when plugin beta releases are missing or fail install validation. Thanks @vincentkoc and @joshavant. |
926 | 927 | - Channels/WhatsApp: support explicit WhatsApp Channel/Newsletter `@newsletter` outbound message targets with channel session metadata instead of DM routing. Fixes #13417; carries forward the narrow outbound target idea from #13424. Thanks @vincentkoc and @agentz-manfred. |
927 | 928 | - Exec approvals: add a tree-sitter-backed shell command explainer for future approval and command-review surfaces. (#75004) Thanks @jesse-merhi. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -146,6 +146,31 @@ describe("openrouter media understanding provider", () => {
|
146 | 146 | ); |
147 | 147 | }); |
148 | 148 | |
| 149 | +it("normalizes parameterized mime for extensionless filenames", async () => { |
| 150 | +const release = vi.fn(async () => {}); |
| 151 | +postJsonRequestMock.mockResolvedValue({ |
| 152 | +response: new Response(JSON.stringify({ text: "ok" }), { status: 200 }), |
| 153 | + release, |
| 154 | +}); |
| 155 | + |
| 156 | +await transcribeOpenRouterAudio({ |
| 157 | +buffer: Buffer.from("audio"), |
| 158 | +fileName: "media-1", |
| 159 | +mime: " Audio/Ogg; codecs=opus ", |
| 160 | +apiKey: "sk-openrouter", |
| 161 | +timeoutMs: 5_000, |
| 162 | +fetchFn: fetch, |
| 163 | +}); |
| 164 | + |
| 165 | +expect(postJsonRequestMock).toHaveBeenCalledWith( |
| 166 | +expect.objectContaining({ |
| 167 | +body: expect.objectContaining({ |
| 168 | +input_audio: expect.objectContaining({ format: "ogg" }), |
| 169 | +}), |
| 170 | +}), |
| 171 | +); |
| 172 | +}); |
| 173 | + |
149 | 174 | it("throws when format cannot be resolved", async () => { |
150 | 175 | await expect( |
151 | 176 | transcribeOpenRouterAudio({ |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -17,11 +17,21 @@ import { OPENROUTER_BASE_URL } from "./provider-catalog.js";
|
17 | 17 | const DEFAULT_OPENROUTER_AUDIO_TRANSCRIPTION_MODEL = "openai/whisper-large-v3-turbo"; |
18 | 18 | const SUPPORTED_AUDIO_FORMATS = new Set(["wav", "mp3", "flac", "m4a", "ogg", "webm", "aac"]); |
19 | 19 | |
20 | | -function resolveFormatFromMime(mime?: string): string | undefined { |
| 20 | +function normalizeMimeType(mime?: string): string | undefined { |
21 | 21 | const normalized = mime?.trim().toLowerCase(); |
22 | 22 | if (!normalized) { |
23 | 23 | return undefined; |
24 | 24 | } |
| 25 | +const [type] = normalized.split(";"); |
| 26 | +const clean = type?.trim(); |
| 27 | +return clean || undefined; |
| 28 | +} |
| 29 | + |
| 30 | +function resolveFormatFromMime(mime?: string): string | undefined { |
| 31 | +const normalized = normalizeMimeType(mime); |
| 32 | +if (!normalized) { |
| 33 | +return undefined; |
| 34 | +} |
25 | 35 | switch (normalized) { |
26 | 36 | case "audio/wav": |
27 | 37 | case "audio/x-wav": |
@@ -32,10 +42,12 @@ function resolveFormatFromMime(mime?: string): string | undefined {
|
32 | 42 | case "audio/flac": |
33 | 43 | return "flac"; |
34 | 44 | case "audio/mp4": |
| 45 | +case "audio/m4a": |
35 | 46 | case "audio/x-m4a": |
36 | 47 | return "m4a"; |
37 | 48 | case "audio/ogg": |
38 | 49 | case "audio/oga": |
| 50 | +case "audio/opus": |
39 | 51 | return "ogg"; |
40 | 52 | case "audio/webm": |
41 | 53 | return "webm"; |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。