Swift client archive

The former Swift SDK is archived. Existing source and package versions may
remain available for historical use, but they receive no compatibility, update,
publication, or support guarantees. Use the supported
REST/OpenAPI contract for new integrations. See the
authoritative client support matrix for lifecycle definitions.

The remaining examples are retained as historical reference. They do not imply
that an archived package matches the current API.

Quick Start

import ModelRelay

let client = try ModelRelayClient.fromAPIKey(ProcessInfo.processInfo.environment["MODELRELAY_API_KEY"]!)

let answer = try await client.responses.text(
    model: "claude-sonnet-5",
    system: "You are a helpful assistant.",
    user: "What is the capital of France?"
)

print(answer)
// "The capital of France is Paris."

Convenience API

Ask — Get a Quick Answer

import ModelRelay

let client = try ModelRelayClient.fromAPIKey(ProcessInfo.processInfo.environment["MODELRELAY_API_KEY"]!)

let answer = try await client.ask(model: "claude-sonnet-5", prompt: "What is 2 + 2?")
print(answer) // "4"

Configuration

From API Key

import ModelRelay

// From API key string
let client = try ModelRelayClient.fromAPIKey("mr_sk_...")

// With custom base URL
let client = try ModelRelayClient.fromAPIKey(
    "mr_sk_...",
    baseURL: URL(string: "https://api.modelrelay.ai/api/v1")!
)

Making Requests

ResponseBuilder

The ResponseBuilder provides a fluent API for constructing requests:

let response = try await client.responses.create(
    client.responses
        .builder()
        .model("claude-sonnet-5")
        .system("You are a helpful assistant.")
        .user("What is 2 + 2?")
        .maxOutputTokens(256)
        .temperature(0.7)
)

print(response.text())

Multi-Turn Conversations

Build conversations with multiple messages:

let response = try await client.responses.create(
    client.responses
        .builder()
        .model("claude-sonnet-5")
        .system("You are a helpful assistant.")
        .user("My name is Alice.")
        .assistant("Hello Alice! How can I help you today?")
        .user("What's my name?")
)

Customer-Attributed Requests

For metered billing, attribute requests to customers:

let response = try await client.responses.create(
    client.responses
        .builder()
        .model("claude-sonnet-5")
        .customerId("customer-123")
        .system("You are helpful.")
        .user("Hello!")
)

Streaming

Stream Events

For real-time response streaming:

let stream = try await client.responses.stream(
    client.responses
        .builder()
        .model("claude-sonnet-5")
        .user("Write a haiku about programming.")
)

for try await event in stream {
    if event.type == .messageDelta, let delta = event.textDelta {
        print(delta, terminator: "")
    }
}
print()

Structured Output

Parse to Typed Struct

Use Codable structs to parse responses:

import ModelRelay

struct Review: Decodable {
    let risk: String
}

let schema: JSONValue = .object([
    "type": .string("object"),
    "properties": .object([
        "risk": .object(["type": .string("string")])
    ]),
    "required": .array([.string("risk")])
])

let review: Review = try await client.responses.object(
    model: "claude-sonnet-5",
    schema: schema,
    prompt: "Classify the risk as low/medium/high"
)

print(review.risk)

SQL Tool Loop

The SDK includes helpers for SQL query generation with validation:

let handlers = SQLToolLoopHandlers(
    listTables: { [SQLTableInfo(name: "users")] },
    describeTable: { _ in SQLTableDescription(table: "users", columns: []) },
    sampleRows: { args in
        SQLExecuteResult(columns: ["id"], rows: [["id": .number(1)]])
    },
    executeSQL: { args in
        SQLExecuteResult(columns: ["id"], rows: [["id": .number(1)]])
    }
)

let result = try await client.sqlToolLoop(
    model: "claude-sonnet-5",
    prompt: "Count users",
    handlers: handlers,
    profileId: "profile_1",
    maxAttempts: 3,
    resultLimit: 100
)

print(result.summary)

SQL Tool Loop (Streaming)

let stream = client.sqlToolLoopStream(
    model: "claude-sonnet-5",
    prompt: "List recent users",
    handlers: handlers,
    profileId: "profile_1"
)

for try await event in stream {
    switch event {
    case .summaryDelta(let delta):
        print(delta, terminator: "")
    case .executeSQL(let exec):
        print("Rows:", exec.result.rows.count)
    case .result(let result):
        print("Final SQL:", result.sql)
    default:
        break
    }
}

Customer-Scoped Requests

Create a customer-scoped client for attributed requests:

let customer = try client.forCustomer("customer-123")
let text = try await customer.responses.text(
    model: "claude-sonnet-5",
    user: "Say hi"
)
print(text)

Customer Token Provider

For frontend use with minted tokens:

let provider = try CustomerTokenProvider(CustomerTokenProviderConfig(
    secretKey: "mr_sk_...",
    request: CustomerTokenRequest(customerExternalId: "customer-123")
))

let tokenClient = try ModelRelayClient.fromTokenProvider(provider)
let text = try await tokenClient.responses.text(
    model: "claude-sonnet-5",
    user: "Hi"
)

Workflows + Runs

let spec: JSONValue = .object([
    "version": .string("v1"),
    "nodes": .array([])
])

let compile = try await client.workflows.compile(spec: spec)
if case .success(_, let planHash) = compile {
    let run = try await client.runs.createFromPlan(planHash: planHash)
    print(run.runId)
}

Platform Support

Platform Minimum Version
macOS 13.0
iOS 16.0
tvOS 16.0
watchOS 9.0

Next Steps