How to Integrate Cloud Agents (Devin, Codex Cloud, Jules) with OmniRoute
OmniRoute treats cloud agents like Devin, Codex Cloud, and Jules as first-class components that you can register, authenticate, and call through a unified API layer.
The diegosouzapw/OmniRoute repository provides a cloud-agent abstraction layer in src/lib/cloudAgent/ that standardizes how external AI agents are discovered, secured, and invoked. This guide walks through the three-step integration pattern using Codex Cloud as the reference implementation.
The Three-Step Integration Pattern
OmniRoute's cloud-agent architecture follows a consistent registration-credential-execution flow. Each step maps to specific source files in the codebase.
Step 1: Register the Agent in the Central Registry
OmniRoute discovers agents at runtime through a class-based registry. In src/lib/cloudAgent/registry.ts, the system iterates over src/lib/cloudAgent/agents/* and maps agent names to their implementing classes.
The registry is a simple Map<string, typeof CloudAgentBase> that the request router consults via open-sse/handlers/agentHandler.ts.
// src/lib/cloudAgent/registry.ts
import { CodexCloudAgent } from '@/lib/cloudAgent/agents/codex';
import { DevinAgent } from '@/lib/cloudAgent/agents/devin';
import { JulesAgent } from '@/lib/cloudAgent/agents/jules';
// Register under canonical names
cloudAgentRegistry.set('codex', CodexCloudAgent);
cloudAgentRegistry.set('devin', DevinAgent);
cloudAgentRegistry.set('jules', JulesAgent);
Any class registered here must extend CloudAgentBase and implement five abstract methods: createTask, getStatus, approvePlan, sendMessage, and listSources.
Step 2: Configure Credentials via the Public-Creds System
Cloud agents require OAuth credentials or API keys that must never be hard-coded. OmniRoute enforces this through the resolvePublicCred() helper in open-sse/utils/publicCreds.ts.
The Codex Cloud agent constructor in src/lib/cloudAgent/agents/codex.ts retrieves its credentials through this abstraction:
// Agent internals automatically call:
const clientId = await resolvePublicCred('PUBLIC_CLOUD_CODEX_CLIENT_ID');
const clientSecret = await resolvePublicCred('PUBLIC_CLOUD_CODEX_CLIENT_SECRET');
Set these in your environment:
# .env (never commit this file)
PUBLIC_CLOUD_CODEX_CLIENT_ID=your-client-id
PUBLIC_CLOUD_CODEX_CLIENT_SECRET=your-client-secret
PUBLIC_CLOUD_DEVIN_API_KEY=your-devin-key
PUBLIC_CLOUD_JULES_API_KEY=your-jules-key
This satisfies OmniRoute's hard rule #11: Never embed public upstream credentials in source code.
Step 3: Call the Agent via HTTP API or SDK
OmniRoute auto-generates REST endpoints for each registered agent at src/app/api/v1/agents/[agent]/route.ts. The request pipeline runs CORS handling → Zod validation → optional authentication → agent delegation. Errors are sanitized via buildErrorBody() per hard rule #12.
HTTP API Example (Codex Cloud)
// Create a task
const createResponse = await fetch('http://localhost:20128/v1/agents/codex/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prompt: 'Refactor this Python class to use dataclasses',
model: 'codex-latest',
temperature: 0.2
})
});
const { taskId, status } = await createResponse.json();
// Poll until completion
while (!['completed', 'failed'].includes(status)) {
await new Promise(r => setTimeout(r, 2000));
const poll = await fetch(`http://localhost:20128/v1/agents/codex/tasks/${taskId}`);
({ status } = await poll.json());
}
// Retrieve messages
const messages = await fetch(
`http://localhost:20128/v1/agents/codex/tasks/${taskId}/messages`
).then(r => r.json());
SDK Client Alternative
For programmatic use, import the typed client from src/lib/cloudAgent/sdk.ts:
import { CloudAgentClient } from '@/lib/cloudAgent/sdk';
const client = new CloudAgentClient({ baseUrl: 'http://localhost:20128' });
// Fire-and-forget with auto-polling
const result = await client.runToCompletion('devin', {
prompt: 'Create a React component for a date picker',
context: { repository: 'github.com/acme/app' }
});
console.log(result.output);
Key Architectural Components
| Component | Location | Purpose |
|---|---|---|
| Agent base class | src/lib/cloudAgent/CloudAgentBase.ts |
Abstract interface all agents must implement |
| Registry | src/lib/cloudAgent/registry.ts |
Runtime discovery and name-to-class mapping |
| Codex implementation | src/lib/cloudAgent/agents/codex.ts |
OAuth flow, task lifecycle, message streaming |
| Auto-generated routes | src/app/api/v1/agents/[agent]/route.ts |
HTTP entry point per registered agent |
| SDK client | src/lib/cloudAgent/sdk.ts |
TypeScript client for programmatic access |
| Error sanitization | open-sse/utils/buildErrorBody.ts |
Security-compliant error responses |
Adding a New Cloud Agent
To integrate additional agents (e.g., a custom enterprise agent), follow the same pattern established for Codex Cloud, Devin, and Jules:
- Create agent file: Add
src/lib/cloudAgent/agents/youragent.tsextendingCloudAgentBase - Implement required methods:
createTask,getStatus,approvePlan,sendMessage,listSources - Register: Add
cloudAgentRegistry.set('youragent', YourAgentClass)inregistry.ts - Configure credentials: Add
PUBLIC_CLOUD_YOURAGENT_*variables to your environment
No other files require modification—the routing and validation layers are fully generic.
Summary
- Registration: Add agent classes to
src/lib/cloudAgent/registry.tsfor runtime discovery - Security: Store all credentials externally via
resolvePublicCred()to satisfy hard rule #11 - Execution: Use auto-generated HTTP endpoints at
/v1/agents/{agent}/or theCloudAgentClientSDK - Extensibility: New agents require only a single source file and one registry line
- Standards: All agents implement
CloudAgentBase, ensuring consistent task lifecycle semantics
Frequently Asked Questions
What authentication methods does OmniRoute support for cloud agent credentials?
OmniRoute's resolvePublicCred() system supports environment variables, secret managers (via pluggable backends), and local .env files. The open-sse/utils/publicCreds.ts module abstracts the source so agent implementations remain environment-agnostic. OAuth client credentials and API keys are both supported—each agent class specifies its required credential keys in the constructor.
How does OmniRoute handle rate limiting and errors from external agent APIs?
Each agent implementation in src/lib/cloudAgent/agents/*.ts wraps upstream API calls with retry logic and exponential back-off. Errors are normalized through buildErrorBody() in open-sse/utils/buildErrorBody.ts, which strips sensitive details before returning them to clients. The HTTP layer returns standard status codes (429 for rate limits, 502/503 for upstream failures) with sanitized error messages.
Can I use multiple cloud agents in a single OmniRoute deployment?
Yes. The registry in src/lib/cloudAgent/registry.ts holds multiple agents simultaneously. Each registered name gets its own route handler under /v1/agents/{name}/. You can call Codex Cloud, Devin, and Jules from the same running OmniRoute instance, with credentials isolated per agent.
Is there a way to stream agent responses instead of polling?
The base interface in CloudAgentBase.ts includes sendMessage() which supports streaming implementations. Check individual agent files—src/lib/cloudAgent/agents/codex.ts implements Server-Sent Events (SSE) for real-time output, while others may return complete responses. The SDK's client.streamTask() method provides a unified async iterator interface regardless of the underlying transport.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →