Solid · guide

Read a reply as it arrives

A reply comes in pieces. After each one you can read an object of your shape, with as much in it as has arrived.

Install it
pnpm add @niscorp/solid zod
Step 1 of 4

The shape

The schema is the shape you asked the model for. Solid needs it before any text arrives.

The shape
import { z } from 'zod';
import { createStream } from '@niscorp/solid';

const Suggestion = z.object({
  show: z.string(),
  seats: z.array(z.string()),
  price_cents: z.number(),
  why: z.string(),
});
Step 2 of 4

A stream

createStream gives you a stream that already holds an object. For this schema that is every string empty, the number 0 and the list empty. current() reads it.

on is called at once with that object, and then after each piece that changed something.

A stream
const stream = createStream({ schema: Suggestion });
console.log('before:', JSON.stringify(stream.current()));

stream.on((suggestion) => console.log(JSON.stringify(suggestion)));
Step 3 of 4

The pieces

A model sends a reply a few characters at a time, and a piece can end anywhere: in the middle of a word, or of a number.

write hands Solid one piece. A string is there as far as it has been written. So is a number: 7600 reads as 76 until the rest of it arrives.

The pieces
const pieces = ['{"show":"The Tem', 'pest","seats":["C4",', '"C5"],"price_cents":76', '00,"why":"Row C."}'];
for (const piece of pieces) stream.write(piece);
Step 4 of 4

The end

final() resolves when the reply’s closing brace has arrived. close() says no more text is coming.

The end
stream.close();
console.log('final:', JSON.stringify(await stream.final()));
Then

Run it.

The first line is the object before any text. The second is on being called at once. Then one line for each piece: the show’s name half written, the first seat, a price of 76, and the whole reply.

Run it
npx tsx reply.mts
It prints
before: {"show":"","seats":[],"price_cents":0,"why":""}
{"show":"","seats":[],"price_cents":0,"why":""}
{"show":"The Tem","seats":[],"price_cents":0,"why":""}
{"show":"The Tempest","seats":["C4"],"price_cents":0,"why":""}
{"show":"The Tempest","seats":["C4","C5"],"price_cents":76,"why":""}
{"show":"The Tempest","seats":["C4","C5"],"price_cents":7600,"why":"Row C."}
final: {"show":"The Tempest","seats":["C4","C5"],"price_cents":7600,"why":"Row C."}