feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters - #140
feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters#140Pantani wants to merge 12 commits into
Conversation
…reate_ai_backdrop New AI texture asset lane (hosted text-to-image), complementing the Milestone 4 realtime img2img path: - create_ai_texture (Layer 2, CLI create-ai-texture): prompt → hosted render (fal.ai) → Movie File In TOP pointing at the cached asset. - create_ai_backdrop (Layer 1, CLI create-ai-backdrop): prompt → fully wired backdrop (Movie File In → Level → Transform → Blur → Null) with exposed Brightness/Blur/Scale live controls. - src/services/imageGen/ hosted provider seam (fal.ai; Flux-schnell default, WAN 2.5 selectable); local cache-file → Movie File In TOP delivery, no new bridge endpoint. A post-generation bridge failure still cites the on-disk cache path so the rendered asset is never lost. - Config (Node-only, never sent to the TD bridge): TDMCP_IMAGE_GEN_PROVIDER (fal|replicate|none, default none), TDMCP_FAL_KEY, TDMCP_REPLICATE_KEY, TDMCP_IMAGE_GEN_MODEL, TDMCP_IMAGE_CACHE_DIR; provider keys redacted in doctor / doctor --json. QA PASS (offline gates + cross-boundary coherence + offline-safety checks); live TD cook + fal contract UNVERIFIED-pending (bridge offline + no fal key at release time). [Unreleased] — no version bump, no tag. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add create_ai_video (L2) + create_ai_video_backdrop (L1) on a new src/services/videoGen/ provider seam with two first-class backends selected by TDMCP_VIDEO_GEN_PROVIDER: local ComfyUI REST (zero per-generation cost, offline, LTX-Video on a local GPU) and hosted fal.ai. Both cache the render and hand it to a Movie File In TOP — no new bridge endpoint. Model default ltx-video, ltx-2 opt-in; schema rejects controls a model lacks. Reuses TDMCP_FAL_KEY (redacted, no new secret). Generation is generate-ahead then play-back-live, not per-frame. Adopts the generator choice (LTX-Video) from the NEvo evolutionary video-synthesis paper (arXiv 2607.02317, CC BY 4.0); no NEvo code. Offline gates green: typecheck, build, biome, 5608 vitest. Live fal/comfyui contracts + TD cook UNVERIFIED-pending (bridge/GPU offline). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the tdmcp-nevo-integration harness (nevo-integration-scout + nevo-integration-architect agents + orchestrator skill) that produced the NEvo->tdmcp INTEGRATION_POINTS + PROJECT_DRAFT under _workspace/nevo/, plus the create_ai_video pipeline artifacts (design/build/integrate/qa). Registers the harness pointer in CLAUDE.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… setup ComfyUI's LTXV latent `length` is a FRAME count requiring length % 8 == 1; the provider was injecting duration_seconds (e.g. 5) directly, which would error or produce a 5-frame clip on a live run. Convert seconds to frames at 24 fps snapped to k*8+1 (5s -> 121). Found while preparing local validation. Add assets/comfyui/: an API-format LTX-Video text-to-video workflow matching the provider's key-based injection contract, plus a README covering the local GPU setup, env vars, injection map, i2v adjustment, and a no-TD smoke test. Gates green: comfyui/video slice 14 tests, tsc, biome. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add evolve_parameters (Layer 1, CLI evolve-parameters, experimental/offline): a categorical genetic-algorithm parameter search adopting the NEvo method (arXiv 2607.02317, CC BY 4.0) with its fMRI fitness retargeted to a TD-measurable one — audio_energy (Info CHOP), top_luma, or top_motion. mu+lambda elitism, seeded-deterministic RNG (no Math.random), hard cap population*generations <= 300, per-candidate teardown with only the champion rebuilt. Design-time search, not real-time. New pure GA module + frameStats + topMotion helpers, all CC <= 10. No bridge endpoint, no config. Gates green: typecheck, build, biome, 5632 vitest, bridge tests. Live cook UNVERIFIED-pending (bridge offline). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the probe-first LICENSE item: LTX-Video 2B is Apache-2.0 code / OpenRAIL-M weights; LTX-2 open weights under the LTX-2 Community License, free commercial use under $10M ARR. Local generation is free regardless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
npm run dev runs the server (src/index.ts), not the tools. The verbs live in the agent CLI (src/cli/agent.ts / bin tdmcp-agent) and take one JSON object via --params. Add a --dry-run offline sanity step, ComfyUI reachability check, and the real generate command (needs ComfyUI + TD bridge up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts/captionTop) Close the QA-flagged duplication: the 8-bit PNG decode mechanics (signature, chunk parse, zlib inflate, un-filter) lived in both frameStats.ts and captionTop.ts. Extract them once into src/feedback/pngDecode.ts, returning a discriminated PngDecodeResult so each caller keeps its own accumulation and messaging — captionTop maps the failure reason to its exact existing warning strings, frameStats falls back to a byte-histogram. Behavior-preserving. Gates green: lint (1427 files), typecheck, build, 5632 tests (caption_top unchanged). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 31 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis PR adds AI image/video generation lanes with fal.ai and ComfyUI providers, cached TouchDesigner asset tools, evolutionary parameter search, shared PNG feedback scoring, CLI/config wiring, tests, and a resumable NEvo integration-study harness. ChangesAI media and NEvo integration
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Agent as CLI/MCP tool
participant Provider as Image/Video provider
participant Cache as Filesystem cache
participant TD as TouchDesigner bridge
Agent->>Provider: Generate requested asset
Provider-->>Agent: Return downloaded bytes and metadata
Agent->>Cache: Write or reuse deterministic cache path
Agent->>TD: Create Movie File In TOP from cache path
TD-->>Agent: Return node and preview metadata
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dc2a596803
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| falKey: "TDMCP_FAL_KEY", | ||
| replicateKey: "TDMCP_REPLICATE_KEY", |
There was a problem hiding this comment.
Redact AI provider keys from --write-env
When TDMCP_FAL_KEY or TDMCP_REPLICATE_KEY is set, adding these keys to ENV_NAMES makes tdmcp-agent config --write-env print the raw secret because SECRET_ENV was not extended with the same entries. The command advertises that secrets are redacted and produces paste/share-ready output, so this can leak provider credentials from the new AI generation lane.
Useful? React with 👍 / 👎.
| model, | ||
| prompt: req.prompt, | ||
| negativePrompt: req.negativePrompt, | ||
| initImagePath: req.initImagePath, |
There was a problem hiding this comment.
Include init image contents in the video cache key
For image-to-video calls, the cache key only records initImagePath; if an artist overwrites the anchor image at the same absolute path and reruns the same prompt/seed, findCachedVideo will return the old clip without calling the provider. Because the image bytes are generation-defining input, the key needs to include a content hash or at least file metadata to avoid stale/corrupt results.
Useful? React with 👍 / 👎.
| frame-streaming bridge that `connect_comfyui` builds. It POSTs an API-format | ||
| workflow to `/prompt`, polls `/history`, and downloads the finished mp4 from `/view`. | ||
|
|
||
| This folder ships a matching workflow: [`ltx-video-t2v.api.json`](./ltx-video-t2v.api.json). |
There was a problem hiding this comment.
Ship the ComfyUI workflow with npm packages
The new ComfyUI instructions point users at assets/comfyui/ltx-video-t2v.api.json, but the published package will not contain this folder: package.json has a files whitelist that excludes assets/, and scripts/copy-assets.mjs only copies knowledge data and recipes; I also checked npm pack --dry-run and no assets/comfyui files were present. Users installing the npm CLI therefore cannot follow this documented local-video setup unless the asset is included or copied into a packaged path.
Useful? React with 👍 / 👎.
| /** Absolute path to a ComfyUI API-format workflow JSON (required for the comfyui video provider). */ | ||
| comfyuiVideoWorkflow: z.string().optional(), | ||
| /** Optional override for the video generation timeout (ms); provider default is 10 min. */ | ||
| videoGenTimeoutMs: z.coerce.number().int().positive().optional(), |
There was a problem hiding this comment.
Wire the configured video timeout into requests
TDMCP_VIDEO_GEN_TIMEOUT_MS is parsed into config, but neither buildToolContext nor toVideoRequest carries it into VideoGenRequest.timeoutMs, so both video tools still use DEFAULT_VIDEO_GEN_TIMEOUT_MS regardless of the user's override. This matters for long local ComfyUI renders that need more than 10 minutes, or for operators trying to fail fast with a shorter timeout.
Useful? React with 👍 / 👎.
The complexity ratchet flagged two functions moved/added in this branch: pngDecode.unfilter (13) and evolveParameters.runEvolution (10). Extract the inner scanline loop (unfilterRow) and the per-generation scoring loop (scoreGeneration) to bound nesting depth. Behavior-preserving. Cognitive ratchet passes; typecheck, biome, and the affected tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 20
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.claude/agents/nevo-integration-architect.md:
- Around line 1-5: Create the Codex counterpart for the
nevo-integration-architect agent at the mirrored `.codex/agents` location,
preserving equivalent metadata, model, responsibilities, workflow constraints,
and artifact-writing behavior from the
`.claude/agents/nevo-integration-architect.md` definition.
In @.claude/agents/nevo-integration-scout.md:
- Around line 1-5: Create the Codex mirror of the nevo-integration-scout agent
at .codex/agents/nevo-integration-scout.md, preserving the equivalent
frontmatter and research-only behavior defined by the existing
nevo-integration-scout agent. Ensure the mirrored agent maintains the same
scope, integration-mapping responsibilities, and prohibition on editing source.
In @.claude/skills/tdmcp-nevo-integration/SKILL.md:
- Around line 1-4: Create a Codex mirror of the tdmcp-nevo-integration skill
under .codex/skills/tdmcp-nevo-integration/, preserving the same SKILL.md
content and workflow as the existing Claude skill. Follow the established
mirrored structure used by tdmcp-quality-audit so both Claude and Codex expose
equivalent behavior.
In `@src/agentCommandCatalog.ts`:
- Around line 756-763: Update the create-ai-video-backdrop catalog entry’s
summary to include the Blur stage in the Movie → Level → Transform pipeline and
mention the exposed Blur control alongside Play, Speed, Brightness, and Scale.
In `@src/feedback/pngDecode.ts`:
- Around line 136-149: Update the PNG decoding flow around parsePngChunks and
unfilter to enforce configured caps on PNG input bytes, width and height, total
pixel count, and expected decompressed output size before calling
zlib.inflateSync or allocating buffers. Reject oversized or unsafe
dimensions/data with the existing failure-result pattern, and ensure validation
uses overflow-safe calculations for width × height × channels.
- Around line 63-79: Reduce the cognitive complexity of unfilter by extracting
per-scanline or neighbor reconstruction into a focused helper. Keep unfilter
responsible for buffer allocation and row iteration, while the helper handles
filter values, neighbor lookup, and reconstruct calls without changing output
behavior.
- Around line 47-59: Update the PNG decode flow around reconstruct, IHDR
parsing, and scanline unfiltering to reject unsupported layouts instead of
fabricating pixels: parse and reject nonzero interlace modes, validate every
scanline filter is 0–4 rather than treating unknown values as filter 0, and
verify the inflated data contains the complete expected scanline bytes before
unfiltering. Propagate these validation failures so decoding does not return ok:
true for Adam7, corrupt, or truncated payloads.
In `@src/feedback/topMotion.ts`:
- Around line 56-61: Update the motion calculation in src/feedback/topMotion.ts
lines 56-61 to return the neutral/unavailable motion score immediately when
either decodePngStats result has decoded: false, while preserving the warning.
Update tests/unit/topMotion.test.ts lines 79-91 to assert the
neutral/unavailable score and warning instead of a positive delta.
In `@src/services/videoGen/cache.ts`:
- Around line 30-43: Update videoCacheKey to derive the init image component
from the file’s content digest or immutable asset identifier rather than only
req.initImagePath, so replacing the image produces a different cache key.
Preserve the existing key fields and behavior when no init image is provided.
In `@src/services/videoGen/comfyuiProvider.ts`:
- Around line 219-229: Update downloadView and the related extractClip output
handling to explicitly support .gif with mimeType image/gif, or reject GIF
inputs as unsupported before downloading. Do not allow the current fallback to
label non-WebM GIF bytes as video/mp4; preserve the existing WebM and MP4
behavior.
- Around line 160-176: The uploadImage method currently uses basename(path) with
overwrite enabled, allowing concurrent or repeated uploads to overwrite each
other. Generate a unique filename by adding a unique suffix to the basename in
the form-data append call, and remove the overwrite=true form field so ComfyUI
does not force replacement.
- Around line 195-205: Update pollHistory to inspect the history entry’s
terminal status metadata after extractClip returns no clip. Continue sleeping
and polling only while the job is running; when status.completed indicates
completion without a clip, derive the failure from status.status_str or
status.messages and throw a descriptive ComfyUI error instead of continuing
until timeout.
In `@src/services/videoGen/resolve.ts`:
- Around line 11-17: Thread the parsed TDMCP_VIDEO_GEN_TIMEOUT_MS setting from
src/utils/config.ts lines 428-429 through src/server/context.ts into the
video-generation execution path, adding it to VideoGenConfig and consuming it
where requests are executed in src/services/videoGen/resolve.ts lines 11-17.
Preserve the configured timeout instead of falling back to per-request or
hardcoded defaults; do not remove the option.
In `@src/tools/layer1/createAiVideoBackdrop.ts`:
- Around line 141-176: Update the catch block surrounding the builder creation
and delivery calls to best-effort delete the partially built container using
builder.containerPath before returning errorResult. Ensure cleanup is attempted
only when the builder was created, and preserve the existing error response and
cache_path details even if deletion also fails.
In `@src/tools/layer1/evolveParameters.ts`:
- Around line 259-270: The evolveParameters flow must not rebuild a winner when
all fitness evaluations failed and best.fitness is the -Infinity failure
sentinel. In src/tools/layer1/evolveParameters.ts:259-270, require
Number.isFinite(best.fitness) alongside the existing best check before calling
rebuildWinner, returning the existing errorResult otherwise. In
tests/unit/evolveParameters.test.ts:178-187, update the unresolved-target case
to expect an error instead of successful winner creation.
- Around line 222-274: Reduce cognitive complexity in runEvolution by extracting
the per-generation candidate scoring and best-winner update into a dedicated
helper. Have the helper receive the required context, population, generation
index, scratch path, and mutable warning/evaluation state, then return the
scored candidates and updated winner; keep runEvolution responsible for
initialization, generation progression, no-candidate handling, rebuilding, and
cleanup.
- Around line 276-311: The evolve_parameters tool must be unavailable when raw
Python execution is disabled. Add an implementation guard in
evolveParametersImpl that rejects direct calls when ctx.allowRawPython is false,
and update registerEvolveParameters to skip registration in that case while
preserving the existing validation and execution flow when enabled.
In `@src/tools/layer2/createAiTexture.ts`:
- Around line 156-157: Update the caching flow around writeCachedImage in the
tool handler to catch file-system failures and prevent exceptions from escaping.
On failure, return the existing errorResult with the caught error details;
preserve the successful cachePath result and cacheHit: false behavior when
writing succeeds.
In `@src/tools/layer2/createAiVideo.ts`:
- Around line 190-228: Update createAiVideo to catch failures from
findCachedVideo and writeCachedVideo, returning consistently structured
errorResult values with provider and model context instead of allowing rejected
handlers. In src/services/videoGen/cache.ts lines 51-59, modify the cache lookup
handling to suppress only ENOENT and rethrow permission or other I/O failures;
apply the tool-layer handling at createAiVideo and the errno filtering at the
cache implementation.
- Around line 340-351: Update the registered create_ai_video handler in
registerCreateAiVideo to validate arguments with createAiVideoSchema.safeParse
instead of parse. When validation fails, return the resulting errorResult, and
pass the parsed data to createAiVideoImpl only on successful validation so
invalid model, duration_seconds, or resolution combinations do not throw.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8b152a09-4dba-48e4-a4e4-5b119f6c9b33
📒 Files selected for processing (42)
.claude/agents/nevo-integration-architect.md.claude/agents/nevo-integration-scout.md.claude/skills/tdmcp-nevo-integration/SKILL.mdCHANGELOG.mdCLAUDE.mdassets/comfyui/README.mdassets/comfyui/ltx-video-t2v.api.jsonsrc/agentCommandCatalog.tssrc/cli/agent.tssrc/feedback/frameStats.tssrc/feedback/pngDecode.tssrc/feedback/topMotion.tssrc/server/context.tssrc/services/imageGen/cache.tssrc/services/imageGen/falProvider.tssrc/services/imageGen/resolve.tssrc/services/imageGen/types.tssrc/services/videoGen/cache.tssrc/services/videoGen/comfyuiProvider.tssrc/services/videoGen/falProvider.tssrc/services/videoGen/resolve.tssrc/services/videoGen/types.tssrc/tools/layer1/createAiBackdrop.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer1/geneticAlgorithm.tssrc/tools/layer1/index.tssrc/tools/layer2/createAiTexture.tssrc/tools/layer2/createAiVideo.tssrc/tools/layer2/index.tssrc/tools/layer3/captionTop.tssrc/tools/types.tssrc/utils/config.tstests/unit/createAiBackdrop.test.tstests/unit/createAiTexture.test.tstests/unit/createAiVideo.test.tstests/unit/createAiVideoBackdrop.test.tstests/unit/evolveParameters.test.tstests/unit/geneticAlgorithm.test.tstests/unit/imageGenProvider.test.tstests/unit/topMotion.test.tstests/unit/videoGenComfyui.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
- GitHub Check: Unit Tests (Node 22.x)
- GitHub Check: Unit Tests (Node 20.x)
- GitHub Check: Coverage Gate
⚠️ CI failures not shown inline (4)
GitHub Actions: Code Quality / 0_Code Quality Success.txt: feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters
Conclusion: failure
##[group]Run set -euo pipefail
�[36;1mset -euo pipefail�[0m
�[36;1mfailed=0�[0m
�[36;1mfor item in \�[0m
�[36;1m "typecheck=${TYPECHECK}" \�[0m
�[36;1m "lint=${LINT}" \�[0m
�[36;1m "recipes=${RECIPES}" \�[0m
�[36;1m "dependency-boundaries=${DEPENDENCY_BOUNDARIES}" \�[0m
�[36;1m "complexity=${COMPLEXITY}" \�[0m
�[36;1m "generated-artifacts=${GENERATED_ARTIFACTS}" \�[0m
�[36;1m "workflow-lint=${WORKFLOW_LINT}"�[0m
�[36;1mdo�[0m
�[36;1m name="${item%%=*}"�[0m
�[36;1m result="${item#*=}"�[0m
�[36;1m echo "$name: $result"�[0m
�[36;1m if [ "$result" != "success" ]; then�[0m
�[36;1m failed=1�[0m
�[36;1m fi�[0m
�[36;1mdone�[0m
�[36;1mexit "$failed"�[0m
shell: /usr/bin/bash -e {0}
env:
NPM_CONFIG_AUDIT: false
NPM_CONFIG_FUND: false
TYPECHECK: success
LINT: success
RECIPES: success
DEPENDENCY_BOUNDARIES: success
COMPLEXITY: failure
GENERATED_ARTIFACTS: success
WORKFLOW_LINT: success
##[endgroup]
typecheck: success
lint: success
recipes: success
dependency-boundaries: success
complexity: failure
generated-artifacts: success
workflow-lint: success
##[error]Process completed with exit code 1.
GitHub Actions: Code Quality / Code Quality Success: feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters
Conclusion: failure
##[group]Run set -euo pipefail
�[36;1mset -euo pipefail�[0m
�[36;1mfailed=0�[0m
�[36;1mfor item in \�[0m
�[36;1m "typecheck=${TYPECHECK}" \�[0m
�[36;1m "lint=${LINT}" \�[0m
�[36;1m "recipes=${RECIPES}" \�[0m
�[36;1m "dependency-boundaries=${DEPENDENCY_BOUNDARIES}" \�[0m
�[36;1m "complexity=${COMPLEXITY}" \�[0m
�[36;1m "generated-artifacts=${GENERATED_ARTIFACTS}" \�[0m
�[36;1m "workflow-lint=${WORKFLOW_LINT}"�[0m
�[36;1mdo�[0m
�[36;1m name="${item%%=*}"�[0m
�[36;1m result="${item#*=}"�[0m
�[36;1m echo "$name: $result"�[0m
�[36;1m if [ "$result" != "success" ]; then�[0m
�[36;1m failed=1�[0m
�[36;1m fi�[0m
�[36;1mdone�[0m
�[36;1mexit "$failed"�[0m
shell: /usr/bin/bash -e {0}
env:
NPM_CONFIG_AUDIT: false
NPM_CONFIG_FUND: false
TYPECHECK: success
LINT: success
RECIPES: success
DEPENDENCY_BOUNDARIES: success
COMPLEXITY: failure
GENERATED_ARTIFACTS: success
WORKFLOW_LINT: success
##[endgroup]
typecheck: success
lint: success
recipes: success
dependency-boundaries: success
complexity: failure
generated-artifacts: success
workflow-lint: success
##[error]Process completed with exit code 1.
GitHub Actions: Code Quality / 4_Complexity Gates.txt: feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters
Conclusion: failure
##[group]Run make complexity
�[36;1mmake complexity�[0m
shell: /usr/bin/bash -e {0}
env:
NPM_CONFIG_AUDIT: false
NPM_CONFIG_FUND: false
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:py
> `@dpantani/tdmcp`@0.13.1 complexity:py
> uvx ruff check td --select C901
Downloading ruff (11.0MiB)
Downloaded ruff
Installed 1 package in 2ms
All checks passed!
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:js
> `@dpantani/tdmcp`@0.13.1 complexity:js
> npm exec --offline -- eslint --no-error-on-unmatched-pattern "src/**/*.{js,mjs,cjs}" "scripts/**/*.{js,mjs,cjs}" "*.{js,mjs,cjs}"
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:cognitive
> `@dpantani/tdmcp`@0.13.1 complexity:cognitive
> npm run complexity:cognitive:js && npm run complexity:cognitive:py
> `@dpantani/tdmcp`@0.13.1 complexity:cognitive:js
> node scripts/check-js-cognitive-complexity.mjs
JS/TS cognitive complexity ratchet failed (2 regression(s)).
- src/feedback/pngDecode.ts:63:17 cognitive complexity 13 is not in the baseline
- src/tools/layer1/evolveParameters.ts:222:16 cognitive complexity 10 is not in the baseline
make[1]: *** [Makefile:27: complexity-cognitive] Error 1
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make: *** [Makefile:14: complexity] Error 2
##[error]Process completed with exit code 2.
GitHub Actions: Code Quality / Complexity Gates: feat: NEvo-inspired AI video lane (local ComfyUI + fal) & evolve_parameters
Conclusion: failure
##[group]Run make complexity
�[36;1mmake complexity�[0m
shell: /usr/bin/bash -e {0}
env:
NPM_CONFIG_AUDIT: false
NPM_CONFIG_FUND: false
UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
##[endgroup]
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:py
> `@dpantani/tdmcp`@0.13.1 complexity:py
> uvx ruff check td --select C901
Downloading ruff (11.0MiB)
Downloaded ruff
Installed 1 package in 2ms
All checks passed!
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:js
> `@dpantani/tdmcp`@0.13.1 complexity:js
> npm exec --offline -- eslint --no-error-on-unmatched-pattern "src/**/*.{js,mjs,cjs}" "scripts/**/*.{js,mjs,cjs}" "*.{js,mjs,cjs}"
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make[1]: Entering directory '/home/runner/work/tdmcp/tdmcp'
npm run complexity:cognitive
> `@dpantani/tdmcp`@0.13.1 complexity:cognitive
> npm run complexity:cognitive:js && npm run complexity:cognitive:py
> `@dpantani/tdmcp`@0.13.1 complexity:cognitive:js
> node scripts/check-js-cognitive-complexity.mjs
JS/TS cognitive complexity ratchet failed (2 regression(s)).
- src/feedback/pngDecode.ts:63:17 cognitive complexity 13 is not in the baseline
- src/tools/layer1/evolveParameters.ts:222:16 cognitive complexity 10 is not in the baseline
make[1]: *** [Makefile:27: complexity-cognitive] Error 1
make[1]: Leaving directory '/home/runner/work/tdmcp/tdmcp'
make: *** [Makefile:14: complexity] Error 2
##[error]Process completed with exit code 2.
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Never allow accidental overlap between UI elements, generated project components, nodes, cards, controls, text, canvases, media, or visual assets
When creating new projects, tools, docs previews, dashboards, diagrams, or frontend screens, keep the composition organized with explicit spacing, stable grids or flex layouts, responsive constraints, and predictable stacking order
Treat any element that covers, invades, clips, or visually competes with another as a defect to fix before delivery, unless the overlap is explicitly requested and intentionally designedFollow Biome formatting and linting: 2-space indentation, double quotes, semicolons, trailing commas, 100-column width, and organized imports.
Files:
tests/unit/imageGenProvider.test.tssrc/services/imageGen/resolve.tssrc/feedback/topMotion.tssrc/tools/layer2/index.tssrc/tools/layer1/index.tssrc/services/videoGen/resolve.tssrc/feedback/frameStats.tssrc/services/videoGen/types.tssrc/server/context.tssrc/feedback/pngDecode.tssrc/tools/types.tstests/unit/topMotion.test.tssrc/services/videoGen/cache.tstests/unit/createAiVideoBackdrop.test.tssrc/agentCommandCatalog.tstests/unit/evolveParameters.test.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/services/imageGen/cache.tssrc/services/imageGen/types.tstests/unit/geneticAlgorithm.test.tssrc/tools/layer1/geneticAlgorithm.tstests/unit/createAiTexture.test.tssrc/services/imageGen/falProvider.tstests/unit/videoGenComfyui.test.tssrc/tools/layer1/createAiBackdrop.tstests/unit/createAiBackdrop.test.tssrc/utils/config.tssrc/cli/agent.tssrc/tools/layer3/captionTop.tssrc/tools/layer2/createAiTexture.tssrc/services/videoGen/falProvider.tssrc/services/videoGen/comfyuiProvider.tstests/unit/createAiVideo.test.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer2/createAiVideo.ts
**/*.{ts,tsx,js,jsx,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
Verify relevant desktop, mobile, or preview states when a change affects visual layout
Files:
tests/unit/imageGenProvider.test.tssrc/services/imageGen/resolve.tssrc/feedback/topMotion.tssrc/tools/layer2/index.tssrc/tools/layer1/index.tssrc/services/videoGen/resolve.tssrc/feedback/frameStats.tssrc/services/videoGen/types.tssrc/server/context.tssrc/feedback/pngDecode.tssrc/tools/types.tstests/unit/topMotion.test.tssrc/services/videoGen/cache.tstests/unit/createAiVideoBackdrop.test.tssrc/agentCommandCatalog.tstests/unit/evolveParameters.test.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/services/imageGen/cache.tssrc/services/imageGen/types.tstests/unit/geneticAlgorithm.test.tssrc/tools/layer1/geneticAlgorithm.tstests/unit/createAiTexture.test.tssrc/services/imageGen/falProvider.tstests/unit/videoGenComfyui.test.tssrc/tools/layer1/createAiBackdrop.tstests/unit/createAiBackdrop.test.tssrc/utils/config.tssrc/cli/agent.tssrc/tools/layer3/captionTop.tssrc/tools/layer2/createAiTexture.tssrc/services/videoGen/falProvider.tssrc/services/videoGen/comfyuiProvider.tstests/unit/createAiVideo.test.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer2/createAiVideo.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use ESM with strict TypeScript and include
.jsextensions on all relative imports; respectnoUncheckedIndexedAccess.
Files:
tests/unit/imageGenProvider.test.tssrc/services/imageGen/resolve.tssrc/feedback/topMotion.tssrc/tools/layer2/index.tssrc/tools/layer1/index.tssrc/services/videoGen/resolve.tssrc/feedback/frameStats.tssrc/services/videoGen/types.tssrc/server/context.tssrc/feedback/pngDecode.tssrc/tools/types.tstests/unit/topMotion.test.tssrc/services/videoGen/cache.tstests/unit/createAiVideoBackdrop.test.tssrc/agentCommandCatalog.tstests/unit/evolveParameters.test.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/services/imageGen/cache.tssrc/services/imageGen/types.tstests/unit/geneticAlgorithm.test.tssrc/tools/layer1/geneticAlgorithm.tstests/unit/createAiTexture.test.tssrc/services/imageGen/falProvider.tstests/unit/videoGenComfyui.test.tssrc/tools/layer1/createAiBackdrop.tstests/unit/createAiBackdrop.test.tssrc/utils/config.tssrc/cli/agent.tssrc/tools/layer3/captionTop.tssrc/tools/layer2/createAiTexture.tssrc/services/videoGen/falProvider.tssrc/services/videoGen/comfyuiProvider.tstests/unit/createAiVideo.test.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer2/createAiVideo.ts
src/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Raw Python execution must be controlled by
TDMCP_RAW_PYTHON=offand the injectedallowRawPythoncontext flag; do not expose execution tools when disabled.
Files:
src/services/imageGen/resolve.tssrc/feedback/topMotion.tssrc/tools/layer2/index.tssrc/tools/layer1/index.tssrc/services/videoGen/resolve.tssrc/feedback/frameStats.tssrc/services/videoGen/types.tssrc/server/context.tssrc/feedback/pngDecode.tssrc/tools/types.tssrc/services/videoGen/cache.tssrc/agentCommandCatalog.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/services/imageGen/cache.tssrc/services/imageGen/types.tssrc/tools/layer1/geneticAlgorithm.tssrc/services/imageGen/falProvider.tssrc/tools/layer1/createAiBackdrop.tssrc/utils/config.tssrc/cli/agent.tssrc/tools/layer3/captionTop.tssrc/tools/layer2/createAiTexture.tssrc/services/videoGen/falProvider.tssrc/services/videoGen/comfyuiProvider.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer2/createAiVideo.ts
src/tools/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
src/tools/**/*.ts: Each tool file must export an…Impl(ctx, args)implementation and aregister…: ToolRegistrarregistrar; add the registrar to the appropriate layer index.
Never throw out of a tool handler. Validate inputs with Zod and convert TouchDesigner failures into friendlyisErrorresults usingerrorResult,runBuild, orfriendlyTdError.
Files:
src/tools/layer2/index.tssrc/tools/layer1/index.tssrc/tools/types.tssrc/tools/layer1/createAiVideoBackdrop.tssrc/tools/layer1/geneticAlgorithm.tssrc/tools/layer1/createAiBackdrop.tssrc/tools/layer3/captionTop.tssrc/tools/layer2/createAiTexture.tssrc/tools/layer1/evolveParameters.tssrc/tools/layer2/createAiVideo.ts
{.claude,codex}/{agents,skills}/**/*
📄 CodeRabbit inference engine (AGENTS.md)
The quality team is defined in
.claude/agents/and mirrored for Codex in.codex/agents/; the skill is mirrored in.claude/skills/tdmcp-quality-audit/and.codex/skills/tdmcp-quality-audit/
Files:
.claude/skills/tdmcp-nevo-integration/SKILL.md.claude/agents/nevo-integration-architect.md.claude/agents/nevo-integration-scout.md
src/utils/config.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Define and validate environment variables through the
TDMCP_*configuration system; bridge authentication requires matchingTDMCP_BRIDGE_TOKENvalues on both sides.
Files:
src/utils/config.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Pantani/tdmcp
Timestamp: 2026-07-15T23:24:45.660Z
Learning: Run the core quality gates before integration: `npm run typecheck`, `npm run build`, `npm run lint`, and `npm test`; bridge changes additionally require `python3 -m unittest discover -s td/tests`.
Learnt from: CR
Repo: Pantani/tdmcp
Timestamp: 2026-07-15T23:24:45.660Z
Learning: When implementing features, tools, bulk tool batches, coverage work, audits, documentation, campaigns, or integrations covered by the CLAUDE.md triggers, use the corresponding repository skill or workflow.
📚 Learning: 2026-06-02T06:35:41.390Z
Learnt from: Pantani
Repo: Pantani/tdmcp PR: 50
File: tests/unit/cliLogTailFilteredRun.test.ts:38-41
Timestamp: 2026-06-02T06:35:41.390Z
Learning: In Vitest unit tests (e.g., when mocking `process.stderr.write` with `vi.spyOn(...).mockImplementation(...)`), using `as never` for `process.stderr.write` overload incompatibilities is an intentional, idiomatic workaround. Do not flag `as never` casts here as fragile/undesirable or request full overload typing; avoid suggesting additional typing noise.
Applied to files:
tests/unit/imageGenProvider.test.tstests/unit/topMotion.test.tstests/unit/createAiVideoBackdrop.test.tstests/unit/evolveParameters.test.tstests/unit/geneticAlgorithm.test.tstests/unit/createAiTexture.test.tstests/unit/videoGenComfyui.test.tstests/unit/createAiBackdrop.test.tstests/unit/createAiVideo.test.ts
🪛 ast-grep (0.44.1)
src/cli/agent.ts
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { spawn } from "node:child_process";
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').
(detect-child-process-typescript)
🪛 GitHub Actions: Code Quality / 4_Complexity Gates.txt
src/feedback/pngDecode.ts
[error] 63-63: Cognitive complexity regression: 13 is not in the baseline (src/feedback/pngDecode.ts:63:17).
src/tools/layer1/evolveParameters.ts
[error] 222-222: Cognitive complexity regression: 10 is not in the baseline (src/tools/layer1/evolveParameters.ts:222:16).
🪛 GitHub Actions: Code Quality / Complexity Gates
src/feedback/pngDecode.ts
[error] 63-63: cognitive complexity ratchet failed. 'JS/TS cognitive complexity ratchet failed (2 regression(s))'. cognitive complexity 13 is not in the baseline.
src/tools/layer1/evolveParameters.ts
[error] 222-222: cognitive complexity ratchet failed. 'JS/TS cognitive complexity ratchet failed (2 regression(s))'. cognitive complexity 10 is not in the baseline.
🪛 LanguageTool
.claude/agents/nevo-integration-scout.md
[grammar] ~65-~65: Use a hyphen to join words.
Context: ...ar? - Realtime honesty — for any "real time" claim, state the true latency path...
(QB_NEW_EN_HYPHEN)
🪛 markdownlint-cli2 (0.23.0)
CLAUDE.md
[warning] 448-448: Tables should be surrounded by blank lines
(MD058, blanks-around-tables)
🪛 OpenGrep (1.25.0)
tests/unit/createAiVideoBackdrop.test.ts
[ERROR] 121-121: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
[ERROR] 160-160: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
tests/unit/evolveParameters.test.ts
[ERROR] 115-115: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
tests/unit/createAiTexture.test.ts
[ERROR] 101-101: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
tests/unit/createAiBackdrop.test.ts
[ERROR] 116-116: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
[ERROR] 161-161: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
tests/unit/createAiVideo.test.ts
[ERROR] 114-114: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.
(coderabbit.command-injection.exec-js)
🔇 Additional comments (37)
tests/unit/imageGenProvider.test.ts (1)
1-65: LGTM!src/feedback/frameStats.ts (1)
1-63: LGTM!tests/unit/topMotion.test.ts (1)
55-77: LGTM!src/tools/layer3/captionTop.ts (1)
3-3: LGTM!Also applies to: 94-109, 150-200
src/feedback/topMotion.ts (1)
32-35: 🔒 Security & PrivacyDrop the extra raw-Python gate here
execute_python_scriptis already disabled whenctx.allowRawPython === false, so this helper doesn’t need to thread its own flag.> Likely an incorrect or invalid review comment.src/services/imageGen/resolve.ts (1)
1-36: LGTM!src/services/imageGen/types.ts (1)
1-54: LGTM!tests/unit/geneticAlgorithm.test.ts (1)
1-124: LGTM!assets/comfyui/ltx-video-t2v.api.json (1)
1-63: LGTM!assets/comfyui/README.md (1)
1-106: LGTM!src/tools/layer1/geneticAlgorithm.ts (1)
1-125: 📐 Maintainability & Code Quality | 💤 Low valueMove helper file outside of the tools directory.
As per coding guidelines, each tool file in
src/tools/**/*.tsmust export an...Impl(ctx, args)implementation and aregister...: ToolRegistrarregistrar.Since this file is a collection of utility functions for the genetic algorithm (and not an active tool), consider moving it to a
utilsdirectory (e.g.,src/utils/geneticAlgorithm.ts) or a dedicated non-tool subfolder to maintain structural hygiene and prevent tool-registrar pattern mismatches.Source: Coding guidelines
src/services/imageGen/falProvider.ts (1)
74-88: 🩺 Stability & Availability | ⚡ Quick winPrevent memory leak by removing the
abortevent listener.If a long-lived
AbortSignalis passed to this function, the anonymous listener attached to it is never removed when the generation operation successfully completes. Over multiple calls, this will cause an accumulation of event listeners on the signal, leading to a memory leak.Extract the listener to a variable and explicitly remove it in the
finallyblock.🛡️ Proposed fix
const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), timeoutMs); + const onAbort = () => controller.abort(); if (signal) { - if (signal.aborted) controller.abort(); - else signal.addEventListener("abort", () => controller.abort(), { once: true }); + if (signal.aborted) onAbort(); + else signal.addEventListener("abort", onAbort, { once: true }); } try { const result = this.usesQueue(model) ? await this.runQueue(model, req, controller.signal) : await this.runSync(model, req, controller.signal); return await this.download(result, model, req, controller.signal); } finally { clearTimeout(timeout); + if (signal) signal.removeEventListener("abort", onAbort); }src/tools/layer2/index.ts (1)
105-106: LGTM!Also applies to: 460-463
src/services/imageGen/cache.ts (1)
1-74: LGTM!src/tools/layer1/createAiBackdrop.ts (1)
14-88: LGTM!Also applies to: 94-174, 180-192
CHANGELOG.md (1)
11-48: LGTM!Also applies to: 390-410
src/cli/agent.ts (1)
86-91: LGTM!Also applies to: 481-481, 889-890, 3342-3371, 5008-5018
src/tools/layer1/index.ts (1)
12-14: LGTM!Also applies to: 147-147, 351-356
src/tools/types.ts (1)
7-8: LGTM!Also applies to: 65-89
src/agentCommandCatalog.ts (1)
725-755: LGTM!Also applies to: 1211-1218
tests/unit/evolveParameters.test.ts (1)
1-177: LGTM!Also applies to: 189-194
src/tools/layer1/createAiVideoBackdrop.ts (2)
1-140: LGTM!Also applies to: 177-183
184-195: 🩺 Stability & AvailabilityThis parse call is acceptable
The MCP SDK catches handler exceptions and returns them as tool errors, socreateAiVideoBackdropSchema.parse(args)won’t escape the tool boundary.> Likely an incorrect or invalid review comment.src/tools/layer1/evolveParameters.ts (1)
1-221: LGTM!src/services/videoGen/resolve.ts (1)
1-10: LGTM!Also applies to: 19-36, 52-56
src/server/context.ts (1)
13-16: LGTM!Also applies to: 33-36, 68-88
tests/unit/createAiTexture.test.ts (2)
1-137: LGTM!Also applies to: 158-194
138-156: 🎯 Functional CorrectnessNo issue here The unset-provider error already tells users to set
TDMCP_IMAGE_GEN_PROVIDER=falandTDMCP_FAL_KEY.> Likely an incorrect or invalid review comment..claude/agents/nevo-integration-scout.md (1)
7-83: LGTM!tests/unit/createAiBackdrop.test.ts (1)
1-175: LGTM!Also applies to: 197-221
src/utils/config.ts (1)
385-427: LGTM!Also applies to: 528-537, 646-647
src/services/videoGen/comfyuiProvider.ts (1)
1-159: LGTM!Also applies to: 177-194, 206-218, 230-250, 265-265
src/services/videoGen/types.ts (1)
13-67: LGTM!tests/unit/createAiVideoBackdrop.test.ts (1)
136-175: 🎯 Functional CorrectnessVerify the generated network layout, not only its topology.
Add assertions for node positions/spacing or record a manual TouchDesigner preview check so the generated container cannot ship with overlapping nodes.
As per coding guidelines, generated project components must use explicit spacing and never overlap.
Source: Coding guidelines
tests/unit/videoGenComfyui.test.ts (1)
1-155: LGTM!src/services/videoGen/falProvider.ts (2)
115-131: 🎯 Functional CorrectnessVerify or replace the undocumented one-step storage upload.
The official integration documents
fal.storage.upload, while this implementation hard-codes an explicitly unverified raw endpoint and response shape. Validate this path live or use the supported client before enabling image-to-video. (fal.ai)
33-43: 🎯 Functional CorrectnessNo change needed. The current
fal-ai/ltx-video/text-to-videoslug matches fal’s documented text-to-video endpoint, and the test mock already uses the same slug.> Likely an incorrect or invalid review comment.
| --- | ||
| name: nevo-integration-architect | ||
| description: Fan-in synthesizer + drafter for the NEvo→tdmcp integration study. Reads every nevo-integration-scout report, dedupes and reconciles them, and produces first the INTEGRATION_POINTS map ("levantar os pontos") and — only on go-ahead — a PROJECT_DRAFT that scopes concrete tdmcp deliverables (e.g. create_ai_video on the hosted media lane; an experimental evolve_* loop) with layer, schema sketch, bridge needs, effort and risks. Reconciles against docs/ROADMAP.md; never edits source, only writes _workspace/nevo/ artifacts. | ||
| model: opus | ||
| --- |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add the required Codex mirror for this agent.
Create .codex/agents/nevo-integration-architect.md with equivalent instructions so the quality workflow remains available across both agent systems.
As per coding guidelines, “The quality team is defined in .claude/agents/ and mirrored for Codex in .codex/agents/.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/agents/nevo-integration-architect.md around lines 1 - 5, Create the
Codex counterpart for the nevo-integration-architect agent at the mirrored
`.codex/agents` location, preserving equivalent metadata, model,
responsibilities, workflow constraints, and artifact-writing behavior from the
`.claude/agents/nevo-integration-architect.md` definition.
Source: Coding guidelines
| --- | ||
| name: nevo-integration-scout | ||
| description: Maps ONE integration surface between the external NEvo research project (EPFL/JHU — Neural-Guided Evolutionary Video Synthesis, arXiv 2607.02317) and tdmcp. NEvo is neuroscience research (evolves AI video to maximally drive a brain ROI), NOT a shippable video generator — so the scout separates the reusable pieces (its off-the-shelf models like LTX-Video, its evolutionary prompt-search method) from the non-reusable objective (fMRI-guided fitness). Research-only: verifies facts from primary sources and writes a structured map of its assigned surface; never edits source. | ||
| model: opus | ||
| --- |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add the corresponding Codex agent mirror.
Create .codex/agents/nevo-integration-scout.md with equivalent behavior so the workflow remains available through both agent systems.
As per coding guidelines, “The quality team is defined in .claude/agents/ and mirrored for Codex in .codex/agents/.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/agents/nevo-integration-scout.md around lines 1 - 5, Create the
Codex mirror of the nevo-integration-scout agent at
.codex/agents/nevo-integration-scout.md, preserving the equivalent frontmatter
and research-only behavior defined by the existing nevo-integration-scout agent.
Ensure the mirrored agent maintains the same scope, integration-mapping
responsibilities, and prohibition on editing source.
Source: Coding guidelines
| --- | ||
| name: tdmcp-nevo-integration | ||
| description: Study whether/how the external NEvo research project (EPFL/JHU — Neural-Guided Evolutionary Video Synthesis, arXiv 2607.02317, nevo-project.epfl.ch) can be integrated into tdmcp, then draft the resulting project. Use whenever the user wants to survey/raise the integration points for NEvo (or a similar external AI-video / evolutionary-synthesis research project), assess feasibility for generating video / real-time use / any interaction, or draft a tdmcp project from it — AND every follow-up: re-run, continue, refresh after a new NEvo release, scope to one surface (e.g. "só o LTX-Video", "só o método evolutivo"), fold in a decision, or go from the points map to the project draft ("agora rascunha o projeto", "levantar os pontos", "montar o build do nevo"). Runs a fan-out of nevo-integration-scouts → 1 nevo-integration-architect. This is a STUDY+DRAFT harness — it produces INTEGRATION_POINTS.md then PROJECT_DRAFT.md; it does NOT build. Once a deliverable is chosen, hand it to tdmcp-pipeline. | ||
| --- |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Add the matching Codex skill mirror.
Mirror this skill under .codex/skills/tdmcp-nevo-integration/ so Claude and Codex expose the same workflow.
As per coding guidelines, “the skill is mirrored in .claude/skills/tdmcp-quality-audit/ and .codex/skills/tdmcp-quality-audit/.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.claude/skills/tdmcp-nevo-integration/SKILL.md around lines 1 - 4, Create a
Codex mirror of the tdmcp-nevo-integration skill under
.codex/skills/tdmcp-nevo-integration/, preserving the same SKILL.md content and
workflow as the existing Claude skill. Follow the established mirrored structure
used by tdmcp-quality-audit so both Claude and Codex expose equivalent behavior.
Source: Coding guidelines
| { | ||
| command: "create-ai-video-backdrop", | ||
| summary: | ||
| "Prompt → a fully wired AI-generated video-backdrop system (movie/level/transform + Play/Speed/Brightness/Scale).", | ||
| mutates: true, | ||
| unsafe: false, | ||
| source: "tool", | ||
| }, |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Include the Blur stage and control in the command summary.
The implementation builds Movie → Level → Transform → Blur and exposes a Blur control, but this catalog entry omits both.
Proposed fix
- "Prompt → a fully wired AI-generated video-backdrop system (movie/level/transform + Play/Speed/Brightness/Scale).",
+ "Prompt → a fully wired AI-generated video-backdrop system (movie/level/transform/blur + Play/Speed/Brightness/Scale/Blur).",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| command: "create-ai-video-backdrop", | |
| summary: | |
| "Prompt → a fully wired AI-generated video-backdrop system (movie/level/transform + Play/Speed/Brightness/Scale).", | |
| mutates: true, | |
| unsafe: false, | |
| source: "tool", | |
| }, | |
| { | |
| command: "create-ai-video-backdrop", | |
| summary: | |
| "Prompt → a fully wired AI-generated video-backdrop system (movie/level/transform/blur + Play/Speed/Brightness/Scale/Blur).", | |
| mutates: true, | |
| unsafe: false, | |
| source: "tool", | |
| }, |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentCommandCatalog.ts` around lines 756 - 763, Update the
create-ai-video-backdrop catalog entry’s summary to include the Blur stage in
the Movie → Level → Transform pipeline and mention the exposed Blur control
alongside Play, Speed, Brightness, and Scale.
| function reconstruct(filter: number, value: number, left: number, up: number, ul: number): number { | ||
| switch (filter) { | ||
| case 1: | ||
| return value + left; | ||
| case 2: | ||
| return value + up; | ||
| case 3: | ||
| return value + ((left + up) >> 1); | ||
| case 4: | ||
| return value + paeth(left, up, ul); | ||
| default: | ||
| return value; // 0 or unknown filter — best effort | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Reject unsupported scanline layouts instead of returning ok: true.
Interlacing is ignored, unknown filters are treated as filter 0, and missing scanline bytes become zero. Valid Adam7 images and corrupt/truncated payloads therefore produce fabricated pixels. Parse the IHDR interlace field, require filters 0–4, and verify the inflated length before unfiltering.
Also applies to: 63-79, 100-104, 147-149
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/feedback/pngDecode.ts` around lines 47 - 59, Update the PNG decode flow
around reconstruct, IHDR parsing, and scanline unfiltering to reject unsupported
layouts instead of fabricating pixels: parse and reject nonzero interlace modes,
validate every scanline filter is 0–4 rather than treating unknown values as
filter 0, and verify the inflated data contains the complete expected scanline
bytes before unfiltering. Propagate these validation failures so decoding does
not return ok: true for Adam7, corrupt, or truncated payloads.
| scored.push({ genome, fitness }); | ||
| if (!best || fitness > best.fitness) best = { genome, fitness }; | ||
| } | ||
| population = nextGeneration(scored, args.genes, opts, rng); | ||
| } | ||
| if (!best) { | ||
| return errorResult("evolve_parameters: no candidate could be scored; nothing to rebuild.", { | ||
| evaluated, | ||
| warnings, | ||
| }); | ||
| } | ||
| return await rebuildWinner(ctx, args, recipe, best, evaluated, warnings); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not report a winner when every fitness evaluation failed.
-Infinity is the scoring-failure sentinel, but the first such candidate populates best, causing an arbitrary genome to be rebuilt successfully.
src/tools/layer1/evolveParameters.ts#L259-L270: requireNumber.isFinite(best.fitness)before rebuilding.tests/unit/evolveParameters.test.ts#L178-L187: expect an error for an unresolved target instead of successful winner creation.
📍 Affects 2 files
src/tools/layer1/evolveParameters.ts#L259-L270(this comment)tests/unit/evolveParameters.test.ts#L178-L187
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tools/layer1/evolveParameters.ts` around lines 259 - 270, The
evolveParameters flow must not rebuild a winner when all fitness evaluations
failed and best.fitness is the -Infinity failure sentinel. In
src/tools/layer1/evolveParameters.ts:259-270, require
Number.isFinite(best.fitness) alongside the existing best check before calling
rebuildWinner, returning the existing errorResult otherwise. In
tests/unit/evolveParameters.test.ts:178-187, update the unresolved-target case
to expect an error instead of successful winner creation.
| export async function evolveParametersImpl( | ||
| ctx: ToolContext, | ||
| args: EvolveParametersArgs, | ||
| ): Promise<CallToolResult> { | ||
| if (Object.keys(args.genes).length === 0) { | ||
| return errorResult( | ||
| "evolve_parameters: `genes` is empty; provide at least one '<node>.<param>' search dimension.", | ||
| ); | ||
| } | ||
| const recipe = ctx.recipes.get(args.build_target); | ||
| if (!recipe) { | ||
| const ids = ctx.recipes.list().map((r) => r.id); | ||
| return errorResult( | ||
| `evolve_parameters: unknown build_target "${args.build_target}". Available recipe ids: ${ids.join(", ")}.`, | ||
| ); | ||
| } | ||
| const budget = args.population * args.generations; | ||
| if (budget > HARD_CAP) { | ||
| return errorResult( | ||
| `evolve_parameters: population*generations (${budget}) exceeds the hard cap of ${HARD_CAP}. Reduce population or generations — this is an offline, minutes-long search that mutates a scratch graph.`, | ||
| ); | ||
| } | ||
| return runBuild(() => runEvolution(ctx, args, recipe)); | ||
| } | ||
|
|
||
| export const registerEvolveParameters: ToolRegistrar = (server, ctx) => { | ||
| server.registerTool( | ||
| "evolve_parameters", | ||
| { | ||
| title: "Evolve parameters (experimental, offline)", | ||
| description: | ||
| "EXPERIMENTAL, OFFLINE / DESIGN-TIME: search a categorical parameter genome over a recipe with a genetic algorithm, scored by a tdmcp-measurable fitness (audio_energy Info-CHOP energy / top_luma / top_motion). Each candidate is built from `build_target`, has its genome-selected params applied, cooked, scored, then its scratch subtree is deleted; across `generations` of μ+λ elitism only genomes+scores are kept, and at the end the single winning genome is rebuilt under `parent_path` with a finalize preview. A full run is minutes and mutates a scratch graph while running — it is NOT a real-time controller. Hard cap: population*generations ≤ 300. Method adopted from NEvo (arXiv 2607.02317, CC BY 4.0).", | ||
| inputSchema: evolveParametersSchema.shape, | ||
| }, | ||
| (args) => evolveParametersImpl(ctx, args), | ||
| ); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Gate this Python-executing tool with allowRawPython.
The tool invokes executePythonScript for cooking and fitness telemetry, but remains exposed when TDMCP_RAW_PYTHON=off. Skip registration when ctx.allowRawPython === false, and retain an implementation guard for direct callers.
As per coding guidelines, raw Python execution must be controlled by TDMCP_RAW_PYTHON=off and the injected allowRawPython flag; execution tools must not be exposed when disabled.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tools/layer1/evolveParameters.ts` around lines 276 - 311, The
evolve_parameters tool must be unavailable when raw Python execution is
disabled. Add an implementation guard in evolveParametersImpl that rejects
direct calls when ctx.allowRawPython is false, and update
registerEvolveParameters to skip registration in that case while preserving the
existing validation and execution flow when enabled.
Source: Coding guidelines
| const cachePath = await writeCachedImage(cacheDir, cacheKey, image); | ||
| return { ok: true, value: { cachePath, image, cacheKey, cacheHit: false } }; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
Catch file system errors to prevent throwing from the tool handler.
As per coding guidelines, tool handlers must never throw. If writeCachedImage fails (e.g., due to file system permission issues or disk space), it will throw an unhandled exception that bubbles up and crashes the MCP server. Wrap it in a try/catch and return an errorResult.
🛡️ Proposed fix to handle the caching error
- const cachePath = await writeCachedImage(cacheDir, cacheKey, image);
- return { ok: true, value: { cachePath, image, cacheKey, cacheHit: false } };
+ let cachePath: string;
+ try {
+ cachePath = await writeCachedImage(cacheDir, cacheKey, image);
+ } catch (err) {
+ return {
+ ok: false,
+ error: errorResult(`Failed to write generated image to cache: ${(err as Error).message}`, {
+ provider: ctx.imageGen.id,
+ model,
+ }),
+ };
+ }
+
+ return { ok: true, value: { cachePath, image, cacheKey, cacheHit: false } };📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const cachePath = await writeCachedImage(cacheDir, cacheKey, image); | |
| return { ok: true, value: { cachePath, image, cacheKey, cacheHit: false } }; | |
| let cachePath: string; | |
| try { | |
| cachePath = await writeCachedImage(cacheDir, cacheKey, image); | |
| } catch (err) { | |
| return { | |
| ok: false, | |
| error: errorResult(`Failed to write generated image to cache: ${(err as Error).message}`, { | |
| provider: ctx.imageGen.id, | |
| model, | |
| }), | |
| }; | |
| } | |
| return { ok: true, value: { cachePath, image, cacheKey, cacheHit: false } }; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tools/layer2/createAiTexture.ts` around lines 156 - 157, Update the
caching flow around writeCachedImage in the tool handler to catch file-system
failures and prevent exceptions from escaping. On failure, return the existing
errorResult with the caught error details; preserve the successful cachePath
result and cacheHit: false behavior when writing succeeds.
Source: Coding guidelines
| const hit = await findCachedVideo(cacheDir, cacheKey); | ||
| if (hit) { | ||
| return { | ||
| ok: true, | ||
| value: { | ||
| cachePath: hit, | ||
| video: { | ||
| bytes: new Uint8Array(0), | ||
| mimeType: mimeFromPath(hit), | ||
| provider: ctx.videoGen.id, | ||
| model, | ||
| durationSec: req.durationSeconds, | ||
| seed: req.seed, | ||
| }, | ||
| cacheKey, | ||
| cacheHit: true, | ||
| }, | ||
| }; | ||
| } | ||
|
|
||
| const controller = new AbortController(); | ||
| const timer = setTimeout(() => controller.abort(), req.timeoutMs ?? DEFAULT_VIDEO_GEN_TIMEOUT_MS); | ||
| let video: VideoGenResult; | ||
| try { | ||
| video = await ctx.videoGen.generate({ ...req, model }, controller.signal); | ||
| } catch (err) { | ||
| return { | ||
| ok: false, | ||
| error: errorResult(`Video generation failed: ${(err as Error).message}`, { | ||
| provider: ctx.videoGen.id, | ||
| model, | ||
| }), | ||
| }; | ||
| } finally { | ||
| clearTimeout(timer); | ||
| } | ||
|
|
||
| const cachePath = await writeCachedVideo(cacheDir, cacheKey, video); | ||
| return { ok: true, value: { cachePath, video, cacheKey, cacheHit: false } }; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Represent cache I/O failures consistently as tool errors. The cache layer currently hides some failures while the tool layer lets others escape as rejected handlers.
src/tools/layer2/createAiVideo.ts#L190-L228: catch cache lookup/write failures and returnerrorResult.src/services/videoGen/cache.ts#L51-L59: suppress onlyENOENT; propagate permission and I/O failures.
📍 Affects 2 files
src/tools/layer2/createAiVideo.ts#L190-L228(this comment)src/services/videoGen/cache.ts#L51-L59
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tools/layer2/createAiVideo.ts` around lines 190 - 228, Update
createAiVideo to catch failures from findCachedVideo and writeCachedVideo,
returning consistently structured errorResult values with provider and model
context instead of allowing rejected handlers. In src/services/videoGen/cache.ts
lines 51-59, modify the cache lookup handling to suppress only ENOENT and
rethrow permission or other I/O failures; apply the tool-layer handling at
createAiVideo and the errno filtering at the cache implementation.
Source: Coding guidelines
| export const registerCreateAiVideo: ToolRegistrar = (server, ctx) => { | ||
| server.registerTool( | ||
| "create_ai_video", | ||
| { | ||
| title: "Create AI video", | ||
| description: | ||
| "Turn a text prompt (+ optional init image) into a short clip via a provider-agnostic engine — hosted fal OR local ComfyUI — and drop it into TouchDesigner as a Movie File In TOP the artist can wire by hand. NOT real time: generate ahead (seconds–minutes), then play live. The clip is generated Node-side, cached to a local dir, and delivered as an absolute file path (server + TD are colocated) — no key ever reaches the bridge. Default model ltx-video (cheapest, fixed 5s); ltx-2 for variable length + higher res + audio. Same request reuses the cached file (no API call). Requires TDMCP_VIDEO_GEN_PROVIDER=fal (+TDMCP_FAL_KEY) or =comfyui (+TDMCP_COMFYUI_VIDEO_WORKFLOW); without them the tool returns a friendly error and builds nothing. Use create_ai_video_backdrop for a fully wired, control-exposed playback system instead of a bare TOP.", | ||
| inputSchema: createAiVideoInputSchema.shape, | ||
| annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }, | ||
| }, | ||
| (args) => createAiVideoImpl(ctx, createAiVideoSchema.parse(args)), | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
set -e
printf 'Inspecting relevant files...\n'
git ls-files 'src/tools/layer2/createAiVideo.ts' 'src/tools/layer2/*' | sed -n '1,120p'
printf '\n--- outline createAiVideo.ts ---\n'
ast-grep outline src/tools/layer2/createAiVideo.ts --view expanded || true
printf '\n--- key symbols around schema/registration ---\n'
rg -n "createAiVideo(Schema|InputSchema|Impl|registerCreateAiVideo|superRefine|safeParse|parse\\()" src/tools/layer2/createAiVideo.ts src/tools/layer2 -SRepository: Pantani/tdmcp
Length of output: 7781
🏁 Script executed:
set -e
printf 'Reading relevant sections...\n'
wc -l src/tools/layer2/createAiVideo.ts
sed -n '1,220p' src/tools/layer2/createAiVideo.ts
printf '\n--- middle ---\n'
sed -n '220,420p' src/tools/layer2/createAiVideo.tsRepository: Pantani/tdmcp
Length of output: 13384
🏁 Script executed:
set -e
printf 'Searching for tool handler wrapping and parse usage...\n'
rg -n "registerTool\\(|safeParse\\(|parse\\(args\\)|try \\{|catch \\(" src -S | sed -n '1,240p'
printf '\n--- tool/server types ---\n'
sed -n '1,240p' src/tools/types.ts
printf '\n--- result helpers ---\n'
sed -n '1,220p' src/tools/result.tsRepository: Pantani/tdmcp
Length of output: 21531
🏁 Script executed:
set -e
printf 'Finding registerTool definition and dispatcher...\n'
rg -n "registerTool\\s*\\(" src -S
printf '\n--- likely server implementation files ---\n'
fd -a "server" src | sed -n '1,120p'
fd -a "tool" src | sed -n '1,120p'Repository: Pantani/tdmcp
Length of output: 34416
🏁 Script executed:
set -e
printf 'Inspecting llm tool runtime...\n'
wc -l src/llm/tools.ts
sed -n '380,520p' src/llm/tools.ts
printf '\n--- server tool dispatch ---\n'
sed -n '1,260p' src/server/tdmcpServer.tsRepository: Pantani/tdmcp
Length of output: 7461
🏁 Script executed:
set -e
printf 'Inspecting tool registration patterns in nearby files...\n'
sed -n '1,240p' src/tools/layer3/execNodeMethod.ts
printf '\n--- another layer2 tool with parse/safeParse ---\n'
sed -n '420,470p' src/tools/layer2/applyLut.tsRepository: Pantani/tdmcp
Length of output: 3047
🏁 Script executed:
set -e
printf 'Inspecting the paired backdrop tool and shared schema usage...\n'
wc -l src/tools/layer1/createAiVideoBackdrop.ts
sed -n '1,260p' src/tools/layer1/createAiVideoBackdrop.ts
printf '\n--- references to createAiVideoSchema / createAiVideoImpl ---\n'
rg -n "createAiVideoSchema|createAiVideoImpl|createAiVideoInputSchema|refineVideoModel" src/tools -SRepository: Pantani/tdmcp
Length of output: 8889
Return validation failures instead of throwing The createAiVideoSchema.parse(args) call in the registered handler can throw on invalid model/duration_seconds/resolution combinations. Use safeParse here and return errorResult so the tool handler stays non-throwing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/tools/layer2/createAiVideo.ts` around lines 340 - 351, Update the
registered create_ai_video handler in registerCreateAiVideo to validate
arguments with createAiVideoSchema.safeParse instead of parse. When validation
fails, return the resulting errorResult, and pass the parsed data to
createAiVideoImpl only on successful validation so invalid model,
duration_seconds, or resolution combinations do not throw.
Source: Coding guidelines
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbab3e3b7f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ("length" in inputs && req.durationSeconds !== undefined) | ||
| inputs.length = secondsToLtxFrames(req.durationSeconds); | ||
| if ("image" in inputs && uploadedImage) inputs.image = uploadedImage; |
There was a problem hiding this comment.
Apply requested dimensions to ComfyUI workflows
With TDMCP_VIDEO_GEN_PROVIDER=comfyui, toVideoRequest passes the parsed resolution as req.width/req.height, and the bundled LTX workflow has width/height inputs on the latent node, but this injection path only mutates length and image. Any request for 1280x720, 1920x1080, or 4k will still render at the workflow's baked dimensions while the cache key/result correspond to the requested size, so either inject width/height when those inputs exist or reject unsupported workflow dimensions.
Useful? React with 👍 / 👎.
| for (const s of scored) if (!best || s.fitness > best.fitness) best = s; | ||
| population = nextGeneration(scored, args.genes, opts, rng); | ||
| } | ||
| if (!best) { |
There was a problem hiding this comment.
Reject all-failed evolution runs
When every candidate fails to score, for example because fitness_target_path does not resolve or preview capture fails for all candidates, each candidate gets -Infinity but best is still assigned on the first scored item. This !best check therefore does not catch the all-failed run, and the tool rebuilds an arbitrary genome with best_fitness: -Infinity, which can corrupt experiment results instead of reporting that nothing was scored.
Useful? React with 👍 / 👎.
| model: z | ||
| .enum(["ltx-video", "ltx-2"]) | ||
| .default("ltx-video") |
There was a problem hiding this comment.
Honor the configured video model default
When callers omit model, this schema default writes ltx-video into the parsed args before both AI video tools call toVideoRequest, so req.model is always set and ctx.videoGen.defaultModel from TDMCP_VIDEO_GEN_MODEL is never used for normal tool calls. Operators who configure the default to ltx-2 or a provider-specific slug still get ltx-video unless every call explicitly supplies a model, unlike the image lane where model remains optional and the provider default can apply.
Useful? React with 👍 / 👎.
|
|
||
| /** Map a friendly model key onto the fal slug for the requested mode. */ | ||
| private resolveSlug(modelKey: string, req: VideoGenRequest): string { | ||
| const entry = MODEL_SLUGS[modelKey] ?? MODEL_SLUGS[DEFAULT_FAL_VIDEO_MODEL]; |
There was a problem hiding this comment.
Pass unknown fal video slugs through
For a configured/custom fal video model not present in MODEL_SLUGS, this expression falls back to the default ltx-video entry before the raw-slug branch, making if (!entry) return modelKey unreachable. If TDMCP_VIDEO_GEN_MODEL or a lower-level request supplies a raw slug, the provider posts to the default ltx-video endpoint while reporting the custom model in metadata/cache results, so custom fal models cannot actually be used.
Useful? React with 👍 / 👎.
|
|
||
| const { cachePath, video, cacheHit } = gen.value; | ||
| try { | ||
| const ref = await ctx.client.createNode({ |
There was a problem hiding this comment.
Place standalone AI TOPs deterministically
AGENTS.md says every operator creation path must assign deterministic nodeX/nodeY; this direct createNode path, and the analogous direct TOP creation in create_ai_texture, has no coordinates or layout pass. On repeated create-ai-video/texture calls under the same parent, the nodes can land at the bridge/default drop position and overlap, so use the existing grid/layout helper after creating these standalone nodes.
Useful? React with 👍 / 👎.
The coverage gate dipped to 72.92% branch (threshold 73%) because the new videoGen/falProvider.ts and feedback/pngDecode.ts branches were under-tested. Add pure pngDecode/frameStats tests (every failure reason, scanline filters 0-4, grayscale + histogram fallback) and msw fal-provider tests (t2v/i2v slug resolution, video.url vs videos[] shapes, cost, and every HTTP error path). Global branch coverage back to 73.02%. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
HttpResponse.json needs a JsonBodyType; the mock helper's result param was unknown. Type it as the fal result shape. vitest was green but tsc/build failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Turns the NEvo evolutionary-video-synthesis paper (EPFL/JHU, arXiv 2607.02317, CC BY 4.0) into two shippable tdmcp capabilities. NEvo itself ships no code/weights/API and its fMRI-guided objective is out of scope, so this adopts its two reusable pieces: its off-the-shelf LTX-Video generator and its evolutionary-search method (retargeted to a TouchDesigner-measurable fitness). Study artifacts under
_workspace/nevo/.What's in it
create_ai_video+create_ai_video_backdrop(hosted or local video lane)create_ai_video) drops a generated clip into a Movie File In TOP; Layer 1 (create_ai_video_backdrop) wires a full moving backdrop (Movie File In → Level → Transform → Blur → Null) with live controls.TDMCP_VIDEO_GEN_PROVIDER:comfyui— LTX-Video on a local GPU via ComfyUI REST: zero cost per generation, fully offline.fal— hosted fal.ai (pay-per-generation), a fork of the imageGen fal provider.src/services/videoGen/seam. Model defaultltx-video,ltx-2opt-in; schema rejects controls a model lacks. No new bridge endpoint. Shipsassets/comfyui/(API-format LTX workflow + setup README).evolve_parameters(experimental, offline)audio_energy(Info CHOP),top_luma, ortop_motion.seed(seeded RNG, noMath.random); losing candidates torn down each generation, only the champion rebuilt. Design-time search, not a live controller.Supporting
main).lengthis frames (k·8+1), not seconds — now converted.src/feedback/pngDecode.ts) used byframeStats+captionTop(behavior-preserving).Testing
biome(1427 files),typecheck,build, 5632 vitest, bridge tests.moviefileinTOPfirst-frame/codec,evolve_parameterscook-settle/delete-churn. Probe steps are inassets/comfyui/README.mdand the_workspace/04_qa_*.mdreports.No release tag cut (project policy: [Unreleased] only).
🤖 Generated with Claude Code
Summary by CodeRabbit