Skip to content

Image and speech tools, and /redrob/speech and /redrob/transcribe routes - #85

Merged
its-janghoon merged 7 commits into
developfrom
feature/media-tools
Oct 12, 2026
Merged

its-janghoon merged 7 commits into
developfrom
feature/media-tools

Conversation

@its-janghoon

Copy link
Copy Markdown
Member

Summary

The media half of the engine work, re-cut from the closed #69, #71, #73 and #74 onto current develop, one commit each, plus harness coverage.

  1. image_generate and speech_generate tools, running on the Redrob credential the engine already holds. speech_generate saves an mp3 under artifacts/ (not attached, so the clip is not billed as input on every later turn).
  2. POST /redrob/speech (mp3 bytes) and POST /redrob/transcribe ({ text, seconds?, costUsd? }), so an app can play and dictate speech without ever holding the key. They relay to the Console audio API that landed in redrob-console#253.
  3. Capability gate, up front. Both tools are registered only when a Redrob credential is connected (the registry already did this for images; speech joins it), so on another provider the model never sees a tool that would fail. Both routes answer 503 service unavailable: redrob before anything is sent when there is no key, and 400 for input the gateway would refuse (empty text, bad base64, unsupported format, over the size cap). Nothing fails silently.

Not in this PR

image_generate editing and reference images (#70): nobody asked for it yet. The on-device labellers (#79) and the consolidated #80.

Tested

  • bun turbo typecheck --concurrency=2: 18/18.
  • packages/redrob: image_generate, speech_generate, registry, httpapi-speech, httpapi-transcribe tests, 37 pass.
  • httpapi-exercise in all three modes: 219 pass, 0 missing. The two new routes are exercised and refuse with 503 in the key-less exercise home.
  • SDK regenerated for the two routes.

Redrob Cowork asks for images through the Redrob gateway, but the key that
pays for them belongs to this engine: it lives in the auth store (or
REDROB_API_KEY), the desktop app never reads it, and no plugin API hands
it out. A Cowork plugin could only reach it by registering a second
`redrob` auth hook, which would replace "Connect Redrob" in onboarding, or
by fishing it out of an undocumented hook argument. So the tool is a
built-in, and the key stays where it is.

image_generate posts the prompt to the gateway's /chat/completions with
modalities ["image", "text"] (relayed since console #230), writes the
returned picture under artifacts/, and returns it as an attachment, which
is what puts it inline in the conversation and in front of the model. The
file name is chosen before anything is spent and an existing file is never
overwritten. Writing is asked as `edit`, like `write`, so plan mode denies
it. A gateway refusal (an empty balance, say) and a model that answers in
words alone are reported with the gateway's or the model's own message.

The registry offers the tool only while a Redrob credential is available,
read per request: without one it would be a tool that fails on every call.
The agent could write a script but not voice it. speech_generate sends text to the Redrob gateway's POST /v1/audio/speech on the engine's own credential, for the reason image_generate gives, and saves the mp3 under artifacts/. The default model is multilingual, so a Korean script is spoken as Korean.

The audio is saved, not attached. An attachment goes back to the model with the next turn, and audio input would steer auto to an audio-input model and bill the clip as input on every later turn, to tell the model nothing: it wrote the words.

Everything that can be refused for free is refused before the request: empty text, more than the gateway's 4096 code points, or no credential. The name is chosen first and an existing file is never overwritten, writing is asked as edit, a gateway refusal is relayed with its own message, and an answer that is not audio is not saved. The registry offers it under the same credential rule as image_generate.
An edit to the expected character count duplicated one line and dropped the model assertion. The block now checks filepath, model, the code-point count and the cost once each.
…he key

Redrob Cowork's read-aloud has to play audio in the app, and the Redrob key that pays for it belongs to this engine. The route speaks text through the gateway on the engine's own credential and answers with the mp3, so the key never leaves this process.

It shares one path with speech_generate: prepareSpeech validates and picks the model and voice, speechKey finds the credential, and requestSpeech makes the one gateway call and checks the answer is audio. Each fails with a typed SpeechError, which the route maps to its declared errors: invalid text is a 400, no credential a 503 (the engine lacks it, not the caller), a gateway refusal or non-audio answer a 502 carrying the gateway's message, and a timeout a 504. The first two are found before anything is sent. The tool's behaviour is unchanged.
POST /redrob/speech exists for audio a client plays at once: a reply read
aloud and the voice conversation's answer, where the wait before the first
word is what the user feels. It now defaults to eleven-flash-v2.5 with the
same voice, sarah. speech_generate keeps eleven-multilingual-v2 for saved
files, and a caller can still name any model.
… Redrob key

Redrob Cowork's push-to-talk needs a transcript without holding the key,
as read-aloud needed audio. The route takes base64 audio, its format and
an optional language and model, refuses anything the gateway would refuse
before sending it, and relays /v1/audio/transcriptions.
Both routes refuse with 503 before anything is sent when no Redrob key is connected.
@its-janghoon
its-janghoon merged commit 4695d20 into develop Oct 12, 2026
27 of 28 checks passed
@its-janghoon
its-janghoon deleted the feature/media-tools branch October 12, 2026 17:49
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