Local Codebase Study: OpenRouter SDK

What Was Researched

Architecture and implementation of the OpenRouter TypeScript SDK (OpenRouterTeam/typescript-sdk) — the official SDK for accessing 400+ language models through OpenRouter's unified API. Auto-generated from OpenAPI specs via Speakeasy, with hand-written extensions for tool orchestration, streaming, and multi-turn agent conversations.

Which Sources Were Used

  • Local clone: c:\Users\Adam\Desktop\agent2\openrouter-sdk
  • Files analyzed: OVERVIEW.md, CLAUDE.md, FUNCTIONS.md, README.md, RUNTIMES.md, package.json, tsconfig.json, src/index.ts, src/core.ts, directory structure of src/, src/lib/, src/models/, src/sdk/, src/funcs/, tests/, examples/

Key Findings

Architecture: Generated + Hand-Written Hybrid

The SDK uses a unique auto-generated + custom extension architecture:

Generated by Speakeasy (DO NOT manually edit):

  • src/models/ — Type definitions from OpenAPI schemas
  • src/funcs/*Send.ts, src/funcs/*Get.ts — API operation functions
  • src/sdk/ — SDK service classes
  • src/hooks/registration.ts — Hook registration

Hand-written (safe to edit):

  • src/lib/ — All library utilities and helpers (36 files)
  • src/funcs/call-model.ts — High-level model calling abstraction
  • src/index.ts — Main exports
  • src/hooks/hooks.ts, src/hooks/types.ts — Custom hooks

Core Abstractions

callModel (src/funcs/call-model.ts)

  • High-level function for making model requests with tools
  • Returns a ModelResult wrapper with multiple consumption patterns
  • Supports async parameter resolution and automatic tool execution
  • Consumption patterns: .getText(), .getTextStream(), .getToolStream(), etc.

ModelResult (src/lib/model-result.ts — 65KB, largest lib file)

  • Wraps streaming responses with multiple consumption patterns
  • Handles automatic tool execution and turn orchestration
  • Uses ReusableReadableStream for multiple parallel consumers
  • Critical for enabling text + tools + reasoning consumption simultaneously

Tool System (src/lib/tool*.ts)

  • tool() helper creates type-safe tools with Zod schemas
  • Three tool types:
    • Regular tools (execute: function) — auto-executed, return final result
    • Generator tools (execute: async generator) — stream preliminary results
    • Manual tools (execute: false) — return tool calls without execution
  • tool-orchestrator.ts — manages multi-turn conversations with tool execution loops
  • tool-executor.ts — executes tool calls and handles results
  • tool-context.ts — provides context to tools during execution
  • tool-event-broadcaster.ts — broadcasts tool events to consumers

Stop Conditions (src/lib/stop-conditions.ts)

  • Controls when tool execution loops terminate
  • Built-in helpers: stepCountIs(), hasToolCall(), maxTokensUsed(), maxCost(), finishReasonIs()
  • Custom conditions receive full step history
  • Default: stepCountIs(5) if not specified

Async Parameter Resolution (src/lib/async-params.ts)

  • Any parameter in CallModelInput can be a function: (ctx: TurnContext) => value
  • Functions resolved before each turn — enables dynamic model switching, temperature adjustment, etc.
  • Example: model: (ctx) => ctx.numberOfTurns > 3 ? 'gpt-4' : 'gpt-3.5-turbo'

Next Turn Params (src/lib/next-turn-params.ts)

  • Tools can modify request parameters for the next turn after execution
  • Applied after tool execution, before next API request
  • Enables dynamic parameter adjustment based on tool results

Streaming Architecture

ReusableReadableStream (src/lib/reusable-stream.ts):

  • Caches stream events to enable multiple independent consumers
  • Critical for parallel consumption (text + tools + reasoning simultaneously)
  • Handles both SSE and standard ReadableStream

Stream Transformers (src/lib/stream-transformers.ts — 32KB):

  • extractTextDeltas(), extractReasoningDeltas(), extractToolDeltas()
  • Build higher-level streams for different consumption patterns
  • Handle both streaming and non-streaming responses uniformly

Message Format Compatibility

  • OpenRouter format (native)
  • Claude format via fromClaudeMessages() / toClaudeMessage() (anthropic-compat.ts)
  • OpenAI Chat format via fromChatMessages() / toChatMessage() (chat-compat.ts)

TypeScript Configuration

  • Target: ES2020, Module: Node16
  • Strict mode: Maximum strictness (exactOptionalPropertyTypes, noUncheckedIndexedAccess)
  • Output: ESM only (no CommonJS)
  • Build: tscesm/ directory

SDK Generation Workflow

  1. Edit code in monorepo sdks/typescript/
  2. PR check dry-runs against OSS repo
  3. Release workflow runs speakeasy run, pushes to OSS repo
  4. Generated src/ copied back
  5. Speakeasy version is pinned — mismatched versions fail CI

Package Structure

Multiple exports:

  • @openrouter/sdk — Main SDK
  • @openrouter/sdk/types — Type definitions
  • @openrouter/sdk/models — Model types
  • @openrouter/sdk/models/operations — Operation types
  • @openrouter/sdk/models/errors — Error types

What Is Confirmed

  • Repository cloned successfully
  • 400+ language models accessible through unified API
  • Auto-generated from OpenAPI specs via Speakeasy
  • Type-safe with full TypeScript strict mode
  • Tool orchestration with multi-turn conversation support
  • Both streaming and non-streaming response handling
  • Message format conversion (OpenAI ↔ Claude ↔ OpenRouter)
  • ESM-only package (no CommonJS)

What Is Uncertain

  • How Speakeasy generation handles breaking API changes
  • Performance of the ReusableReadableStream for high-throughput scenarios
  • How well the async parameter resolution scales with complex tool chains
  • Whether the tool system supports MCP tools natively or requires adaptation
  • How the cost tracking works end-to-end with OpenRouter's pricing

How This Applies to Building a Modern Model-Agnostic Agent Harness

OpenRouter SDK is relevant to the harness as both a potential dependency and an architectural reference:

  1. Multi-Provider Routing: OpenRouter routes to 400+ models — the harness could use OpenRouter as a provider backend or replicate its routing model
  2. Tool System Design: The three-tier tool system (regular/generator/manual) with Zod schema validation is the most sophisticated tool abstraction studied. The harness tool layer should learn from this
  3. Stop Conditions Pattern: Programmatic control over tool execution loops (stepCountIs(), maxCost(), etc.) is essential for agent safety and directly applicable
  4. Async Parameter Resolution: The pattern of dynamically resolving parameters per-turn based on context is powerful for adaptive agent behavior
  5. Streaming Architecture: The ReusableReadableStream pattern for multiple parallel consumers is a key insight for streaming agent responses
  6. Message Format Bridges: The anthropic-compat.ts and chat-compat.ts converters show how to handle format translation at the SDK level
  7. Code Generation Strategy: The Speakeasy-based auto-generation from OpenAPI specs is a reference for keeping SDKs in sync with APIs
  8. Type Safety: The extreme TypeScript strictness (exactOptionalPropertyTypes, noUncheckedIndexedAccess) shows what production-grade SDK type safety looks like

Relevance Score: HIGH — primary reference for tool system and SDK design