Commit Graph

71 Commits

Author SHA1 Message Date
Calesthio
796f5d7c6e Merge pull request #281 from scorp323/oracle/batch-b-safe-hardening-20260703
fix: harden tool governance and subprocess safety
2026-07-06 18:17:08 -07:00
Calesthio
f9f53ecbcf Merge pull request #286 from drainsmichael-tech/claude/eloquent-feistel-40f311
fix: check ffmpeg availability via shutil.which instead of hardcoding True
2026-07-06 17:59:42 -07:00
0xDevNinja
4c10481011 fix(audio_mixer): stop segmented_music from halving narration volume
`_segmented_music` mixed the video's audio with the shaped music via
`amix=inputs=2`, whose default `normalize=1` scales every input by 1/inputs
(x0.5, -6 dB). Unlike `_mix` and `_full_mix`, this path has no `loudnorm` stage
afterward to re-normalize, so the narration was permanently attenuated across
the entire timeline — including the stretches where the music volume expression
evaluates to 0. A one-second music segment quietly dropped the narration by
~6 dB for the whole video.

Add `normalize=0` to the amix: the music is already scaled to `music_volume`
by the `volume` expression, so speech passes at unity. Verified with ffmpeg —
narration in a no-music region tracks the stereo/aac conversion baseline
instead of sitting 6 dB below it.
2026-07-06 13:12:33 +05:30
0xDevNinja
7fff88af3c fix(openai_image): return all n generated images, not just the first
The tool advertised `multiple_outputs: True`, accepted `n` (1-4) in its schema,
requested `n` images from the API, and scaled `estimate_cost` by `n` — but the
result handling was hardcoded to `response.data[0]`. Images 1..n-1 were decoded
never, written never, and absent from `artifacts`, so a caller who set `n=4`
paid for four images and received one.

