API Reference
August 21, 2026 · View on GitHub
Agent
The main class for creating AI agents that can use tools.
Constructor
Agent(
name: str,
llm: Optional[LLM] = None,
tools: Optional[List[Callable]] = None,
system_prompt: Union[str, Path, None] = None,
api_key: Optional[str] = None,
model: str = "co/gemini-3.7-flash"
)
Parameters
- name (
str): Unique identifier for the agent - llm (
Optional[LLM]): Custom LLM instance (defaults to OpenAILLM) - tools (
Optional[List[Callable]]): List of functions the agent can use - system_prompt (
Union[str, Path, None]): Agent's personality and behavior definitionstr: Can be either a direct prompt text or a file path (auto-detected)Path: Path object pointing to a prompt fileNone: Uses default prompt
- api_key (
Optional[str]): OpenAI API key (if not using custom LLM) - model (
str): Model to use (default: "co/gemini-3.7-flash")- Managed keys:
co/gemini-3.7-flash,co/gpt-4o-mini,co/claude-sonnet-4-5 - Your own key:
gpt-4o-mini,claude-sonnet-4-5,gemini-3.7-flash
- Managed keys:
System Prompt Options
The system_prompt parameter accepts multiple input types:
# 1. Direct string
agent = Agent(name="bot", system_prompt="You are helpful")
# 2. File path as string (auto-detected if file exists)
agent = Agent(name="bot", system_prompt="prompts/assistant.md")
# 3. Path object (must point to existing file)
from pathlib import Path
agent = Agent(name="bot", system_prompt=Path("prompts/assistant.txt"))
# 4. None (uses default)
agent = Agent(name="bot") # Default: "You are a helpful assistant..."
File Loading Rules:
- Any text file can be used (no extension restrictions)
- Files must be valid UTF-8 encoded text
- Empty files raise
ValueError - Non-existent Path objects raise
FileNotFoundError - Strings that don't exist as files are treated as literal prompts
Methods
input(prompt: str, max_iterations: Optional[int] = None) -> str
Provide input to the agent and get response.
Parameters:
prompt- User input/task for the agentmax_iterations- Override agent's default max_iterations for this task only
result = agent.input("Calculate 2 + 2")
# Override iterations for complex tasks
result = agent.input("Complex multi-step task", max_iterations=25)
add_tool(tool: Callable) -> None
Add a new tool to the agent.
def new_tool(param: str) -> str:
return f"Processed {param}"
agent.add_tool(new_tool)
remove_tool(tool_name: str) -> None
Remove a tool from the agent.
agent.remove_tool("calculator")
list_tools() -> List[str]
Get list of available tool names.
tools = agent.list_tools()
# ['calculator', 'search', 'get_time']
Tools
Function-Based Tools
Any Python function can be used as a tool:
def my_tool(param: str, optional: int = 10) -> str:
"""Tool description from docstring.
Args:
param: The main parameter.
Returns:
Formatted result.
"""
return f"Result: {param} with {optional}"
agent = Agent("bot", tools=[my_tool])
How schemas are generated:
name← function namedescription← first paragraph of docstring (Args/Returns NOT included)parameters← from Python type hintsrequired← parameters without default values
Everything is optional:
- No docstring? Description defaults to "Execute the {name} tool."
- No type hints? Defaults to string type
Tool Conversion
The create_tool_from_function utility converts functions to tools:
from connectonion import create_tool_from_function
def simple_function(x: int) -> int:
"""Double a number."""
return x * 2
tool = create_tool_from_function(simple_function)
# tool now has: .name, .description, .run(), .to_function_schema()
Logging
Automatic activity logging for agents. Three output destinations:
- Console: Rich-formatted terminal output
- Plain text:
.co/logs/{name}.log - Session YAML:
.co/evals/{name}_{timestamp}.yaml
Configuration
Control logging via quiet and log parameters:
# Default: everything on (console + logs + sessions)
agent = Agent("assistant")
# Quiet mode: suppress console, keep sessions for eval
agent = Agent("assistant", quiet=True)
# Disable all file logging (console only)
agent = Agent("assistant", log=False)
# Custom log file path
agent = Agent("assistant", log="my_logs/custom.log")
Logging Modes
| quiet | log | Console | Plain Text | Sessions | Use Case |
|---|---|---|---|---|---|
| False | True/None | ✓ | ✓ | ✓ | Development (default) |
| True | True/None | ✗ | ✗ | ✓ | Eval/testing |
| False | False | ✓ | ✗ | ✗ | Benchmarking |
| False | "path" | ✓ | custom | ✓ | Custom log path |
Log Format
Plain text logs include:
- Timestamp
- User input
- LLM calls with timing, tokens, cost
- Tool executions with parameters and results
- Final agent responses
Example log output:
[10:30:15] INPUT: Calculate 2 + 2
[10:30:15] -> LLM Request (gpt-4o-mini) • 2 msgs • 1 tools
[10:30:16] <- LLM Response (234ms) • 1 tools • 156 tokens • \$0.0001
[10:30:16] -> Tool: calculator({"expression": "2+2"})
[10:30:16] <- Result (1ms): 4
[10:30:16] [OK] Complete (1.2s)
Session YAML Format
Sessions are saved for replay and eval:
name: assistant
timestamp: 2024-12-02 10:30:15
turns:
- input: "Calculate 2 + 2"
model: "gpt-4o-mini"
duration_ms: 1200
tokens: 156
cost: 0.0001
tools_called: [calculator]
result: "The answer is 4"
messages: '[{"role":"system",...}]'
LLM
Abstract base class for language models. ConnectOnion supports multiple LLM providers through a unified interface.
Model Routing
The create_llm() factory function routes models to the appropriate provider:
from connectonion.core.llm import create_llm
# OpenAI models
llm = create_llm("gpt-4o-mini") # → OpenAILLM
llm = create_llm("o4-mini") # → OpenAILLM
# Anthropic models
llm = create_llm("claude-sonnet-4-5") # → AnthropicLLM
# Google Gemini models
llm = create_llm("gemini-3.7-flash") # → GeminiLLM
# ConnectOnion managed keys (co/ prefix)
llm = create_llm("co/gpt-4o-mini") # → OpenOnionLLM
llm = create_llm("co/gemini-3.7-flash") # → OpenOnionLLM
co/ Models (Managed Keys)
Models prefixed with co/ use ConnectOnion's managed API keys through the OpenOnion proxy:
from connectonion import Agent
# Uses OpenOnion managed keys - no API key needed
agent = Agent(name="bot", model="co/gemini-3.7-flash")
How it works:
- Client detects
co/prefix → routes toOpenOnionLLM - Prefix is stripped before sending to server
- Server routes to appropriate provider (OpenAI, Anthropic, Gemini)
- Response returned in OpenAI-compatible format
Available co/ models:
co/gpt-4o-mini,co/gpt-4o,co/gpt-5,co/gpt-5-mini,co/gpt-5-nano,co/o4-minico/gemini-3.7-flash(default),co/gemini-3.6-flash,co/gemini-3.5-flash,co/gemini-2.5-pro,co/gemini-2.5-flashco/claude-opus-4-5,co/claude-sonnet-4-5,co/claude-haiku-4-5
Environment variable: OPENONION_API_KEY (auto-loaded from .env)
OpenAILLM
OpenAI API implementation.
from connectonion.core.llm import OpenAILLM
llm = OpenAILLM(
api_key="your-key", # or OPENAI_API_KEY env var
model="gpt-4o-mini",
temperature=0.7
)
agent = Agent("bot", llm=llm)
AnthropicLLM
Anthropic Claude API implementation.
from connectonion.core.llm import AnthropicLLM
llm = AnthropicLLM(
api_key="your-key", # or ANTHROPIC_API_KEY env var
model="claude-sonnet-4-5"
)
agent = Agent("bot", llm=llm)
GeminiLLM
Google Gemini API implementation (uses OpenAI-compatible endpoint).
from connectonion.core.llm import GeminiLLM
llm = GeminiLLM(
api_key="your-key", # or GEMINI_API_KEY env var
model="gemini-3.7-flash"
)
agent = Agent("bot", llm=llm)
OpenOnionLLM
ConnectOnion managed keys implementation.
from connectonion.core.llm import OpenOnionLLM
llm = OpenOnionLLM(
api_key="your-token", # or OPENONION_API_KEY env var
model="co/gemini-3.7-flash"
)
agent = Agent("bot", llm=llm)
Base URLs:
- Production:
https://oo.openonion.ai/v1 - Development:
http://localhost:8000/v1(whenENVIRONMENT=development)
Prompts Module
Utilities for loading system prompts.
load_system_prompt(prompt: Union[str, Path, None]) -> str
Load system prompt from various sources.
from connectonion.prompts import load_system_prompt
# From string
prompt = load_system_prompt("You are helpful")
# From file
prompt = load_system_prompt("prompts/assistant.md")
# From Path
from pathlib import Path
prompt = load_system_prompt(Path("prompts/assistant.txt"))
# Default
prompt = load_system_prompt(None)
Raises:
FileNotFoundError: If Path object points to non-existent fileValueError: If file is empty or not valid UTF-8TypeError: If invalid type provided
Decorators
@xray
Enable detailed execution tracing.
from connectonion import xray
@xray
def my_agent_function():
agent = Agent("tracer")
return agent.input("task")
# After execution:
xray.trace() # Shows detailed execution flow
@replay
Record and replay agent interactions.
from connectonion import replay
@replay
def workflow():
agent = Agent("bot")
return agent.input("task")
# Replay the recorded interaction
replay.last()
Examples
Basic Agent
from connectonion import Agent
# Simple calculator agent
def calculate(expression: str) -> str:
"""Evaluate mathematical expressions."""
return str(eval(expression))
agent = Agent("calculator", tools=[calculate])
result = agent.input("What is 15 * 4?")
Agent with Custom Prompt File
# prompts/expert.md
"""
You are an expert Python developer with 10 years of experience.
Focus on clean code, best practices, and performance.
"""
# main.py
agent = Agent(
name="python_expert",
system_prompt="prompts/expert.md",
tools=[code_review, suggest_improvement]
)
Multi-Tool Agent
def search(query: str) -> str:
"""Search the web."""
# Implementation
def calculate(expr: str) -> str:
"""Do math."""
# Implementation
def get_time() -> str:
"""Get current time."""
# Implementation
agent = Agent(
name="assistant",
system_prompt="You are a helpful research assistant.",
tools=[search, calculate, get_time]
)
# Agent can use multiple tools in one request
result = agent.input("Search for Python tutorials, calculate 42*17, and tell me the time")
Networking
Host an agent and connect to it from anywhere. Full guides live in
network/; the core surface:
host(create_agent, **kwargs)
Serve an agent over HTTP/WebSocket with relay discovery. create_agent is a
factory called once per request (isolation). See network/host.md.
from connectonion import host
host(lambda: Agent("assistant", tools=[...]))
connect(address, *, keys=None, relay_url=...) -> RemoteAgent
Client to a remote agent. See network/connect.md.
from connectonion import connect
remote = connect("0x3d40...")
# LLM-driven task
resp = remote.input("Book a flight") # -> Response(text, done)
# The Host advertises the exact permission modes this session may select. The setter returns
# only after the Host has durably committed the new policy.
remote.set_session_mode("auto")
print(remote.available_modes)
# Direct tool execution — no LLM (see network/remote-call.md)
res = remote.call("bash", command="co status") # -> ExecResult
| Method | Returns | Purpose |
|---|---|---|
remote.input(prompt, timeout=60) | Response(text, done) | Hand the remote LLM a task |
remote.call(tool, timeout=60, **args) | ExecResult(text, status, duration_ms, error) | Run one tool directly, no LLM |
remote.set_session_mode(mode, timeout=30) | None | Durably select one Host-advertised OIP permission mode |
set_session_mode() returning means the Host committed the policy. A
TimeoutError is an unknown outcome, not a rollback: the Host may have
committed before its acknowledgement was lost. Reconnect and read
available_modes plus current_session["mode"] from the next authoritative
CONNECTED response before retrying.
ExecResult: .ok (bool), .images (base64 data URLs pulled from .text).
Direct execution is gated by the host's .co/host.yaml permission whitelist.
From the shell: co call <address> <command...> (see cli/call.md).