Agents Agents — TypeScript examples backed by real provider calls. typescript examples examples/short-agents src/examples/typescript/short-agents example Agents

These TypeScript examples are real runnable files. Edit the source file first; this page is rebuilt from the checked-in example and its metadata header.

TypeScript Grounded Support Agent

Answers a support question grounded in a handbook that is kept out of the model prompt via contextFields.

TypeScript
import { AxAIOpenAIModel, AxJSRuntime, agent, ai } from '@ax-llm/ax';

const apiKey = process.env.OPENAI_API_KEY ?? process.env.OPENAI_APIKEY;
if (!apiKey) {
  throw new Error('Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.');
}

const llm = ai({
  name: 'openai',
  apiKey,
  config: {
    model: AxAIOpenAIModel.GPT54Mini,
    temperature: 0,
  },
});

// The handbook can be arbitrarily large. Listing it in `contextFields` keeps it
// in the agent's runtime so it never inflates the model prompt — the agent reads
// it through code, not through tokens. That is the whole point of an Ax agent
// over a plain `ax()` call: the source material stays out of the context window.
const handbook = `
# Acme Cloud — Support Handbook

## Billing
- Invoices are issued on the 1st of each month and are due net-15.
- Plan downgrades take effect at the END of the current billing cycle, not immediately.
- Refunds are issued to the original payment method within 5 business days.

## Access
- Seats can be added by any workspace Owner under Settings -> Members.
- SSO (SAML) is available on Enterprise; SCIM provisioning is Owner-only.

## Incidents
- Status and uptime are published at status.acme.example.
- Sev-1 incidents page the on-call within 5 minutes; updates post every 30 minutes.

## Data
- Exports are available in CSV and JSON from Settings -> Data.
- Deleted workspaces are recoverable for 30 days, then permanently purged.
`.trim();

const assistant = agent(
  'question:string, handbook:string -> answer:string, citations:string[] "Handbook sections the answer relies on"',
  {
    runtime: new AxJSRuntime(),
    // Keep the handbook in the runtime, out of the prompt.
    contextFields: ['handbook'],
    maxTurns: 6,
  }
);

const result = await assistant.forward(llm, {
  question:
    'A customer downgraded their plan today. When does it take effect, and can they get a refund for the current cycle?',
  handbook,
});

console.log(JSON.stringify(result, null, 2));

TypeScript Incident Triage Agent

Triages a noisy incident report held in contextFields, using a lean contextPolicy to keep the raw log out of the prompt while it reasons.

TypeScript
import { AxAIOpenAIModel, AxJSRuntime, agent, ai } from '@ax-llm/ax';

const apiKey = process.env.OPENAI_API_KEY ?? process.env.OPENAI_APIKEY;
if (!apiKey) {
  throw new Error('Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.');
}

const llm = ai({
  name: 'openai',
  apiKey,
  config: {
    model: AxAIOpenAIModel.GPT54Mini,
    temperature: 0,
  },
});

// A raw, noisy incident report. It lives in `contextFields`, so the agent works
// it inside the runtime; `contextPolicy: lean` keeps the prompt compact by
// preferring live runtime state and summaries over replaying the raw text.
const report = `
[2026-03-02 14:01:22Z] INFO  gateway       deploy svc-checkout-edge v812 -> prod (channel: canary 10%)
[2026-03-02 14:03:10Z] WARN  checkout-api  p95 latency 1180ms (baseline 240ms) region=eu-west-1
[2026-03-02 14:04:55Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise
[2026-03-02 14:05:01Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise
[2026-03-02 14:05:40Z] WARN  payments-gw   circuit half-open, 3 retries exhausted for order=ord_99214
[2026-03-02 14:06:12Z] INFO  gateway       canary widened 10% -> 50% for svc-checkout-edge v812
[2026-03-02 14:07:33Z] ERROR checkout-api  502 from svc-payments-gw: upstream timeout (10s) tenant_tier=enterprise
[2026-03-02 14:08:02Z] ERROR checkout-api  user-visible: "Payment could not be processed" shown to 1,284 sessions
[2026-03-02 14:09:48Z] WARN  payments-gw   connection pool exhausted (max=64) waiting=210
[2026-03-02 14:11:20Z] INFO  on-call       paged: SEV-2 opened (eu-west-1 checkout error rate 38%)
[2026-03-02 14:14:05Z] INFO  gateway       rollback svc-checkout-edge v812 -> v811 (channel: prod 100%)
[2026-03-02 14:17:41Z] INFO  checkout-api  p95 latency 260ms, error rate 0.4% region=eu-west-1
[2026-03-02 14:19:10Z] INFO  on-call       SEV-2 mitigated, monitoring for 30m
`.trim();

const triage = agent(
  'report:string, question:string -> severity:class "low, medium, high, critical", rootCause:string, nextSteps:string[], evidence:string[] "Quoted log lines that support the assessment"',
  {
    runtime: new AxJSRuntime(),
    contextFields: ['report'],
    contextPolicy: {
      preset: 'lean',
      budget: 'balanced',
    },
    maxTurns: 10,
  }
);

const result = await triage.forward(llm, {
  report,
  question:
    'What happened, how bad was it, and what should the on-call do next? Cite the lines you relied on.',
});

console.log(JSON.stringify(result, null, 2));

TypeScript Specialist Planner Agent

A specialist that plans a migration from a long brief held in contextFields, using a checkpointed contextPolicy and a runtime-output cap to stay compact.

