CocoaPods trunk is moving to be read-only. Read more on the blog, there are 9 months to go.

SwiftAIRouter 1.0.0

SwiftAIRouter 1.0.0

Maintained by Ahsan Iqbal.



  • By
  • Ahsan Iqbal

SwiftAIRouter

SwiftAIRouter is a production-oriented, vendor-neutral iOS Swift Package for routing AI requests across multiple providers through one clean API.

Overview

SwiftAIRouter lets you integrate providers like OpenAI, Anthropic, Google, or custom backends without coupling your app architecture to one vendor.

The package provides:

  • Unified request/response types
  • Strategy-based provider and model routing
  • Automatic fallback on recoverable failures
  • Capability-aware model matching
  • Optional streaming
  • Structured JSON-oriented requests

Why SwiftAIRouter Exists

Most AI integrations become provider-specific quickly, making migration, cost optimization, and reliability difficult.

SwiftAIRouter separates:

  • Routing and selection logic
  • Provider transport/mapping logic
  • Public app-facing API

This gives teams flexibility to switch providers, add failover, and evolve model strategy without rewriting app call sites.

Installation (Swift Package Manager)

Add the dependency in Xcode using the package URL, or in Package.swift:

.package(url: "https://github.com/Ahsan-Pitafi/SwiftAIRouter.git", from: "1.0.0")

Then add the product dependency:

.product(name: "SwiftAIRouter", package: "SwiftAIRouter")

Installation (CocoaPods)

Add this line to your Podfile:

pod 'SwiftAIRouter', '~> 1.0'

Then run:

pod install

Quick Start

import SwiftAIRouter

let openAIConfig = AIProviderConfiguration(
    provider: .openAI,
    apiKey: ProcessInfo.processInfo.environment["OPENAI_API_KEY"] ?? "",
    baseURL: URL(string: "https://api.openai.com")!,
    supportedModels: [
        AIModelDescriptor(
            id: "gpt-4o-mini",
            capabilities: [.textGeneration, .streaming, .jsonOutput],
            estimatedLatencyMs: 220,
            estimatedCostScore: 18
        )
    ]
)

let config = AIRouterConfiguration(
    registeredProviders: [openAIConfig],
    defaultRoutingStrategy: .balanced,
    timeout: 60,
    retryPolicy: AIRetryPolicy(maxRetriesPerProvider: 1, baseDelayMs: 150),
    isLoggingEnabled: true
)

let router = AIRouter(configuration: config)

let response = try await router.send(
    request: AIRequest(
        prompt: "Explain Swift concurrency",
        requiredCapabilities: [.textGeneration]
    )
)

print(response.text)

Provider Configuration Example

let anthropic = AIProviderConfiguration(
    provider: .anthropic,
    apiKey: tokenStore.anthropicKey,
    baseURL: URL(string: "https://api.anthropic.com")!,
    supportedModels: [
        AIModelDescriptor(
            id: "claude-3-5-sonnet-latest",
            capabilities: [.textGeneration, .streaming, .jsonOutput, .reasoning],
            estimatedLatencyMs: 280,
            estimatedCostScore: 24
        )
    ],
    defaultHeaders: ["anthropic-version": "2023-06-01"]
)

Routing Example

let request = AIRequest(
    prompt: "Design a resilient networking layer",
    preferredProvider: .google,
    requiredCapabilities: [.textGeneration, .reasoning]
)

let response = try await router.send(request: request)

Supported strategies:

  • .balanced
  • .lowestLatency
  • .lowestCost
  • .highestCapability
  • .providerPriority([AIProviderKind])

Fallback Example

let config = AIRouterConfiguration(
    registeredProviders: [openAIConfig, anthropicConfig, googleConfig],
    defaultRoutingStrategy: .providerPriority([.openAI, .anthropic, .google]),
    retryPolicy: AIRetryPolicy(maxRetriesPerProvider: 1, baseDelayMs: 200)
)

let router = AIRouter(configuration: config)
let response = try await router.send(request: AIRequest(prompt: "Summarize this article"))

If the first provider fails with retryable/recoverable conditions, SwiftAIRouter attempts compatible fallback providers.

Streaming Example

let stream = try await router.stream(
    request: AIRequest(
        prompt: "Explain networking in iOS",
        requiredCapabilities: [.textGeneration, .streaming]
    )
)

for try await chunk in stream {
    print(chunk.delta)
}

Security Notes for API Keys

  • Never hardcode API keys in source control.
  • Inject keys from secure runtime storage (Keychain, encrypted config, CI secrets, environment variables in dev).
  • Keep key ownership in the app/infrastructure layer; SwiftAIRouter only consumes injected keys.
  • Rotate keys and scope permissions per provider.

Roadmap

  • Better cost estimation hooks using token accounting profiles
  • Circuit-breaker policy and health scoring per provider
  • Richer streaming support for tool-calling events
  • Additional provider adapters
  • Expanded integration and performance test suites