Cloud Agent Integrations in OmniRoute: How External AI Services Are Implemented as First-Class Providers
OmniRoute integrates five cloud agents (Jules, Devin, Codex, Cursor, and Cursor-cloud) through a pluggable framework defined in src/lib/cloudAgent/baseAgent.ts, where each agent extends CloudAgentBase and implements four lifecycle methods: createTask, getStatus, sendMessage, and listSources.
The cloud agent integrations in OmniRoute transform external AI coding services into native routing targets. Rather than treating these platforms as black-box APIs, OmniRoute's architecture—as implemented in diegosouzapw/OmniRoute—abstracts them through a common interface that inherits the router's resilience patterns, credential encryption, and task persistence.
Supported Cloud Agents in OmniRoute
The current release (v3.8.50) ships with five built-in cloud agent integrations. Each maps to a unique provider ID and serves distinct AI-assisted development workflows.
| Agent | Provider ID | Core Purpose |
|---|---|---|
| Jules | jules |
Connects to the Jules.ai cloud API for chat-completion style interactions |
| Devin | devin |
Drives the Devin CLI service for autonomous code-generation tasks |
| Codex | codex |
Calls the OpenAI Codex endpoint via a thin TypeScript wrapper |
| Cursor | cursor |
Uses Cursor's public REST API with API-key-only authentication |
| Cursor-cloud | cursor-cloud |
OAuth-free variant added in v3.8.50 for streamlined background agents |
The Cloud Agent Base Class Architecture
All cloud agent integrations in OmniRoute derive from a single abstract class defined in src/lib/cloudAgent/baseAgent.ts. This common abstraction enforces a four-method contract that every concrete agent must fulfill.
Required Lifecycle Methods
| Method | Signature | Purpose |
|---|---|---|
createTask |
(prompt: string, …): Promise<string> |
Starts a remote task and stores the external task ID |
getStatus |
(taskId: string): Promise<CloudAgentStatus> |
Polls the remote service and maps status to CREATING, RUNNING, FINISHED, or ERROR |
sendMessage |
(taskId: string, message: string): Promise<void> |
Sends incremental input to an already-running task |
listSources |
(taskId: string): Promise<SourceFile[]> |
Retrieves generated artifacts or source files |
The CloudAgentBase constructor handles credential decryption and exposes baseUrl and authentication headers to subclasses, eliminating redundant security logic across agent implementations.
How the Framework Is Wired Together
Four core modules orchestrate cloud agent integrations in OmniRoute:
src/lib/cloudAgent/registry.ts — Provider Resolution
- Maintains a map
providerId → CloudAgentClass - Factory method instantiates agents with decrypted credentials
- New agents register via
cloudAgentRegistry.register('id', AgentClass)
src/lib/cloudAgent/credentials.ts — Secure Authentication
- Encrypts API keys and OAuth tokens in the
cloud_agent_credentialsSQLite table - Decrypts on agent instantiation
- Supports per-provider credential schemas
src/lib/cloudAgent/db.ts — Task Persistence
- Stores task records in
cloud_agent_taskslinking OmniRoute task IDs to externalexternal_idvalues - Enables asynchronous polling and UI state synchronization
src/lib/cloudAgent/api.ts and src/lib/cloudAgent/index.ts — Public REST API
- Exposes endpoints under
/api/v1/agents/* - Validates inputs with Zod schemas
- Enforces authentication before delegating to agent implementations
Agent Implementation Pattern
Each concrete agent follows an identical skeleton. Here is the structural pattern from src/lib/cloudAgent/agents/jules.ts, agents/devin.ts, agents/cursor.ts, and agents/codex.ts:
export class XxxAgent extends CloudAgentBase {
async createTask(prompt: string, …): Promise<string> {
// HTTP POST to provider endpoint
// Store returned external ID in cloud_agent_tasks table
}
async getStatus(taskId: string): Promise<CloudAgentStatus> {
// HTTP GET to provider status endpoint
// Map provider-specific enum to CloudAgentStatus union
}
async sendMessage(taskId: string, msg: string): Promise<void> {
// HTTP PATCH or POST for incremental prompts
}
async listSources(taskId: string): Promise<SourceFile[]> {
// HTTP GET to fetch generated files or code snippets
}
}
All HTTP traffic routes through open-sse/executors/, inheriting OmniRoute's retry logic, circuit breakers, and rate limiting. Errors are sanitized through open-sse/utils/error.ts before client exposure.
Request Flow Through the Cloud Agent System
Understanding the end-to-end flow clarifies how cloud agent integrations in OmniRoute maintain stateful, resilient interactions with external services.
- Client submits task →
POST /api/v1/agents/taskswith provider ID and prompt - API handler validates payload with Zod, resolves provider from registry
- Agent instantiation → registry returns concrete class with decrypted credentials
createTaskexecution → HTTP POST to remote service, external ID persisted tocloud_agent_tasks- Polling loop →
GET /agents/tasks/:idinvokesgetStatus, updates database, returns to client - Continued interaction →
sendMessagefor follow-up prompts,listSourcesfor artifact retrieval
Practical Code Examples
Creating a Task with the Jules Agent
import { cloudAgentRegistry } from '@/lib/cloudAgent/registry';
const agent = cloudAgentRegistry.get('jules'); // returns JulesAgent instance
const externalId = await agent.createTask('Write a TypeScript utility for parsing JSON streams');
// externalId stored in cloud_agent_tasks with status 'CREATING'
Source: src/lib/cloudAgent/registry.ts
Polling Task Status and Retrieving Results
const status = await agent.getStatus(externalId);
if (status === 'FINISHED') {
const files = await agent.listSources(externalId);
// files: Array<{ path: string; content: string }>
} else if (status === 'ERROR') {
// Handle failure per open-sse/utils/error.ts patterns
}
Source: src/lib/cloudAgent/agents/jules.ts
Registering a New Custom Agent
// src/lib/cloudAgent/registry.ts
import { MyAIAgent } from './agents/myai';
cloudAgentRegistry.register('myai', MyAIAgent);
Only three steps required: extend CloudAgentBase, register in registry.ts, and add credential definition if needed. No modifications to core routing logic.
Key Files for Cloud Agent Integrations in OmniRoute
| File | Role |
|---|---|
src/lib/cloudAgent/baseAgent.ts |
Abstract base class defining the cloud-agent contract |
src/lib/cloudAgent/registry.ts |
Provider-ID to implementation mapping and factory |
src/lib/cloudAgent/credentials.ts |
Encrypted storage and retrieval of API keys/tokens |
src/lib/cloudAgent/db.ts |
SQLite persistence layer for tasks and credentials |
src/lib/cloudAgent/api.ts |
Public HTTP endpoints for agent operations |
src/lib/cloudAgent/agents/jules.ts |
Jules.ai integration implementation |
src/lib/cloudAgent/agents/devin.ts |
Devin CLI service integration |
src/lib/cloudAgent/agents/cursor.ts |
Cursor REST API integration |
src/lib/cloudAgent/agents/codex.ts |
OpenAI Codex wrapper implementation |
Summary
- OmniRoute supports five cloud agent integrations (Jules, Devin, Codex, Cursor, Cursor-cloud) through a unified framework
- The
CloudAgentBaseabstraction insrc/lib/cloudAgent/baseAgent.tsenforces consistent lifecycle methods across all providers - Registry pattern enables runtime provider resolution without core router modifications
- Encrypted credential storage and SQLite task persistence provide production-grade security and state management
- New agents require only three implementation steps; the framework inherits OmniRoute's retry, circuit-breaker, and rate-limiting capabilities automatically
Frequently Asked Questions
How do I add a new cloud agent integration to OmniRoute?
Extend CloudAgentBase from src/lib/cloudAgent/baseAgent.ts, implement the four required methods (createTask, getStatus, sendMessage, listSources), then register your class in src/lib/cloudAgent/registry.ts with cloudAgentRegistry.register('your-id', YourAgentClass). Add credential definitions in credentials.ts if your service requires API keys or tokens.
Where are cloud agent API keys stored in OmniRoute?
API keys and OAuth tokens are encrypted in the cloud_agent_credentials SQLite table, managed by src/lib/cloudAgent/credentials.ts. The CloudAgentBase constructor automatically decrypts credentials when instantiating agent classes, exposing baseUrl and auth headers to implementations without exposing secrets in code.
What happens when a cloud agent task fails?
Errors propagate through open-sse/utils/error.ts for sanitization before reaching clients. The getStatus method returns ERROR status, which persists in the cloud_agent_tasks table. All HTTP calls inherit retry logic and circuit-breaker patterns from OmniRoute's executor layer in open-sse/executors/.
How does OmniRoute track cloud agent task state across restarts?
The cloud_agent_tasks table in src/lib/cloudAgent/db.ts persists the mapping between OmniRoute task IDs and provider external_id values. This allows polling endpoints to resume status checks after service restarts, and enables the UI to reconstruct task history from durable storage.
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 →