vercel-labs / vercel-labs/json-render
Documentation mismatch: useUIStream expects JSONL patch format but API route example outputs plain JSON
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 16.8k
- Forks
- 901
- Avg merge
- 3h 14m
- Merged PRs (30d)
- 4
Description
Problem
The documentation for API route setup in AI SDK Integration and Streaming shows a simple example that directly returns result.textStream:
// From docs (https://json-render.dev/docs/ai-sdk)
export async function POST(req: Request) {
const { prompt } = await req.json();
const systemPrompt = generateCatalogPrompt(catalog);
const result = streamText({
model: 'anthropic/claude-haiku-4.5',
system: systemPrompt,
prompt,
});
return new Response(result.textStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
I followed this pattern with a minor difference (using @ai-sdk/openai provider instead of AI Gateway string format):
// My implementation
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { generateCatalogPrompt } from '@json-render/core';
import { catalog } from '@/lib/catalog';
export async function POST(req: Request) {
const { prompt } = await req.json();
const systemPrompt = generateCatalogPrompt(catalog);
const result = streamText({
model: openai('gpt-5.2'), // Using @ai-sdk/openai provider
system: systemPrompt,
prompt,
});
return new Response(result.textStream, {
headers: { 'Content-Type': 'text/plain; charset=utf-8' },
});
}
Actual Output
The AI model outputs nested JSON (not JSONL patch format):
{
"type": "Card",
"props": {
"title": "Claim Form"
},
"children": [
{
"type": "Text",
"props": {
"text": "Please review your details and submit your claim."
}
},
{
"type": "Button",
"props": {
"text": "Submit Claim",
"action": {
"type": "submit"
}
}
}
]
}
Expected Format by useUIStream
However, looking at the source code of useUIStream, it expects JSONL patch format (one JSON patch per line):
{"op":"set","path":"/root","value":"el-1"}
{"op":"add","path":"/elements/el-1","value":{"key":"el-1","type":"Card","props":{...}}}
{"op":"add","path":"/elements/el-2","value":{"key":"el-2","type":"Text","props":{...},"parentKey":"el-1"}}
The hook parses each line as a patch operation:
// From @json-render/react source
const lines = buffer.split("\n");
for (const line of lines) {
const patch = parsePatchLine(line);
if (patch) {
currentTree = applyPatch(currentTree, patch);
}
}
Result
When following the documentation example:
- AI model outputs nested JSON (as shown above)
useUIStreamtries to parse each line as a JSON patch- Parsing fails because the format doesn't match
treeremains{ root: "", elements: {} }(empty)- Nothing renders on the page
Environment
- @json-render/core: ^0.3.0
- @json-render/react: ^0.2.0
- ai: ^6.0.44
- @ai-sdk/openai: latest
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Compare the API route examples in the linked AI SDK Integration and Streaming documentation with the useUIStream parsing behavior in @json-render/react, especially parsePatchLine. Update the examples so the documented response format matches what the hook consumes, then verify that the resulting stream produces a rendered tree rather than an empty one.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- documentation, frontend
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100