Integrating Coding Agents with OmniRoute: A Complete Implementation Guide

OmniRoute is a unified AI proxy/router that lets coding agents plug into a single API endpoint and automatically dispatch requests to 340+ LLM providers through its modular AgentRouter protocol.

In this guide, you'll learn how to integrate custom coding agents—whether built-in agents like DevIn and HyperAgent or your own implementations—into the OmniRoute architecture. The platform's provider-agnostic design, implemented in diegosouzapw/OmniRoute, makes it straightforward to extend routing logic, add specialized executors, and expose agent-specific tools through the MCP server.


Understanding the OmniRoute Architecture for Coding Agents

OmniRoute organizes functionality into eight distinct layers. Each layer plays a specific role in request processing, allowing coding agents to hook into exactly the right abstraction.

Layer Location Role
API Routes src/app/api/v1/ Next.js App Router entry points. Each route follows the pattern: CORS → Zod validation → optional auth → handler delegation.
Handlers open-sse/handlers/ Core request processing. chatCore.ts orchestrates the chat flow, delegating to the AgentRouter protocol.
AgentRouter Protocol open-sse/handlers/chatCore/agentRouterProtocol.ts Determines which agent should handle a request, rewrites the payload accordingly, and selects the appropriate executor.
Executors open-sse/executors/ Low-level HTTP dispatchers for each provider. Specialized executors exist for agents needing extra handling, such as hyperagent.ts and devin-cli-agentic.ts.
Translators open-sse/translator/ Convert between provider-specific request/response formats (OpenAI ↔ Claude ↔ Gemini).
Services open-sse/services/ Higher-level logic: combo routing, rate-limit handling, caching, and resilience (circuit breakers, connection cooldowns, model lockouts).
Database src/lib/db/ SQLite-backed domain modules for persistence (quota tracking, agent-bridge state, feature flags).
Skills & Memory src/lib/skills/, src/lib/memory/ Extensible skill framework and persistent conversational memory that agents can query or update.
MCP Server open-sse/mcp-server/ 44 canonical tools (including agent-skill tools) exposing a JSON-RPC-2.0 API used by agents for tool execution.
A2A Server src/lib/a2a/ Agent-to-Agent protocol letting agents invoke each other's capabilities via standardized JSON-RPC.

The critical integration point for coding agents is the AgentRouter protocol in open-sse/handlers/chatCore/agentRouterProtocol.ts. This file's resolveAgent() function inspects incoming requests and returns the correct executor and translator pair.


Step-by-Step: Integrating a Coding Agent with OmniRoute

Follow these six steps to integrate any coding agent into the OmniRoute pipeline. Each step maps to a specific file location and includes runnable code examples.

Step 1: Register the Agent in the Provider Registry

All providers and agents must be declared in src/shared/constants/providers.ts. This registry defines the agent's name, authentication method, default model, and optional custom executor class.

// src/shared/constants/providers.ts
export const PROVIDER_REGISTRY = {
  // Existing providers …
  hyperagent: {
    name: "hyperagent",
    auth: "apiKey",
    defaultModel: "hyperagent-gpt-4",
    // Optional: custom executor class
    executor: "HyperAgentExecutor",
  },
  devin: {
    name: "devin",
    auth: "bearer",
    defaultModel: "devin-2024",
    executor: "DevInExecutor",
  },
};

The registry is imported by the AgentRouter and used to validate model identifiers before routing.


Step 2: Implement a Custom Executor (If Needed)

Most agents can reuse the generic executor. However, coding agents often require specialized authentication, custom headers, or non-standard HTTP handling. In these cases, extend BaseExecutor as shown in open-sse/executors/hyperagent.ts.

// open-sse/executors/hyperagent.ts
import { BaseExecutor } from "./base.ts";

export class HyperAgentExecutor extends BaseExecutor {
  async execute(request: any, ctx: ExecutionContext) {
    // Add HyperAgent-specific headers or auth here
    request.headers.set("x-hyperagent-key", ctx.credentials.apiKey);
    request.headers.set("x-hyperagent-version", "2024.06");
    
    // Optional: transform request body for agent-specific format
    const agentPayload = this.transformToAgentFormat(request.body);
    
    return await super.execute({ ...request, body: agentPayload }, ctx);
  }
  
  private transformToAgentFormat(body: any) {
    // Convert OpenAI-compatible messages to HyperAgent's expected schema
    return {
      prompt: body.messages.map(m => m.content).join("\n"),
      mode: "coding",
      context_window: 128000,
    };
  }
}

The DevIn executor in open-sse/executors/devin-cli-agentic.ts demonstrates another pattern: handling streaming responses with server-sent events and agentic tool loops.


Step 3: Extend the AgentRouter Decision Logic

