Cortex · guide

Preview a run

What an agent would send a model, shown without calling one. And every event of a run, as it happens.

Install it
pnpm add @niscorp/cortex @niscorp/signal zod openai
Step 1 of 4

The 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.

The model
import { z } from 'zod';
import { createSignal } from '@niscorp/signal';
import { defineAgent, defineTool } from '@niscorp/cortex';

const llm = createSignal('groq');
Step 2 of 4

An agent

An agent with one tool, and an answer that has a shape.

An agent
const seatsLeft = defineTool({
  id: 'seatsLeft',
  name: 'seatsLeft',
  description: 'How many seats are left on a night',
  input: z.object({ night: z.string().describe('The night, as YYYY-MM-DD') }),
  execute: ({ night }) => ({ night, left: night === '2026-10-24' ? 113 : 120 }),
});

const boxOffice = defineAgent({
  id: 'box-office',
  instructions: 'Look the night up with the seatsLeft tool, then give the answer.',
  tools: [seatsLeft],
  output: { schema: z.object({ left: z.number() }) },
});
Step 3 of 4

Preview

preview puts together exactly what a run would send: the messages, the tools, and how the answer will travel back. No model is called.

If something in the preview does not make sense to you, it will not make sense to the model either.

Preview
const question = 'How many seats are left on 2026-10-24?';
const preview = await boxOffice.preview(question, { llm });

console.log('answer travels by:', preview.strategy);
console.log('messages:', preview.messages.length, '· tools:', preview.tools.length);
console.log('about', preview.estimatedTokens, 'tokens');
Step 4 of 4

Every event

A run is a stream of events. for await reads them in order: the run starting, each step, each tool call before and after it runs, the answer as it is written, and the end.

Every event
const run = boxOffice.run(question, { llm });
for await (const event of run.events) {
  if (event.type === 'tool-start') console.log('tool-start', event.call.toolId);
  else if (event.type === 'tool-end') console.log('tool-end', event.observation.kind);
  else if (!['model-delta', 'output-delta', 'output-partial'].includes(event.type)) console.log(event.type);
}
Then

Run it.

This file asks a model, so it is not run on this site. The preview needs no model: it prints how the answer will travel, the number of messages and tools, and a token estimate. Then, when the model calls the tool once and answers, the run’s events in order: run-start, step-start, tool-start seatsLeft, tool-end result, step-start, run-end. An answer that is sent back adds a retry.

Run it
GROQ_API_KEY=your-key npx tsx look.mts