Skip to content

fix: default caption length to none#433

Merged
sweetmantech merged 2 commits intotestfrom
feature/caption-default-none
Apr 14, 2026
Merged

fix: default caption length to none#433
sweetmantech merged 2 commits intotestfrom
feature/caption-default-none

Conversation

@recoup-coding-agent
Copy link
Copy Markdown
Collaborator

@recoup-coding-agent recoup-coding-agent commented Apr 13, 2026

Summary

  • Adds "none" to CAPTION_LENGTHS enum across API and changes default from "short" to "none"
  • Updates the Slack bot prompt parsing agent to only set captions when explicitly requested
  • Updates all validation schemas (createContentBody, createCaptionBody) and trigger payload types
  • Updates all affected tests to reflect new defaults

Test plan

  • All 1893 API tests pass (8 pre-existing failures unrelated to this change)
  • Verify in Slack: sending a prompt without caption request produces a video with no captions
  • Verify in Slack: sending "make a video with a short caption" still produces captions
  • Verify via API: POST /api/content/create without caption_length defaults to "none"

🤖 Generated with Claude Code


Summary by cubic

Default caption length is now "none" so videos render without captions unless requested. The caption endpoint only runs when captions are requested and defaults to "short" there.

  • Bug Fixes

    • Added "none" to CAPTION_LENGTHS; createContentBody defaults to none; TriggerCreateContentPayload accepts "none".
    • /content/caption now uses local GENERATED_CAPTION_LENGTHS (short|medium|long) with default "short" and rejects "none".
    • Slack prompt agent defaults to none and only sets captions when requested; refined prompt description, applied CaptionLength type, and removed redundant fallback; tests updated.
  • Migration

    • API: Omitting caption_length yields no captions. Send "short" | "medium" | "long" to opt in.
    • Slack: Say "with captions" or "short caption" to add captions; say "no captions" (or say nothing) to keep none.

Written for commit 771d8ed. Summary will update on new commits.

Summary by CodeRabbit

  • Changes
    • Updated default caption behavior: content now defaults to no captions when caption preference is not specified. Users can explicitly request short, medium, or long captions as needed.

…ly requested

Captions were always generated with a default of "short", even when not requested
or explicitly asked for "no captions". Now defaults to "none" across the full pipeline:
API validation, Slack bot prompt parsing, and Trigger.dev task schema. When "none",
caption generation is skipped entirely and the video renders without text overlay.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
recoup-api Ready Ready Preview Apr 14, 2026 6:55pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Warning

Rate limit exceeded

@sweetmantech has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 40 minutes and 59 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 40 minutes and 59 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b5b7db94-9f1c-4f69-91b7-4a05c529e294

📥 Commits

Reviewing files that changed from the base of the PR and between 648f634 and 771d8ed.

⛔ Files ignored due to path filters (1)
  • lib/content/__tests__/schemas.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (3)
  • lib/agents/content/createContentPromptAgent.ts
  • lib/content/caption/validateCreateCaptionBody.ts
  • lib/content/validateCreateContentBody.ts
📝 Walkthrough

Walkthrough

A coordinated update across five files introduces "none" as a caption length option and shifts the default from "short" to "none". Changes propagate through type definitions, validation schemas, and API payloads to consistently handle caption-free content requests.

Changes

Cohort / File(s) Summary
Caption Type Definition
lib/content/captionLengths.ts
Expands CAPTION_LENGTHS array to include "none" as first element, updating the CaptionLength union type to `"none"
Validation & Schema Layer
lib/content/caption/validateCreateCaptionBody.ts, lib/content/validateCreateContentBody.ts, lib/agents/content/createContentPromptAgent.ts
Updates Zod schema defaults and validation logic to use "none" instead of "short" when caption length is omitted; aligns validation descriptions with "no captions" as baseline behavior.
API Payload Type
lib/trigger/triggerCreateContent.ts
Extends TriggerCreateContentPayload.captionLength type union to include "none"; updates JSDoc to clarify that "none" skips caption generation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested reviewers

  • sweetmantech

Poem

🎬 Silent captions take the stage,
"none" inscribed on every page,
From schema to the payload's heart,
A quieter, cleaner work of art. ✨

🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Solid & Clean Code ⚠️ Warning Pull request violates DRY and KISS principles through hardcoded union types and missing guard clause for unnecessary LLM operations. Import CaptionLength type in validateCreateContentBody.ts and triggerCreateContent.ts; add early-exit guard in createTextHandler.ts for 'none' case.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/caption-default-none

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
lib/content/validateCreateContentBody.ts (1)

94-94: Redundant nullish coalescing—Zod's .default("none") already handles this.

Since the schema on line 19 has .optional().default("none"), result.data.caption_length will always be defined after parsing. The ?? "none" fallback is unreachable and adds noise.

♻️ Suggested fix
-    captionLength: result.data.caption_length ?? "none",
+    captionLength: result.data.caption_length,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/content/validateCreateContentBody.ts` at line 94, In
validateCreateContentBody, remove the redundant nullish coalescing on
captionLength: the schema's .default("none") ensures result.data.caption_length
is always defined, so replace the expression using result.data.caption_length ??
"none" with just result.data.caption_length (refer to the mapping that sets
captionLength and the parsed result variable `result.data.caption_length` in the
validateCreateContentBody logic).
lib/trigger/triggerCreateContent.ts (1)

