Migrating from the TypeScript Agent SDK

May 7, 2026 ยท View on GitHub

The Swift AgentSDK mirrors the TypeScript @autohandai/agent-sdk-typescript architecture with Swift-native idioms. This guide maps TypeScript patterns to their Swift equivalents.

Key Differences

TypeScript SDKSwift SDK
Agent class with run() methodAgent class + Runner.run() static method
Promise-based asyncSwift concurrency (async/await)
Tool string union typeToolName enum
Message discriminated unionMessage enum with associated values
SDKError class hierarchyAgentSDKError enum
Provider interfaceProvider protocol
ToolDefinition abstract classToolDefinition protocol
LoopStrategy interfaceLoopStrategy protocol
Zod validationCodable + manual validation
Runner static classRunner class with static methods

Replacing Agent.run()

TypeScript:

import { Agent, OpenRouterProvider } from '@autohandai/agent-sdk-typescript';

const agent = new Agent('Assistant', 'You are helpful.', tools);
agent.setProvider(new OpenRouterProvider('api-key', 'gpt-4'));

const result = await agent.run('Summarize the API');
console.log(result);

Swift:

import AgentSDK

let provider = OpenAIProvider(apiKey: "sk-...")

let agent = Agent(
    name: "Assistant",
    instructions: "You are a helpful coding assistant.",
    tools: [.readFile, .bash],
    model: ModelID("gpt-4o"),
    provider: provider
)

let result = try await Runner.runSync(
    agent: agent,
    prompt: "Summarize the API"
)
print(result)

Replacing Provider Configuration

TypeScript:

import { OpenRouterProvider } from '@autohandai/agent-sdk-typescript/providers';

const provider = new OpenRouterProvider({ apiKey: 'sk-or-...' });

Swift:

// OpenAI
let provider = OpenAIProvider(apiKey: "sk-...")

// OpenRouter (uses OpenAI-compatible API)
let provider = OpenAIProvider(
    apiKey: "sk-or-...",
    baseURL: URL(string: "https://openrouter.ai/api/v1")!
)

// Via factory
let provider = try ProviderFactory.create(
    providerName: "openrouter",
    apiKey: "sk-or-..."
)

Replacing Tool Registration

TypeScript:

import { ToolDefinition } from '@autohandai/agent-sdk-typescript';

class MyTool extends ToolDefinition {
    getName() { return 'my_tool'; }
    getDescription() { return 'Does something.'; }
    getParameters() { return { type: 'object', properties: {} }; }
    async executeInternal(params) {
        return { data: 'result' };
    }
}

Swift:

struct MyTool: ToolDefinition {
    let name = "my_tool"
    let description = "Does something."
    let annotations = ToolAnnotations()
    let parameters: [String: AnyCodable] = [
        "type": AnyCodable("object"),
        "properties": AnyCodable([:] as [String: Any]),
    ]

    func execute(params: [String: AnyCodable]) async throws -> ToolResult {
        return .success(data: "result")
    }
}

Replacing Streaming

TypeScript:

for await (const event of agent.stream('Hello')) {
    if (event.type === 'content') {
        process.stdout.write(event.data);
    }
}

Swift:

let stream = Runner.runStream(agent: agent, prompt: "Hello")

for try await event in stream {
    if event.type == .content {
        print(event.data ?? "", terminator: "")
    }
}

Replacing Error Handling

TypeScript:

try {
    await agent.run('Do something');
} catch (error) {
    if (error instanceof ToolExecutionError) {
        console.error(`Tool ${error.toolName} failed`);
    }
}

Swift:

do {
    let result = try await Runner.runSync(agent: agent, prompt: "Do something")
} catch let error as AgentSDKError {
    switch error {
    case .toolExecution(_, let toolName, _):
        print("Tool \(toolName) failed")
    default:
        print(error.localizedDescription)
    }
}

Replacing Hooks

TypeScript:

import { HookManager } from '@autohandai/agent-sdk-typescript';

const hookManager = new HookManager();
hookManager.addHook({
    event: 'before-execution',
    command: 'echo "Starting..."',
});

Swift:

let hookManager = HookManager()
hookManager.addHook(HookDefinition(
    event: .beforeExecution,
    command: "echo 'Starting...'"
))
Runner.setHookManager(hookManager)

Replacing Permissions

TypeScript:

import { PermissionManager } from '@autohandai/agent-sdk-typescript';

const permManager = new PermissionManager(hookManager, 'ask');
const result = await permManager.requestPermission({
    tool: 'bash',
    args: { command: 'rm -rf /' },
});

Swift:

let permManager = PermissionManager(hookManager: hookManager, mode: .ask)
let result = await permManager.requestPermission(
    PermissionRequest(tool: .bash, command: "rm -rf /")
)

Type Mapping Reference

TypeScriptSwift
string & { __brand: 'ToolCallId' }ToolCallID
string & { __brand: 'SessionId' }SessionID
string & { __brand: 'ModelId' }ModelID
(typeof TOOL_NAMES)[number]ToolName enum
UserMessage | AssistantMessage | ...Message enum
ToolResultSuccess | ToolResultErrorToolResult enum
RunResultSuccess | RunResultMaxTurnsRunResult enum
Record<string, unknown>[String: AnyCodable]
AsyncGenerator<StreamEvent>AsyncThrowingStream<StreamEvent, Error>
Promise<T>async throws -> T

When to Stay on the TypeScript SDK

  • You need the full CLI wrapper with JSON-RPC subprocess management
  • You're building Node.js/Bun server applications
  • You need the MCP server integration

For native macOS/iOS applications, the Swift SDK provides a lightweight, in-process alternative with the same agent execution semantics.