Connect to Agents
Use any agent, anywhere, as if local. Create a proxy to a remote agent with the same interface.
Why connect? Access specialized agents from anywhere, build distributed workflows, scale horizontally across multiple machines.
60-Second Quick Start
Connect to a remote agent with one function call:
What Just Happened?
wss://oo.openonion.ai/ws/announceComplete Example: Two Terminals
Terminal 1: Host an Agent
Terminal 2: Connect and Use
Common Patterns
1. Connect to Multiple Agents
Build workflows with specialized remote agents:
2. Retry on Connection Failure
Handle network failures gracefully:
3. Agent Pool (Load Balancing)
Distribute load across multiple identical agents:
Multi-Turn Conversations
Remote agents maintain conversation state across multiple input() calls:
Direct Tool Execution: remote.call()
input(prompt) sends a task to the remote agent's LLM — it reasons, picks tools, and comes back when the whole task is done. When you already know the exact tool and arguments and just want the result, call(tool, **args) is the fast path: no reasoning, no session, no conversation history.
The result is an ExecResult: .text, .status ("success"/"error"), .ok, .error, .duration_ms, and .images. It never raises for a tool failure — a crash inside the tool comes back as status="error", same as how the LLM loop reports tool errors for retry.
Gated by the remote's whitelist. What may run via call() is the same permissions: whitelist in the remote's .co/host.yaml that its own LLM approval flow uses — one list, same meaning either way. Not on the list → refused with an error result, never executed.
From the shell, without writing Python: co call 0x3d40... co status — see co call.
Real-World: Distributed Workflow
Local orchestrator using remote specialized agents:
Configuration
Default Relay (Production)
Local Relay (Development)
Environment-Based
Local vs Remote Agents
Local Agent
+ No network latency
+ Works offline
− Limited to one machine
− No sharing
Remote Agent
+ Access from anywhere
+ Share across team
− Network latency
− Requires connectivity
TypeScript clients
The connectonion npm package provides the same connect() interface for TypeScript and JavaScript:
Basic Usage
Direct Connection (Deployed Agents)
Streaming Events
While the agent works, events stream in real-time via the ui property. Each event is a ChatItem:
| Event Type | Description |
|---|---|
| user | User message |
| agent | Agent response text |
| thinking | LLM thinking/reasoning |
| tool_call | Tool execution with name, args, result |
| ask_user | Agent asking a question (with options) |
| approval_needed | Tool requires user approval before running |
| plan_review | Agent presenting a plan for review |
React Hook: useAgentForHuman()
React applications should use @connectonion/react. Since version 0.3.0 it includes the browser connection layer, state management, and localStorage persistence; React is its only peer dependency, so the legacy connectonion TypeScript core is not required:
Session persistence: The hook automatically saves conversation state to localStorage using the sessionId. Page refreshes restore the full conversation.
Interactive Features
Agents can ask questions, request approval for dangerous tools, and present plans for review. Here's how to handle each:
Ask User
Agent needs information from the user:
Tool Approval
Agent wants to run a tool that needs permission:
Plan Review
Agent presenting a plan before executing:
Sending Files
All SDKs support sending files alongside prompts. Files are base64-encoded and sent inline as data URLs.
Python
TypeScript
React (useAgentForHuman)
FileAttachment Type
How It Works
Client Server
│ │
│ Convert file to base64 data URL │
│ │
│── INPUT ──────────────────────────►│
│ { prompt, files: [ │
│ { name, data: "data:...;base64,│
│ ..." } │
│ ]} │
│ │
│ Validate file limits│
│ Decode base64 │
│ Save to .co/uploads│
│ Tell agent paths │
│ │
│ Agent reads files │
│ via read_file tool │
│ │
│◄── OUTPUT ────────────────────────│
│ { result } │File limits: Default 10MB per file, 10 files per request. Check agent limits via GET /info → accepted_inputs.files. Server-side, files are saved to .co/uploads/ and the agent reads them via tools. See host() for server-side details.
oo-chat: Open-Source Reference Client
oo-chat is an open-source Next.js chat client built on @connectonion/react. It's a complete working example of how to build a chat UI for ConnectOnion agents.
oo-chat/ ├── app/[address]/[sessionId]/page.tsx ← session page (uses useAgentForHumanSDK) ├── components/chat/ │ ├── chat.tsx ← main Chat component │ ├── chat-input.tsx ← message input │ ├── chat-messages.tsx ← message list │ ├── use-agent-sdk.ts ← wrapper hook around useAgentForHuman() │ └── messages/ │ ├── tool-call.tsx ← tool call rendering │ └── tools/plan-card.tsx ← plan review UI └── package.json ← depends on connectonion
How oo-chat Connects
Architecture
┌──────────────────────────────────────────────────┐
│ oo-chat (Next.js) │
│ │
│ page.tsx │
│ └─ useAgentForHumanSDK() ← elapsed time, pending │
│ └─ useAgentForHuman() ← @connectonion/react│
│ └─ connect() ← WebSocket to agent │
│ │
│ <Chat /> │
│ ├─ <ChatMessages /> ← renders ui: ChatItem[] │
│ ├─ <AskUser /> ← from pendingAskUser │
│ ├─ <Approval /> ← from pendingApproval │
│ └─ <ChatInput /> ← calls send() │
└──────────────────────────────────────────────────┘
│ WebSocket
▼
┌──────────────────────────────────────────────────┐
│ Hosted Agent (Python) │
│ host(agent) │
└──────────────────────────────────────────────────┘Ready to Use Remote Agents?
Python, TypeScript, or React — connect to any agent with one function call.
ConnectOnion