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.
If an agent uses simple strings for inputs or outputs, schema definitions are not required.
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.
@tool('Get weather info')getWeatherInfo(weather: WeatherParams): string {return`The weather is rainy today in ${weather.location}.`;}
Tools can only accept objects as parameters, and these objects must have a defined schema.
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
@schema()exportclassSupportResponse { @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.
@schema()classPostList {// 'Post' is a previously defined @schema. @arrayItems(() => Post) items:Post[];}
Defining enum properties
The @enumValues() decorator defines valid values for an enum property.
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 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:
import { model, systemPrompt, Agent, output, input } from'@axarai/axar';import { z } from'zod';// Define input schemaconstGreetingAgentRequestSchema=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 schemaconstGreetingAgentResponseSchema=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 schemastypeGreetingAgentRequest=z.infer<typeof GreetingAgentRequestSchema>;typeGreetingAgentResponse=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)exportclassGreetingAgentextendsAgent<GreetingAgentRequest,GreetingAgentResponse> {}// Instantiate and run the agent(async () => {constresponse=awaitnewGreetingAgent().run({ userName:'Alice', userMood:'happy', dayOfWeek:'Saturday', language:'English', });console.log(response);})();
The @input and @output annotations accept both @schema-based definitions and ZodSchema.
Using Zod with tools
Zod can also define the schema for tool parameters. Here's an example:
import { model, systemPrompt, Agent, tool } from'@axarai/axar';import { z } from'zod';// Define tool parameter schemaconstWeatherParamsSchema=z.object({ location:z.string().describe('Location of the user'),});// Infer TypeScript type from schematypeWeatherParams=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.`)exportclassGreetingAgentextendsAgent<string,string> {// Define a tool for current time @tool('Get current time')getCurrentTime():string {return`The current time is ${newDate().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 () => {constresponse=awaitnewGreetingAgent().run('Hello, my name is Alice. I am from San Francisco.', );console.log(response);})();
When using ZodSchemas with tools, we need to specify the schema as the second argument in the @tool decorator.