A config-driven agent

This concierge reads its tone from config instead of hard-coding it in the prompt. A tool exposes the current setting and the prompt tells the model to adopt it. Config reads come back as a { data, error } envelope, so the tool picks its own fallback when the key is not set.

The agent is a single deep-agents/concierge/index.ts file, the same shape as the greeter. The difference is the tool: it reads the tone key from the ambient stackbone client every time the model asks for 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({
  name: 'concierge',
  model: 'openai/gpt-4o-mini',
  tools: [getTone],
});

The prompt keyed concierge is what tells it to use the tool:

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.

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

The operator sets the tone once in config, and the agent reads it at the start of each new conversation. They edit the value in the dashboard, or you push one from the CLI with stackbone config set. See Setting config.

The read above is untyped: tone.data arrives as unknown, so the tool wraps it in String(...). Declare a config.schema.ts at your project root and run stackbone config types to make it strict. stackbone.config.get('tone') then returns string, and a misspelt key is a compile error. See Typed config.

What's next

BUILT WITH ❤️ FROM CANADA AND SPAIN