> For the complete documentation index, see [llms.txt](https://axar-ai.gitbook.io/axar/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://axar-ai.gitbook.io/axar/basics/schema.md).

# Schema

AXAR uses structured input and output to provide a consistent and reliable way to work with agents and tools. It adopts a decorator-based approach that works seamlessly with TypeScript's strong typing. AXAR allows us to define object schema with decorators for metadata, validation, and property descriptions. Alternatively, AXAR also supports Zod, offering a flexible option for schema definitions alongside the decorator-based approach.

### Where schemas are needed

Schemas are necessary in the following contexts:

**Agent input and output**

Schemas define the format of data that an agent receives and returns. For example, in the code below, the `GreetingAgent` takes input of type `GreetingAgentRequest` and produces output of type `GreetingAgentResponse`. We  must define schema definitions for both.

```typescript
@input(GreetingAgentRequest)
@output(GreetingAgentResponse)
export class GreetingAgent extends Agent<
  GreetingAgentRequest,
  GreetingAgentResponse
> {}
```

{% hint style="info" %}
If an agent uses simple strings for inputs or outputs, schema definitions are not required.
{% endhint %}

**Tool parameters**

Schemas describe the format of objects passed as parameters to tools. In the example below, the tool `getWeatherInfo()` accepts a parameter of type `WeatherParams`. A schema definition is required for this type.

```tsx
@tool('Get weather info')
getWeatherInfo(weather: WeatherParams): string {
  return `The weather is rainy today in ${weather.location}.`;
}
```

{% hint style="info" %}
Tools can only accept objects as parameters, and these objects must have a defined schema.
{% endhint %}

### Defining a schema

Schemas are defined using TypeScript classes annotated with `@schema()`. Each property of that class must have a `@property()` decorator that describes its purpose.

* **Required properties**: Use `!` after the property name.
* **Optional properties**: Use `?` and include the `@optional()` decorator.

#### **Example: Complete schema definition**

```tsx
@schema()
export class SupportResponse {
  @property('Human-readable advice to give to the customer.')
  support_advice!: string;

  @property("Indicates whether the customer's card should be blocked.")
  block_card!: boolean;

  @property('Risk level of the query (0 to 1).')
  @min(0)
  @max(1)
  risk!: number;

  @property("Customer's emotional state.")
  @enumValues(['Happy', 'Sad', 'Neutral'])
  @optional()
  status?: 'Happy' | 'Sad' | 'Neutral';
}
```

#### Special annotations for enums and arrays

**Defining array items**

The `@arrayItems()` decorator specifies the schema for array elements.

```tsx
@schema()
class PostList {
  // 'Post' is a previously defined @schema.
  @arrayItems(() => Post)
  items: Post[];
}
```

**Defining enum properties**

The `@enumValues()` decorator defines valid values for an enum property.

```tsx
@schema()
class User {
  @enumValues(['admin', 'user', 'guest'])
  role: 'admin' | 'user' | 'guest';
}
```

#### Validation decorators

AXAR includes a set of validation decorators to apply constraints on schema properties:

* **Range**: `@min(value)`, `@max(value)`
* **Optional**: `@optional()`
* **Uniqueness**: `@uniqueItems()` (for arrays)
* **Pattern matching**: `@pattern(regex)`
* **Common formats**: `@email()`, `@url()`, `@uuid()`, `@datetime()`, etc.

### Using Zod with AXAR

[Zod](https://zod.dev) is a popular TypeScript library for runtime type validation and schema definitions. AXAR supports using Zod schemas alongside its decorator-based schema definition approach.

#### Defining Agent Input and Output with Zod

We can define agent input and output schemas using Zod. Here's an example:

```typescript
import { model, systemPrompt, Agent, output, input } from '@axarai/axar';
import { z } from 'zod';

// Define input schema
const GreetingAgentRequestSchema = z.object({
  userName: z.string().describe('User name'),
  userMood: z.enum(['happy', 'neutral', 'sad']).describe('User mood'),
  dayOfWeek: z.string().describe('Day of the week'),
  language: z.string().describe('User language preference'),
});

// Define output schema
const GreetingAgentResponseSchema = z.object({
  greeting: z.string().describe('Greeting message to cater to the user mood'),
  moodResponse: z.string().describe('Line acknowledging the user mood'),
  weekendMessage: z
    .string()
    .describe('Personalized message if it is the weekend'),
});

// Infer TypeScript types from schemas
type GreetingAgentRequest = z.infer<typeof GreetingAgentRequestSchema>;
type GreetingAgentResponse = z.infer<typeof GreetingAgentResponseSchema>;

// Create the agent
@model('openai:gpt-4o-mini')
@systemPrompt(
  `Greet the user by their name in a friendly tone in their preferred language.`,
)
@input(GreetingAgentRequestSchema)
@output(GreetingAgentResponseSchema)
export class GreetingAgent extends Agent<
  GreetingAgentRequest,
  GreetingAgentResponse
> {}

// Instantiate and run the agent
(async () => {
  const response = await new GreetingAgent().run({
    userName: 'Alice',
    userMood: 'happy',
    dayOfWeek: 'Saturday',
    language: 'English',
  });
  console.log(response);
})();

```

{% hint style="success" %}
The `@input` and `@output` annotations accept both `@schema`-based definitions and `ZodSchema`.
{% endhint %}

#### Using Zod with tools

Zod can also define the schema for **tool** parameters. Here's an example:

```typescript
import { model, systemPrompt, Agent, tool } from '@axarai/axar';
import { z } from 'zod';

// Define tool parameter schema
const WeatherParamsSchema = z.object({
  location: z.string().describe('Location of the user'),
});

// Infer TypeScript type from schema
type WeatherParams = z.infer<typeof WeatherParamsSchema>;

// Create the agent
@model('openai:gpt-4o-mini')
@systemPrompt(`
  Greet the user based on the current time and weather.
  Get the current time and weather if you need it.
`)
export class GreetingAgent extends Agent<string, string> {
  // Define a tool for current time
  @tool('Get current time')
  getCurrentTime(): string {
    return `The current time is ${new Date().toLocaleString()}.`;
  }

  // Define a tool with a Zod schema for parameters
  @tool('Get weather info', WeatherParamsSchema)
  getWeatherInfo(weather: WeatherParams): string {
    return `The weather is rainy today in ${weather.location}.`;
  }
}

// Instantiate and run the agent
(async () => {
  const response = await new GreetingAgent().run(
    'Hello, my name is Alice. I am from San Francisco.',
  );
  console.log(response);
})();

```

{% hint style="success" %}
When using `ZodSchema`s with **tools**, we need to specify the schema as the second argument in the `@tool` decorator.&#x20;
{% endhint %}
