Skip to content

feat(media): keep AI-enhanced prompts inside the render backend's character cap - #6354

Merged
atomantic merged 1 commit into
mainfrom
cos/task-mtp4tv6f/agent-ac64261f
Sep 6, 2026
Merged

feat(media): keep AI-enhanced prompts inside the render backend's character cap#6354
atomantic merged 1 commit into
mainfrom
cos/task-mtp4tv6f/agent-ac64261f

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

reactor.inc's fast-h3 rejects a prompt over 800 characters outright rather than truncating it. The VideoGen form already counted characters and gated Generate on that cap — but the two AI paths that write into the prompt field did not know about it, so "Enhance with AI" reliably produced a richer prompt the renderer then refused.

Both AI paths now receive the backend's budget:

  • Enhance with AI (POST /api/media-jobs/refine-prompt) — new optional maxPromptLength
  • Prompt from media (POST /api/media-jobs/prompt-from-media) — new optional maxVideoPromptLength

Each states the limit in the LLM prompt as a hard constraint ("AT MOST N characters … the renderer REJECTS a longer prompt outright rather than trimming it"), then clamps the answer if the model overshoots anyway. The clamp is reported (truncated / videoPromptTruncated), not silent — the UI toasts "trimmed to fit the N character render limit" so it doesn't read as the AI losing detail on its own.

The budget is the cap minus the style-preset prefix. Style presets prepend to what PortOS actually submits, so enhancing to exactly 800 characters would still be rejected once the preset is applied. VideoGen derives the budget from the same submitted-length calculation that drives the character counter.

New shared helper

clampToCharLimit(text, max) in server/lib/textUtils.js{ text, truncated }. It cuts at the last sentence end when one sits 60%+ into the allowance, else at the last word boundary — a mid-word cut in a render prompt can change what the final phrase asks for. Deliberately distinct from the two existing capping helpers (clampText, truncateForTelegram), which append a marker: a marker would count against the same renderer cap.

Backends with no cap pass nothing and behave exactly as before (ImageGen, local video models, grok, fal).

Test plan

  • server/lib/textUtils.test.js — pass-through (no cap / already fits / non-string), sentence-end cut, word-boundary fallback
  • server/services/mediaPromptRefiner.test.js — the cap reaches the LLM prompt; an over-length answer is clamped and reported; a within-limit answer is untouched; no cap ⇒ no length rule
  • server/services/mediaPromptFromMedia.test.js — cap stated only when the caller has one; over-length videoPrompt clamped while imagePrompt is untouched
  • client/src/components/media/PromptEnhancer.test.jsx — forwards the cap, warns on a trimmed result, shows the budget hint
  • client/src/pages/VideoGen.reactor.test.jsx — enhancer budget is undefined off the reactor lane, 800 on it, and 785 once a 15-character style prefix is applied

Full suites green: server 2004 files / 39,881 tests, client 867 files / 10,564 tests.

…racter cap

reactor.inc's fast-h3 rejects a prompt over 800 characters outright rather
than truncating it, so "Enhance with AI" reliably produced a richer prompt
the render then refused — and the same for "Prompt from media", which writes
into the same field.

Both AI paths now receive the backend's budget, state it in the LLM prompt as
a hard limit, and clamp the answer on a sentence or word boundary if the model
overshoots anyway. The clamp is reported rather than silent, so a trimmed
prompt reads as "trimmed to fit the render limit" instead of the AI losing
detail on its own.

The budget VideoGen sends is the cap MINUS the style-preset prefix, since that
prefix is part of what PortOS submits — enhancing to exactly 800 characters
would still be rejected once the preset is prepended.

Adds clampToCharLimit() to server/lib/textUtils.js: unlike the existing
marker-appending helpers (clampText, truncateForTelegram), it appends nothing,
because a marker would count against the same renderer cap.
@atomantic
atomantic merged commit dae1348 into main Sep 6, 2026
7 checks passed
@atomantic
atomantic deleted the cos/task-mtp4tv6f/agent-ac64261f branch September 6, 2026 01:49
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