ConnectOnion
from connectonion import Agent
agent = Agent("You are helpful", tools=[get_weather])
agent.input("What's the weather in NYC?")See the Difference
Same task, dramatically different complexity. Scroll to see real code comparisons.
Calculator Agent
vs LangChain
Type hints = automatic tool conversion. No wrappers needed.
from connectonion import Agent
def add(a: float, b: float) -> float:
return a + b
def multiply(a: float, b: float) -> float:
return a * b
agent = Agent("You are a calculator", tools=[add, multiply])
agent.input("What is 5 + 3, then multiply by 2?")from langchain.agents import Tool, AgentExecutor, create_react_agent
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
def add(input_str: str) -> str:
"""Add two numbers. Input: 'a,b'"""
a, b = map(float, input_str.split(','))
return str(a + b)
def multiply(input_str: str) -> str:
"""Multiply two numbers. Input: 'a,b'"""
a, b = map(float, input_str.split(','))
return str(a * b)
tools = [
Tool(name="add", func=add, description="Add two numbers. Input: 'a,b'"),
Tool(name="multiply", func=multiply, description="Multiply. Input: 'a,b'"),
]
template = """You are a calculator assistant.
Available tools: {tools}
Tool names: {tool_names}
Question: {input}
{agent_scratchpad}"""
prompt = PromptTemplate.from_template(template)
llm = ChatOpenAI(model="gpt-4", temperature=0)
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({"input": "What is 5 + 3, then multiply by 2?"})Browser Automation
vs OpenAI SDK
Just pass a class. Public methods become tools, self = shared state.
from connectonion import Agent
class BrowserAutomation:
def __init__(self):
self._browser = None
self._page = None
self._screenshots = []
def start_browser(self):
self._browser = launch_browser()
self._page = self._browser.new_page()
return "Browser started"
def navigate(self, url: str):
self._page.goto(url) # Uses shared state via self
return f"Navigated to {url}"
def take_screenshot(self, path: str):
self._page.screenshot(path=path)
self._screenshots.append(path)
return f"Saved: {path}"
browser = BrowserAutomation()
agent = Agent("You automate browsers", tools=[browser])from dataclasses import dataclass
from agents import Agent, Runner, function_tool
from agents.types import RunContextWrapper
@dataclass
class BrowserContext:
browser: object = None
page: object = None
screenshots: list = None
def __post_init__(self):
self.screenshots = self.screenshots or []
@function_tool
def start_browser(wrapper: RunContextWrapper[BrowserContext]):
wrapper.context.browser = launch_browser()
wrapper.context.page = wrapper.context.browser.new_page()
return "Browser started"
@function_tool
def navigate(wrapper: RunContextWrapper[BrowserContext], url: str):
wrapper.context.page.goto(url) # Access via wrapper.context
return f"Navigated to {url}"
@function_tool
def take_screenshot(wrapper: RunContextWrapper[BrowserContext], path: str):
wrapper.context.page.screenshot(path=path)
wrapper.context.screenshots.append(path)
return f"Saved: {path}"
agent = Agent(name="browser", instructions="...",
tools=[start_browser, navigate, take_screenshot])
ctx = BrowserContext()
result = await Runner.run(agent, "Open google", context=ctx)ReAct Reasoning
vs Google ADK
plugins=[re_act] - one line adds Plan + Act + Reflect loop.
from connectonion import Agent
from connectonion.useful_plugins import re_act
def search(query: str) -> str:
return f"Results for: {query}"
# Just add plugins=[re_act] - that's it!
agent = Agent(
"You are a research assistant",
tools=[search],
plugins=[re_act] # Plan + Act + Reflect loop
)
agent.input("Research the history of Python")from google.adk import Agent
from google.adk.planners import PlanReActPlanner
def search(query: str) -> dict:
"""Search for information.
Args:
query: The search query.
Returns:
dict with search results.
"""
return {"status": "success", "results": f"Results for: {query}"}
# Must use special planner class
agent = Agent(
model="gemini-2.0-flash",
planner=PlanReActPlanner(), # Special planner object
tools=[search],
)
# Run with: adk webMemory System
vs All Frameworks
Memory is just a tool. No services, no sessions, no deprecated APIs.
from connectonion import Agent, Memory
memory = Memory() # That's it!
agent = Agent(
"You remember user preferences",
tools=[memory] # Memory is just a tool
)
agent.input("Remember: I prefer dark mode")
agent.input("What are my preferences?")from langchain.memory import ConversationBufferMemory
from langchain.chains import LLMChain
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts.chat import MessagesPlaceholder
# Choose from 6+ memory types:
# - ConversationBufferMemory
# - ConversationSummaryMemory
# - ConversationBufferWindowMemory
# - ConversationKGMemory
# - VectorStoreRetrieverMemory
# ... and more
prompt = ChatPromptTemplate([
MessagesPlaceholder(variable_name="chat_history"),
# ... more setup
])
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
# DEPRECATED in v0.3.1 - must migrate to LangGraphEvent Hooks
vs All Frameworks
9 event types with full agent access. Not just guardrails.
from connectonion import after_tools
def my_hook(agent):
# Access EVERYTHING:
session = agent.current_session
messages = session['messages'] # All conversation
trace = session['trace'] # Every LLM call
user_input = session['user_prompt'] # Original request
# Modify ANYTHING:
session['messages'].append({
'role': 'assistant',
'content': 'Thinking about next step...'
})
# That's it - just pass it
agent = Agent("assistant", tools=[...],
on_events=[after_tools(my_hook)])
# Available: after_user_input, before_llm, after_llm,
# before_tools, before_each_tool, after_each_tool,
# after_tools, on_error, on_completefrom agents import Agent, output_guardrail
from agents.types import OutputGuardrailTripwireTriggered
# OpenAI SDK has NO event system
# Only "guardrails" for input/output validation
@output_guardrail
async def check_output(ctx, agent, output):
# Can only validate, not modify behavior
# No access to tool execution
# No access to conversation history
if "bad" in output:
raise OutputGuardrailTripwireTriggered("Invalid")
return output
# Want ReAct? Build it yourself
# Want custom logging? No standard way
# Want approval flows? No standard wayQuick Comparison
| Feature | ConnectOnion | Others |
|---|---|---|
| Tool definition | Just a function | Decorators, wrappers, classes |
| Shared state | self.field | wrapper.context, dataclass, services |
| Add ReAct | plugins=[re_act] | Planner classes, different agent types |
| Memory | Memory as tool | Sessions, services, deprecated APIs |
| Event hooks | 9 types, full access | Guardrails only, limited callbacks |
| Free credits | Yes | No |
Start Free - No API Key Needed
Get started immediately with free credits for GPT-4o, Claude, and Gemini.
What You Can Build
Functions = Tools
No wrappers. No decorators. Just functions.
Deploy Anywhere
From your laptop. No AWS needed.
Connect Agents
Build agent networks. Like the internet, but for AI.
Production Ready
Built for production from day one
Auto Log
.co/logs/
@xray
Breakpoints
Plugins
Just functions
Human Loop
Approval flows
For basic agents. No boilerplate.
Production features when you need them.
Not framework code. Just Python.
Ready to Start?
60 seconds to your first agent. No AWS. Just code.
