An answer as it arrives
A model writes its answer a few characters at a time. Cortex hands you what there is of it so far, each time it changes.
pnpm add @niscorp/cortex @niscorp/signal zod openaiThe model
createSignal makes the client that calls the model. Cortex is handed this client, here for Groq, and Signal reads the key from GROQ_API_KEY.
import { z } from 'zod';
import { createSignal } from '@niscorp/signal';
import { defineAgent } from '@niscorp/cortex';
const llm = createSignal('groq');An answer with a list in it
The longer the answer, the more there is to gain from reading it early. This one is a list of what was ordered.
const Orders = z.object({
items: z.array(z.object({ item: z.string(), quantity: z.number() })),
});
const reader = defineAgent({
id: 'order-reader',
instructions: 'Read every item of the order out of the message.',
output: { schema: Orders },
});What there is so far
An output-partial event carries the answer as far as it has been written, under data: first an empty list, then one item with only its name, then the item whole, and so on.
What it carries is not checked yet. It is there to be shown: a list that grows, a screen that fills in.
const run = reader.run('Two coffees and a cake, please.', { llm });
run.onEvent((event) => {
if (event.type === 'output-partial') console.log('so far:', JSON.stringify(event.output));
});The whole answer
The result is the answer once it is whole and has passed the schema. Use the partial ones to draw, and this one to act on.
const result = await run.result;
console.log('whole:', result.ok ? JSON.stringify(result.output.data) : result.error.message);Run it.
This file asks a model, so it is not run on this site. It prints a line of so far: each time more of the answer can be read, the list growing by an item or part of one, and then whole: with both items.
GROQ_API_KEY=your-key npx tsx arrives.mts