API Reference

This section contains the complete API reference for python-agents.

Client

LLM client with tool calling capabilities.

This module provides the LLMClient class, which wraps the OpenAI API to provide a simple interface for interacting with Large Language Models. It supports automatic tool calling, where Python functions are converted to tool schemas and executed when the LLM requests them.

class python_agents.client.BaseLLMClient[source]

Bases: ABC

Abstract base class for LLM clients.

abstractmethod async invoke(query, model_name=None, verbose=False)[source]
class python_agents.client.MCPClient[source]

Bases: object

__init__()[source]
async cleanup()[source]
async connect_to_server(command, arguments)[source]

Connect to an MCP server.

async list_available_tools()[source]
async call_tool(tool_name, tool_args)[source]
class python_agents.client.LLMClient(model_name, base_url='https://openrouter.ai/api/v1')[source]

Bases: BaseLLMClient

Client for interacting with Large Language Models with tool calling support.

LLMClient provides a high-level interface for calling LLMs through the OpenAI API. It automatically handles tool registration, schema generation from Python functions, and tool execution when requested by the LLM. By default, it uses OpenRouter as the API endpoint, but can be configured for any OpenAI-compatible service.

model_name

Default model to use for LLM calls (e.g., “openai/gpt-4”).

Type:

str

client

Underlying async OpenAI client.

Type:

AsyncOpenAI

tools

Dictionary mapping tool names to their functions and schemas.

Type:

dict

Example

Basic usage without tools:

client = LLMClient("openai/gpt-4.1-mini")
response = await client.invoke("What is 2+2?")
print(response.message.content)

Using tools with automatic function calling:

def calculator(operation: str, a: int, b: int) -> int:
    '''Perform arithmetic operations.

    Args:
        operation: The operation ('+', '-', '*', '/')
        a: First number
        b: Second number

    Returns:
        Result of the operation
    '''
    if operation == "+":
        return a + b
    # ... more operations

client = LLMClient("openai/gpt-4-turbo")
client.add_tool(calculator)
response = await client.invoke("What is 15 + 27?")
# LLM will automatically call calculator tool
__init__(model_name, base_url='https://openrouter.ai/api/v1')[source]

Initialize the LLM client.

Parameters:
  • model_name (str, optional) – Default model name to use for requests. Can be overridden per request. Format depends on the API provider (e.g., “openai/gpt-4-turbo” for OpenRouter). Defaults to None.

  • base_url (str, optional) – Base URL for the OpenAI-compatible API. Defaults to “https://openrouter.ai/api/v1”.

Note

Requires OPENAI_API_KEY environment variable to be set for authentication. When using OpenRouter, this should be your OpenRouter API key.

async cleanup()[source]

Cleanup resources that were acquired and used by the LLMClient.

add_mcp_server(mcp_client)[source]

Register an MCPClient as a tool provider.

The tools available from the MCPClient will be made available to the LLM for function calling.

Parameters:

mcp_client (MCPClient) – An instance of MCPClient connected to an MCP server.

add_tool(func)[source]

Register a Python function as a tool that the LLM can call.

The function is automatically converted to an OpenAI function schema using introspection of the function signature, type hints, and docstring. The LLM can then request to call this tool during conversation.

Parameters:

func (callable) – A Python function to register as a tool. The function should have: - Type hints for all parameters - A clear docstring describing what it does - A descriptive name All parameters must be JSON-serializable types (str, int, float, bool).

Example:

def get_weather(location: str, units: str = "celsius") -> str:
    '''Get the weather for a location.

    Args:
        location: City name
        units: Temperature units (celsius or fahrenheit)
    '''
    # Implementation
    return f"Weather in {location}: 20°{units[0].upper()}"

client.add_tool(get_weather)

Note

The function will be called synchronously when the LLM requests it, and the result will be stringified before being returned to the LLM.

async invoke(query, model_name=None, verbose=False)[source]

Send a query to the LLM and handle any tool calls.

This is the main method for interacting with the LLM. It accepts various input formats, calls the LLM, automatically executes any requested tool calls, and returns the final response. The method handles one round of tool calling - if the LLM requests tools, they are all executed, and then a final LLM call is made with the tool results.

Parameters:
  • query (list[Message] | Message | str) – The input to send to the LLM. Can be: - str: Converted to a single user message - Message: Single message to send - list[Message]: Full conversation history

  • model_name (str, optional) – Model to use for this request. Overrides the default model_name set during initialization. Defaults to None.

  • verbose (bool, optional) – If True, prints response content to stdout when no tools are called. Defaults to False.

Returns:

The LLM’s response containing the message content.

Access the text response via response.message.content.

Return type:

ChatCompletionChoice

Raises:
  • ValueError – If query is not a str, Message, or list[Message].

  • RuntimeError – If the LLM requests an unregistered tool.