TypeScript
import { AxAIOpenAIModel, AxJSRuntime, agent, ai } from '@ax-llm/ax';

const apiKey = process.env.OPENAI_API_KEY ?? process.env.OPENAI_APIKEY;
if (!apiKey) {
  throw new Error('Set OPENAI_API_KEY or OPENAI_APIKEY to run this example.');
}

const llm = ai({
  name: 'openai',
  apiKey,
  config: {
    model: AxAIOpenAIModel.GPT54Mini,
    temperature: 0,
  },
});

// A long, messy brief — exactly the kind of input you do not want replayed into
// the prompt on every turn. `contextFields` holds it in the runtime, the
// `checkpointed` policy compacts older turns once the prompt grows, and
// `maxRuntimeChars` caps how much runtime output is echoed back.
const brief = `
# Migration brief: monolith -> services (draft, unordered notes)

Current: single Rails monolith, Postgres primary + 1 replica, Sidekiq for jobs.
Pain: deploys take 40m, one bad migration locks the orders table, on-call burnout.
Constraints: no downtime windows > 5m, PCI scope must shrink, team of 6, 2 quarters.
Hot paths: checkout (writes orders, payments), search (read-heavy), notifications (async).
Known landmines: payments code has no tests; search shares the orders DB; a nightly
cron rebuilds the catalog and pins CPU for ~20m; the replica lags up to 90s under load.
Org wants: independent deploys for checkout, smaller blast radius, an audit trail.
Nice to have: event log for orders, read-model for search, feature flags.
Hard no: a big-bang rewrite; introducing Kubernetes this year.
`.trim();

const specialist = agent(
  'brief:string, goal:string -> plan:string[] "Ordered, concrete steps", answer:string, risks:string[]',
  {
    runtime: new AxJSRuntime(),
    contextFields: ['brief'],
    contextPolicy: {
      preset: 'checkpointed',
      budget: 'balanced',
    },
    maxRuntimeChars: 3000,
    maxTurns: 12,
  }
);

const result = await specialist.forward(llm, {
  brief,
  goal: 'Propose a safe, incremental 2-quarter plan to split checkout out first, respecting the hard constraints.',
});

console.log(JSON.stringify(result, null, 2));

TypeScript Multi-Model Panel

Fans one question across three providers (OpenAI, Gemini, Anthropic), then judges the candidates and synthesizes a single grounded answer.

TypeScript
import {
  AxAIAnthropicModel,
  AxAIGoogleGeminiModel,
  AxAIOpenAIModel,
  ai,
  ax,
} from '@ax-llm/ax';

const openaiKey = process.env.OPENAI_API_KEY ?? process.env.OPENAI_APIKEY;
const googleKey = process.env.GOOGLE_APIKEY ?? process.env.GOOGLE_API_KEY;
const anthropicKey =
  process.env.ANTHROPIC_APIKEY ?? process.env.ANTHROPIC_API_KEY;
if (!openaiKey || !googleKey || !anthropicKey) {
  throw new Error(
    'Set OPENAI_APIKEY, GOOGLE_APIKEY, and ANTHROPIC_APIKEY to run this multi-provider panel.'
  );
}

// A panel of three different providers, each answering the same question
// independently. This is plain `ax()` composition (no agent runtime) — fan out
// to the panel, judge the candidates, then synthesize one grounded answer.
const panel = [
  {
    model: 'openai/gpt-5.4-mini',
    llm: ai({
      name: 'openai',
      apiKey: openaiKey,
      config: { model: AxAIOpenAIModel.GPT54Mini, temperature: 0 },
    }),
  },
  {
    model: 'google/gemini-3.5-flash',
    llm: ai({
      name: 'google-gemini',
      apiKey: googleKey,
      config: { model: AxAIGoogleGeminiModel.Gemini35Flash },
    }),
  },
  {
    model: 'anthropic/claude-haiku-4.5',
    llm: ai({
      name: 'anthropic',
      apiKey: anthropicKey,
      config: { model: AxAIAnthropicModel.Claude45Haiku },
    }),
  },
];

const researcher = ax(
  'question:string -> answer:string, keyFindings:string[], citations:string[], confidence:number'
);
researcher.setInstruction(
  'Answer independently. Use evidence. Call out uncertainty. Do not optimize for consensus.'
);

const judge = ax(
  'question:string, candidates:json -> consensus:string[], contradictions:string[], uniqueInsights:string[], blindSpots:string[]'
);
judge.setInstruction(
  'Compare the candidates. Find agreement, conflicts, missing coverage, and unique useful points.'
);

const synthesizer = ax(
  'question:string, candidates:json, review:json -> answer:string, citations:string[], caveats:string[]'
);
synthesizer.setInstruction(
  'Write one final answer grounded in the candidates and review. Resolve conflicts explicitly.'
);

async function fusion(question: string) {
  // Each panelist is a different provider answering independently.
  const candidates = await Promise.all(
    panel.map(async ({ model, llm }) => ({
      model,
      ...(await researcher.forward(llm, { question })),
    }))
  );
  // The judge + synthesizer run on one of the panel clients (OpenAI here).
  const orchestrator = panel[0].llm;
  const review = await judge.forward(orchestrator, { question, candidates });
  return synthesizer.forward(orchestrator, { question, candidates, review });
}

const final = await fusion(
  'What are the strongest arguments for and against a national carbon tax?'
);

console.log(JSON.stringify(final, null, 2));
Docs