9-10: Consider using CaptionLength type for consistency across the codebase.

Similar to the suggestion for validateCreateContentBody.ts, the hardcoded union could be replaced with the CaptionLength type. However, for cross-boundary contracts like Trigger.dev payloads, explicit typing can aid readability—so this is purely optional.

♻️ Optional refactor
+import { CaptionLength } from "@/lib/content/captionLengths";
+
 export interface TriggerCreateContentPayload {
   accountId: string;
   artistSlug: string;
   template?: string;
   lipsync: boolean;
-  /** Controls caption length: "none" skips captions, "short", "medium", or "long". */
-  captionLength: "none" | "short" | "medium" | "long";
+  /** Controls caption length: "none" skips captions, "short", "medium", or "long". */
+  captionLength: CaptionLength;
   /** Whether to upscale image and video for higher quality. */
   upscale: boolean;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/trigger/triggerCreateContent.ts` around lines 9 - 10, Replace the
hardcoded union type on the captionLength property with the shared CaptionLength
type to ensure consistency: import CaptionLength into the module (if not
already) and change the property declaration from captionLength: "none" |
"short" | "medium" | "long"; to use captionLength: CaptionLength; and run type
checks to confirm no other files rely on the explicit union; keep the property
name captionLength to locate it easily.
lib/content/caption/validateCreateCaptionBody.ts (1)

22-24: Minor: JSDoc @param annotation could include type/description.

The @param request annotation is sparse. Consider adding a brief description or removing it entirely if the type signature is self-documenting.

 /**
  * Validates auth and request body for POST /api/content/caption.
- *
- * `@param` request
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/content/caption/validateCreateCaptionBody.ts` around lines 22 - 24,
Update the JSDoc for the validateCreateCaptionBody function to either remove the
bare "@param request" line or expand it with a short type/description (e.g.,
"@param request CreateCaptionRequest - payload for creating a caption, including
fields X, Y") so the parameter is self-documenting; adjust the comment block
above validateCreateCaptionBody to consistently describe the expected
shape/fields of the request parameter.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/content/caption/validateCreateCaptionBody.ts`:
- Line 13: The handler createTextHandler should skip caption generation when the
validated input length is "none"; add a guard at the start of createTextHandler
that checks if validated.length === "none" and immediately returns the same JSON
response shape currently expected (e.g., content: "", font: null, color:
"white", borderColor: "black", maxFontSize: 42) via NextResponse.json with
getCorsHeaders(), instead of calling composeCaptionPrompt and generateText; this
avoids invoking composeCaptionPrompt and generateText when length === "none".

In `@lib/content/validateCreateContentBody.ts`:
- Line 32: Replace the hardcoded union type for the captionLength property with
the existing exported type from captionLengths.ts: import and use CaptionLength
(or the exact exported symbol) in the validateCreateContentBody type definition
so the property reads captionLength: CaptionLength instead of "none" | "short" |
"medium" | "long"; update any related imports/exports so the
validateCreateContentBody module references the centralized CaptionLength type
to keep types DRY.

---

Nitpick comments:
In `@lib/content/caption/validateCreateCaptionBody.ts`:
- Around line 22-24: Update the JSDoc for the validateCreateCaptionBody function
to either remove the bare "@param request" line or expand it with a short
type/description (e.g., "@param request CreateCaptionRequest - payload for
creating a caption, including fields X, Y") so the parameter is
self-documenting; adjust the comment block above validateCreateCaptionBody to
consistently describe the expected shape/fields of the request parameter.

In `@lib/content/validateCreateContentBody.ts`:
- Line 94: In validateCreateContentBody, remove the redundant nullish coalescing
on captionLength: the schema's .default("none") ensures
result.data.caption_length is always defined, so replace the expression using
result.data.caption_length ?? "none" with just result.data.caption_length (refer
to the mapping that sets captionLength and the parsed result variable
`result.data.caption_length` in the validateCreateContentBody logic).

In `@lib/trigger/triggerCreateContent.ts`:
- Around line 9-10: Replace the hardcoded union type on the captionLength
property with the shared CaptionLength type to ensure consistency: import
CaptionLength into the module (if not already) and change the property
declaration from captionLength: "none" | "short" | "medium" | "long"; to use
captionLength: CaptionLength; and run type checks to confirm no other files rely
on the explicit union; keep the property name captionLength to locate it easily.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8d03a9e2-8235-4894-8cd5-27c49594c16b

📥 Commits

Reviewing files that changed from the base of the PR and between 8562fa9 and 648f634.

⛔ Files ignored due to path filters (4)
  • lib/agents/content/__tests__/parseContentPrompt.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/content/__tests__/captionLengths.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/content/__tests__/schemas.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
  • lib/content/__tests__/validateCreateContentBody.test.ts is excluded by !**/*.test.*, !**/__tests__/** and included by lib/**
📒 Files selected for processing (5)
  • lib/agents/content/createContentPromptAgent.ts
  • lib/content/caption/validateCreateCaptionBody.ts
  • lib/content/captionLengths.ts
  • lib/content/validateCreateContentBody.ts
  • lib/trigger/triggerCreateContent.ts

template: z.enum(TEMPLATE_IDS).optional(),
topic: z.string().min(1),
length: z.enum(CAPTION_LENGTHS).optional().default("short"),
length: z.enum(CAPTION_LENGTHS).optional().default("none"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if createTextHandler has any guards for length === "none"

ast-grep --pattern $'async function createTextHandler($_) {
  $$$
}'

# Also check for any conditional logic around length/captionLength
rg -n --type=ts -C3 'length.*none|none.*length' lib/content/caption/

Repository: recoupable/api

Length of output: 682


🏁 Script executed:

# Find where createTextHandler is defined
rg -n "createTextHandler" --type=ts --type=tsx

# Also search for composeCaptionPrompt to understand the flow
rg -n "composeCaptionPrompt" --type=ts --type=tsx

Repository: recoupable/api

Length of output: 113


🏁 Script executed:

# Search for createTextHandler and composeCaptionPrompt without type flags
rg "createTextHandler" -n -A 5 -B 1 lib/

# Search for composeCaptionPrompt
rg "composeCaptionPrompt" -n -A 3 -B 1 lib/

Repository: recoupable/api

Length of output: 2018


🏁 Script executed:

# Get the full createTextHandler.ts file
cat lib/content/caption/createTextHandler.ts

# Find CAPTION_LENGTHS definition
rg "CAPTION_LENGTHS" -n -B 2 -A 5 lib/

Repository: recoupable/api

Length of output: 6878


Add a guard in createTextHandler to skip caption generation when length === "none".

Based on the codebase, "none" is explicitly defined as "no captions" (see createContentPromptAgent.ts line 27). However, createTextHandler.ts (lines 22–23) unconditionally calls composeCaptionPrompt and generateText, passing "Length: none" to the LLM.

With the new default of "none", most requests will now incur an unnecessary LLM call. Consider adding a check around line 21:

if (validated.length === "none") {
  return NextResponse.json(
    { content: "", font: null, color: "white", borderColor: "black", maxFontSize: 42 },
    { status: 200, headers: getCorsHeaders() },
  );
}

This prevents wasting tokens and aligns the behavior with the semantic intent of the "none" option.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/content/caption/validateCreateCaptionBody.ts` at line 13, The handler
createTextHandler should skip caption generation when the validated input length
is "none"; add a guard at the start of createTextHandler that checks if
validated.length === "none" and immediately returns the same JSON response shape
currently expected (e.g., content: "", font: null, color: "white", borderColor:
"black", maxFontSize: 42) via NextResponse.json with getCorsHeaders(), instead
of calling composeCaptionPrompt and generateText; this avoids invoking
composeCaptionPrompt and generateText when length === "none".

Comment thread lib/content/validateCreateContentBody.ts Outdated
.enum(CAPTION_LENGTHS)
.describe(
"Caption length: 'short' (default), 'medium', or 'long'. Extract from phrases like 'long caption', 'detailed text', 'brief caption'.",
"Caption length: 'none' (default — no captions), 'short', 'medium', or 'long'. Only set to short/medium/long when the user explicitly requests captions. Extract from phrases like 'add a caption', 'with captions', 'long caption', 'detailed text'. If no captions are mentioned or the user says 'no captions', use 'none'.",
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.

Suggested change
"Caption length: 'none' (default — no captions), 'short', 'medium', or 'long'. Only set to short/medium/long when the user explicitly requests captions. Extract from phrases like 'add a caption', 'with captions', 'long caption', 'detailed text'. If no captions are mentioned or the user says 'no captions', use 'none'.",
"Caption length: 'none' (default — no captions), 'short', 'medium', or 'long'. Only set to short/medium/long when captions are explicitly requested. Extract from phrases like 'add a caption', 'with captions', 'long caption', 'detailed text'. If no captions are mentioned or 'no captions', use 'none'.",

sweetmantech added a commit to recoupable/docs that referenced this pull request Apr 13, 2026
Reflects API change in recoupable/api#433 — caption length now defaults
to "none" (skip caption generation) instead of "short". Adds "none" to
the enum for both POST /api/content/create (caption_length) and the
caption endpoint (length).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files

Confidence score: 3/5

  • There is a concrete regression risk: lib/content/caption/validateCreateCaptionBody.ts now defaults length to "none", but downstream handling does not appear to support that value.
  • In createTextHandler.ts, the flow still unconditionally calls composeCaptionPrompt and generateText, so requests can send "Length: none" to the LLM and produce user-facing caption quality/behavior issues.
  • Given the high-severity/high-confidence mismatch between validation defaults and generation logic, this is moderate merge risk rather than a hard block if a follow-up fix is immediate.
  • Pay close attention to lib/content/caption/validateCreateCaptionBody.ts and createTextHandler.ts - default/value contract mismatch for length can leak unsupported prompt input.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/content/caption/validateCreateCaptionBody.ts">

<violation number="1" location="lib/content/caption/validateCreateCaptionBody.ts:13">
P1: The default `length` is now `"none"`, but `createTextHandler.ts` has no guard for this value — it unconditionally calls `composeCaptionPrompt` and `generateText`, passing `"Length: none"` to the LLM. This means most caption requests will still incur an LLM call and may return non-empty caption text even though the intent is "no captions". Add an early return in `createTextHandler` when `length === "none"` to skip the LLM call entirely.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant User as User (Slack/API)
    participant Agent as Prompt Parsing Agent
    participant Validator as Request Validator
    participant Trigger as Trigger.dev (Worker)
    participant Gen as Content Generator

    Note over User,Gen: Content Creation Flow (Updated Defaults)

    alt Interaction via Slack
        User->>Agent: "Create a video about coffee"
        Agent->>Agent: Parse natural language
        Note right of Agent: NEW: If no caption specified,<br/>defaults to "none"
        Agent-->>User: Confirming (captionLength: "none")
    else Interaction via API
        User->>Validator: POST /api/content/create {}
        Validator->>Validator: Apply Zod Schema
        Note right of Validator: CHANGED: Omitted field<br/>now defaults to "none"
    end

    Validator->>Trigger: triggerCreateContent(payload)
    Note over Validator,Trigger: payload.captionLength = "none"

    Trigger->>Gen: Execute Task
    
    alt captionLength is "none"
        Gen->>Gen: NEW: Skip caption generation
        Gen->>Gen: Process Video + Audio only
    else captionLength is "short" | "medium" | "long"
        Gen->>Gen: Generate Script
        Gen->>Gen: Generate Captions
        Gen->>Gen: Overlay Captions on Video
    end

    Gen-->>User: Content Ready (No captions by default)
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread lib/content/caption/validateCreateCaptionBody.ts Outdated
sweetmantech added a commit to recoupable/docs that referenced this pull request Apr 14, 2026
* docs: add "none" to caption length enum and update default

Reflects API change in recoupable/api#433 — caption length now defaults
to "none" (skip caption generation) instead of "short". Adds "none" to
the enum for both POST /api/content/create (caption_length) and the
caption endpoint (length).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: revert "none" from /content/caption length enum

The /content/caption endpoint should only be called when captions are
wanted — the orchestrator decides whether to invoke it. Keep "none" only
on /content/create (caption_length).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove "none" from /content/caption length enum; default to "short".
  The caption endpoint is only invoked when a caption is wanted — "none"
  is a create-time opt-out, not a generation mode. Adds a local
  GENERATED_CAPTION_LENGTHS narrower than CAPTION_LENGTHS. (cubic P1 +
  coderabbit Major)
- Use CaptionLength type on ValidatedCreateContentBody instead of
  hardcoded union (coderabbit DRY nit).
- Drop redundant `?? "none"` fallback — Zod default already applies
  (coderabbit nit).
- Refine captionLength prompt description per reviewer suggestion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/content/caption/validateCreateCaptionBody.ts">

<violation number="1" location="lib/content/caption/validateCreateCaptionBody.ts:19">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**

The PR description claims that `createCaptionBody` was updated to accept `"none"` and default to `"none"`. However, this line does the exact opposite: it rejects `"none"` (via `GENERATED_CAPTION_LENGTHS`) and changes the default from `"none"` to `"short"`.

Please update the PR description to accurately reflect that the caption generation endpoint intentionally rejects `"none"`, or update this code if the PR description's stated goal is correct.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread lib/content/caption/validateCreateCaptionBody.ts
@sweetmantech sweetmantech merged commit b9341e3 into test Apr 14, 2026
5 of 6 checks passed
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.

2 participants