The resolveAgent() function in open-sse/handlers/chatCore/agentRouterProtocol.ts is the routing brain. It inspects the model name, optional agent flag in the request body, and route metadata to select the correct executor.

// open-sse/handlers/chatCore/agentRouterProtocol.ts
import { HyperAgentExecutor } from "@/open-sse/executors/hyperagent";
import { DevInExecutor } from "@/open-sse/executors/devin-cli-agentic";
import { defaultTranslator, claudeTranslator } from "@/open-sse/translator/";

export interface AgentResolution {
  executor: BaseExecutor;
  translator: Translator;
  modelId: string;
}

export function resolveAgent(model: string, flags?: RequestFlags): AgentResolution {
  // HyperAgent routing
  if (model.startsWith("hyperagent-") || flags?.agent === "hyperagent") {
    return {
      executor: new HyperAgentExecutor(),
      translator: defaultTranslator,
      modelId: model.replace("hyperagent-", ""),
    };
  }
  
  // DevIn routing with specialized translator
  if (model.startsWith("devin-") || flags?.agent === "devin") {
    return {
      executor: new DevInExecutor(),
      translator: claudeTranslator, // DevIn expects Anthropic-compatible format
      modelId: model,
    };
  }
  
  // Fallback to standard provider routing...
  return resolveStandardProvider(model);
}

Add your conditional branch here to route new model identifiers to your custom executor.


Step 4: Expose Agent-Specific Tools via MCP

Coding agents often need to execute tools—file operations, code search, terminal commands. OmniRoute's MCP server exposes these capabilities through JSON-RPC-2.0. Register new tools in open-sse/mcp-server/tools/.

// open-sse/mcp-server/tools/agentSkillTools.ts
import { defineTool } from "@/open-sse/mcp-server/tools/base";
import { z } from "zod";

export const executeCode = defineTool({
  name: "executeCode",
  description: "Execute code in a sandboxed environment and return stdout/stderr.",
  inputSchema: z.object({
    language: z.enum(["typescript", "python", "rust", "go"]),
    code: z.string().max(10000),
    timeoutMs: z.number().max(60000).default(30000),
  }),
  async handler(args, ctx) {
    const result = await ctx.agent.executeInSandbox({
      language: args.language,
      code: args.code,
      timeout: args.timeoutMs,
    });
    
    return {
      stdout: result.stdout,
      stderr: result.stderr,
      exitCode: result.exitCode,
      executionTimeMs: result.duration,
    };
  },
});

export const listAgentTools = defineTool({
  name: "listAgentTools",
  description: "Returns the list of tools available to the current coding agent.",
  inputSchema: z.object({}),
  async handler(_, ctx) {
    const tools = await ctx.agent.getAvailableTools();
    return { tools };
  },
});

Tools are automatically discovered by the MCP server and exposed to any agent that connects via the JSON-RPC interface.


Step 5: Persist Agent-Specific State

Use the SQLite-backed database modules in src/lib/db/ to store per-agent quotas, connection health, or custom metadata. The agentBridgeState.ts module provides a pattern for agent-specific persistence.

// src/lib/db/agentBridgeState.ts
import { getDbInstance } from "./core";

export interface AgentState {
  lastExecutionAt: string;
  accumulatedCost: number;
  sessionTokens: number;
  customConfig: Record<string, any>;
}

export async function setAgentState(agentId: string, state: AgentState) {
  const db = getDbInstance();
  await db.run(
    `INSERT INTO agent_bridge_state (agent_id, state, updated_at) 
     VALUES (?, ?, datetime('now')) 
     ON CONFLICT(agent_id) DO UPDATE 
     SET state = excluded.state, updated_at = excluded.updated_at`,
    [agentId, JSON.stringify(state)]
  );
}

export async function getAgentState(agentId: string): Promise<AgentState | null> {
  const db = getDbInstance();
  const row = await db.get(
    `SELECT state FROM agent_bridge_state WHERE agent_id = ?`,
    [agentId]
  );
  return row ? JSON.parse(row.state) : null;
}

For quota tracking specifically, see open-sse/services/agentrouterQuotaFetcher.ts, which aggregates usage across providers and enforces limits.


Step 6: Add Dashboard UI and API Endpoints

Complete the integration with user-facing configuration and direct API access.

Dashboard pages for the new agent live under src/app/(dashboard)/dashboard/providers/:

// src/app/(dashboard)/dashboard/providers/hyperagent/page.tsx
export default function HyperAgentConfigPage() {
  return (
    <ProviderConfigForm
      providerKey="hyperagent"
      fields={[
        { name: "apiKey", type: "secret", label: "HyperAgent API Key" },
        { name: "defaultModel", type: "select", options: ["hyperagent-gpt-4", "hyperagent-claude-3"] },
        { name: "sandboxEnabled", type: "boolean", label: "Enable Code Sandbox" },
      ]}
    />
  );
}

