Streaming Partial streams
Partial streams
Update one fixed row ID from partial async-iterable values.
Use connectPartialStream when one row grows over time, such as a token-streamed assistant message. Row msg-1 below is seeded before its stream connects, so that connection only ever patches it. Row msg-2 isn't seeded — its first partial is reported through onIssue, then createRow turns the accumulated changes into the row. Both fill in one partial at a time:
Grow one row's content cell in place with connectPartialStream, covering both the seeded-row and createRow/onIssue patterns.
Signature
function connectPartialStream<
TRow extends object,
TRowId extends string | number,
>(
rowModel: RowModelLike<TRow, TRowId>,
stream: AsyncIterable<Partial<TRow>>,
options: PartialStreamOptions<TRow, TRowId>,
): StreamConnection;Every partial becomes an exact { id: options.rowId, changes: partial } update.
Existing row
msg-1 above is seeded in the row model's initial rows before its connection is made; seeding through a transaction after creation works the same way:
rowModel.applyTransaction({
add: [{ id: "msg-1", role: "assistant", content: "", tokens: 0 }],
});
const connection = connectPartialStream(rowModel, partials, {
rowId: "msg-1",
onIssue: (issue) => console.warn(issue.code, issue.rowId),
});Create a missing row explicitly
The connector never asserts that a partial is a complete row. Supply a factory when creation is allowed — msg-2 above follows exactly this pattern:
connectPartialStream(rowModel, partials, {
rowId: "msg-2",
createRow(partial, id) {
return {
id,
role: "assistant",
content: partial.content ?? "",
tokens: partial.tokens ?? 0,
};
},
});onIssue fires whether or not createRow is supplied — the connector reports the unknown target first, then builds the row if it has a factory. That ordering is what msg-2 shows above: it logs the unknown-update-id warning for its first partial and then gains its row. Without createRow, the report is all that happens and no row is fabricated.
createRow receives the changes accumulated across that frame, not just the one partial that triggered it: partials arriving in the same animation frame are batched into a single transaction, so a row created on the first frame already carries every field that landed in it.
Lifecycle
done resolves when the iterator finishes or the connection is disposed. Source and model failures reject it with the original error.