`createStreamableUI` creates a streamable React UI value that server-side code can change as work progresses. It does not call an LLM provider itself. Use it when a server action or another stream produces updates that should appear immediately in the client. section 4.1.6 section 6.1.2
The returned object controls the UI stream:
- `update(content)` replaces the current content. section 4.1.6
- `append(content)` adds content to what is already shown. section 4.1.6
- `done()` marks the stream complete; `error(error)` handles a streaming failure. section 4.1.6
Show progress through a two-step process
Create the stream, show an initial message, then append each completed step. Replace the progress messages with a final result and close the stream. Handle failures rather than leaving the UI waiting: ```jsx const ui = createStreamableUI(); ui.update(<p>Starting process...</p>); try { await firstStep(); ui.append(<p>Step 1 complete</p>); await secondStep(); ui.append(<p>Step 2 complete</p>); ui.update(<p>Process complete!</p>); ui.done(); } catch (error) { ui.error(error); } return ui; ``` `firstStep` and `secondStep` stand for the application’s asynchronous work. section 4.1.6
For a LangChain.js workflow, call `chain.stream()`, create the UI stream, and iterate over the chain’s results. Accumulate response text and pass an updated React component to `update()` for each result; call `done()` when iteration finishes. This separates chain execution from rendering because `streamUI` cannot directly use the LangChain.js chain in this integration. section 6.1.2
Listing 6.4 Integrating the chain into the conversation chain
export async function getChainStream(city) {
const chain = RunnableLambda.from(fetchWeatherData) #1
.pipe(promptTemplate)
.pipe(llm)
.pipe(new StringOutputParser());
const stream = await chain.stream({ city }); #2
return stream;
}
export async function continueConversation(input) {
const aiState = getMutableAIState();
const stream = createStreamableUI(); #3
stream.update(<div>Processing your request...</div>);
const aiResponseStream = await getChainStream(input);
let textContent = '';
for await (const item of aiResponseStream) { #4
textContent += item;
stream.update(<ChatBubble role="assistant"
text={textContent} className={`mr-auto border-none`} />);
}
stream.done();
aiState.done({ #5
...aiState.get(),
messages: [
...aiState.get().messages,
{
id: generateId(),
role: 'assistant',
content: textContent,
},
],
});
return {
id: generateId(),
display: stream.value,
role: 'assistant',
};
}
The listing connects a weather-data chain to a conversation handler: each streamed item updates the assistant chat bubble, followed by stream completion. section 6.1.2
