Agent class

The Agent class is the core class in Agenite that orchestrates interactions between LLMs and tools.

Constructor

new Agent<
  Reducer extends AnyStateReducer = typeof defaultStateReducer,
  Steps extends BaseSteps = typeof defaultStepConfig,
  Middlewares extends BaseMiddlewares = [],
  Extensions extends Record<string, unknown> | undefined = undefined
>({
  name: string;
  provider: LLMProvider;
  tools?: Tool[];
  instructions?: string;
  description?: string;
  agents?: Agent[];
  stateReducer?: Reducer;
  initialState?: Partial<StateFromReducer<Reducer>>;
  steps?: Steps;
  startStep?: string;
  middlewares?: Middlewares;
  extensions?: Extensions;
})

Parameters

  • name (required): Unique identifier for the agent
  • provider (required): LLM provider instance
  • tools: Array of tools available to the agent
  • instructions: System instructions for the agent (default: “You are a helpful assistant.”)
  • description: Description of the agent’s purpose
  • agents: Sub-agents that can be called by this agent
  • stateReducer: Custom state management functions
  • initialState: Initial agent state
  • steps: Custom execution steps
  • startStep: First step to execute (default: “agenite.llm-call”)
  • middlewares: Array of middleware functions to modify agent behavior
  • extensions: Additional custom functionality

Methods

execute

Execute the agent with a set of inputs.

execute(
  input: Partial<StateFromReducer<Reducer>>,
  options?: ExecutionOptions
): Promise<{
  messages: BaseMessage[];
  tokenUsage: TokenUsage;
  [key: string]: unknown;
}>
Parameters
  • input (required): Input state, typically containing messages
  • options: Additional execution options
    • stream: Enable streaming responses
    • context: Additional execution context
    • parentExecution: Context from a parent execution (for nested agents)
Returns

Returns the final state object containing:

  • messages: Array of messages from the conversation
  • tokenUsage: Token usage statistics
  • Additional properties from the state

iterate

Get an iterator for streaming responses.

iterate(
  input: Partial<StateFromReducer<Reducer>>,
  options?: ExecutionOptions
): AsyncGenerator<YieldValue, ReturnValue, NextValue>
Parameters

Same as execute

Returns

An AsyncGenerator that yields various events during execution:

// Example yield types
{ type: 'agenite.start', executionContext: StepContext }
{ type: 'agenite.llm-call.input', content: { messages, instructions, tools } }
{ type: 'agenite.llm-call.streaming', content: PartialReturn }
{ type: 'agenite.tool-call.params', toolUseBlocks: ToolUseBlock[], hasAgentCall: boolean }
{ type: 'agenite.end', executionContext: StepContext }

State and Messages

State Structure

The agent maintains state which typically includes at minimum:

interface DefaultState {
  messages: BaseMessage[];
  [key: string]: unknown;
}

Message Structure

Messages follow the structure defined in the LLM package:

interface BaseMessage {
  role: 'user' | 'assistant' | 'system';
  content: ContentBlock[];
}

type ContentBlock =
  | TextBlock        // { type: 'text', text: string }
  | ImageBlock       // { type: 'image', source: { type: 'url', url: string } | { type: 'base64', ... } }
  | ToolUseBlock     // { type: 'toolUse', id: string, name: string, input: unknown }
  | ToolResultBlock  // { type: 'toolResult', toolUseId: string, toolName: string, content?: string | Array<...> }
  | DocumentBlock    // { type: 'document', source: { ... } }
  | ThinkingBlock    // { type: 'thinking', thinking: string }
  | RedactedThinkingBlock; // { type: 'redactedThinking', redactedThinking: string }

Step Interface

Custom steps implement the Step interface:

interface Step<
  ReturnValue,
  YieldValue,
  Params,
  Context
> {
  name: string;
  beforeExecute?: (context: Context) => Promise<Params>;
  execute: (params: Params, context: Context) => AsyncGenerator<
    YieldValue,
    ReturnValue,
    NextValue
  >;
  afterExecute?: (
    result: ReturnValue,
    context: Context
  ) => Promise<ReturnValue>;
}

Middleware Interface

Middlewares wrap the generator function:

type Middleware<
  YieldValue = unknown,
  ReturnValue = unknown,
  NextValue = unknown
> = (
  generator: AsyncGenerator<YieldValue, ReturnValue, NextValue>,
  context: StepContext<AnyStateReducer>
) => AsyncGenerator<YieldValue, ReturnValue, NextValue>;

Examples

Basic usage

import { Agent } from '@agenite/agent';
import { Ollama } from '@agenite/ollama';
import { Calculator } from '@agenite/tool';

const agent = new Agent({
  name: 'simple-agent',
  provider: new Ollama({ model: 'llama3.2' }),
  tools: [new Calculator()],
  instructions: 'You are a helpful assistant.',
});

const result = await agent.execute({
  messages: [
    {
      role: 'user',
      content: [{ type: 'text', text: 'What is 137 * 456?' }],
    },
  ],
});

console.log(result.messages[result.messages.length - 1].content);

With custom state

interface ChatState {
  messages: BaseMessage[];
  messageCount: number;
  lastMessage: string;
}

const agent = new Agent<{
  messageCount: (newValue: number, prevValue?: number) => number;
  lastMessage: (newValue: string) => string;
}>({
  name: 'stateful-agent',
  provider: new Ollama({ model: 'llama3.2' }),
  initialState: {
    messages: [],
    messageCount: 0,
    lastMessage: '',
  },
  stateReducer: {
    messageCount: (_, prev = 0) => prev + 1,
    lastMessage: (newValue) => newValue,
  },
});

With middleware

import { prettyLogger } from '@agenite/middleware-pretty-logger';

const agent = new Agent({
  name: 'middleware-agent',
  provider: new Ollama({ model: 'llama3.2' }),
  middlewares: [
    prettyLogger(),
    // Custom middleware example
    (generator, context) => {
      return (async function* () {
        for await (const value of generator) {
          // Do something with each yielded value
          console.log(`Event: ${value.type}`);
          yield value;
        }
      })();
    }
  ],
});

With custom steps

const agent = new Agent({
  name: 'custom-steps-agent',
  provider: new Ollama({ model: 'llama3.2' }),
  steps: {
    'custom.confirmation': {
      name: 'custom.confirmation',
      execute: async function* (params, context) {
        const response = yield {
          type: 'custom.needs-confirmation',
          message: 'Do you want to proceed?',
        };
        
        if (response?.confirmed) {
          return { next: 'agenite.llm-call', state: {} };
        } else {
          return { next: 'agenite.end', state: {} };
        }
      }
    },
    // Include default steps here if needed
    'agenite.llm-call': LLMStep,
    'agenite.tool-call': ToolStep,
  },
  // Start with the custom step instead of the default
  startStep: 'custom.confirmation',
});

Next steps