Example:

# String query
response = await client.invoke("Hello!")

# With message history
messages = [
    Message(role="system", content="You are helpful"),
    Message(role="user", content="Hi")
]
response = await client.invoke(messages)

# Override model
response = await client.invoke("Quick question", model_name="openai/gpt-3.5-turbo")

Note

This method only handles ONE round of tool calling. For multi-step reasoning with multiple tool call rounds, use ReactAgent instead.

Agents

REACT agent implementation for step-by-step reasoning and acting.

This module provides the ReactAgent class, which implements the REACT (Reasoning and Acting) pattern for AI agents. REACT agents combine reasoning about problems with taking actions (via tool calls) in an iterative loop, continuing until a task is completed or a maximum number of iterations is reached.

class python_agents.agents.ReactAgent(client, max_iterations=10)[source]

Bases: object

Agent that uses iterative reasoning and acting (REACT) to solve tasks.

ReactAgent implements the REACT pattern where the agent follows a loop of: 1. Reasoning about what to do next 2. Acting by calling tools to gather information or perform actions 3. Observing the results 4. Repeating until the task is complete

The agent uses a system prompt that guides it to think step-by-step, call tools when needed, and provide a final answer when done. The loop continues until the agent includes “Final Answer:” in its response or max_iterations is reached.

client

The LLM client used to interact with the language model. Should have any required tools already registered via add_tool().

Type:

LLMClient

max_iterations

Maximum number of reasoning/acting iterations before stopping.

Type:

int

iteration_count

Current iteration number (set during run()).

Type:

int

task_completed

Whether the agent has completed the task (set during run()).

Type:

bool

Example

Basic usage with tools:

def search_web(query: str) -> str:
    '''Search the web for information.

    Args:
        query: Search query string

    Returns:
        Search results as text
    '''
    # Implementation
    return "Search results..."

client = LLMClient("openai/gpt-4-turbo")
client.add_tool(search_web)

agent = ReactAgent(client, max_iterations=5)
result = await agent.run("What is the capital of France?", verbose=True)
print(result)  # Will include "Final Answer: Paris"

With multiple tools and complex reasoning:

agent = ReactAgent(client, max_iterations=10)
result = await agent.run(
    "Find the weather in Tokyo and calculate the temperature in Fahrenheit",
    verbose=True
)
# Agent will:
# 1. Think about what tools to use
# 2. Call weather tool for Tokyo
# 3. Observe the celsius result
# 4. Call calculator to convert to Fahrenheit
# 5. Provide final answer with both values
__init__(client, max_iterations=10)[source]

Initialize a ReactAgent.

Parameters:
  • client (LLMClient) – The LLM client to use. Tools should be registered on this client before creating the agent.

  • max_iterations (int, optional) – Maximum number of reasoning iterations before stopping. Prevents infinite loops. Defaults to 10.

async run(task, verbose=False)[source]

Run the agent on a task using iterative reasoning and acting.

This method executes the REACT loop: the agent reasons about the task, calls tools as needed, observes results, and repeats until it provides a final answer or reaches max_iterations. The conversation history is maintained across iterations, with the REACT system prompt prepended to guide the agent’s behavior.

Parameters:
  • task (str) – The task or question for the agent to solve. Should be a clear description of what you want the agent to accomplish.

  • verbose (bool, optional) – If True, prints iteration numbers and agent responses to stdout for debugging. Defaults to False.

Returns:

The final response from the agent, which should include “Final Answer:”

followed by the result. If max_iterations is reached before completion, returns the last response received.

Return type:

str

Example:

# Simple task
agent = ReactAgent(client)
result = await agent.run("What is 25 * 4?")

# Complex task with verbose output
result = await agent.run(
    "Research the population of New York City and compare it to Los Angeles",
    verbose=True
)
# Prints iteration progress and all agent reasoning steps

Note

  • The agent’s iteration_count and task_completed attributes are set during execution

  • If the agent doesn’t complete within max_iterations, task_completed will be False

  • All conversation history (including tool calls and results) is maintained throughout

  • The REACT system prompt is automatically added as the first message

Tools

Tool schema generation and conversion utilities.

This module provides utilities for converting Python functions and MCP tools into OpenAI-compatible tool schemas. It handles automatic schema generation through function introspection, extracting type information from annotations and documentation from docstrings.

class python_agents.tools.ParameterSchema[source]

Bases: TypedDict

type: str
description: str | None
default: Any | None
class python_agents.tools.ToolFunctionSchema[source]

Bases: TypedDict

name: str
description: str
parameters: dict[str, ParameterSchema] | dict[str, Any]
class python_agents.tools.ToolSchema[source]

Bases: TypedDict

type: str
function: ToolFunctionSchema
python_agents.tools.create_tool_schema(func)[source]

