What's Changed
A board-clearing release: fourteen of the fifteen open issues, most of them the operational
costs that agents using this tool had been absorbing by hand. Long audio no longer truncates
silently, podcast renders can now prove they contain the words you wrote, ElevenLabs reports what
it spent, batch inputs may span directories, and the simulated-podcast producer steers the turns
it was previously leaving generic. Plus one data-loss bug.
Features
- Long files are windowed for transcription instead of truncating. A 13-minute mp3 came back
cut off around 10.5 minutes with no error, and another run silently dropped a stretch from the
middle; 30 minutes failed outright. Over 8 minutes, the file is now cut into overlapping 90s
windows at a 75s stride, transcribed concurrently, and stitched —chunked: trueand a
windowslist make coverage inspectable rather than assumed. Do not pre-cut long audio
yourself any more. (#64) podcast generate --verifytranscribes each rendered unit, checks it against the script,
and re-renders what is missing, once. TTS drops segment tails and whole short segments at
random with no error, andtranscriptis only an echo of your input — so this replaces an
external QC discipline that cost a median of three renders per episode. A segment failing twice
is reported, not re-rendered a third time. (#65)- ElevenLabs reports characters submitted, per provider and model, on both
audio speakand
podcast generate.sanzaru capabilities --quotareads the remaining monthly allowance
without spending any of it. On a 10,000-character tier this was the number you previously had
to count by hand. (#66) - Batch inputs may span directories.
audio transcribe a/ep.mp3 b/window.mp3used to exit 2;
each input is now anchored and validated under its own parent. Only a shared basename is
still refused. (#62) ActBrief.closing_notedirects the turn that lands an act without spending the
max_turns - 1index, which was unavoidably a takeover. Talking points now also schedule across
the extension turns instead of leaving them on a generic anti-recap note. (#61)PodcastScriptrequires onlyspeakersandsegments.id,speed,instructions,
titleand the wholeconfigblock default, and an invalid script reports every problem at
once rather than one per round trip. (#57)
Fixes
audio compress -odestroyed the input when the file was already under the size budget:
the service wrote nothing and the CLI moved the source away. The documented "compress first,
then transcribe" workflow therefore lost exactly the originals that did not need compressing.
(#60)- An act is now bounded in wall clock against the Realtime API's 60-minute connection close,
landing early withstop_reason: "wall_clock"rather than risking the loss of everything
recorded so far. QC also flagscapped_short, the undershootstop_reasonthat #46 exposed and
nothing consumed. (#63) result.output_filenames the file that actually exists, including when-orenamed it or it
was staged under a temporary name. (#56)- Dialogue mode documents its retry trade, and its 2000-character limit is presented as the
planning number it is. (#58)
Internal
- New
audio/verification.py—words,similarity,transcribe_bytes— shared by realtime QC,
the podcast verify pass, and window merging, instead of three copies that would drift. (#64) AudioProcessorgained audio slicing;TranscriptionServicegained its first tests. (#64)
⚠️ Behavior changes
- Duplicate speaker ids are now a hard error. Previously the last one silently won. (#57)
- The dry-run cost projection rises slightly.
turn_countand thetext_interm project
against the extension ceiling rather than the plannedmax_turns— the same recording, a more
honest number, and you no longer have to inflatemax_cost_usdby hand. (#61) synthesize_speechreturns aSpeechResultrather than bare bytes. Internal, but it is the one
signature change here. (#66)
Still open: #37 (async job mode for podcast generate), blocked on the official mcp SDK
shipping a stable tasks API. See docs/async-task-tracking.md.
Full Changelog: v0.9.1...v0.10.0