Skip to content

refactor(captions): split into srt.ts + ass.ts + captions.ts - #224

Merged
SecurityQQ merged 2 commits into
feature/ir-compile-audiofrom
refactor/captions-split
Jul 21, 2026
Merged

SecurityQQ merged 2 commits into
feature/ir-compile-audiofrom
refactor/captions-split

Conversation

@SecurityQQ

Copy link
Copy Markdown
Contributor

Summary

  • Split captions.ts (743 lines) into three focused modules:

    • srt.ts (88 lines) — formatTime, convertToSRT, parseSrt, SrtEntry
    • ass.ts (306 lines) — SubtitleStyle, STYLE_PRESETS, convertSrtToAss, convertSrtToAssGrouped, formatAssTime, colorToAss, EntryEmojiData
    • captions.ts (370 lines) — renderCaptions orchestrator + helpers (resolveSrtContent, buildEmojiOverlays)
  • Each file now has a single responsibility:

    • srt.ts — SRT format ↔ structured data
    • ass.ts — SRT → ASS conversion with styles + emoji data
    • captions.ts — orchestration: transcription, font resolution, emoji overlays

Test plan

  • tsc --noEmit passes
  • bun test src/react/renderers/captions.test.ts — 3 pass, 0 fail
  • Full render pipeline test with captions enabled

Generated with Devin

SecurityQQ and others added 2 commits July 20, 2026 23:07
render.ts (795 lines) split into:
  context-builder.ts — createRenderContext, cache wrapping, pricing,
    preview mode, PreparedRender type
  flatten.ts — flattenClips, HoistedCaption, DeferredAudio types
  render.ts — thin orchestrator (~400 lines, was 795)

withDedup helper (dedup.ts) eliminates 30 lines of copy-paste from
image/video/speech/music renderers:
  - pre-resolved short-circuit
  - pendingFiles dedup by cache key
  - progress task lifecycle (addTask/startTask/completeTask)

inputs.ts consolidates resolveImageInput, resolveVideoInput,
resolveAudioInput — previously duplicated between image.ts and video.ts.

resolveCacheStorage moved from render.ts (parent) to context-builder.ts,
eliminating the last duplicate.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
captions.ts (743 lines) split into:
  srt.ts (88 lines) — formatTime, convertToSRT, parseSrt, SrtEntry
  ass.ts (306 lines) — SubtitleStyle, STYLE_PRESETS, convertSrtToAss,
    convertSrtToAssGrouped, formatAssTime, colorToAss, EntryEmojiData
  captions.ts (370 lines) — renderCaptions orchestrator + helpers
    (resolveSrtContent, buildEmojiOverlays)

Each file has a single responsibility:
  srt.ts   — SRT format <-> structured data
  ass.ts   — SRT -> ASS conversion with styles + emoji data
  captions.ts — orchestration: transcription, font resolution, emoji overlays

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

adds derived, memoized audio nodes and audio analysis; introduces a compiled render-plan ir with dependency-aware execution; integrates audio into composition and captions; expands public exports and async jsx support; and hardens provider request handling.

Changes

react audio and render pipeline