Generate an OpenAI tool schema from a Python function.

This function uses introspection to automatically create a tool schema in OpenAI’s function calling format. It extracts parameter information from the function signature, including type hints and default values, and uses the function’s docstring as the tool description.

Type mapping:
  • int → “integer”

  • float → “number”

  • str → “string”

  • bool → “boolean”

  • Other types → “string” (default)

Parameters without default values are marked as required in the schema.

Parameters:

func (callable) – A Python function to convert into a tool schema. Should have type hints for parameters and a descriptive docstring.

Returns:

A tool schema in OpenAI format with structure:

{
    "type": "function",
    "function": {
        "name": str,
        "description": str,
        "parameters": {
            "type": "object",
            "properties": dict,
            "required": list[str]
        }
    }
}

Return type:

dict

Example

Converting a simple function to a tool schema:

def add_numbers(a: int, b: int) -> int:
    '''Add two numbers together.'''
    return a + b

schema = create_tool_schema(add_numbers)
# Returns:
# {
#     "type": "function",
#     "function": {
#         "name": "add_numbers",
#         "description": "Add two numbers together.",
#         "parameters": {
#             "type": "object",
#             "properties": {
#                 "a": {"type": "integer"},
#                 "b": {"type": "integer"}
#             },
#             "required": ["a", "b"]
#         }
#     }
# }

With optional parameters:

def greet(name: str, greeting: str = "Hello") -> str:
    '''Greet someone with a custom message.'''
    return f"{greeting}, {name}!"

schema = create_tool_schema(greet)
# required list will only contain ["name"]
python_agents.tools.convert_tool_format(tool)[source]

Convert an MCP tool to OpenAI tool format.

This function transforms tools from the Model Context Protocol (MCP) format into OpenAI’s function calling schema format. It maps the MCP tool’s inputSchema directly to OpenAI’s parameters structure.

Parameters:

tool

An MCP tool object with the following attributes:

  • name (str): The tool’s name

  • description (str): Description of what the tool does

  • inputSchema (dict): JSON schema for the tool’s input parameters, containing “properties” and optionally “required” fields

Returns:

A tool schema in OpenAI format with structure:

{
    "type": "function",
    "function": {
        "name": str,
        "description": str,
        "parameters": {
            "type": "object",
            "properties": dict,
            "required": list[str]
        }
    }
}

Return type:

dict

Example

Converting an MCP tool:

from types import SimpleNamespace

mcp_tool = SimpleNamespace(
    name="search_database",
    description="Search the database for records",
    inputSchema={
        "properties": {
            "query": {"type": "string"},
            "limit": {"type": "integer"}
        },
        "required": ["query"]
    }
)

openai_tool = convert_tool_format(mcp_tool)
# Returns OpenAI-compatible tool schema

Note

If the MCP tool’s inputSchema doesn’t specify a “required” field, an empty list is used for the required parameters.

Message

Message structure for LLM conversations.

This module defines the Message TypedDict, which represents individual messages in conversations with Large Language Models. Messages can represent user input, assistant responses, system instructions, or tool call results.

class python_agents.message.Message[source]

Bases: TypedDict

TypedDict representing a message in an LLM conversation.

Message defines the structure for all messages exchanged in conversations with language models. It supports different message roles (user, assistant, system, tool) and includes optional fields for tool calling functionality. This structure is compatible with the OpenAI chat completions API format.

role

The role of the message sender. Valid values are: - “user”: Messages from the user/human - “assistant”: Responses from the LLM - “system”: System instructions that guide the LLM’s behavior - “tool”: Results returned from tool function calls

Type:

str

content

The text content of the message. For tool messages, this contains the stringified result of the tool execution.

Type:

str

tool_call_id

The ID of the tool call this message is responding to. Required for role=”tool” messages, links the tool result back to the original tool call request.

Type:

NotRequired[str]

name

The name of the tool that was called. Used with role=”tool” to identify which tool produced this result.

Type:

NotRequired[str]

tool_calls

List of tool calls requested by the assistant. Present when role=”assistant” and the LLM wants to call one or more tools. Each tool call contains the function name, arguments, and a unique ID.

Type:

NotRequired[list[Any]]

Example

Creating different message types:

# User message
user_msg = Message(role="user", content="What is the weather in Paris?")

# Assistant message without tools
assistant_msg = Message(role="assistant", content="Let me check that for you.")

# System message
system_msg = Message(
    role="system",
    content="You are a helpful weather assistant."
)

# Tool result message
tool_msg = Message(
    role="tool",
    content="Temperature: 18°C, Conditions: Partly cloudy",
    tool_call_id="call_abc123",
    name="get_weather"
)

