Skip to content

fix(sdk): flatten createTranscription and createSpeech method signatures#366

Draft
charlesrockhead-OR wants to merge 3 commits intoOpenRouterTeam:mainfrom
charlesrockhead-OR:charlesrockhead-OR/flatten-stt-tts-sigs
Draft

fix(sdk): flatten createTranscription and createSpeech method signatures#366
charlesrockhead-OR wants to merge 3 commits intoOpenRouterTeam:mainfrom
charlesrockhead-OR:charlesrockhead-OR/flatten-stt-tts-sigs

Conversation

@charlesrockhead-OR
Copy link
Copy Markdown

Summary

openrouter.stt.createTranscription({ model, inputAudio }) and openrouter.tts.createSpeech({ model, input }) did not compile against @openrouter/sdk v0.12.28 — the request body was wrapped under a sttRequest / speechRequest field, so callers had to write { sttRequest: { model, inputAudio } }.

This was caused by Speakeasy's maxMethodParams heuristic: STT and TTS each had 4 parameters (the request body plus 3 globally-injected app-identification headers — HTTP-Referer, X-OpenRouter-Title, X-OpenRouter-Categories). With 4 > the per-route override of 1 in x-speakeasy-max-method-params, Speakeasy collapsed everything into a single wrapper object, defeating the override.

Fix

Add x-speakeasy-globals-hidden: true on the per-operation declarations of those headers for /audio/transcriptions and /audio/speech only, via the existing add-headers.overlay.yaml. Per Speakeasy's docs, this hides the global from the per-call method signature while keeping it set via the SDK constructor. The body is then the only parameter Speakeasy counts, so it rides at the top of the method signature instead of being wrapped.

API change

// Before
openrouter.stt.createTranscription({
  sttRequest: { model: "openai/whisper-large-v3", inputAudio: { data, format: "wav" } },
});

// After
openrouter.stt.createTranscription({
  model: "openai/whisper-large-v3",
  inputAudio: { data, format: "wav" },
});

Same for openrouter.tts.createSpeech.

What's unchanged

  • Wire behavior. HTTP-Referer / X-OpenRouter-Title / X-OpenRouter-Categories are still emitted on every STT/TTS request from client._options.httpReferer / appTitle / appCategories. See src/funcs/sttCreateTranscription.ts and src/funcs/ttsCreateSpeech.ts — the header injection block is identical to before.
  • Constructor surface. new OpenRouter({ httpReferer, appTitle, appCategories }) works exactly as before.
  • All other methods. chat.send, embeddings.generate, responses.send, guardrails.*, videoGeneration.generate, etc. still accept their existing wrapped request shape and still expose per-call header overrides.

Breaking change for STT/TTS only

Anyone passing per-call header overrides to STT or TTS specifically (createTranscription({ sttRequest, httpReferer: "..." })) will see a TS error — those headers must now be set on the OpenRouter constructor. In practice these are app-identification headers that almost always come from constructor options, not from per-call overrides, so the impact should be small.

Why an overlay (not a hand-written wrapper)

Hand-written wrappers around generated SDKs are explicitly disallowed for OpenRouter's generated SDKs. This change uses Speakeasy's own documented mechanism (x-speakeasy-globals-hidden) and is contained to a single overlay file.

Add x-speakeasy-globals-hidden: true to the app-identification headers
(HTTP-Referer, X-OpenRouter-Title, X-OpenRouter-Categories) on
/audio/transcriptions and /audio/speech so they no longer count toward
x-speakeasy-max-method-params. Speakeasy still injects them from the SDK
constructor, but the per-call method signature stays flat — callers can
now write:

  openrouter.stt.createTranscription({ model, inputAudio })
  openrouter.tts.createSpeech({ model, input, voice })

instead of wrapping the body under { sttRequest: ... } / { speechRequest: ... }.

Scoped to STT/TTS only; all other endpoints keep their existing per-call
header override capability.
…atten-stt-tts-sigs

# Conflicts:
#	.speakeasy/gen.lock
#	package.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant