Skip to main content

ag_kit_py.agents

The Agents module provides the core abstractions and implementations for building AI agents with AG-Kit. It defines the base agent interface and provides framework-specific implementations like LangGraph.

Installation

pip install ag_kit_py

Available Agents

Agent TypeClassStatusDescription
LangGraphLangGraphAgent✅ AvailableLangGraph-based agent with stability patches
BaseBaseAgent✅ AvailableAbstract base class for custom agents

Quick Start

Creating a LangGraph Agent

from ag_kit_py.agents import LangGraphAgent
from ag_kit_py.providers import create_provider
from langgraph.graph import StateGraph, MessagesState

# Create provider
provider = create_provider("openai")
model = provider.get_langchain_model()

# Define chat node
def chat_node(state: MessagesState):
    response = model.invoke(state["messages"])
    return {"messages": [response]}

# Build workflow
workflow = StateGraph(MessagesState)
workflow.add_node("chat", chat_node)
workflow.set_entry_point("chat")
workflow.set_finish_point("chat")

# Compile and create agent
graph = workflow.compile()
agent = LangGraphAgent(
    name="ChatAgent",
    description="A conversational agent",
    graph=graph
)

Using with Server

from ag_kit_py.server import AGKitAPIApp

def create_agent():
    return {"agent": agent}

AGKitAPIApp().run(create_agent, port=8000)

BaseAgent

Abstract base class that all agents must extend.

Class Definition

from abc import ABC, abstractmethod
from typing import Any, AsyncGenerator
from ag_ui.core import BaseEvent, RunAgentInput

class BaseAgent(ABC):
    """Abstract base class for all AG-Kit agents."""
    
    def __init__(self, name: str, description: str, agent: Any):
        """Initialize the base agent.
        
        Args:
            name: Human-readable name for the agent
            description: Detailed description of the agent's purpose
            agent: The underlying agent implementation
        """
        self._name = name
        self._description = description
        self._agent = agent

Properties

name

Get the agent name.
@property
def name(self) -> str:
    """Get the agent name."""
    return self._name

description

Get the agent description.
@property
def description(self) -> str:
    """Get the agent description."""
    return self._description

agent

Get the underlying agent implementation.
@property
def agent(self) -> Any:
    """Get the underlying agent instance."""
    return self._agent

Abstract Methods

run()

Execute the agent with the given input.
@abstractmethod
async def run(
    self, 
    run_input: RunAgentInput
) -> AsyncGenerator[BaseEvent, None]:
    """Execute the agent with the given input.
    
    Args:
        run_input: Input data for agent execution
        
    Yields:
        BaseEvent: Events representing execution progress
    """

Concrete Methods

destroy()

Clean up resources used by the agent.
def destroy(self) -> None:
    """Clean up resources used by the agent."""
    pass

RunAgentInput

Input data structure for agent execution.
from ag_ui.core import RunAgentInput
from typing import Any, Dict, List

class RunAgentInput:
    """Input data for agent execution."""
    
    messages: List[Dict[str, Any]]      # Conversation messages
    run_id: str                         # Unique run identifier
    thread_id: str                      # Thread/conversation identifier
    state: Dict[str, Any]               # Agent state
    context: List[Any]                  # Additional context
    tools: List[Any]                    # Available tools
    forwarded_props: Dict[str, Any]     # Forwarded properties

BaseEvent

Base event class for agent execution events.
from ag_ui.core import BaseEvent, EventType

class BaseEvent:
    """Base event for agent execution."""
    
    type: EventType                     # Event type
    thread_id: str                      # Thread identifier
    run_id: str                         # Run identifier
    raw_event: Any                      # Raw event data

Event Types

from ag_ui.core import EventType

# Available event types
EventType.RUN_STARTED              # Agent execution started
EventType.RUN_FINISHED             # Agent execution finished
EventType.RUN_ERROR                # Agent execution error
EventType.TEXT_MESSAGE_START       # Text message started
EventType.TEXT_MESSAGE_CONTENT     # Text message content chunk
EventType.TEXT_MESSAGE_END         # Text message ended
EventType.TOOL_CALL_START          # Tool call started
EventType.TOOL_CALL_ARGS           # Tool call arguments (streaming)
EventType.TOOL_CALL_END            # Tool call ended
EventType.TOOL_CALL_RESULT         # Tool call result
EventType.CUSTOM                   # Custom event

Creating Custom Agents

To create a custom agent, extend BaseAgent and implement the run method:
from ag_kit_py.agents import BaseAgent
from ag_ui.core import RunAgentInput, BaseEvent, EventType
from typing import AsyncGenerator

class CustomAgent(BaseAgent):
    """Custom agent implementation."""
    
    def __init__(self, name: str, description: str, custom_config: dict):
        # Initialize your custom agent
        agent_impl = create_custom_agent(custom_config)
        super().__init__(name, description, agent_impl)
    
    async def run(
        self, 
        run_input: RunAgentInput
    ) -> AsyncGenerator[BaseEvent, None]:
        """Execute the custom agent."""
        # Emit run started event
        yield BaseEvent(
            type=EventType.RUN_STARTED,
            thread_id=run_input.thread_id,
            run_id=run_input.run_id
        )
        
        try:
            # Execute your agent logic
            result = await self._agent.execute(run_input)
            
            # Emit result events
            yield BaseEvent(
                type=EventType.TEXT_MESSAGE_CONTENT,
                thread_id=run_input.thread_id,
                run_id=run_input.run_id,
                raw_event={"data": {"chunk": {"content": result}}}
            )
            
            # Emit run finished event
            yield BaseEvent(
                type=EventType.RUN_FINISHED,
                thread_id=run_input.thread_id,
                run_id=run_input.run_id
            )
        except Exception as e:
            # Emit error event
            yield BaseEvent(
                type=EventType.RUN_ERROR,
                thread_id=run_input.thread_id,
                run_id=run_input.run_id,
                raw_event={"error": str(e)}
            )
    
    def destroy(self) -> None:
        """Clean up resources."""
        # Implement cleanup logic
        self._agent.cleanup()

Best Practices

1. Use Type Hints

from ag_kit_py.agents import BaseAgent
from ag_ui.core import RunAgentInput, BaseEvent
from typing import AsyncGenerator

class MyAgent(BaseAgent):
    async def run(
        self, 
        run_input: RunAgentInput
    ) -> AsyncGenerator[BaseEvent, None]:
        # Type hints improve code quality
        pass

2. Handle Errors Gracefully

async def run(self, run_input: RunAgentInput) -> AsyncGenerator[BaseEvent, None]:
    try:
        # Agent logic
        yield event
    except Exception as e:
        # Always emit error events
        yield BaseEvent(
            type=EventType.RUN_ERROR,
            thread_id=run_input.thread_id,
            run_id=run_input.run_id,
            raw_event={"error": str(e)}
        )

3. Clean Up Resources

def destroy(self) -> None:
    """Always implement cleanup."""
    if hasattr(self._agent, 'close'):
        self._agent.close()
    if hasattr(self, '_db_connection'):
        self._db_connection.close()

4. Use Async/Await

async def run(self, run_input: RunAgentInput) -> AsyncGenerator[BaseEvent, None]:
    # Use async operations for better performance
    result = await self._agent.async_execute(run_input)
    yield result

5. Emit Appropriate Events

async def run(self, run_input: RunAgentInput) -> AsyncGenerator[BaseEvent, None]:
    # Always emit RUN_STARTED
    yield BaseEvent(type=EventType.RUN_STARTED, ...)
    
    try:
        # Emit progress events
        yield BaseEvent(type=EventType.TEXT_MESSAGE_CONTENT, ...)
        
        # Always emit RUN_FINISHED on success
        yield BaseEvent(type=EventType.RUN_FINISHED, ...)
    except Exception as e:
        # Always emit RUN_ERROR on failure
        yield BaseEvent(type=EventType.RUN_ERROR, ...)