Iterate over `response.data`, writing each image to a distinct path (suffixed
`_1`, `_2`, … when several are requested, mirroring `grok_image` /
`dashscope_image`), and return `outputs` / `images_generated` alongside the
full `artifacts` list. A single image keeps its exact requested path.
2026-07-06 13:12:33 +05:30
Calesthio
89d5f1f88b Merge pull request #293 from ketpatil77/codex/openmontage-wan22-vae
fix(comfyui): use 14B-compatible VAE for wan22 t2v
2026-07-05 11:04:27 -07:00
calesthio
0eaef99902 Merge main into Sora provider branch 2026-07-05 07:03:26 -07:00
Calesthio
ce11f6a24f Merge pull request #285 from calesthio/codex/taste-governance
Add taste direction governance
2026-07-05 06:58:18 -07:00
Calesthio
c3c6b03877 Merge pull request #252 from 0xDevNinja/fix/issue-219-math-animate-codeexec
fix(math_animate): gate caller-supplied scene_code execution (#219)
2026-07-05 06:48:40 -07:00
Calesthio
97fa905ded Merge pull request #266 from 0xDevNinja/fix/audio-mixer-ducking-filtergraph
fix: three independent zero-key correctness bugs (audio_mixer ducking, scene-variation run count, source-media schema)
2026-07-05 06:48:28 -07:00
Calesthio
6809c7e052 Merge pull request #289 from ketpatil77/codex/openmontage-source-led-motion
fix(delivery): recompute motion requirement after source-led override
2026-07-05 06:37:55 -07:00
Calesthio
6e67e2f7d7 Merge pull request #288 from ketpatil77/codex/openmontage-scoring-tokenizer-punctuation
fix(scoring): strip trailing punctuation from tokens
2026-07-05 06:32:03 -07:00
Your Name
2beda014be fix(comfyui): pair wan22 t2v workflow with 14b-compatible vae 2026-07-04 19:45:47 +05:30
Your Name
84532dae63 fix(delivery): recompute motion requirement after source-led override 2026-07-04 19:37:33 +05:30
MVizu
dc25d6d60a fix: check ffmpeg availability via shutil.which instead of hardcoding True
video_compose.get_info() reported render_engines.ffmpeg as always
available, unlike the real availability checks used for remotion and
hyperframes. On a machine without ffmpeg on PATH, preflight would
falsely report ffmpeg as usable, letting render_runtime="ffmpeg" get
locked at proposal time only to fail at compose.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 23:09:09 -04:00
calesthio
fd086a38c6 Add taste direction governance 2026-07-03 19:01:10 -07:00
Calesthio
e09afaa280 Merge pull request #240 from yiyabo/feat/dashscope-integration
Add DashScope (Alibaba Cloud Bailian) provider: image gen + TTS + ASR
2026-07-03 18:04:53 -07:00
calesthio
0bfa7f1f8c test: include dashscope in tts provider contract 2026-07-03 18:00:18 -07:00
Your Name
32d34a7ca8 fix(scoring): strip trailing punctuation from tokens 2026-07-03 20:15:17 +05:30
Calesthio
f4b8b90a24 Merge pull request #273 from calesthio/feat/backlot-living-storyboard
Release Backlot: the living storyboard for OpenMontage
2026-07-03 07:29:04 -07:00
calesthio
4f9c612b28 backlot: address review findings (SVG visuals, decision-key doc, tests)
From an independent review of the branch:

- Regression: existing non-raster-but-showable visuals (.svg diagrams) were
  dropped by the renderable filter — they were served fine before via <img>
  (/thumb passes SVG through). Add .svg to MEDIA_IMAGE_EXT.
- Doc accuracy: the board dedupes decisions by (category, subject), not category
  alone (category-only would wrongly merge distinct decisions that share a
  category, e.g. TTS vs image provider_selection). Correct AGENT_GUIDE to say
  the pair is the key and to reuse the same subject when re-logging.
- Coverage: the new visual-selection logic was untested (which let the earlier
  missing-file regression through). Add TestStoryboardVisualSelection covering
  the .tsx-animation exclusion, snapshot fallback (exact + <id>_* match), SVG
  renderability, the preserved missing-file indicator, and takes = renderable.

Not changed (reviewed, deliberate): .narr clamp at --fs-scale 1.16 degrades
gracefully via the fade + click-to-expand modal; decision dedupe stays keyed on
(category, subject) as the more-correct behavior.
2026-07-03 07:25:39 -07:00
Morpheus
14ebc56123 fix: preserve subprocess error type in tool runner
- raise a CalledProcessError subclass that surfaces stderr/stdout detail
- keep existing callers that catch subprocess.CalledProcessError working
- reject lavfi movie paths containing single quotes fail-closed
- add regression coverage for both review findings

Verification:
- python3 -m unittest tests.tools.test_base_tool_dependencies tests.tools.test_scene_detect_lavfi_escape tests.tools.test_cost_tracker_governance
- python3 -m py_compile tools/base_tool.py tools/analysis/scene_detect.py tools/cost_tracker.py tests/tools/test_base_tool_dependencies.py tests/tools/test_scene_detect_lavfi_escape.py tests/tools/test_cost_tracker_governance.py
2026-07-03 22:00:38 +08:00
Morpheus
6580987931 fix: harden tool governance and subprocess safety
- persist budget warnings and approved paid-tool decisions
- support binary dependency declarations
- include stderr/stdout details for failed subprocesses
- escape lavfi movie paths used by ffmpeg scene detection

Verification:
- python3 tests/tools/test_cost_tracker_governance.py
- python3 tests/tools/test_scene_detect_lavfi_escape.py
- python3 tests/tools/test_base_tool_dependencies.py
- python3 -m py_compile ...
2026-07-03 20:07:00 +08:00
0xDevNinja
9613a3acfd fix(math_animate): block all reflection dunders, not an enumerated set
The prior dunder denylist was still bypassable via print.__self__ (the builtins
module) -> .open(...), reachable with no import and no bare open/__builtins__/
getattr name. Enumerating dangerous dunders is whack-a-mole, so block ALL
dunder attribute access generically and allow only the tiny set legitimate
scenes need (super().__init__, occasional Type.__name__). This closes the
print.__self__ / .__class__ / .__globals__ introspection-escape class at once.

Static analysis still has a ceiling — a real subprocess sandbox is the complete
fix — but the default path no longer executes the reported secret-read payloads.

Adds regression tests for print.__self__ and for super().__init__ staying allowed.

Refs #219
2026-07-03 13:04:33 +05:30
0xDevNinja
f265afde5d fix(math_animate): harden scan against no-import builtins/reflection bypass
The scan only flagged dangerous builtins as direct call targets (ast.Name func)
and dunders as attribute access, so it missed indirection like
`__builtins__['open']('.env').read()` and `getattr(o, '__class__')` — the
default path still executed secret-reading code.

Block dangerous identifiers wherever they appear as a bare name (open, eval,
exec, compile, __import__, __builtins__, getattr/setattr/delattr, globals/
locals/vars) rather than only as a call target, and extend the blocked dunder
set (__class__, __dict__, __getattribute__, __reduce__, ...). This closes the
reported no-import bypass while genuine math scenes still pass.

Still defense-in-depth, not a full sandbox; the allow_unsafe_code opt-out and
explicit code-execution contract remain. A subprocess-level sandbox is the
right follow-up for complete isolation.

Refs #219
2026-07-03 13:04:33 +05:30
0xDevNinja
b69ce5f9a2 fix(math_animate): gate caller-supplied scene_code execution (#219)
math_animate writes caller-supplied Python to scene.py and runs Manim on it —
arbitrary local code execution with no boundary surfaced in the tool contract.
In an agent-driven system the scene_code may be LLM-generated or influenced by
untrusted prompt content, so import-time code or construct() could read
secrets/SSH material, open network connections, or spawn subprocesses.

Add a static AST safety scan that rejects dangerous imports (os, subprocess,
socket, requests, ctypes, ...), dangerous builtins (eval/exec/compile/open/
__import__), and sandbox-escape dunders (__globals__, __subclasses__, ...)
before Manim runs. Genuine math scenes (manim, numpy, math, ...) pass
untouched. This is defense-in-depth, not a sandbox: a determined attacker can
evade a static denylist, so it is paired with an explicit allow_unsafe_code
opt-out and a tool contract (schema + side_effects) that names the boundary.

Closes #219
2026-07-03 13:04:33 +05:30
Calesthio
0c202b507a Merge pull request #226 from 0xDevNinja/feat/publish-tier-export-bundle
feat(publish): add export_bundle, the first PUBLISH-tier tool
2026-07-02 15:06:03 -07:00
calesthio
280400d479 Ship Backlot living storyboard release hardening 2026-07-02 12:19:06 -07:00
calesthio
1d60f0da14 backlot: fix all five dogfood findings (F-01..F-05)
- F-01: cost bar crit (red) state past 90% of budget
- F-02: normalize() hardens fetched board state against sparse payloads
- F-03: /thumb 404s for videos with no extractable poster frame instead
  of serving raw video bytes
- F-04: checkpoint artifact path refs only resolve inside the project dir
- F-05 (board half): stall detection — in_progress stage with no disk
  activity >10min renders red 'stalled?' + header badge flips to STALLED?;
  verified against the real wedged why-cities-glow project
- eval harness from dogfood session committed (visual regression +
  interaction smoke, capture watcher, server/gate test suites) +
  regression tests for each finding; 46 backlot tests green, visual eval
  green (restage-before-capture note logged)
2026-07-02 08:22:03 -07:00
0xDevNinja
f08a77979c fix(schema): allow empty files[] in source_media_review artifact
review_source_media deliberately returns files:[] with a 'no source media —
fully generated production' summary when no user media is supplied or none can
be reviewed, but the schema declared files.minItems:1, so that intended
artifact failed its own validation. Relax files.minItems to 0 to match the
code's deliberate empty-media state (planning_implications still carries an
entry, so its minItems:1 remains satisfied).

Adds a regression test validating the no-source-media artifact.

Closes #269
2026-07-02 16:52:00 +05:30
0xDevNinja
364182cc39 fix(variation_checker): measure longest run for consecutive same-size shots
Check 2 flagged 'N consecutive same-size shots' from a count of every equal
adjacent pair across the whole plan, not the length of any real run. So three
separate 2-shot groups (wide,wide,cu,cu,med,med) tripped a false '3
consecutive' violation, while a genuine run of 3 (only 2 pairs) was never
flagged. Track the current run length, reset on change, and compare the longest
run >= 3.

Adds regression tests: non-consecutive pairs pass, a true run of 3 is flagged,
unspecified shots don't form a run.

Closes #268
2026-07-02 16:52:00 +05:30
0xDevNinja
febc9244d3 fix(audio_mixer): drop dangling speech_dup pad in full_mix ducking
full_mix with ducking enabled (the default) failed for a single narration
track + one music bed — the most common shape — because the ducking branch
appended an acopy[speech_dup] filter whose output pad was never consumed,
leaving the filtergraph with a dangling output that ffmpeg rejects.

For a single speech track speech_out is '[a0]' (starts with '[a'), so the
guarded append fired; the compensating pop() only removes the empty-string
case from the multi-speech branch, so the dead pad survived exactly in the
single-narration case. The speech stream is already re-derived for the final
mix via [speech_out], and ffmpeg auto-splits the reused input label, so the
duplicate is unnecessary. Multi-speech and SFX paths are unaffected.

Adds regression tests for single- and multi-narration full_mix with ducking.

Closes #265
2026-07-02 16:41:58 +05:30
0xDevNinja
8c9af320b6 fix(video_compose): forward remotion_timeout_ms through high-level render path
The timeout handling only took effect on a direct _remotion_render() call. The
high-level execute(operation='render') path goes through _render(), which builds
a fresh remotion_inputs dict (edit_decisions, output_path, profile) and dropped
remotion_timeout_ms — so callers of the documented operation='render' path never
got the timeout passed to the Remotion CLI. Forward it there.

Adds a test exercising _render() (not just _remotion_render()) to cover the
high-level forwarding path.

Refs #217
2026-07-02 11:59:53 +05:30
0xDevNinja
fbbe32a676 fix(video_compose): surface Remotion failures and add render timeout passthrough
The high-level Remotion render path hid the useful failure reason. run_command
runs with check=True + capture_output, so a non-zero exit raised
CalledProcessError whose str() is only 'returned non-zero exit status 1' — the
actual Remotion diagnostics in stderr were dropped. Catch CalledProcessError
and surface the stderr/stdout tail, and TimeoutExpired with an actionable hint.

Also add a creator-facing remotion_timeout_ms input, passed through as
Remotion's --timeout (headless-browser setup + delayRender). Slow browser
startup on restricted networks previously failed opaquely at the default 30s
with no way to raise it. The subprocess timeout is widened to match so
run_command does not kill Remotion before its own timeout fires.

Closes #217
2026-07-02 11:59:53 +05:30
calesthio
c80ecbcb2d backlot phase 1: board server (state derivation, watcher, SSE, media, CLI)
- backlot/state.py: BoardState from disk — stage rail with gate audit
  (gate_skipped detection from history/), scene_plan x script x
  asset_manifest storyboard join, takes, generating-state from events,
  media discovery incl. atelier root-render heuristic, degradation ladder,
  library summaries
- backlot/server.py: FastAPI on 4750 — /api/projects, /api/project/{id}/state,
  SSE change feeds (project + library) fed by a watchfiles watcher,
  /media with range support and traversal protection, UI mounts
- backlot/__main__.py: 'python -m backlot open [project]' idempotent
  launcher (spawns detached server, opens browser); 'serve' foreground
- verified against real projects: 73 listed, full state for
  signal-from-tomorrow, 206 range responses, SSE change push on
  filesystem write
2026-07-01 23:26:30 -07:00
calesthio
722491d732 backlot phase 0: artifact contract + gate hardening
- init_project() writes project.json marker + canonical workspace layout
- write_checkpoint enforces approval gates: completed on a gated stage
  requires human_approved=True (GATE VIOLATION otherwise)
- superseded checkpoints archived to projects/<id>/history/ (stage
  versioning, gate audit trail, replay)
- BaseTool auto-instruments execute() -> projects/<id>/events.jsonl
  (start/finish/error, scene_id, cost) for the Backlot live board
- assets stage now gates (human_approval_default: true) in all manifests
- checkpoint-protocol + AGENT_GUIDE: manifest gate value is binding,
  awaiting_human + end-turn protocol, per-gate approval, canonical
  checkpoint location fixed to projects/<id>/
- gate reminder footer on all gating stage director skills
- /backlot command files for Claude Code, Codex, Cursor, Copilot
2026-07-01 23:08:51 -07:00
Remotely Human
fabc0e7088 Replace retired OpenAI image models with gpt-image-2 (DALL-E shut down 2026-05-12)
- openai_image: enum narrowed to ["gpt-image-2"]; DALL-E code path, sizes
  (1024x1792/1792x1024) and qualities (standard/hd) removed; estimate_cost
  updated to real GPT Image 2 pricing ($0.006/$0.053/$0.211 at 1024x1024)
- image_gen (deprecated but callable): default dall-e-3 -> gpt-image-2; drop
  response_format="b64_json", which GPT image models reject; update pricing
- docs/skills sweep: scrub retired-model references from README (en/zh),
  .env.example, docs/PROVIDERS.md (incl. pricing table + deprecation note),
  docs/ARCHITECTURE.md, AGENT_GUIDE.md, skills/creative/*, 14 pipeline
  director skills, and tests/qa/QA_PLAN.md

Source: https://developers.openai.com/api/docs/deprecations

proofread by fable 5 + codex
2026-07-02 11:36:31 +08:00
calesthio
b3ff734b5a Add first-class Sora video provider 2026-07-01 10:51:48 -07:00
Yiyabo
b4bed5735a dashscope: fix multi-image download and complete idempotency keys
Address PR #240 review feedback from @calesthio:

1. dashscope_image: save EVERY returned image URL, not just the first.
   The tool advertised multiple_outputs and accepted n>1 but only read
   content[0], silently dropping paid outputs. Now collects all image
   URLs across choices/content and downloads each to a distinct indexed
   path (foo.png -> foo_1.png, foo_2.png, ...). images_generated now
   reflects the actual count downloaded.

   Per Qwen Cloud docs, a multi-output task is SUCCEEDED if at least one
   image is generated; choices with finish_reason != "stop" are skipped
   to avoid downloading partial/failed results.

2. Complete idempotency_key_fields so different requests no longer
   collide and reuse stale artifacts:
   - image: + negative_prompt, seed, prompt_extend, watermark
   - tts:   + instructions
   - asr:   + enable_words, language_hints

Adds 19 regression tests (114 total, all pass, no API keys needed):
- TestDashscopeImageMultiOutput: URL extraction across choices / within
  one choice / failed-choice skipping, path resolution for
  single/multi/no-extension, end-to-end multi-image download with a
  mocked 3-URL DashScope response verifying all 3 files land on disk,
  single-image legacy path behavior
- TestDashscopeIdempotencyKeys: field presence + key-differs-on-value
  for every newly added field across all three tools
2026-07-02 00:37:51 +08:00
Calesthio
1188e1bee9 Merge pull request #199 from An-idd/fix/video-compose-vertical-resolution
fix(video_compose): honor target resolution in FFmpeg compose (vertical/9:16)
2026-06-30 20:45:49 -07:00
Calesthio
1242f8459e Merge pull request #227 from kapil971390/fix/character-reviewer-success-contract
fix(reviewer): success=False when CharacterAnimationReviewer finds QA issues
2026-06-30 20:40:30 -07:00
Calesthio
7b8d59186d Merge pull request #223 from 0xDevNinja/feat/issue-168-music-library-preflight
feat(audio): add music_library tool so user tracks surface at preflight
2026-06-30 20:40:14 -07:00
kapil971390
5782f704b3 fix(character-reviewer): align success contract with visual_qa pattern
Per maintainer feedback on PR #227:
- Revert success=not issues back to success=True — tool execution
  succeeded even when QA finds issues; verdict lives in status/issues
- Update test to assert the real contract: success=True + status='revise'
  + issues non-empty, matching how compose-director actually gates
- Consistent with visual_qa.py: success=True, verdict in validation_passed
2026-06-30 22:23:52 +05:30
Yiyabo
7473d0d1bb dashscope: add contract tests (95 tests, no API calls needed) 2026-06-30 14:35:34 +08:00
0xDevNinja
9bcccce2db fix(publish): validate optional assets and default export inside project
Addresses review feedback on export_bundle:

- If subtitles_path or thumbnail_path is provided but the file is missing, the
  tool now fails with an explicit error instead of silently producing a package
  without that asset (which could ship an approved deliverable missing part of
  its content).
- Default export location now stays inside the project workspace: when the
  render lives at projects/<name>/renders/..., the bundle defaults to
  projects/<name>/exports/ (alongside artifacts/, assets/, renders/) rather than
  a repo-root exports/<name>/. export_dir remains an explicit override.

Tests cover both: missing optional asset errors, and the project-workspace
default path.
2026-06-30 12:05:23 +05:30
Calesthio
46ed550883 Merge pull request #229 from calesthio/codex/expressive-tts-governance
[codex] Add expressive TTS governance
2026-06-29 23:04:56 -07:00
Alastair Beal
85cf047c93 comfyui: route custom workflows through image/video selectors
The selector path previously hid the custom-workflow feature: video_selector
filtered tools on per-operation readiness (bundled WAN models) and both
selectors only chose ToolStatus.AVAILABLE providers, so comfyui_image/
comfyui_video — DEGRADED when bundled model metadata is missing — were
dropped even when the ComfyUI server was up and the caller supplied a full
workflow_json/workflow_path plus output_node.

- Add a custom-workflow readiness path to both selectors: when a custom
  workflow is supplied, eligibility is based on server availability (status
  != UNAVAILABLE) for any provider advertising supports.custom_workflow,
  not on bundled-model readiness. A custom workflow also restricts routing
  to custom-workflow-capable providers, since the graph JSON is ComfyUI
  specific.
- Expose workflow_json, workflow_path, output_node, workflow_name,
  workflow_model, and workflow_model_stack in both selector schemas so
  agents can discover the feature without bypassing the selectors.
- image_selector only forwards the workflow inputs to providers that
  declare them.
- Add contract tests for the new eligibility path and schema exposure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:38:18 +01:00
calesthio
5e4943a41b Add expressive TTS governance 2026-06-29 12:16:07 -07:00
calesthio
7c4bb08890 comfyui: satisfy provider contract review items 2026-06-29 19:09:22 +01:00
martimramos
4c62186c95 comfyui: drop music tool — ACE-Step node interface not standardized
Removed comfyui_music and its workflow. The ACE-Step model runs in
ComfyUI but the node class names differ across custom node packs
(AceStepModelLoader vs native TextEncodeAceStepAudio, etc.), so a
bundled workflow would break for most users.

Documented the reasoning in the plan doc and listed it as an open
question for future work. Users with ACE-Step working can still use
the workflow_json override on any tool.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-29 19:09:22 +01:00
martimramos
e3947e1f11 comfyui: add model discovery and actionable error messages
- Client queries ComfyUI /object_info to discover installed models
  (checkpoints, diffusion models, VAE, CLIP, LoRAs)
- Each tool declares its required models and checks them on execute()
- get_status() returns DEGRADED when server is up but models are missing
- Clear error messages tell the user exactly which models to download
- When COMFYUI_SERVER_URL is not set, error message tells the user to
  configure it in .env instead of silently failing on localhost:8188
- 8 new tests covering URL config, error messages, and model requirements

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-29 19:08:49 +01:00