blog: surviving the refresh - #1112
Conversation
Launch post for the TanStack AI durability release: chat persistence, resumable streams, generation persistence and durable sandboxed agent runs, plus server-side memory, the rebuilt interrupt lifecycle, multi-instance locks and the BytePlus adapter. Every snippet is taken from the new docs pages, so the API names match what ships.
📝 WalkthroughWalkthroughChangesThe new “Surviving the refresh” article documents TanStack AI persistence and durability features. It covers chat recovery, resumable streams, media generation, sandboxed agents, server-side memory, interrupts, locks, the BytePlus adapter, and dependency changes. Surviving the refresh article
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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/blog/surviving-the-refresh.md`:
- Around line 107-120: Update the storage section text around defineMessageStore
to replace “typers” with “type helpers” or the correct exported type name, and
change “testkit” to “test kit” unless it is an official product name.
- Around line 164-170: Update the imports for the POST generation example to
include the exported generationParamsFromRequest helper from `@tanstack/ai`,
alongside generateImage and toServerSentEventsResponse, so the existing call
resolves correctly.
🪄 Autofix
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 Plus
Run ID: db479a20-881a-4bf7-a646-f677fb53c982
📒 Files selected for processing (1)
src/blog/surviving-the-refresh.md
| **Bring your own storage.** There is no required database. You implement a small store contract, and the package ships typers so you get autocomplete and contract checking with no annotations: | ||
|
|
||
| ```ts | ||
| import { defineMessageStore } from '@tanstack/ai-persistence' | ||
|
|
||
| export const messages = defineMessageStore({ | ||
| // Returns [] for a thread that was never saved. Never null. | ||
| loadThread: (threadId) => db.transcripts.read(threadId), | ||
| // A full replace: `messages` is the complete authoritative history. | ||
| saveThread: (threadId, messages) => db.transcripts.write(threadId, messages), | ||
| }) | ||
| ``` | ||
|
|
||
| A basic adapter is about 40 lines, and `memoryPersistence()` covers local dev. If you are writing one, the shared conformance testkit now covers the generation stores too, so you can prove your implementation is correct instead of hoping. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the storage-section terminology.
“typers” is not a clear term. Use “type helpers” or the actual exported type name. If testkit is not a product name, write “test kit.”
🧰 Tools
🪛 LanguageTool
[grammar] ~120-~120: Ensure spelling is correct
Context: ...are writing one, the shared conformance testkit now covers the generation stores too, s...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🤖 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/blog/surviving-the-refresh.md` around lines 107 - 120, Update the storage
section text around defineMessageStore to replace “typers” with “type helpers”
or the correct exported type name, and change “testkit” to “test kit” unless it
is an official product name.
Source: Linters/SAST tools
| import { generateImage, toServerSentEventsResponse } from '@tanstack/ai' | ||
| import { openaiImage } from '@tanstack/ai-openai' | ||
| import { withGenerationPersistence } from '@tanstack/ai-persistence' | ||
| import { persistence } from './persistence' | ||
|
|
||
| export async function POST(request: Request) { | ||
| const { prompt, threadId } = await generationParamsFromRequest(request) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file locations =="
fd -a 'surviving-the-refresh\.md|persistence\.ts' . || true
echo "== blog file around lines 140-190 =="
cat -n src/blog/surviving-the-refresh.md | sed -n '130,190p'
echo "== surrounding sections mentioning generationParamsFromRequest =="
rg -n "generationParamsFromRequest|from '`@tanstack/ai`'" src/blog/surviving-the-refresh.md . --glob '!node_modules' --glob '!dist' --glob '!build' | head -200
echo "== package files mentioning `@tanstack/ai` version =="
for f in package.json pnpm-lock.yaml package-lock.json yarn.lock bun.lockb; do
[ -f "$f" ] && { echo "--- $f"; rg -n "`@tanstack/ai`|`@tanstack/ai-openai`|`@tanstack/ai-persistence`" "$f" | head -100; }
doneRepository: TanStack/tanstack.com
Length of output: 8544
🌐 Web query:
@tanstack/ai 0.20.1 exports generationParamsFromRequest
💡 Result:
Yes, the @tanstack/ai package exports generationParamsFromRequest [1][2]. This function is used to parse and validate HTTP requests in the context of media generation (e.g., image generation), similar to how chatParamsFromRequest is used for chat agents [1][2][3][4]. In practice, you typically use it within a server-side route handler (such as a POST request handler) to extract parameters like the input and threadId from the incoming request [1][2]: import { generationParamsFromRequest } from '@tanstack/ai'; export async function POST(request: Request) { const { input, threadId } = await generationParamsFromRequest('image', request); //... proceed with generation logic } The function validates the request against the expected schema for the specified generation type (e.g., 'image') and throws a 400 response if the input is malformed, which is a pattern consistent with other request parsing utilities in the library [1][2][4]. Version 0.20.1 of @tanstack/ai exists and is referenced in the library's dependency history [5].
Citations:
- 1: https://tanstack.com/ai/latest/docs/persistence/keep-generated-files
- 2: https://tanstack.com/ai/latest/docs/persistence/generation-persistence
- 3: https://tanstack.com/ai/latest/docs/api/ai
- 4: https://tanstack.com/ai/latest/docs/reference/functions/chatParamsFromRequest
- 5: https://github.com/TanStack/ai/blob/main/packages/ai-client/CHANGELOG.md
Import generationParamsFromRequest in the generation example.
@tanstack/ai exports this helper, but the import list here does not include it, so the example code references an undefined call.
Proposed import
-import { generateImage, toServerSentEventsResponse } from '`@tanstack/ai`'
+import {
+ generateImage,
+ generationParamsFromRequest,
+ toServerSentEventsResponse,
+} from '`@tanstack/ai`'📝 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.
| import { generateImage, toServerSentEventsResponse } from '@tanstack/ai' | |
| import { openaiImage } from '@tanstack/ai-openai' | |
| import { withGenerationPersistence } from '@tanstack/ai-persistence' | |
| import { persistence } from './persistence' | |
| export async function POST(request: Request) { | |
| const { prompt, threadId } = await generationParamsFromRequest(request) | |
| import { | |
| generateImage, | |
| generationParamsFromRequest, | |
| toServerSentEventsResponse, | |
| } from '`@tanstack/ai`' | |
| import { openaiImage } from '`@tanstack/ai-openai`' | |
| import { withGenerationPersistence } from '`@tanstack/ai-persistence`' | |
| import { persistence } from './persistence' | |
| export async function POST(request: Request) { | |
| const { prompt, threadId } = await generationParamsFromRequest(request) |
🤖 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/blog/surviving-the-refresh.md` around lines 164 - 170, Update the imports
for the POST generation example to include the exported
generationParamsFromRequest helper from `@tanstack/ai`, alongside generateImage
and toServerSentEventsResponse, so the existing call resolves correctly.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
tanstack-com | c67ec2a | Commit Preview URL Branch Preview URL |
Aug 04 2026, 04:44 PM |
Launch post for the TanStack AI durability release.
What it covers
The problem framing is one user action: a reload mid-answer breaks the transcript, the stream, and the sandboxed agent doing the work. Three layers, three fixes.
POST+GETand theuseChatcall, in a single snippet.withPersistence, client ownership choice, adefineMessageStoreadapter).durabilityadapter,memoryStreamtodurableStreamswap, SSE and NDJSON).withGenerationPersistence,useGenerateImage({ persistence: true })).reapDetachedRuns).@tanstack/ai.Notes
TanStack/ai, so the API names, option shapes and model ids match what ships. Four snippets I first wrote from memory were corrected against the source.library: aiposts. Docs links use/ai/docs/..../blog-assets/<slug>/header.png. Happy to add one before merge.Summary by CodeRabbit