feat: previousJobId and previousImage for follow-up media edits#927
feat: previousJobId and previousImage for follow-up media edits#927jherr wants to merge 8 commits into
Conversation
Unify video follow-up edits behind previousJobId (adapters resolve job vs media), and add previousImage sugar for image edits, with docs and e2e coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
🚀 Changeset Version Preview19 package(s) bumped directly, 26 bumped as dependents. 🟥 Major bumps
🟨 Minor bumps
🟩 Patch bumps
|
|
View your CI Pipeline Execution ↗ for commit 49e9d02
☁️ Nx Cloud last updated this comment at |
📝 WalkthroughWalkthroughAdds first-class follow-up editing for generated images through ChangesMedia editing
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant MediaActivity
participant Adapter
participant ProviderAPI
Client->>MediaActivity: previousImage or previousJobId
MediaActivity->>Adapter: normalize, validate, and forward edit input
Adapter->>ProviderAPI: submit provider-specific edit request
ProviderAPI-->>Adapter: edited media job or result
Adapter-->>MediaActivity: generated media result
MediaActivity-->>Client: edited image or video
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
testing/e2e/global-setup.tsParsing error: "parserOptions.project" has been provided for testing/e2e/tests/image-edit.spec.tsParsing error: "parserOptions.project" has been provided for testing/e2e/tests/video-edit.spec.tsParsing error: "parserOptions.project" has been provided for 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 |
@tanstack/ai
@tanstack/ai-acp
@tanstack/ai-angular
@tanstack/ai-anthropic
@tanstack/ai-bedrock
@tanstack/ai-claude-code
@tanstack/ai-client
@tanstack/ai-code-mode
@tanstack/ai-code-mode-skills
@tanstack/ai-codex
@tanstack/ai-devtools-core
@tanstack/ai-elevenlabs
@tanstack/ai-event-client
@tanstack/ai-fal
@tanstack/ai-gemini
@tanstack/ai-grok
@tanstack/ai-grok-build
@tanstack/ai-groq
@tanstack/ai-isolate-cloudflare
@tanstack/ai-isolate-node
@tanstack/ai-isolate-quickjs
@tanstack/ai-mcp
@tanstack/ai-mistral
@tanstack/ai-ollama
@tanstack/ai-openai
@tanstack/ai-opencode
@tanstack/ai-openrouter
@tanstack/ai-preact
@tanstack/ai-react
@tanstack/ai-react-ui
@tanstack/ai-sandbox
@tanstack/ai-sandbox-cloudflare
@tanstack/ai-sandbox-daytona
@tanstack/ai-sandbox-docker
@tanstack/ai-sandbox-local-process
@tanstack/ai-sandbox-sprites
@tanstack/ai-sandbox-vercel
@tanstack/ai-solid
@tanstack/ai-solid-ui
@tanstack/ai-svelte
@tanstack/ai-utils
@tanstack/ai-vue
@tanstack/ai-vue-ui
@tanstack/openai-base
@tanstack/preact-ai-devtools
@tanstack/react-ai-devtools
@tanstack/solid-ai-devtools
commit: |
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
testing/e2e/src/lib/server-functions.ts (1)
46-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider extracting the
previousImagenormalization into a shared helper.The same url-or-b64Json narrowing logic is duplicated in
api.image.stream.ts(lines 34-39) andapi.image.ts(lines 34-39). If the wire shape orgenerateImage'spreviousImagecontract changes, all three copies need updating in sync.♻️ Optional: shared helper
+// e.g. in media-providers.ts or a new test-utils file +export function normalizePreviousImage( + raw: { url?: string; b64Json?: string } | undefined, +): { url: string } | { b64Json: string } | undefined { + if (raw?.url != null) return { url: raw.url } + if (raw?.b64Json != null) return { b64Json: raw.b64Json } + return undefined +}Then in each call site:
- const previousImage = - data.previousImage?.url != null - ? { url: data.previousImage.url } - : data.previousImage?.b64Json != null - ? { b64Json: data.previousImage.b64Json } - : undefined + const previousImage = normalizePreviousImage(data.previousImage)🤖 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 `@testing/e2e/src/lib/server-functions.ts` around lines 46 - 56, Extract the duplicated previousImage URL-or-b64Json normalization into a shared helper, then replace the inline logic in server-functions.ts, api.image.stream.ts, and api.image.ts with calls to that helper. Preserve the existing undefined behavior and generateImage-compatible shape, and place the helper where all three call sites can import it.
🤖 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 `@docs/media/image-generation.md`:
- Around line 219-239: Extend the image-generation example with a minimal server
endpoint matching the client request, validating the wire-friendly previousImage
shape, narrowing it to a GeneratedImage, and passing it to generateImage.
Reference the route handler and generateImage usage, and show handling for
invalid payloads and both URL and base64 image variants.
In `@docs/media/video-generation.md`:
- Around line 531-536: Update handleEdit to use the hook-provided job identifier
rather than result?.jobId: destructure jobId (or videoStatus.jobId) from the
hook and use it for the guard and as generate’s previousJobId value.
- Around line 520-536: Add the corresponding server endpoint example after the
client snippet, defining a minimal route that validates the incoming prompt and
optional previousJobId, then passes both values to generateVideo. Show the
response returned to the client and ensure the route’s symbols clearly
demonstrate forwarding previousJobId.
In `@examples/ts-react-media/src/components/ImageGenerator.tsx`:
- Around line 362-379: Remove the unnecessary non-null assertions from
modelResult.result in both handleEditImage calls within the success block, while
retaining the images[0]! assertion. Update both the Enter-key handler and button
onClick handler.
In `@packages/ai-fal/src/adapters/video.ts`:
- Around line 237-243: The polling path must use the model submitted for the job
rather than this.model. Update getVideoStatus and getVideoUrl, along with their
callers and job state as needed, to preserve submitModel from the queue
submission and pass it to fal.queue.status and fal.queue.result for edit jobs.
In `@testing/e2e/tests/video-edit.spec.ts`:
- Around line 17-20: Add a runtime guard wherever the video-edit test looks up
EXPECTED_EDITED_SRC by provider, including the assertions around the affected
test cases, and fail clearly if the provider is missing instead of relying on a
non-null assertion. Use the provider value to validate the map entry before
passing it to toHaveAttribute, while preserving the existing expected regex
behavior.
---
Nitpick comments:
In `@testing/e2e/src/lib/server-functions.ts`:
- Around line 46-56: Extract the duplicated previousImage URL-or-b64Json
normalization into a shared helper, then replace the inline logic in
server-functions.ts, api.image.stream.ts, and api.image.ts with calls to that
helper. Preserve the existing undefined behavior and generateImage-compatible
shape, and place the helper where all three call sites can import it.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: ccfc2443-dc3d-4ced-81d9-5cf40ba1e607
📒 Files selected for processing (56)
.agentsroom/.gitignore.agentsroom/agents.json.agentsroom/prompts.json.changeset/media-edit-from.mddocs/config.jsondocs/media/image-generation.mddocs/media/video-generation.mdexamples/ts-react-media/src/components/ImageGenerator.tsxexamples/ts-react-media/src/components/OmniStudio.tsxexamples/ts-react-media/src/components/VideoGenerator.tsxexamples/ts-react-media/src/lib/models.tsexamples/ts-react-media/src/lib/server-functions.tspackages/ai-client/src/generation-types.tspackages/ai-fal/src/adapters/video.tspackages/ai-fal/src/index.tspackages/ai-fal/src/model-meta.tspackages/ai-fal/tests/video-adapter.test.tspackages/ai-gemini/src/adapters/video.tspackages/ai-gemini/src/index.tspackages/ai-gemini/src/video/video-provider-options.tspackages/ai-gemini/tests/video-adapter.test.tspackages/ai-grok/src/adapters/video.tspackages/ai-grok/src/index.tspackages/ai-grok/src/video/video-provider-options.tspackages/ai-grok/tests/video-adapter.test.tspackages/ai-openai/src/adapters/video.tspackages/ai-openai/src/index.tspackages/ai-openai/src/video/video-provider-options.tspackages/ai-openai/tests/video-adapter.test.tspackages/ai/skills/ai-core/media-generation/SKILL.mdpackages/ai/src/activities/generateImage/index.tspackages/ai/src/activities/generateVideo/adapter.tspackages/ai/src/activities/generateVideo/index.tspackages/ai/src/activities/index.tspackages/ai/src/client.tspackages/ai/src/index.tspackages/ai/src/types.tspackages/ai/src/utilities/media-prompt.tspackages/ai/tests/generate-image-previous-image.test.tspackages/ai/tests/generate-video-previous-job-id.test.tspackages/ai/tests/stream-generation.test.tstesting/e2e/global-setup.tstesting/e2e/src/components/ImageGenUI.tsxtesting/e2e/src/components/VideoGenUI.tsxtesting/e2e/src/lib/feature-support.tstesting/e2e/src/lib/features.tstesting/e2e/src/lib/media-providers.tstesting/e2e/src/lib/server-functions.tstesting/e2e/src/lib/types.tstesting/e2e/src/routes/$provider/$feature.tsxtesting/e2e/src/routes/api.image.stream.tstesting/e2e/src/routes/api.image.tstesting/e2e/src/routes/api.video.stream.tstesting/e2e/src/routes/api.video.tstesting/e2e/tests/image-edit.spec.tstesting/e2e/tests/video-edit.spec.ts
| **Client** — the hook's `ImageGenerateInput.previousImage` is a wire-friendly | ||
| `{ url? }` / `{ b64Json? }` shape; your server route should narrow it back | ||
| to a `GeneratedImage` before calling `generateImage`: | ||
|
|
||
| ```tsx | ||
| import { useGenerateImage, fetchServerSentEvents } from '@tanstack/ai-react' | ||
|
|
||
| function ImageEditor() { | ||
| const { generate, result, isLoading } = useGenerateImage({ | ||
| connection: fetchServerSentEvents('/api/generate/image'), | ||
| }) | ||
|
|
||
| const handleEdit = () => { | ||
| const image = result?.images[0] | ||
| if (!image) return | ||
| void generate({ | ||
| prompt: 'Same scene, but make it rain', | ||
| previousImage: image.url | ||
| ? { url: image.url } | ||
| : { b64Json: image.b64Json }, | ||
| }) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Include the server endpoint half of this example.
The client snippet sends a wire-friendly { url? } / { b64Json? } value and explicitly says the server must narrow it, but no route showing that conversion is provided. Add a minimal server endpoint that validates the payload and passes a GeneratedImage to generateImage.
🤖 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 `@docs/media/image-generation.md` around lines 219 - 239, Extend the
image-generation example with a minimal server endpoint matching the client
request, validating the wire-friendly previousImage shape, narrowing it to a
GeneratedImage, and passing it to generateImage. Reference the route handler and
generateImage usage, and show handling for invalid payloads and both URL and
base64 image variants.
Source: Coding guidelines
| **Client** — pass the completed job's id through the hook; your server | ||
| forwards it to `generateVideo`: | ||
|
|
||
| ```tsx | ||
| import { useGenerateVideo, fetchServerSentEvents } from '@tanstack/ai-react' | ||
|
|
||
| function VideoEditor() { | ||
| const { generate, result, isLoading } = useGenerateVideo({ | ||
| connection: fetchServerSentEvents('/api/generate/video'), | ||
| }) | ||
|
|
||
| const handleEdit = () => { | ||
| if (!result?.jobId) return | ||
| void generate({ | ||
| prompt: 'Make it rain', | ||
| previousJobId: result.jobId, | ||
| }) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add the server endpoint half of the client example.
The example says the server forwards previousJobId but does not show that endpoint. Add a minimal route that validates the client input and forwards the job ID to generateVideo.
🤖 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 `@docs/media/video-generation.md` around lines 520 - 536, Add the corresponding
server endpoint example after the client snippet, defining a minimal route that
validates the incoming prompt and optional previousJobId, then passes both
values to generateVideo. Show the response returned to the client and ensure the
route’s symbols clearly demonstrate forwarding previousJobId.
Source: Coding guidelines
| const handleEdit = () => { | ||
| if (!result?.jobId) return | ||
| void generate({ | ||
| prompt: 'Make it rain', | ||
| previousJobId: result.jobId, | ||
| }) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use the hook’s job id instead of result.jobId.
The documented hook exposes the job identifier separately (jobId/videoStatus.jobId), while the completed result contains the video result. As written, result?.jobId can be undefined and the edit handler silently returns. Destructure jobId and pass that value as previousJobId.
🤖 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 `@docs/media/video-generation.md` around lines 531 - 536, Update handleEdit to
use the hook-provided job identifier rather than result?.jobId: destructure
jobId (or videoStatus.jobId) from the hook and use it for the guard and as
generate’s previousJobId value.
| onKeyDown={(e) => { | ||
| if (e.key === 'Enter') | ||
| handleEditImage( | ||
| modelId, | ||
| modelResult.result!.images[0]!, | ||
| ) | ||
| }} | ||
| placeholder="Describe an edit — e.g. 'make it night time'..." | ||
| disabled={isLoading} | ||
| className="flex-1 px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white text-sm placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent disabled:opacity-50" | ||
| /> | ||
| <button | ||
| onClick={() => | ||
| handleEditImage( | ||
| modelId, | ||
| modelResult.result!.images[0]!, | ||
| ) | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the redundant modelResult.result! non-null assertion (ESLint error).
Inside the status === 'success' && modelResult.result && ... block, modelResult.result is already narrowed to non-null, so the ! after result is unnecessary and is flagged as an error by @typescript-eslint/no-unnecessary-type-assertion (lines 366 and 377), which will fail lint. Keep the ! on images[0] only.
🧹 Proposed fix
onKeyDown={(e) => {
if (e.key === 'Enter')
handleEditImage(
modelId,
- modelResult.result!.images[0]!,
+ modelResult.result.images[0]!,
)
}} onClick={() =>
handleEditImage(
modelId,
- modelResult.result!.images[0]!,
+ modelResult.result.images[0]!,
)
}📝 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.
| onKeyDown={(e) => { | |
| if (e.key === 'Enter') | |
| handleEditImage( | |
| modelId, | |
| modelResult.result!.images[0]!, | |
| ) | |
| }} | |
| placeholder="Describe an edit — e.g. 'make it night time'..." | |
| disabled={isLoading} | |
| className="flex-1 px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white text-sm placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent disabled:opacity-50" | |
| /> | |
| <button | |
| onClick={() => | |
| handleEditImage( | |
| modelId, | |
| modelResult.result!.images[0]!, | |
| ) | |
| } | |
| onKeyDown={(e) => { | |
| if (e.key === 'Enter') | |
| handleEditImage( | |
| modelId, | |
| modelResult.result.images[0]!, | |
| ) | |
| }} | |
| placeholder="Describe an edit — e.g. 'make it night time'..." | |
| disabled={isLoading} | |
| className="flex-1 px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white text-sm placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent disabled:opacity-50" | |
| /> | |
| <button | |
| onClick={() => | |
| handleEditImage( | |
| modelId, | |
| modelResult.result.images[0]!, | |
| ) | |
| } |
🧰 Tools
🪛 ESLint
[error] 366-366: This assertion is unnecessary since the receiver accepts the original type of the expression.
(@typescript-eslint/no-unnecessary-type-assertion)
[error] 377-377: This assertion is unnecessary since the receiver accepts the original type of the expression.
(@typescript-eslint/no-unnecessary-type-assertion)
🤖 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 `@examples/ts-react-media/src/components/ImageGenerator.tsx` around lines 362 -
379, Remove the unnecessary non-null assertions from modelResult.result in both
handleEditImage calls within the success block, while retaining the images[0]!
assertion. Update both the Enter-key handler and button onClick handler.
Source: Linters/SAST tools
| const { request_id } = await fal.queue.submit(submitModel, { | ||
| input, | ||
| }) | ||
|
|
||
| return { | ||
| jobId: request_id, | ||
| model: this.model, | ||
| model: submitModel, |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if fal.queue.status/result require the correct model or work with just requestId.
# Inspect the fal SDK types for queue status and result method signatures.
fd -t f 'client' packages/ai-fal/node_modules/@fal-ai/client/dist --exec cat -n {} 2>/dev/null | head -200
# Also check the SDK's type definitions for queue methods
fd -e d.ts . packages/ai-fal/node_modules/@fal-ai/client --exec cat -n {} 2>/dev/null | rg -C5 'queue\.(status|result)' | head -60Repository: TanStack/ai
Length of output: 149
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the adapter file and inspect the relevant symbols.
ast-grep outline packages/ai-fal/src/adapters/video.ts --view expanded
# Read the relevant section around submit/status/result.
sed -n '180,340p' packages/ai-fal/src/adapters/video.ts
# Find all references to the edit-sibling mapping and polling calls.
rg -n "FAL_VIDEO_EDIT_BY_SOURCE|getVideoStatus|getVideoUrl|queue\.(submit|status|result)|submitModel|previousJobId" packages/ai-fal/src/adapters/video.ts packages/ai-fal/src -SRepository: TanStack/ai
Length of output: 11238
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the fal package version and any local type references.
sed -n '1,220p' packages/ai-fal/package.json
rg -n "`@fal-ai/client`|queue\.(status|result)|requestId|model:" packages/ai-fal -S
# Look for lockfile entries that reveal the installed SDK version.
rg -n '"`@fal-ai/client`"|`@fal-ai/client`' package-lock.json pnpm-lock.yaml yarn.lock -SRepository: TanStack/ai
Length of output: 14728
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the video adapter tests around edit jobs and polling.
sed -n '240,470p' packages/ai-fal/tests/video-adapter.test.ts
# Inspect any local mock of `@fal-ai/client` to see how queue.status/result are exercised.
sed -n '1,120p' packages/ai-fal/tests/video-adapter.test.tsRepository: TanStack/ai
Length of output: 10623
🌐 Web query:
@fal-ai/client queue.status queue.result signature requestId model
💡 Result:
In the @fal-ai/client (and the corresponding Python fal_client), the queue-based workflow allows for asynchronous inference [1][2]. When you submit a request to a model, you receive a request ID, which is then used to track the status and retrieve the final result [1][2]. Queue Methods: 1. queue.submit: Initiates an asynchronous request to a model [1][2]. It accepts the model identifier (e.g., 'username/app-name') and an input object, returning a response that includes the request_id [1]. 2. queue.status: Used to poll the state of a submitted request using its request_id [1][3]. You can optionally enable logs by setting the logs parameter to true [1][3]. The status indicates whether the request is IN_QUEUE, IN_PROGRESS, or COMPLETED [2][3]. If in queue, it provides the queue position [2][3]. 3. queue.result: Retrieves the final output of the model once the request has transitioned to the COMPLETED state [1][2]. This method is called with the model identifier and the request_id [1][3]. Example Usage (JavaScript): const { request_id } = await fal.queue.submit("your-username/your-app-name", { input: { prompt: "a sunset over mountains" }, }); // Check status const status = await fal.queue.status("your-username/your-app-name", { requestId: request_id, logs: true, }); // Get result when ready const result = await fal.queue.result("your-username/your-app-name", { requestId: request_id, });
Citations:
- 1: https://fal.ai/docs/documentation/development/calling-your-endpoints
- 2: https://fal.ai/docs/documentation/deployment/requests
- 3: https://fal-ai.github.io/fal/client/fal_client.html
Poll edit jobs against submitModel
getVideoStatus and getVideoUrl still call fal.queue.status/fal.queue.result with this.model, but previousJobId flows submit to the mapped edit sibling. That can hit the wrong queue endpoint for edit jobs; pass the submitted model through the polling path as well.
🤖 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 `@packages/ai-fal/src/adapters/video.ts` around lines 237 - 243, The polling
path must use the model submitted for the job rather than this.model. Update
getVideoStatus and getVideoUrl, along with their callers and job state as
needed, to preserve submitModel from the queue submission and pass it to
fal.queue.status and fal.queue.result for edit jobs.
| const EXPECTED_EDITED_SRC: Record<string, RegExp> = { | ||
| openai: /guitar-store-remixed\.mp4$/, | ||
| gemini: /^data:video\/mp4;base64,AAAAIGZ0eXBpc29tAAACAGVkaXRlZA==$/, | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Guard against missing provider in EXPECTED_EDITED_SRC.
If providersFor('video-edit') returns a provider not in the map, the ! assertion silently passes undefined to toHaveAttribute, producing a confusing failure. A runtime guard gives a clear error instead.
🛡️ Proposed guard
const EXPECTED_EDITED_SRC: Record<string, RegExp> = {
openai: /guitar-store-remixed\.mp4$/,
gemini: /^data:video\/mp4;base64,AAAAIGZ0eXBpc29tAAACAGVkaXRlZA==$/,
}
for (const provider of providersFor('video-edit')) {
+ const expectedEditedSrc = EXPECTED_EDITED_SRC[provider]
+ if (!expectedEditedSrc) {
+ throw new Error(`No expected edited src configured for provider: ${provider}`)
+ }
test.describe(`${provider} -- video-edit`, () => {
test('sse -- edits a completed generation via previousJobId', async ({
// ...
await expect(video).toHaveAttribute(
'src',
- EXPECTED_EDITED_SRC[provider]!,
+ expectedEditedSrc,
{ timeout: 60_000 },
)
// ...
})
test('fetcher -- edits a completed generation via server function', async ({
// ...
await expect(video).toHaveAttribute(
'src',
- EXPECTED_EDITED_SRC[provider]!,
+ expectedEditedSrc,
{ timeout: 60_000 },
)
})
})
}Also applies to: 47-47, 75-75
🤖 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 `@testing/e2e/tests/video-edit.spec.ts` around lines 17 - 20, Add a runtime
guard wherever the video-edit test looks up EXPECTED_EDITED_SRC by provider,
including the assertions around the affected test cases, and fail clearly if the
provider is missing instead of relying on a non-null assertion. Use the provider
value to validate the map entry before passing it to toHaveAttribute, while
preserving the existing expected regex behavior.
Summary
previousJobIdongenerateVideoso callers always pass the prior job id;'job'-kind adapters (Sora remix, Gemini Omni) reference it server-side,'media'-kind adapters (Grok, fal) resolve the clip viagetVideoUrl(fal generate→edit sibling routing included). Omni’sprevious_interaction_idis removed from videomodelOptions.previousImageongenerateImageto prepend a priorGeneratedImage(or array / result) into the prompt for models that accept image inputs.Test plan
pnpm test:prpnpm --filter @tanstack/ai-e2e test:e2e(353 passed; video-edit / image-edit specs green)docs/media/video-generation.md(previousJobId) anddocs/media/image-generation.md(previousImage)Made with Cursor
Summary by CodeRabbit
New Features
Documentation
Chores