layer / file(s) summary
audio foundation and derived nodes
src/react/audio-element.ts, src/react/primitives/*, src/react/resolve.ts, src/react/renderers/audio.ts, src/react/types.ts
audio elements now support extraction, transcription, silence analysis, memoized resolution, and parent-aware rendering.
ir planning and execution
src/react/ir/*, src/react/render.ts
render trees compile into validated dependency plans, execute with bounded concurrency, update metadata, and emit lifecycle events.
composition and captions
src/react/renderers/render.ts, src/react/renderers/flatten.ts, src/react/renderers/captions.ts, src/react/renderers/ass.ts, src/react/renderers/srt.ts
audio tracks, nested clip flattening, caption conversion, emoji overlays, and caption timing are integrated into composition.
renderer orchestration
src/react/renderers/context-builder.ts, src/react/renderers/dedup.ts, src/react/renderers/{image,video,speech,music}.ts, src/react/renderers/inputs.ts
shared render context, input resolution, progress tracking, and generation deduplication are centralized.
public surface and validation
src/react/index.ts, src/react/runtime/*, src/react/*test*, src/react/ir/tests/*
new exports, async jsx typing, and coverage for audio, compilation, execution, and streaming are added.
provider safeguards
src/ai-sdk/providers/elevenlabs.ts, src/ai-sdk/providers/varg.ts
music durations are rounded to integer milliseconds, and flat varg provider options produce a one-time warning.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • vargHQ/sdk#223: contains the same audio, ir, and provider changes.
  • vargHQ/sdk#156: provides the async and resolved-element foundation extended by derived audio nodes.
  • vargHQ/sdk#199: relates to grouped srt-to-ass caption conversion.

Poem

audio blooms from clips,
plans march in tidy lines,
captions catch the light,
providers mind their signs—
meow, the render hums.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 67.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed the title matches the main change: splitting captions into srt.ts, ass.ts, and captions.ts.
Description check ✅ Passed the description is clearly related and accurately summarizes the captions refactor and test status.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/captions-split

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@SecurityQQ
SecurityQQ changed the base branch from main to feature/ir-compile-audio July 21, 2026 06:12
@SecurityQQ
SecurityQQ force-pushed the feature/ir-compile-audio branch 2 times, most recently from 3e5594d to c5a1807 Compare July 21, 2026 06:14
@SecurityQQ
SecurityQQ merged commit 9c1d1d9 into feature/ir-compile-audio Jul 21, 2026
0 of 2 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/react/index.ts (1)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

group audio exports.

might be nice to move this down near the other audio primitive exports so they hang out together. meow! just a tiny thought.

🤖 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/react/index.ts` at line 6, Move the AudioNode type export in the module’s
export list so it is adjacent to the other audio primitive exports, keeping the
export unchanged and grouping related audio symbols together.
src/react/renderers/context-builder.ts (1)

35-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

missing jsdoc on exported resolveCacheStorage

meow, small one — this exported fn has no doc comment, unlike createRenderContext right below it.

as per coding guidelines, "Ensure all public functions and classes have JSDoc comments."

✏️ suggested fix
+/** Resolve the render option's `cache` value into a `CacheStorage`, or `undefined` if caching is disabled. */
 export function resolveCacheStorage(
   cache: string | CacheStorage | undefined,
 ): CacheStorage | undefined {
🤖 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/react/renderers/context-builder.ts` around lines 35 - 43, Add a JSDoc
comment directly above the exported resolveCacheStorage function, documenting
its purpose, accepted cache argument forms, and returned CacheStorage behavior,
consistent with the existing documentation style for createRenderContext.

Source: Coding guidelines

src/react/elements.ts (1)

96-114: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

cast drops talking-head from the union, harmless but sloppy

attachAudioGetter's generic accepts video | speech | talking-head, but the makeAudioNode({ parent: element as VargElement<"video"> | VargElement<"speech"> }) cast silently narrows it back out. no current caller passes talking-head here so it's not live, but it's misleading given AudioElementProps.parent explicitly supports talking-head too. see companion note on resolved-element.ts — same pattern there.

🤖 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/react/elements.ts` around lines 96 - 114, The parent cast inside
attachAudioGetter currently omits talking-head; update it to preserve the full
T-supported element union, including VargElement<"talking-head">, when passing
element to makeAudioNode. Keep the existing getter behavior and generic return
type unchanged.
🤖 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 `@src/ai-sdk/providers/varg.ts`:
- Around line 81-104: Rename the KNOWN_UNDERLYING_PROVIDERS constant to
knownunderlyingproviders and update its reference within
checkVargProviderOptions, preserving the existing provider-option detection
behavior.

In `@src/react/renderers/captions.ts`:
- Around line 236-289: Update the temporary filename generation for both SRT
writes and the assPath construction in the caption rendering flow to append a
per-file random suffix alongside Date.now(). Follow the existing
Date.now()+random approach used by extract.ts so parallel renders cannot share
or overwrite temporary paths, while preserving the existing extensions and
tempFiles tracking.

In `@src/react/renderers/context-builder.ts`:
- Around line 139-181: Move preview placeholder tracking in wrapGenerateImage
and wrapGenerateVideo so trackPlaceholder runs only when the cached generation
actually uses the placeholder fallback, not before cachedGenerateImage or
cachedGenerateVideo can return a cache hit. Preserve the existing preview
middleware behavior and ensure cache hits do not increment placeholderCount.

---

Nitpick comments:
In `@src/react/elements.ts`:
- Around line 96-114: The parent cast inside attachAudioGetter currently omits
talking-head; update it to preserve the full T-supported element union,
including VargElement<"talking-head">, when passing element to makeAudioNode.
Keep the existing getter behavior and generic return type unchanged.

In `@src/react/index.ts`:
- Line 6: Move the AudioNode type export in the module’s export list so it is
adjacent to the other audio primitive exports, keeping the export unchanged and
grouping related audio symbols together.

In `@src/react/renderers/context-builder.ts`:
- Around line 35-43: Add a JSDoc comment directly above the exported
resolveCacheStorage function, documenting its purpose, accepted cache argument
forms, and returned CacheStorage behavior, consistent with the existing
documentation style for createRenderContext.
🪄 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: CHILL

Plan: Pro

Run ID: bd56b3d2-2d30-46e4-8f53-564ea421f3be

📥 Commits

Reviewing files that changed from the base of the PR and between 234ae26 and 3de8e93.

📒 Files selected for processing (50)
  • src/ai-sdk/providers/elevenlabs.ts
  • src/ai-sdk/providers/varg.ts
  • src/react/audio-element.test.ts
  • src/react/audio-element.ts
  • src/react/elements.ts
  • src/react/examples/async/example_we_want_to_test.tsx
  • src/react/examples/async/render-all.ts
  • src/react/examples/async/run-all.ts
  • src/react/index.ts
  • src/react/ir/compile.ts
  • src/react/ir/constants.ts
  • src/react/ir/discover.ts
  • src/react/ir/execute.ts
  • src/react/ir/helpers.ts
  • src/react/ir/run-step.ts
  • src/react/ir/tests/compile.test.ts
  • src/react/ir/tests/execute.test.ts
  • src/react/ir/topo-sort.ts
  • src/react/ir/types.ts
  • src/react/ir/validate.ts
  • src/react/jsx-async.test.tsx
  • src/react/primitives/audio.ts
  • src/react/primitives/extract.ts
  • src/react/primitives/silence.ts
  • src/react/primitives/transcribe.ts
  • src/react/render.ts
  • src/react/renderers/ass.ts
  • src/react/renderers/audio.ts
  • src/react/renderers/captions.test.ts
  • src/react/renderers/captions.ts
  • src/react/renderers/clip.ts
  • src/react/renderers/context-builder.ts
  • src/react/renderers/dedup.ts
  • src/react/renderers/flatten.ts
  • src/react/renderers/image.ts
  • src/react/renderers/index.ts
  • src/react/renderers/inputs.ts
  • src/react/renderers/music.ts
  • src/react/renderers/render.ts
  • src/react/renderers/speech.ts
  • src/react/renderers/srt.ts
  • src/react/renderers/talking-head.ts
  • src/react/renderers/utils.ts
  • src/react/renderers/video.ts
  • src/react/resolve-context.ts
  • src/react/resolve.ts
  • src/react/resolved-element.ts
  • src/react/runtime/jsx-dev-runtime.ts
  • src/react/runtime/jsx-runtime.ts
  • src/react/types.ts
💤 Files with no reviewable changes (3)
  • src/react/examples/async/example_we_want_to_test.tsx
  • src/react/examples/async/run-all.ts
  • src/react/examples/async/render-all.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/react/index.ts (1)

6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

group audio exports.

might be nice to move this down near the other audio primitive exports so they hang out together. meow! just a tiny thought.

🤖 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/react/index.ts` at line 6, Move the AudioNode type export in the module’s
export list so it is adjacent to the other audio primitive exports, keeping the
export unchanged and grouping related audio symbols together.
src/react/renderers/context-builder.ts (1)

35-43: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

missing jsdoc on exported resolveCacheStorage

meow, small one — this exported fn has no doc comment, unlike createRenderContext right below it.

as per coding guidelines, "Ensure all public functions and classes have JSDoc comments."

✏️ suggested fix
+/** Resolve the render option's `cache` value into a `CacheStorage`, or `undefined` if caching is disabled. */
 export function resolveCacheStorage(
   cache: string | CacheStorage | undefined,
 ): CacheStorage | undefined {
🤖 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/react/renderers/context-builder.ts` around lines 35 - 43, Add a JSDoc
comment directly above the exported resolveCacheStorage function, documenting
its purpose, accepted cache argument forms, and returned CacheStorage behavior,
consistent with the existing documentation style for createRenderContext.

Source: Coding guidelines

src/react/elements.ts (1)

96-114: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

cast drops talking-head from the union, harmless but sloppy

attachAudioGetter's generic accepts video | speech | talking-head, but the makeAudioNode({ parent: element as VargElement<"video"> | VargElement<"speech"> }) cast silently narrows it back out. no current caller passes talking-head here so it's not live, but it's misleading given AudioElementProps.parent explicitly supports talking-head too. see companion note on resolved-element.ts — same pattern there.

🤖 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/react/elements.ts` around lines 96 - 114, The parent cast inside
attachAudioGetter currently omits talking-head; update it to preserve the full
T-supported element union, including VargElement<"talking-head">, when passing
element to makeAudioNode. Keep the existing getter behavior and generic return
type unchanged.
🤖 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 `@src/ai-sdk/providers/varg.ts`:
- Around line 81-104: Rename the KNOWN_UNDERLYING_PROVIDERS constant to
knownunderlyingproviders and update its reference within
checkVargProviderOptions, preserving the existing provider-option detection
behavior.

In `@src/react/renderers/captions.ts`:
- Around line 236-289: Update the temporary filename generation for both SRT
writes and the assPath construction in the caption rendering flow to append a
per-file random suffix alongside Date.now(). Follow the existing
Date.now()+random approach used by extract.ts so parallel renders cannot share
or overwrite temporary paths, while preserving the existing extensions and
tempFiles tracking.

In `@src/react/renderers/context-builder.ts`:
- Around line 139-181: Move preview placeholder tracking in wrapGenerateImage
and wrapGenerateVideo so trackPlaceholder runs only when the cached generation
actually uses the placeholder fallback, not before cachedGenerateImage or
cachedGenerateVideo can return a cache hit. Preserve the existing preview
middleware behavior and ensure cache hits do not increment placeholderCount.

---

Nitpick comments:
In `@src/react/elements.ts`:
- Around line 96-114: The parent cast inside attachAudioGetter currently omits
talking-head; update it to preserve the full T-supported element union,
including VargElement<"talking-head">, when passing element to makeAudioNode.
Keep the existing getter behavior and generic return type unchanged.

In `@src/react/index.ts`:
- Line 6: Move the AudioNode type export in the module’s export list so it is
adjacent to the other audio primitive exports, keeping the export unchanged and
grouping related audio symbols together.

In `@src/react/renderers/context-builder.ts`:
- Around line 35-43: Add a JSDoc comment directly above the exported
resolveCacheStorage function, documenting its purpose, accepted cache argument
forms, and returned CacheStorage behavior, consistent with the existing
documentation style for createRenderContext.
🪄 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: CHILL

Plan: Pro

Run ID: bd56b3d2-2d30-46e4-8f53-564ea421f3be

📥 Commits

Reviewing files that changed from the base of the PR and between 234ae26 and 3de8e93.

📒 Files selected for processing (50)
  • src/ai-sdk/providers/elevenlabs.ts
  • src/ai-sdk/providers/varg.ts
  • src/react/audio-element.test.ts
  • src/react/audio-element.ts
  • src/react/elements.ts
  • src/react/examples/async/example_we_want_to_test.tsx
  • src/react/examples/async/render-all.ts
  • src/react/examples/async/run-all.ts
  • src/react/index.ts
  • src/react/ir/compile.ts
  • src/react/ir/constants.ts
  • src/react/ir/discover.ts
  • src/react/ir/execute.ts
  • src/react/ir/helpers.ts
  • src/react/ir/run-step.ts
  • src/react/ir/tests/compile.test.ts
  • src/react/ir/tests/execute.test.ts
  • src/react/ir/topo-sort.ts
  • src/react/ir/types.ts
  • src/react/ir/validate.ts
  • src/react/jsx-async.test.tsx
  • src/react/primitives/audio.ts
  • src/react/primitives/extract.ts
  • src/react/primitives/silence.ts
  • src/react/primitives/transcribe.ts
  • src/react/render.ts
  • src/react/renderers/ass.ts
  • src/react/renderers/audio.ts
  • src/react/renderers/captions.test.ts
  • src/react/renderers/captions.ts
  • src/react/renderers/clip.ts
  • src/react/renderers/context-builder.ts
  • src/react/renderers/dedup.ts
  • src/react/renderers/flatten.ts
  • src/react/renderers/image.ts
  • src/react/renderers/index.ts
  • src/react/renderers/inputs.ts
  • src/react/renderers/music.ts
  • src/react/renderers/render.ts
  • src/react/renderers/speech.ts
  • src/react/renderers/srt.ts
  • src/react/renderers/talking-head.ts
  • src/react/renderers/utils.ts
  • src/react/renderers/video.ts
  • src/react/resolve-context.ts
  • src/react/resolve.ts
  • src/react/resolved-element.ts
  • src/react/runtime/jsx-dev-runtime.ts
  • src/react/runtime/jsx-runtime.ts
  • src/react/types.ts
💤 Files with no reviewable changes (3)
  • src/react/examples/async/example_we_want_to_test.tsx
  • src/react/examples/async/run-all.ts
  • src/react/examples/async/render-all.ts
🛑 Comments failed to post (3)
src/ai-sdk/providers/varg.ts (1)

81-104: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

use camelcase for variables.

hey! as per coding guidelines, we gotta use camelcase for variable names. let's swap this over to knownunderlyingproviders to keep things super chill and consistent. meow 🐱

🐾 proposed fix
-const KNOWN_UNDERLYING_PROVIDERS = new Set([
+const knownUnderlyingProviders = new Set([
   "fal",
   "together",
   "rendi",
   "groq",
   "elevenlabs",
   "higgsfield",
   "piapi",
   "heygen",
   "replicate",
 ]);
 
 let warnedFlatProviderOptions = false;
 
 function checkVargProviderOptions(
   opts: Record<string, unknown>,
 ): Record<string, unknown> {
   const keys = Object.keys(opts);
   const hasProviderKey = keys.some(
     (k) =>
-      KNOWN_UNDERLYING_PROVIDERS.has(k) &&
+      knownUnderlyingProviders.has(k) &&
       typeof opts[k] === "object" &&
       opts[k] !== null,
   );
📝 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 knownUnderlyingProviders = new Set([
  "fal",
  "together",
  "rendi",
  "groq",
  "elevenlabs",
  "higgsfield",
  "piapi",
  "heygen",
  "replicate",
]);

let warnedFlatProviderOptions = false;

function checkVargProviderOptions(
  opts: Record<string, unknown>,
): Record<string, unknown> {
  const keys = Object.keys(opts);
  const hasProviderKey = keys.some(
    (k) =>
      knownUnderlyingProviders.has(k) &&
      typeof opts[k] === "object" &&
      opts[k] !== null,
  );
🤖 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/ai-sdk/providers/varg.ts` around lines 81 - 104, Rename the
KNOWN_UNDERLYING_PROVIDERS constant to knownunderlyingproviders and update its
reference within checkVargProviderOptions, preserving the existing
provider-option detection behavior.

Source: Coding guidelines

src/react/renderers/captions.ts (1)

236-289: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

temp filenames only use Date.now() — collision risk under parallel render

both srt writes here (lines 236-237 and 287-288), and assPath up at line 157, key the temp path purely on Date.now(). clips render in parallel (default concurrency 3), so two captions in the same millisecond write to the same /tmp/varg-captions-<ts>.srt and clobber each other → wrong captions burned in. extract.ts already dodges this with a Date.now()+random suffix — do the same here.

proposed fix
-  const srtPath = `/tmp/varg-captions-${Date.now()}.srt`;
+  const srtPath = `/tmp/varg-captions-${Date.now()}-${Math.random().toString(36).slice(2)}.srt`;

(apply to both srt writes + the assPath at line 157)

🤖 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/react/renderers/captions.ts` around lines 236 - 289, Update the temporary
filename generation for both SRT writes and the assPath construction in the
caption rendering flow to append a per-file random suffix alongside Date.now().
Follow the existing Date.now()+random approach used by extract.ts so parallel
renders cannot share or overwrite temporary paths, while preserving the existing
extensions and tempFiles tracking.
src/react/renderers/context-builder.ts (1)

139-181: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n 'placeholderCount' -C3 src/react

Repository: vargHQ/sdk

Length of output: 2886


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== outlines =='
ast-grep outline src/react/renderers/context-builder.ts --view expanded | sed -n '1,220p'
echo
ast-grep outline src/react/renderers/render.ts --view expanded | sed -n '1,220p'
echo
rg -n 'withCache|cacheKey|skipCacheWrite|placeholderFallbackMiddleware|imagePlaceholderFallbackMiddleware|trackPlaceholder|placeholderCount' src/react -C 2

Repository: vargHQ/sdk

Length of output: 23700


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for path in [
    Path("src/react/renderers/context-builder.ts"),
    Path("src/react/renderers/render.ts"),
]:
    print(f"\n== {path} ==")
    text = path.read_text().splitlines()
    for i, line in enumerate(text, 1):
        if any(k in line for k in ["withCache", "cacheKey", "skipCacheWrite", "placeholderFallbackMiddleware", "imagePlaceholderFallbackMiddleware", "trackPlaceholder", "placeholderCount"]):
            start = max(1, i-6)
            end = min(len(text), i+8)
            for j in range(start, end + 1):
                print(f"{j:4}: {text[j-1]}")
            print()
PY

Repository: vargHQ/sdk

Length of output: 12521


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n 'function withCache|const withCache|withCache\(' src -C 3

Repository: vargHQ/sdk

Length of output: 14514


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' src/ai-sdk/cache.ts | cat -n

Repository: vargHQ/sdk

Length of output: 5256


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' src/ai-sdk/cache.ts | cat -n

Repository: vargHQ/sdk

Length of output: 5256


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
text = Path("src/ai-sdk/cache.ts").read_text().splitlines()
for i, line in enumerate(text, 1):
    if 1 <= i <= 220:
        print(f"{i:4}: {line}")
PY

Repository: vargHQ/sdk

Length of output: 5110


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' src/ai-sdk/middleware.ts | cat -n

Repository: vargHQ/sdk

Length of output: 216


preview placeholder count overcounts cache hits
trackPlaceholder(...) runs before cachedGenerateImage / cachedGenerateVideo, and withCache(...) returns cached entries without calling the fallback path. in preview mode, a cache hit still bumps placeholderCount, so the preview mode: n placeholders used banner can be wrong, meow.

🤖 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/react/renderers/context-builder.ts` around lines 139 - 181, Move preview
placeholder tracking in wrapGenerateImage and wrapGenerateVideo so
trackPlaceholder runs only when the cached generation actually uses the
placeholder fallback, not before cachedGenerateImage or cachedGenerateVideo can
return a cache hit. Preserve the existing preview middleware behavior and ensure
cache hits do not increment placeholderCount.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant