> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Defining an Agent

> Subclass Chat, implement four getters, and register the agent with the container

An agent is a class that extends the abstract `Chat` base. You describe *what* the agent is — its model, system prompts, tools, and middleware — and the base class owns *how* those pieces are wired into the agent loop. You never call the model directly.

## The four getters

Every agent implements exactly four abstract getters:

```typescript theme={null}
import { Chat, decorator } from "@ooneex/ai";
import type { AiMiddlewareClassType, AiToolClassType } from "@ooneex/ai";

@decorator.chat()
class ResearchChat extends Chat {
  /** OpenRouter `provider/model` identifier. */
  public getModel = (): string => "anthropic/claude-sonnet-4.5";

  /** System prompts prepended to every conversation. */
  public getSystemPrompts = (): string[] => [
    "You are a research assistant.",
    "Always cite your sources.",
  ];

  /** Tool classes the model may call. */
  public getTools = (): AiToolClassType[] => [];

  /** Middleware classes applied to every run. */
  public getMiddlewares = (): AiMiddlewareClassType[] => [];
}
```

| Getter             | Returns                   | Purpose                                                           |
| ------------------ | ------------------------- | ----------------------------------------------------------------- |
| `getModel`         | `string`                  | OpenRouter model in `provider/model` form.                        |
| `getSystemPrompts` | `string[]`                | Base prompts, prepended before any per-request prompts.           |
| `getTools`         | `AiToolClassType[]`       | [Tool](/ai/agents/tools) classes available for function calling.  |
| `getMiddlewares`   | `AiMiddlewareClassType[]` | [Middleware](/ai/agents/middleware) classes applied to every run. |

Tools and middleware are returned as **class references**, not instances. The base class resolves each one from the DI container on demand, so any constructor dependencies are injected automatically.

<Note>
  Return empty arrays for `getTools` and `getMiddlewares` when you don't need them — both getters are required even when the agent is a plain chat.
</Note>

## Registering with the container

The `decorator.chat()` decorator registers the agent class with the [container](/advanced/dependency-injection) so it can be resolved and have its own dependencies injected:

```typescript theme={null}
import { container } from "@ooneex/container";

const chat = container.get(ResearchChat);
const answer = await chat.run<string>({ prompt: "What is RAG?" });
```

By default the agent is registered as a **singleton** — one shared instance. Pass a scope to change that:

```typescript theme={null}
import { EContainerScope } from "@ooneex/container";

@decorator.chat(EContainerScope.Transient)
class PerCallChat extends Chat {
  // ...
}
```

| Scope                   | Behavior                                    |
| ----------------------- | ------------------------------------------- |
| `Singleton` *(default)* | One instance reused everywhere.             |
| `Request`               | One instance per request scope.             |
| `Transient`             | A fresh instance every time it is resolved. |

## Injecting dependencies

Because the agent is container-managed, you can inject services into its constructor and use them inside the getters — for example to read prompts from configuration or to build the tool list dynamically:

```typescript theme={null}
import { inject } from "@ooneex/container";
import { AppEnv } from "@ooneex/app-env";

@decorator.chat()
class ConfiguredChat extends Chat {
  public constructor(@inject(AppEnv) private readonly env: AppEnv) {
    super();
  }

  public getModel = (): string => "anthropic/claude-sonnet-4.5";
  public getSystemPrompts = (): string[] => [`Environment: ${this.env.APP_ENV}`];
  public getTools = (): AiToolClassType[] => [];
  public getMiddlewares = (): AiMiddlewareClassType[] => [];
}
```

## Inspecting an agent

The base class exposes read-only getters that mirror what was configured — handy for tests, logging, or building admin views:

```typescript theme={null}
chat.getModel();          // "anthropic/claude-sonnet-4.5"
chat.getSystemPrompts();  // ["You are a research assistant.", ...]
chat.getTools();          // [ ...tool classes ]
chat.getMiddlewares();    // [ ...middleware classes ]
```

Next, learn how to [run the agent](/ai/agents/running) and pass per-request input.