# Assistant message with tool calls (typically created by LLM response)
assistant_with_tools = Message(
    role="assistant",
    content="I'll check the weather for you.",
    tool_calls=[{
        "id": "call_abc123",
        "type": "function",
        "function": {
            "name": "get_weather",
            "arguments": '{"location": "Paris"}'
        }
    }]
)

Note

  • NotRequired fields are optional and may be omitted when not needed

  • Tool-related fields (tool_call_id, name, tool_calls) are only used in specific contexts: tool_call_id and name for tool messages, tool_calls for assistant messages

  • This structure is passed to and returned from LLMClient.invoke() and used throughout the conversation history in ReactAgent

role: str
content: str
tool_call_id: NotRequired[str]
name: NotRequired[str]
tool_calls: NotRequired[list[Any]]

Memory

Memory management for conversation history in agents.

This module provides abstract and concrete implementations for storing and managing conversation history (messages) in AI agents. Memory classes handle message storage, retrieval, and manipulation for maintaining context across agent interactions.

class python_agents.memory.BaseMemory[source]

Bases: ABC

Abstract base class for memory implementations.

BaseMemory defines the interface that all memory implementations must follow. It provides methods for adding messages, clearing history, and managing system messages. Subclasses must implement all abstract methods to provide specific storage strategies.

abstractmethod add_message(message)[source]

Add a message to the conversation history.

Parameters:

message (Message) – The message to add to memory. Should contain role, content, and optionally tool call information.

abstractmethod clear()[source]

Clear all messages from memory.

Removes all stored messages, resetting the conversation history to empty state.

abstractmethod insert_system_message(message)[source]

Insert or replace a system message at the beginning of conversation history.

System messages provide instructions or context to the LLM and should always appear first in the message list. This method either inserts a new system message or replaces an existing one.

Parameters:

message (Message) – The system message to insert. Should have role=”system”.

class python_agents.memory.SimpleMemory[source]

Bases: BaseMemory

Simple in-memory storage for conversation history.

SimpleMemory provides a basic list-based implementation of conversation history storage. Messages are stored in chronological order in a Python list, with no size limits or special processing. This implementation is suitable for most use cases where conversation history fits in memory.

messages

List of messages in chronological order.

Type:

list[Message]

Example

Basic usage with message storage:

memory = SimpleMemory()
memory.add_message(Message(role="user", content="Hello"))
memory.add_message(Message(role="assistant", content="Hi there!"))
print(len(memory.messages))  # 2
memory.clear()
print(len(memory.messages))  # 0
__init__()[source]

Initialize an empty SimpleMemory instance.

add_message(message)[source]

Add a message to the end of the conversation history.

Messages are appended in the order they are added, maintaining chronological order.

Parameters:

message (Message) – The message to add. Can be user, assistant, system, or tool message.

insert_system_message(message)[source]

Insert or replace the system message at the beginning of the conversation.

This method ensures the system message is always first in the message list. If a system message already exists at position 0, it is replaced. Otherwise, the new system message is inserted at the beginning.

Parameters:

message (Message) – The system message to insert. Should have role=”system”.

Note

System messages provide instructions or context to the LLM and must appear before any user or assistant messages to be effective.

clear()[source]

Clear all messages from memory.

Resets the conversation history to an empty state by clearing the messages list.

Utilities

Utility functions for the python-agents library.

This module provides helper functions for common tasks like formatting and displaying data structures in a human-readable format.

python_agents.utils.pretty_print(data)[source]

Print a dictionary in a formatted, human-readable JSON format.

This utility function converts a dictionary to JSON and prints it with sorted keys and 4-space indentation, making it easier to read complex nested data structures. Commonly used for debugging or displaying API responses, message histories, and tool call results.

Parameters:

data (dict) – The dictionary to print. Can contain nested dictionaries, lists, strings, numbers, booleans, and None values - any JSON-serializable types.

Example

Displaying simple data:

data = {"name": "Alice", "age": 30, "city": "Paris"}
pretty_print(data)
# Output:
# {
#     "age": 30,
#     "city": "Paris",
#     "name": "Alice"
# }

Displaying nested conversation messages:

message = {
    "role": "assistant",
    "content": "Hello!",
    "metadata": {
        "model": "gpt-4",
        "tokens": 5
    }
}
pretty_print(message)
# Output:
# {
#     "content": "Hello!",
#     "metadata": {
#         "model": "gpt-4",
#         "tokens": 5
#     },
#     "role": "assistant"
# }

Displaying tool call information:

tool_call = {
    "id": "call_abc123",
    "function": {
        "name": "get_weather",
        "arguments": {"location": "Tokyo"}
    }
}
pretty_print(tool_call)

Note

  • Keys are automatically sorted alphabetically for consistent output

  • Uses 4-space indentation for readability

  • Non-JSON-serializable objects will raise a TypeError

  • Output is printed directly to stdout, not returned