A streamable UI component lets a React interface show server-generated content as it arrives. A server action can use `streamUI` to turn an LLM response into React nodes, then return its `value` for display in a client component. The response can appear and change without a page reload or polling. section 4.1.5
Choose `streamUI` when the model response drives the component: its `text` callback can render generated content in a chat bubble, while tool calls can produce more complex UI. Choose `createStreamableUI` when application code needs to control successive updates. Unlike `streamUI`, it does not call the LLM provider with a prompt. section 4.1.5 section 4.1.6
A `createStreamableUI` value supports four operations:
- `update` replaces the current content; use it for a changing status or the latest accumulated response. section 4.1.6 section 6.1.2
- `append` adds content, such as another completed step, without replacing earlier steps. section 4.1.6
- `done` marks the stream complete; `error` handles a failure or displays an error component. section 4.1.6
Show progress during a server-side process
Create a streamable UI, call `update` with “Starting process…”, then `append` a message as each step finishes. Replace the progress messages with “Process complete!” and call `done`; call `error` if processing fails. Users see progress before the whole process finishes. section 4.1.6
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',
};
}
For a streamed weather report, a LangChain chain fetches data and generates text. The server accumulates each output chunk, replaces a `ChatBubble` through `createStreamableUI`, then marks the UI stream complete. section 6.1.2
