Skip to content

Develop - #65

Merged
dkackman merged 17 commits into
masterfrom
develop
Sep 11, 2026
Merged

Develop#65
dkackman merged 17 commits into
masterfrom
develop

Conversation

@dkackman

Copy link
Copy Markdown
Owner

No description provided.

dkackman and others added 17 commits September 11, 2026 10:02
…p_audio

T009: slice_audio read the source's sample rate and dropped it, so a
resample_audio chained off it failed until the rate was restated by hand.
Every audio task now returns an AudioTrack - the waveform with the rate it
is at - which _waveform_and_rate, pair_audio and the save path all already
read. A rate declared on the step or its result still wins.

T001: loop_audio makes a bed of a requested length (seconds, or frames at an
fps) out of a short recording, laps joined with an equal-power crossfade so
the loop point neither clicks nor ticks. It is the missing half of the fix
for the hole under a cut: slice tone out of a shot, loop it to the length of
the episode, mix_audio it under and pair_audio it back on. Wiring it into
dialogue-short waits on a bed measured from real H3 output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
probe_media(path, envelope=True) reports the soundtrack's level second by
second - rms_dbfs and peak_dbfs, one entry each per second - from the decode
pass it already makes. That is what locates something in a track: whether a
shot is still sounding at its last frame, how deep the hole at a seam goes,
where a score goes quiet. Off by default, since a ten-minute track is 600
numbers and the default metadata call has to stay small.

Carried by GET /api/gallery/{name}/metadata?envelope=true and MCP
get_gallery_metadata(name, envelope=True).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eaply

T013: upload_asset(file_path, asset_name=...) and POST /api/uploads?asset_name=
store an upload under a readable name instead of a random hex one. A recurring
cast referenced as asset:uploads/084eaecc....wav in every workflow cannot be
told apart without opening each file. The name may carry folders, is validated
by validate_asset_reference and confined to the library the way keep_output's
is, and takes the uploaded file's extension when it has none. No name given
means the old random one, so two uploads of the same file still never collide.

T006: GET /api/workflows/{name}/variables and get_workflow(name,
variables_only=True) answer with a workflow's variables and their defaults and
nothing else - confirming audio_bleed_ms defaults to 1800 otherwise meant
pulling the whole definition, SDNQ quantization blocks and all, for one
integer. String defaults over 200 characters are cut and named in `truncated`;
full=true returns them whole.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A multi-shot workflow repeats each character's description and voice in every
shot, and the engine has no interpolation to splice a shared block in with -
deliberately, since a {{name}} inside a prompt makes every prompt a template
language nobody declared. compose_text is the composition answer instead: the
parts are whole values (variable:, prompt:, previous_result:) joined in order,
so a character bible is written once as a variable and named by every shot
that needs it, and a voice string is kept in step by being the same value
rather than by being compared.

Positional rather than named, because a named form would be that
interpolation one layer down. Documented in TASKS.md and beside the
no-interpolation rule in WORKFLOW_GUIDE.md, which is where an author meets
the problem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… clips

T005 (breaking rename): dialogue-short's variables and step names are roles,
not the cast of the example - character_a_portrait_prompt,
character_b_portrait_prompt, shot_2_deflect, shot_3_react, shot_4_button,
draw_character_a, draw_character_b. Every run was carrying
howie_portrait_prompt and shot_3_howie_incredulous through its arguments,
manifest and export whatever the cast was; the beats are the reusable part.

T010: character_a_voice / character_b_voice default to null and, when they
name a clip, append a MiniMaxH3AudioReference to each shot that character
speaks in, so a recurring voice is a value rather than a description copied
into every prompt.

That needed one engine rule: an object description in a list whose source
(from_file / from_previous_result / from_arguments) is null is left out of
the list rather than built. It is what makes any reference optional without
a second spelling of the steps, and it is documented beside the from_file
convention in the workflow guide. Alone rather than in a list, a null source
is still an error - there is nothing to leave it out of.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Assets are per workspace, which is right for the inputs of one piece of work
and wrong for a recurring cast: the portraits and voice clips uploaded while
making episode one were invisible from the workspace episode four was made
in, and the only way through was to copy the files across. The prompt library
has been shared from the start for the same reason.

<root>/common/assets is that library for assets. It sits on every workspace's
asset search path behind the workspace's own, so a workspace name still
shadows a shared one; GET /api/assets spans it and tags each entry
origin: workspace | common | examples; /inputs previews it like any other;
and writes still land in the workspace unless the call says otherwise -
POST /api/uploads?shared=true, {"shared": true} on /api/assets/keep, and
shared=True on MCP upload_asset / keep_output. 'common' joins the reserved
workspace names.

dw.serve creates it and pins it ahead of the examples libraries on
DW_ASSET_PATH, so the worker resolves 'asset:' exactly as the API lists it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… a failed run says

T005: dialogue-short's concat step still named three steps the rename
replaced, so the template drew both portraits, generated all five H3 shots
and then died with no episode assembled. Fixed, and made static: once the
schema passes, validation reports any literal 'previous_result:' or
'from_previous_result' that names no earlier step, with the JSON path it
sits at. References otherwise resolve lazily per step, which is why nothing
warned until 42 minutes in.

T014: keep_output's asset_name now takes the kept file's extension when it
carries none and refuses one that contradicts it - what upload_asset's
already does. Without it a kept asset landed under an extensionless name
that the library listing, which reads by kind, never showed again. Adds
DELETE /api/assets/{name} and MCP delete_asset, the counterpart uploads and
keeps had none of.

T015: the worker carries its partial manifest on the error and cancelled
messages as well as on success, and the job manager records it, so a run
that died at step five reports the four that wrote files. 'Previous result
not found' now names the steps that ran even after
release_unreferenced_results has dropped their results - which is why it
printed 'Available results: []' on a run where a step had demonstrably
completed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A caller asking for 600s got 55 and no way to tell that from an elapsed
wait. Every reply now carries waited_seconds, timeout_requested_seconds,
timeout_applied_seconds and timeout_capped, the capped return's `next`
says what happened and how to pace, and the tool description names the
cap rather than calling it "well under a generation's real runtime".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ht that covers the arguments

T018: list_jobs was unbounded. On a server with a few months of history it
answered 176 entries, past the client's tool-result limit, so the one tool
that supplies job ids could not be called at all from the default workspace.
GET /api/jobs grows `status` and `limit` and always reports `total`; the MCP
tool takes the newest 20 by default, answers newest first, and says when the
answer was cut. The unparameterised route is byte-for-byte what it was, which
is what the web UI polls.

T019: validate_workflow only ever checked the stored definition and its stock
defaults - everything about a run except the part the caller writes. It now
takes the same `arguments` run_workflow takes: an undeclared or renamed
variable name, a value that will not coerce to the declared type, and an
'asset:'/'prompt:'/'output:' reference that names nothing this workspace can
reach, each at `arguments.<name>`. `checked_arguments` says what was covered.
POST /api/jobs makes the same check and answers 400 rather than queuing a job
that dies on its first step - a workflow declaring no variables took no
arguments at all before, in silence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ot the last root tried

The resolvers name the path they searched; taking the last root's error made
the message read as though the caller's own library was never looked in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dkackman
dkackman merged commit 7f0e6ae into master Sep 11, 2026
5 checks passed
@dkackman
dkackman deleted the develop branch September 11, 2026 21:22
@dkackman
dkackman restored the develop branch September 11, 2026 21:24
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