Dashboard|

Agent definitions

Configure a single agent cleanly before you build a team of them.

An agent packages a model, instructions and optional behaviour: tools, handoffs, guardrails, structured output and widgets.

What belongs on an agent

PropertyUse it forRead next
nameIts identity in traces and in handoff tool namesThis page
instructionsThe job, constraints and style. A string, or a function of the run contextThis page
modelAny catalog model. Default gpt-oss-120bModels
modelSettingstemperature, maxTokens, reasoningEffortModels
toolsFunctions the agent can callTools
handoffsAgents it can hand the conversation toOrchestration
handoffDescriptionTells other agents when to hand off to this oneOrchestration
outputTypeStructured output instead of textThis page
inputGuardrails, outputGuardrailsChecking input and outputGuardrails and approvals
widgetsAnswering with UI: charts, tables, formsAgent UI
Agent.fromCencori(id)Running an agent stored in CencoriThis page

Start with one focused agent

Give an agent one clear job. Add more agents only when you need different instructions, different tools, or a different approval policy.

import { Agent } from 'cencori/agents';
 
const billing = new Agent({
    name: 'Billing',
    instructions: 'You handle refunds and invoices. Never promise a refund before checking the order.',
    model: 'claude-sonnet-4-5',
    modelSettings: { temperature: 0.2 },
    tools: [getOrder, issueRefund],
});

Instructions from context

instructions can be a function. It gets the run context, so instructions can depend on who's asking.

const support = new Agent<{ plan: 'free' | 'pro' }>({
    name: 'Support',
    instructions: ({ context }) =>
        context.plan === 'pro' ? 'Offer a call with an engineer when stuck.' : 'Point to the docs first.',
});
 
await run(support, 'My deploy fails', { context: { plan: 'pro' } });

Keep local context separate from model context

context is your value: a user, a database handle, permissions. Tools, guardrails and instructions receive it, and it never leaves your process. Only what you put in instructions, messages and tool results reaches the model.

const getInvoices = tool({
    name: 'get_invoices',
    description: "The signed-in user's invoices.",
    parameters: z.object({}),
    execute: async (_args, { context }) => db.invoices.forUser(context.userId),
});

Structured output

Set outputType to a zod schema (or JSON Schema) and finalOutput is the parsed, validated object.

const triage = new Agent({
    name: 'Triage',
    instructions: 'Classify the ticket.',
    outputType: z.object({
        category: z.enum(['billing', 'bug', 'question']),
        urgent: z.boolean(),
    }),
});
 
const { finalOutput } = await run(triage, 'I was charged twice!!');
finalOutput.category; // 'billing'

The agent can still call its tools before answering.

Agents stored in Cencori

Run an agent defined in Cencori (stored agents) by id. Its model, instructions and widgets setting come from Cencori; add your own tools on top:

const analyst = Agent.fromCencori('fea49590-...', { tools: [getSales] });
await run(analyst, 'How is revenue trending?');

A stored agent can be called as a tool (analyst.asTool()), but can't be a handoff target yet.

Copy an agent

const fastSupport = support.clone({ model: 'gpt-oss-120b', modelSettings: { reasoningEffort: 'low' } });

When to split one agent into several

  • Its instructions are trying to do two jobs.
  • Some tools need approval and others don't, and you want that boundary clear.
  • Part of the work is better on a different model (a cheap fast one for triage, a strong one for analysis).

See Orchestration.