Agent examples

Three agents, from the smallest possible one to a retrieval-backed support agent. Each is a single deep-agents/<name>/index.ts file you can drop into a workspace and run with stackbone dev. They follow the layout from Getting started.

Every tool below reads from the ambient stackbone client. Reads from that client come back as a { data, error } envelope, so each example checks .error before using .data. The one exception is stackbone.database, which is native Drizzle and throws on error.

1. A plain greeter

The smallest useful agent: a model and a system prompt, no tools. It answers in the voice you set in the prompt.

deep-agents/greeter/index.ts
import { defineDeepAgent } from '@stackbone/sdk/deep';

export default defineDeepAgent({
  model: 'openai/gpt-4o-mini',
  systemPrompt: [
    'You are a warm, concise greeter.',
    'Welcome the person by name when they give it, and offer one helpful next step.',
    'Keep every reply to two sentences.',
  ].join('\n'),
});

Run stackbone dev, then:

curl http://127.0.0.1:4242/openai/v1/chat/completions \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer local-dev' \
  -d '{"model":"greeter","messages":[{"role":"user","content":"Hi, I am Sam"}]}'

2. A config-driven agent

This agent reads its tone from the config surface so an operator can change behaviour without a redeploy. The tool exposes the current tone, and the system prompt tells the model to apply it.

deep-agents/concierge/index.ts
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { defineDeepAgent } from '@stackbone/sdk/deep';
import { stackbone } from '@stackbone/sdk';

const getTone = tool(
  async () => {
    const tone = await stackbone.config.get('tone');
    return tone.error ? 'neutral' : String(tone.data);
  },
  {
    name: 'get_tone',
    description: "Return the agent's current tone setting.",
    schema: z.object({}),
  },
);

export default defineDeepAgent({
  model: 'openai/gpt-4o-mini',
  systemPrompt: [
    'You are a hotel concierge.',
    'Before your first reply in a conversation, call get_tone and adopt that tone',
    '(for example "formal" or "playful") for the rest of the chat.',
  ].join('\n'),
  tools: [getTone],
});

Because the tone comes from config, the operator sets it once and every new conversation picks it up.

3. A retrieval-backed support agent

A support agent that searches a knowledge base with RAG and looks up orders in its own database. Two tools, one agent.

deep-agents/support/index.ts
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { defineDeepAgent } from '@stackbone/sdk/deep';
import { stackbone } from '@stackbone/sdk';
import { eq } from '@stackbone/sdk/db';
import { orders } from './schema';

const searchKb = tool(
  async ({ query }: { query: string }) => {
    const result = await stackbone.rag.retrieve({ text: query, topK: 5 });
    if (result.error) throw new Error(result.error.code);
    return JSON.stringify(result.data.map((hit) => ({ score: hit.score, content: hit.content })));
  },
  {
    name: 'search_kb',
    description: 'Search the help-center knowledge base before answering.',
    schema: z.object({ query: z.string() }),
  },
);

const lookupOrder = tool(
  async ({ orderId }: { orderId: string }) => {
    const [order] = await stackbone.database
      .select()
      .from(orders)
      .where(eq(orders.id, orderId))
      .limit(1);
    return order ? JSON.stringify(order) : 'not_found';
  },
  {
    name: 'lookup_order',
    description: 'Look up an order by its id.',
    schema: z.object({ orderId: z.string() }),
  },
);

export default defineDeepAgent({
  model: 'openai/gpt-4o-mini',
  systemPrompt: [
    "You are Acme's support agent.",
    'Search the knowledge base with search_kb before answering policy questions.',
    'Use lookup_order when the user gives an order number.',
    "Answer in two sentences or fewer, and say plainly when you don't know.",
  ].join('\n'),
  tools: [searchKb, lookupOrder],
});

The model picks the right tool from each description. Send an x-stackbone-session header on every call to keep one running conversation per user, so a follow-up question lands in the same context without you re-sending the history.

Where to go next

The platform for agent developers.Build, ship and observe agentsthat survive prod.

© 2026 · STACKBONEBUILT WITH ❤️ FROM CANADA AND SPAIN