Quick start
Everything below compiles and runs from the command line. You need Swift 6.2+ (Xcode 26+) and an OpenAI API key.
Single-agent CLI
Section titled “Single-agent CLI”1. Package.swift
Section titled “1. Package.swift”import PackageDescription
let package = Package( name: "quickstart", platforms: [.macOS(.v14)], dependencies: [ .package(url: "https://github.com/2FastLabs/agent-squad", branch: "main") ], targets: [ .executableTarget(name: "quickstart", dependencies: [ .product(name: "AgentSquad", package: "agent-squad") ]) ])2. Sources/quickstart/main.swift
Section titled “2. Sources/quickstart/main.swift”import AgentSquadimport Foundation
guard let apiKey = ProcessInfo.processInfo.environment["OPENAI_API_KEY"] else { fatalError("set OPENAI_API_KEY")}
// LLM client — any OpenAI-compatible endpointlet model = ChatCompletionsClient(model: "gpt-4o-mini", apiKey: apiKey)
// One agent: name + description drive the default system promptlet agent = Agent(name: "Shop", description: "Shopping assistant", model: model)
// Orchestrator with no classifier — the single agent always handles every turnlet orchestrator = Orchestrator( agents: [agent], store: try DeviceChatStorage(userId: "u1", inMemory: true))
// route(_:userId:sessionId:) returns an AsyncThrowingStream<AgentEvent, any Error>for try await event in orchestrator.route( .text("wireless headphones under €100?"), userId: "u1", sessionId: "s1") { if case .textDelta(let token) = event { print(token, terminator: "") }}print()3. Run
Section titled “3. Run”OPENAI_API_KEY=sk-… swift runRouting between agents
Section titled “Routing between agents”Add a second agent and an LLMClassifier — the call site is identical:
let shop = Agent(name: "Shop", description: "Product search, prices, recommendations.", model: model)let support = Agent(name: "Support", description: "Orders, returns, and account help.", model: model)
let orchestrator = Orchestrator( agents: [shop, support], // first agent is the default / fallback classifier: LLMClassifier(model: model), // picks the agent for each turn store: try DeviceChatStorage(userId: "u1", inMemory: true))
for try await event in orchestrator.route( .text("where is my order #1234?"), userId: "u1", sessionId: "s1") { if case .textDelta(let token) = event { print(token, terminator: "") }}LLMClassifier uses the same LLMClient type as the agents. You can pass a separate, cheaper model for routing if you like:
let router = ChatCompletionsClient(model: "gpt-4o-mini", apiKey: apiKey)LLMClassifier(model: router)Key types at a glance
Section titled “Key types at a glance”| Type | Role |
|---|---|
ChatCompletionsClient | LLMClient for any OpenAI-compatible endpoint (OpenAI, Azure, Groq, OpenRouter, Ollama, …) |
Agent | Single-LLM agent; accepts optional tools: and a custom systemPrompt: |
Orchestrator | Drives a turn end-to-end: classify → run agent → stream events → persist |
LLMClassifier | Routes turns to agents via a select_agent tool call |
AgentEvent.textDelta | Token-by-token text streamed from the agent |
What to do next
Section titled “What to do next”- Add tools to an agent — see Agents and Tools.
- Swap
AgentforGroundedAgentfor hallucination-resistant answers — see GroundedAgent. - Understand every event the stream can emit — see Messages & events.
- Point
ChatCompletionsClientat a different provider — see LLM clients. - Persist chat history across sessions — see Chat history.
- Observe what happens inside a turn — see Tracing.