Agent

The building blocks of an agentic app

Agents in AXAR AI are the primary building blocks. They represent a tightly coupled set of tasks. Agents can work independently in a developer-defined workflow or collaborate to build more complex autonomous workflows.

Creating an agent

Here’s a simple example of creating an agent in AXAR AI. This agent greets the user by their name.

import { model, systemPrompt, Agent } from "@axarai/axar";

// Specify the AI model used by the agent
@model('openai:gpt-4o-mini')
// Provide a system-level prompt to guide the agent's behavior
@systemPrompt(`Greet the user by their name in a friendly tone.`)
export class GreetingAgent extends Agent<string, string> {
  
}

// Instantiate and run the agent
(async () => {
  const response = await new GreetingAgent().run("My name is Alice.");
  console.log(response); // Output: "Hello, Alice! It's great to meet you! How are you doing today?"
})();

What just happened?

1

Model

The @model decorator sets the AI model to use. Here, it’s using openai:gpt-4o-mini.

2

Prompt

The @systemPrompt decorator defines the agent’s behavior. In this case, the agent greets users by their name in a friendly way.

3

Agent

The GreetingAgent class extends Agent, taking a string as input and returning a string as output.

4

Run

The agent runs with the input "My name is Alice." and generates a friendly greeting based on the system prompt.

Dynamic system prompts

In the previous example, the run() method assumes the user's name is included in the input. But what if the input doesn’t contain the name?

We can handle this by modifying the agent to accept the user's name as a parameter in its constructor(). We can then generate a dynamic system prompt using the provided name. This is done by combining the @systemPrompt annotation with an instance method inside the agent class.

With this setup, the username is passed during instantiation every time and also doesn't need to be included in every run() call.

Here’s how it works:

import { model, systemPrompt, Agent } from "@axarai/axar";

@model('openai:gpt-4o-mini')
@systemPrompt(`
  Greet the user by their name in a friendly tone.
`)
export class GreetingAgent extends Agent<string, string> {
  constructor(private userName: string) {
    super();
  }

  // A dynamic system prompt generated in runtime
  @systemPrompt()
  getUserName(): string {
    return `User's name is: ${this.userName}!`;
  }
}

// Instantiate and run the agent
(async () => {
  const response = await new GreetingAgent('Alice').run('Greet me.');
  console.log(response); // Output: "Hello, Alice! 😊 It's great to see you! How are you doing today?"
})();

The above example also shows how to inject external dependencies to an agent. Anything passed into the agent's constructor() can be accessed within the agent throughout its lifetime.

Structured I/O

So far, we’ve seen how to pass a string to an agent and get a string response. However, in many cases, we might want our agent to handle structured input and output for better control, validation, and clarity. AXAR makes this possible with schemas, allowing us to define structured data formats for both input and output.

The following example demonstrates a GreetingAgent that takes structured input, including the user's name, mood, day of the week, and language preference. The agent then generates structured output with a greeting, a response to the user's mood, and an optional weekend message.

import {
  model,
  systemPrompt,
  Agent,
  schema,
  property,
  output,
  input,
  optional,
} from '@axarai/axar';

@schema()
class GreetingAgentRequest {
  @property("User's full name")
  userName!: string;

  @property("User's current mood")
  userMood!: 'happy' | 'neutral' | 'sad';

  @property('Day of the week')
  dayOfWeek!: string;

  @property("User's language preference")
  language!: string;
}

@schema()
class GreetingAgentResponse {
  @property("A greeting message to cater to the user's mood")
  greeting!: string;

  @property("A line acknowledging the user's mood")
  moodResponse!: string;

  @property("A personalized message only if it's the weekend")
  @optional()
  weekendMessage?: string;
}


@model('openai:gpt-4o-mini')
@systemPrompt(`Greet the user by their name in a friendly tone in their preferred language.`)
@input(GreetingAgentRequest)
@output(GreetingAgentResponse)
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);
})();

Running agents

AXAR AI provides two methods for running agents:

agent.run()

The run() method is an asynchronous function that processes the input and returns the complete output in a single response.

const greetingAgent = new GreetingAgent();
const response = await greetingAgent.run(input);
console.log(response);

agent.stream()

The stream() method provides a streaming interface that yields partial results as they become available, useful for real-time UI updates or processing long responses.

const greetingAgent = new GreetingAgent();
const { stream } = await agent.stream(input);
for await (const chunk of stream) {
    // Process each chunk as it arrives
    console.log(chunk);
}

Both methods support the full range of AXAR AI features including:

  • Input/output schema validation

  • Tool execution

  • Telemetry and monitoring

  • Error handling

  • Model configuration

Last updated