---
title: "Custom Agents"
framework: react
version: "2.1.1"
---

# Custom Agents

The [Default Agents](https://www.ag-grid.com/studio/react/ai-ax/) cover most dashboard-building tasks, but you can change how the built-in runtime's agents behave: rewrite an agent's instructions, change the tools it can use, or add an agent of your own. You supply agents through the `agents` field on your [Adapter](https://www.ag-grid.com/studio/react/ai-adapter/).

## Supplying Agents

`agents` is the set of agents the runtime runs. Omit it and you get the defaults. Provide it and you control the set - so include `agStudioDefaultAgents` when you want to keep the built-in agents alongside your own.

```ts
import { agStudioDefaultAgents } from 'ag-studio';
```

```jsx
const ai = {
    executeTurn,
    agents: [chartBuilder],
    primaryAgent: 'chart-builder',
};

<AgStudio ai={ai} />
```

`primaryAgent` is the agent a conversation starts from - it defaults to `'lead'`. Set it to one of your own to start there instead. The array above runs a single custom agent; to keep the built-in agents alongside yours, spread `agStudioDefaultAgents` into it (`agents: [...agStudioDefaultAgents, chartBuilder]`).

## Defining an Agent

An agent has a `type`, a `schema` for its parameters, and a `config` factory that returns its behaviour. The factory receives the parameters and returns the agent's name, instructions, tools, and delegation permissions - so an agent's behaviour can vary by input.

```ts
import type { AgAiAgent } from 'ag-studio';

const chartBuilder: AgAiAgent = {
    type: 'chart-builder',
    description: 'Explores the data and builds bar charts.',
    schema: (s) => s.undefined(),
    config: () => ({
        name: 'Chart Builder',
        instructions: (api) => {
            const { tables } = api.getAiContext().schema();
            return `You are a bar-chart specialist for this dashboard.

Voice: always reply in British English, in a warm and concise tone. Open each reply with a one-sentence summary of the action you are about to take.

Build charts with add_widget then configure_widget, using a bar-chart type only. Manage filters with the page and widget filter tools. Explore the data with view_schema and execute_query before building.

Available tables: ${tables.map((t) => t.name).join(', ')}.`;
        },
        tools: [
            { name: 'view_schema' },
            { name: 'execute_query' },
            { name: 'add_widget' },
            { name: 'configure_widget' },
            { name: 'position_widget' },
            { name: 'add_page_filter' },
            { name: 'remove_page_filter' },
            { name: 'add_widget_filter' },
            { name: 'remove_widget_filter' },
        ],
    }),
};
```

### Instructions

`instructions` receives the studio `api`, so an agent can ground itself in the live dashboard - the schema, the widget catalogue, current page state. Retrieve these through `api.getAiContext()`; see [Context](https://www.ag-grid.com/studio/react/ai-context/) for the full surface. Instructions also shape how the agent *responds* - the `Voice` line above steers its tone and language, so you can give an agent a house style or have it reply in another language.

### Tools

`tools` lists the tools the agent may call, by name - and it is also how you constrain an agent. `chartBuilder` is given the query, widget, and filter tools but not `remove_widget` or the planning tools, so it stays within building bar charts and managing filters. The full set is in the [Built-in Tools Reference](https://www.ag-grid.com/studio/react/ai-ax#tool-reference).

### Delegation

`delegateAgents` lists the agent types this agent may hand work to. `chartBuilder` runs alone, so it needs none. The built-in Lead delegates to the planning, data, page, and widget agents; to have a coordinator delegate to an agent of your own, supply your own coordinator that lists it in `delegateAgents`.

## Example

The example below runs `chartBuilder` as the only agent. Open the AI panel and ask it to "chart net sales by region" to watch it query the data and build a bar chart - and note the British-English, summary-first voice its instructions give it. Ask for a line chart and it will decline and offer a bar chart instead.

#### Custom Agents

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgStudio, AgStudioRef } from "ag-studio-react";
import { openaiAdapter } from "./shared/openaiAdapter.tsx";
import {
  AgAiAgent,
  AgAiAssistant,
  AgDataEngine,
  AgDataSourcesDefinition,
  AgReportState,
  AgStudioAiModule,
  AgStudioApi,
  AgStudioMode,
  AgStudioModuleRegistry,
  AgStudioProperties,
} from "ag-studio";
import { getMainDemoData } from "./data.tsx";

AgStudioModuleRegistry.registerModules([AgStudioAiModule]);

export const AI_API_URL = "https://ai-api.ag-grid.com/api/openai/v1";

export const AI_API_TOKEN = "";

const chartBuilder: AgAiAgent = {
  type: "chart-builder",
  description: "Explores the data and builds bar charts.",
  schema: (s) => s.undefined(),
  config: () => ({
    name: "Chart Builder",
    instructions: (api) => {
      const { tables } = api.getAiContext().schema();
      return `You are a bar-chart specialist for this dashboard. You explore the user's data and build bar charts.

Voice: always reply in British English, in a warm and concise tone. Open each reply with a one-sentence summary of the action you are about to take, then keep any explanation to a sentence or two.

What you do:
- Explore the data with view_schema and execute_query before building anything.
- Build charts with add_widget then configure_widget, and place them with position_widget. Only ever use a bar-chart type: 'bar-chart', 'bar-chart-grouped', 'bar-chart-stacked', or 'bar-chart-stacked-100'. If asked for any other chart type, explain that you build bar charts only and offer the closest bar-chart alternative.
- Manage filters with add_page_filter / remove_page_filter and add_widget_filter / remove_widget_filter.

Available tables: ${tables.map((t) => t.name).join(", ")}.`;
    },
    tools: [
      { name: "view_schema" },
      { name: "execute_query" },
      { name: "view_page" },
      { name: "view_widget" },
      { name: "add_widget" },
      { name: "configure_widget", params: { widgetType: "bar-chart-grouped" } },
      { name: "position_widget" },
      { name: "add_page_filter" },
      { name: "remove_page_filter" },
      { name: "add_widget_filter" },
      { name: "remove_widget_filter" },
    ],
  }),
};

const StudioExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const studioStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [data, setData] = useState<AgDataSource>(
    getMainDemoData("https://www.ag-grid.com/studio/example-assets"),
  );
  const initialState = useMemo<AgReportState>(() => {
    return {
      pages: [{ id: "main", widgets: {}, widgetLayout: {} }],
      selectedPageId: "main",
      panels: {
        filters: { collapsed: true },
        edit: { collapsed: true },
        data: { collapsed: true },
      },
    };
  }, []);
  const ai = useMemo<AgAiAssistant>(() => {
    return {
      ...openaiAdapter({
        endpoint: AI_API_URL,
        key: AI_API_TOKEN,
      }),
      agents: [chartBuilder],
      primaryAgent: "chart-builder",
    };
  }, []);

  return (
    <div style={containerStyle}>
      <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
        <AgStudio
          style={studioStyle}
          className="my-studio-container"
          data={data}
          mode={"edit"}
          initialState={initialState}
          ai={ai}
        />
      </div>
    </div>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <StudioExample />
  </StrictMode>,
);
```

[Live example: Custom Agents](https://www.ag-grid.com/studio/examples/ai-custom-agents/ai-custom-agents-example/reactFunctionalTs/)

## Interface Reference

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `string` |  | Unique identifier for this agent type. |
| `description` | `string` |  | Short description of what this agent does, shown to a delegating agent so it can decide when to hand off. Falls back to type when omitted. |
| `schema` | `Function` |  | Builds the shape that validates this agent's parameters, given the shape builder. Return `s.undefined()` for a param-less agent, or e.g. `s.object({ region: s.string() })` to require parameters. |
| `config` | `Function` |  | Agent configuration. The factory function receives parameters and returns the configuration, allowing dynamic agent behaviour based on input. |

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  | Display name for the agent, shown in UI. |
| `icon` | `string` |  | SVG icon string for the agent, rendered in delegate cards. Uses `currentColor` for theme adaptability. |
| `instructions` | `Function` |  | System instructions that guide the AI's behaviour for this agent. |
| `delegateAgents` | `string[]` |  | Agent types this agent can delegate tasks to. Enables hierarchical task decomposition across specialised agents. |
| `tools` | `AgToolRef[]` |  | Tool names available to this agent for performing actions. |
| `defaultToolCalls` | `{ tool: string; args?: Record<string, unknown> }[]` |  | Tools to call automatically before the agent's first turn, their results prepended to the agent's instructions. Each named tool must be in tools. |

## Next Steps

- [Context](https://www.ag-grid.com/studio/react/ai-context/) - Build agent instructions from live dashboard and data state.
- [Default Agents](https://www.ag-grid.com/studio/react/ai-ax/) - The built-in agents you are extending or replacing.
