---
product: "AG Studio"
title: "Agent Configuration"
description: "Learn how to change the built-in agents - their instructions, their tools and who they delegate to - or declare a team of your own."
framework: angular
version: "3.0.0"
related:
    - title: "Agent Overview"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-agents/"
    - title: "Built-in Agents"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-builtin-agents/"
    - title: "Agent Context"
      url: "https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-context/"
llms: "https://www.ag-grid.com/studio/archive/3.0.0/llms.txt"
---

# Agent Configuration

The built-in agents are a starting point, not a fixed team. You can change what they say, what they can do and who they hand work to, all while keeping Studio's harness and chat panel.

To own the run loop instead, see [Client Tool Runner](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-client-tool-runner/).

## Declare Your Own Team

`builtIn` is a convenience. Declare agents directly and you control every part:

```ts
// Your AgLlmAdapter - see Direct LLM Runner.
const adapter = myOpenAiAdapter({ endpoint: '/api/llm' });

ai: ({ api }) =>
    createAiHarness(api, ({ tools: { studio } }) => ({
        agents: [
            directLlmRunner({
                id: 'analyst',
                adapter,
                instructions: () => 'You build sales dashboards. Prefer bar charts over pie charts.',
                tools: () => [
                    studio.viewSchema(),
                    studio.viewPage(),
                    studio.executeQuery(),
                    studio.addWidget(),
                ],
            }),
        ],
        primary: 'analyst',
    })),
```

The builder hands you the Studio tools on `tools.studio`, so there is no need to call `api.getAiTools()` yourself. Each tool is a function: call it where you list it. Instructions and tools are callbacks, re-resolved every run, and `primary` names the agent a new thread starts from.

The example below declares one agent of its own - a chart builder with its own instructions and a narrow tool set - in place of the default team.

#### Configure Agents

```ts
import '@angular/compiler';
import { provideHttpClient } from '@angular/common/http';
import { bootstrapApplication } from '@angular/platform-browser';

import { AppComponent } from './app.component.ts';

const app = bootstrapApplication(AppComponent, {
    providers: [provideHttpClient()],
});
```

[Live example: Configure Agents](https://www.ag-grid.com/studio/archive/3.0.0/examples/ai-custom-agents/ai-custom-agents-example/angular/)

## Change Instructions

Instructions are a function, so build them from live context rather than hardcoding what the data looks like:

```ts
// Your AgLlmAdapter - see Direct LLM Runner.
const adapter = myOpenAiAdapter({ endpoint: '/api/llm' });

const studio = api.getAiTools();

directLlmRunner({
    id: 'analyst',
    adapter,
    instructions: () => {
        const { tables } = api.getAiContext().schema();
        const names = tables.map((table) => table.name).join(', ');
        return [
            'You build dashboards for the finance team.',
            `Available data: ${names}.`,
            'Currency is GBP. Never mix currencies in one chart.',
            'When asked for a trend, prefer a line chart over a bar chart.',
        ].join('\n');
    },
    tools: () => [studio.viewSchema(), studio.executeQuery()],
});
```

See [Agent Context](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-context/) for everything available to build instructions from.

## Change the Tool Set

The simplest control over what an agent can do is which tools you list. An agent with no mutating tools cannot change the dashboard, whatever the model decides:

```ts
// A read-only analyst: it can look and answer, but not touch the page.
tools: () => [studio.viewSchema(), studio.viewPage(), studio.executeQuery()],
```

Every Studio tool takes the same optional overrides, applied to that listing only:

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  | Advertise the tool under a different name. |
| `description` | `string` |  | Advertise a different description to this agent. |

```ts
tools: () => [
    studio.addWidget({ description: 'Add a widget. Prefer charts; only use a grid when asked for a table.' }),
    // Renamed to avoid a clash with a tool of your own
    studio.executeQuery({ name: 'query_dashboard_data' }),
],
```

A `description` here applies to one agent's listing. To change a description everywhere, use the `aiText` property instead, which is keyed by the name the tool advertises:

```ts
aiText: {
    'tools.add_widget.description': 'Add a widget to the grid. Position is 0-indexed.',
},
```

### Binding a Widget Tool

`configureWidget` is the one tool that takes parameters rather than only overrides. Its schema is narrowed to a single widget type's options, so it has to be told which widget it configures:

```ts
tools: () => [studio.configureWidget({ widgetType: 'grid', widgetId: 'main' })],
```

The built-in widget agent resolves those two values from its delegation parameters, which is how one agent configures whichever widget the lead hands it.

## Add Tools of Your Own

Anything from [`api.defineAiTool`](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-custom-tools/) sits alongside the built-ins in the same array:

```ts
tools: () => [studio.viewSchema(), studio.executeQuery(), setThemeTool, notifyTeamTool],
```

## Change Delegation

`tools.delegateTo` builds the delegation tool for a set of target ids. Give an agent a narrower set and it can only hand off to those:

```ts
// Your AgLlmAdapter - see Direct LLM Runner.
const adapter = myOpenAiAdapter({ endpoint: '/api/llm' });

createAiHarness(api, ({ tools }) => ({
    agents: [
        directLlmRunner({
            id: 'lead',
            adapter,
            instructions: () => 'Coordinate. Delegate data questions; never answer them yourself.',
            tools: () => [tools.studio.viewSchema(), tools.delegateTo(['data'])],
        }),
        directLlmRunner({
            id: 'data',
            adapter,
            description: 'Answers questions about the data by running queries.',
            instructions: () => 'You are a data analyst. Answer with numbers, not adjectives.',
            tools: () => [tools.studio.executeQuery(), tools.studio.viewSchema()],
        }),
    ],
    primary: 'lead',
}));
```

A delegate target needs a `description`, which is what the delegating model reads to decide whether to hand off. Give it delegation parameters with `schema`, and the delegating agent must supply them:

```ts
directLlmRunner<{ region: string }>({
    id: 'regional-analyst',
    adapter,
    description: 'Answers questions about one region.',
    schema: (s) => s.object({ region: s.string() }),
    instructions: ({ region }) => `You only discuss the ${region} region.`,
    tools: () => [studio.executeQuery()],
});
```

`delegate_to`'s schema advertises those parameters, resolved per turn.

> **Warning**
>
> An agent that takes no delegation parameters must declare `schema: (s) => s.undefined()`, not an empty object. A primary agent is run with `undefined` parameters, and an object schema rejects that, so the agent fails to start.

## Mix Built-ins With Your Own

Spread the defaults and add to them. Keep `primary` pointing at whichever agent should front the conversation:

```ts
// Your AgLlmAdapter - see Direct LLM Runner.
const adapter = myOpenAiAdapter({ endpoint: '/api/llm' });

const studio = api.getAiTools();

// An agent of your own, built as in Declare Your Own Team above.
const auditAgent = directLlmRunner({
    id: 'audit',
    adapter,
    description: 'Reviews a page for missing or misleading widgets.',
    instructions: () => 'You review dashboards and report what is missing.',
    tools: () => [studio.viewPage(), studio.viewWidget()],
});

createAiHarness(api, ({ builtIn }) => ({
    agents: [...Object.values(builtIn).map((definition) => directLlmRunner({ ...definition, adapter })), auditAgent],
    primary: 'lead',
}));
```

The built-in lead delegates to a fixed set of ids, so it will not discover `auditAgent` on its own. To have work delegated to it, declare your own lead with a wider `delegateTo`.

## Next

- [Custom Tools](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-custom-tools/) - adding actions of your own
- [Client Tool Runner](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-client-tool-runner/) - owning the loop
- [Built-in Agents](https://www.ag-grid.com/studio/archive/3.0.0/angular/ai-builtin-agents/) - what you are starting from
