A package’s own agent
Prism ships an agent that writes a mapping. Run it once with Cortex, then use what it wrote with no model at all.
pnpm add @niscorp/cortex @niscorp/prism @niscorp/strata @niscorp/signal zod openaiThe model, and Prism’s agent
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.
Vex, Nova, Prism and Tide each ship an agent of their own under /agent. Each writes one kind of document for its package. Prism’s writes a mapping: a config that turns a row of one shape into another.
import { createSignal } from '@niscorp/signal';
import { evaluate } from '@niscorp/prism';
import { mappingAgent } from '@niscorp/prism/agent';
const llm = createSignal('groq');What you have, and what you want
The agent is not asked in words. It is given a row as it is, and an example of the row as it should come out.
const row = { first: 'Ada', last: 'Lovelace', born: 1815 };
const wanted = { fullName: '', born: 0 };The mapping, written once
This is the only place a model is called. The agent’s answer is a Prism config, checked against Prism’s own schema before it is handed over.
const written = await mappingAgent.run({ sampleInput: row, targetShape: wanted }, { llm }).result;
if (!written.ok) throw new Error(written.error.message);
const config = written.output.data;
console.log(JSON.stringify(config));Run it, as often as you like
The config is plain JSON. Save it, and evaluate runs it on any row of that shape. No model is involved from here on.
console.log(evaluate(config, row));
console.log(evaluate(config, { first: 'Grace', last: 'Hopper', born: 1906 }));Run it.
This file asks a model, so it is not run on this site. It prints the config the model wrote, and then the two rows mapped by it: { fullName: 'Ada Lovelace', born: 1815 } and { fullName: 'Grace Hopper', born: 1906 }, when the config joins the two names as asked.
GROQ_API_KEY=your-key npx tsx mapping.mts