API routes for direct agent access go under src/app/api/v1/agent/:

// src/app/api/v1/agent/hyperagent/route.ts
import { NextRequest } from "next/server";
import { validateAuth } from "@/src/lib/auth";
import { resolveAgent } from "@/open-sse/handlers/chatCore/agentRouterProtocol";

export async function POST(req: NextRequest) {
  await validateAuth(req);
  const body = await req.json();
  
  const { executor, translator } = resolveAgent(body.model, { agent: "hyperagent" });
  const response = await executor.execute(translator.translateRequest(body), getContext(req));
  
  return Response.json(translator.translateResponse(response));
}

Resilience and Rate-Limit Handling for Coding Agents

OmniRoute's three-layer resilience mechanism applies automatically to all agents because they share the same ProviderConnection abstraction. Coding agents that exceed quota or encounter transient errors are isolated without affecting other agents.

Mechanism Implementation Behavior
Provider Circuit Breaker src/shared/utils/circuitBreaker.ts Opens after consecutive failures; fast-fails requests until health recovers.
Connection Cooldown src/sse/services/auth.ts::markAccountUnavailable() Temporarily disables a specific agent-provider pair when rate limits hit.
Model Lockout open-sse/services/accountFallback.ts::checkFallbackError() Removes problematic models from rotation until manually cleared.

These mechanisms ensure that a misbehaving coding agent cannot destabilize the broader provider fleet.


Security Guarantees for Agent Integration

OmniRoute enforces security at multiple layers:

  • Input validation via Zod schemas runs before any agent logic executes in API routes.
  • Error sanitization through open-sse/utils/error.ts (buildErrorBody, sanitizeErrorMessage) prevents credential leakage in stack traces.
  • Public credential resolution via open-sse/utils/publicCreds.ts (resolvePublicCred()) safely exposes non-sensitive OAuth client IDs to agents.

Coding agents that generate goals are additionally subject to policy enforcement in open-sse/utils/agentGoalPolicy.ts, which validates goal structure and prevents recursive or excessively expensive agent loops.


Testing Your Agent Integration

All agent-related changes must be covered by:

  • Unit tests in tests/unit/ for executor and translator logic
  • MCP tool tests in tests/unit/mcp-server/ for tool handlers
  • Integration tests verifying end-to-end routing through chatCore.ts

The test suite guarantees that new agents do not break existing routing, combo strategies, or resilience layers.


Summary

Integrating coding agents with OmniRoute requires six focused steps:

  • Register the agent in src/shared/constants/providers.ts to declare capabilities and defaults
  • Implement a custom executor in open-sse/executors/ only when specialized HTTP handling is needed
  • Extend resolveAgent() in open-sse/handlers/chatCore/agentRouterProtocol.ts to route requests to your executor
  • Expose agent-specific tools through the MCP server in open-sse/mcp-server/tools/
  • Persist state using database modules in src/lib/db/ for quotas and session tracking
  • Surface configuration via dashboard pages and dedicated API routes under src/app/api/v1/agent/

Your agent automatically inherits OmniRoute's resilience, security, and multi-provider routing capabilities.


Frequently Asked Questions

How does OmniRoute decide which executor to use for a coding agent?

The resolveAgent() function in open-sse/handlers/chatCore/agentRouterProtocol.ts inspects the request's model name, optional agent flag, and route metadata. It returns an AgentResolution containing the executor, translator, and resolved model ID. Add a conditional branch matching your agent's model prefix to route requests appropriately.

Can I integrate a coding agent without building a custom executor?

Yes. If your agent uses standard API key authentication and accepts OpenAI-compatible request/response formats, you can register it in the provider registry with no custom executor. The generic BaseExecutor handles HTTP dispatch. Build a custom executor only when you need specialized headers, non-standard auth, or request/response transformation that translators cannot handle.

How do coding agents access tools like file operations or code execution?

Agents call tools through OmniRoute's MCP server, which exposes 44 canonical tools via JSON-RPC-2.0. Register new tools in open-sse/mcp-server/tools/ using defineTool(), then reference them by name in agent conversations. The agentSkillTools.ts file demonstrates the pattern for agent-specific capabilities.

What happens when a coding agent hits rate limits?

OmniRoute's resilience layer automatically puts the affected connection into cooldown via markAccountUnavailable() in src/sse/services/auth.ts. Subsequent requests to that agent-provider pair fast-fail with a 429 status, while other agents and providers remain operational. The circuit breaker in src/shared/utils/circuitBreaker.ts opens if failures persist, preventing cascade failures.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →