Skip to content

fix: genera el video queues the prepared Studio form - #46

Merged
IAnMove merged 3 commits into
mainfrom
fix/wizard-resume-prepared-studio-video
Sep 1, 2026
Merged

fix: genera el video queues the prepared Studio form#46
IAnMove merged 3 commits into
mainfrom
fix/wizard-resume-prepared-studio-video

Conversation

@IAnMove

@IAnMove IAnMove commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Qué

Arregla el caso Sheldon: tras prepare_video, «genera el video» preguntaba el tema y solo abría Studio.

  • «hazme un video» sin tema sigue preguntando (bare create).
  • «genera el video» / «lanza el vídeo» reutiliza el prompt ya relleno y emite prepare_video + start_generation en el mismo turno (el runner no acepta start suelto).
  • Si Studio no tiene prompt, pide la escena.

No toca slices. Independiente de #42#45.

Verificación

agentActions.test.mjs 52 pass, incluido el caso Sheldon.

Dueño del merge: humano. No auto-merge.


Note

Low Risk
Localized agent intent reconciliation and tests only; no queue, auth, or persistence changes beyond reusing existing Studio store fields.

Overview
Fixes the post-prepare_video loop where «genera el video» made the agent ask for a topic instead of enqueueing the form already filled in Studio.

Adds isResumePreparedStudioVideoRequest to recognize narrow “launch/queue the video” phrasing (ES/EN) with no new subject after the noun. reconcileAgentTurnWithRequest handles that before example/topical video repair: it pulls the prompt from an existing prepare_video action or from Studio state (params.prompt / savedPromptPerMode.video), returns prepare_video + start_generation (confirm: true) when a prompt exists, or open_tab → studio when it does not. modelType is not copied from the current form so image/audio/3D/I2V selections are not forced onto T2V.

Bare «hazme un video» and requests with extra topic (e.g. «genera el video de un mapache») are unchanged. Tests cover the Sheldon case, topical override, and incompatible models.

Reviewed by Cursor Bugbot for commit 37bb43b. Configure here.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

PR Review — Loreframe Studio

Risk: low
Scope: 2 file(s); +129/-0; React UI

Automated review from scripts/analyze_pr.py. This is a heuristic pass (no LLM) so humans still own the merge decision.

Findings

  • low — UI changed — rebuild before merge
    Run cd ui && npm run build (CI already does this). Pinokio Update rebuilds for end users; keep ui/dist untracked.

Changed files

  • modified: ui/src/features/agent/agentActions.ts, ui/tests/agentActions.test.mjs

CONTRIBUTING checklist

  • python scripts/verify_clean_repo.py
  • python -m compileall -q app/services app/launch.py scripts
  • cd ui && npm run build if the UI changed
  • No weights, CivitAI sidecars, or generated guides
  • Stays local-first (no required accounts / telemetry)

Posted by the repo PR review workflow. Re-runs on each push to the PR.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Resume matcher captures topical requests
    • isResumePreparedStudioVideoRequest now requires leftover text after the article-plus-video command to be empty, so topical and example phrasing fall through to maybeExampleTurn and isExplicitVideoGenerationRequest.
  • ✅ Fixed: Resume copies incompatible current model
    • The store-built resume action omits modelType so prepareVideo can pick a T2V model, and it reads savedPromptPerMode.video after leaving Video instead of the active mode prompt.

Create PR

Or push these changes by commenting:

@cursor push f01673620c
Preview (f01673620c)
diff --git a/ui/src/features/agent/agentActions.ts b/ui/src/features/agent/agentActions.ts
--- a/ui/src/features/agent/agentActions.ts
+++ b/ui/src/features/agent/agentActions.ts
@@ -1697,14 +1697,21 @@
   return EXPLICIT_VIDEO_REQUESTS.some(pattern => pattern.test(text))
 }
 
-const RESUME_PREPARED_VIDEO_REQUESTS = [
-  /\b(?:genera|generad|lanza|lanzad|encola|encolad|env[ií]a|enviad|start|queue|launch)\b[^.!?\n]{0,24}\b(?:el|la|este|esta|the)\s+(?:video|v[ií]deo|clip)\b/i,
-]
-
 export function isResumePreparedStudioVideoRequest(request: string): boolean {
   const text = request.trim()
   if (!text || NEGATED_VIDEO_REQUEST.test(text)) return false
-  return RESUME_PREPARED_VIDEO_REQUESTS.some(pattern => pattern.test(text))
+  const match = text.match(
+    /\b(?:genera|generad|lanza|lanzad|encola|encolad|env[ií]a|enviad|start|queue|launch)\b[^.!?\n]{0,24}\b(?:el|la|este|esta|the)\s+(?:video|v[ií]deo|clip)\b(.*)$/i,
+  )
+  if (!match) return false
+  const leftover = match[1]
+    .toLowerCase()
+    .normalize('NFD')
+    .replace(/[\u0300-\u036f]/g, '')
+    .replace(/[¿?¡!.,:;]/g, ' ')
+    .replace(/\b(?:por favor|please|ya|ahora|now)\b/g, ' ')
+    .replace(/\s+/g, '')
+  return leftover.length === 0
 }
 
 const EXPLICIT_IMAGE_REQUESTS = [
@@ -1858,7 +1865,10 @@
       (action): action is AgentPrepareVideoAction => action.type === 'prepare_video',
     )
     const state = useStore.getState()
-    const prompt = existing?.prompt.trim() || String(state.params.prompt || '').trim()
+    const studioPrompt = state.generationMode === 'video'
+      ? String(state.params.prompt || '').trim()
+      : String(state.savedPromptPerMode?.video || '').trim()
+    const prompt = existing?.prompt.trim() || studioPrompt
     if (!prompt) {
       return {
         reply: 'Studio no tiene un prompt preparado. Dime la escena y la encolo.',
@@ -1868,10 +1878,9 @@
     const prepare: AgentPrepareVideoAction = existing || {
       type: 'prepare_video',
       prompt,
-      modelType: typeof state.params.model_type === 'string' ? state.params.model_type : undefined,
-      durationSeconds: state.durationSeconds,
-      resolutionPreset: state.resolutionPreset,
-      aspectRatio: state.aspectRatio,
+      durationSeconds: state.generationMode === 'video' ? state.durationSeconds : undefined,
+      resolutionPreset: state.generationMode === 'video' ? state.resolutionPreset : undefined,
+      aspectRatio: state.generationMode === 'video' ? state.aspectRatio : undefined,
     }
     return {
       reply: 'Lanzo a la cola el vídeo ya preparado en Studio. 🪄',

diff --git a/ui/tests/agentActions.test.mjs b/ui/tests/agentActions.test.mjs
--- a/ui/tests/agentActions.test.mjs
+++ b/ui/tests/agentActions.test.mjs
@@ -1332,17 +1332,51 @@
 test('genera el video reuses a prepared Studio prompt instead of asking for a topic', async () => {
   const { useStore } = await import('../src/stores/useStore.ts')
   const { reconcileAgentTurnWithRequest } = await import('../src/features/agent/agentActions.ts')
+  const original = {
+    generationMode: useStore.getState().generationMode,
+    params: useStore.getState().params,
+    durationSeconds: useStore.getState().durationSeconds,
+    savedPromptPerMode: useStore.getState().savedPromptPerMode,
+  }
   useStore.setState({
+    generationMode: 'video',
     params: { ...useStore.getState().params, prompt: 'Sheldon Cooper cuenta un chiste en su salón, bata verde, Bazinga.' },
     durationSeconds: 5.2,
   })
   const resumed = await reconcileAgentTurnWithRequest('genera el video', { reply: '¿De qué?', actions: [] })
   assert.deepEqual(resumed.actions.map(action => action.type), ['prepare_video', 'start_generation'])
   assert.equal(resumed.actions[0].prompt.includes('Sheldon'), true)
+  assert.equal(resumed.actions[0].modelType, undefined)
   assert.equal(resumed.actions[1].confirm, true)
 
-  useStore.setState({ params: { ...useStore.getState().params, prompt: '' } })
+  const topical = await reconcileAgentTurnWithRequest('genera el video de un mapache', { reply: '¿De qué?', actions: [] })
+  assert.deepEqual(topical.actions.map(action => action.type), ['prepare_video', 'start_generation'])
+  assert.ok(topical.actions[0].prompt.includes('mapache'))
+  assert.equal(topical.actions[0].prompt.includes('Sheldon'), false)
+
+  const example = await reconcileAgentTurnWithRequest('genera el video de ejemplo', { reply: '¿De qué?', actions: [] })
+  assert.deepEqual(example.actions.map(action => action.type), ['prepare_video', 'start_generation'])
+  assert.ok(example.actions[0].prompt.length > 40)
+  assert.equal(example.actions[0].prompt.includes('genera el video'), false)
+  assert.equal(example.actions[0].prompt.includes('Sheldon'), false)
+
+  useStore.setState({
+    generationMode: 'image',
+    params: { ...useStore.getState().params, model_type: 'image-only-model', prompt: 'un retrato de estudio' },
+    savedPromptPerMode: { ...useStore.getState().savedPromptPerMode, video: 'Sheldon Cooper cuenta un chiste en su salón, bata verde, Bazinga.' },
+  })
+  const afterModeSwitch = await reconcileAgentTurnWithRequest('genera el video', { reply: '¿De qué?', actions: [] })
+  assert.deepEqual(afterModeSwitch.actions.map(action => action.type), ['prepare_video', 'start_generation'])
+  assert.equal(afterModeSwitch.actions[0].prompt.includes('Sheldon'), true)
+  assert.equal(afterModeSwitch.actions[0].modelType, undefined)
+
+  useStore.setState({
+    generationMode: 'video',
+    params: { ...useStore.getState().params, prompt: '' },
+    savedPromptPerMode: { ...useStore.getState().savedPromptPerMode, video: '' },
+  })
   const asked = await reconcileAgentTurnWithRequest('genera el video', { reply: '¿De qué?', actions: [] })
   assert.equal(asked.actions[0].type, 'open_tab')
   assert.equal(asked.actions.some(action => action.type === 'start_generation'), false)
+  useStore.setState(original)
 })

You can send follow-ups to the cloud agent here.

Comment thread ui/src/features/agent/agentActions.ts
Comment thread ui/src/features/agent/agentActions.ts
@IAnMove

IAnMove commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2a9c53f. Configure here.

IAnMove and others added 3 commits September 1, 2026 14:34
Bare “hazme un video” still asks for a topic. “genera el video”
reuses the current Studio prompt and emits prepare+start in the
same turn so the runner will actually enqueue.
Bare "genera el video" still queues the prepared form, but leftover
subject text now falls through to example/topical generation. Resume
also omits the current model id and reads the saved Video prompt after
a mode switch so I2V or Image leftovers do not fail prepareVideo.
Cherry-pick Cursor Autofix, then split the tests: resume the prepared
form, use a new topic when one is named, and never copy an I2V/audio/3D
model as T2V.
@IAnMove
IAnMove force-pushed the fix/wizard-resume-prepared-studio-video branch from 2a9c53f to 37bb43b Compare September 1, 2026 12:37
@IAnMove

IAnMove commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 37bb43b. Configure here.

@IAnMove
IAnMove merged commit abeb46b into main Sep 1, 2026
5 checks passed
@IAnMove
IAnMove deleted the fix/wizard-resume-prepared-studio-video branch September 5, 2026 11:54
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