Custom Classifiers
Any type that conforms to Classifier can be passed to the Orchestrator in place of LLMClassifier. This is the right choice when you need deterministic routing (keyword rules, regex, external service calls, ML models) without an LLM round-trip.
See the Classifiers overview for how ClassifierResult drives the dispatch.
Protocol
Section titled “Protocol”public protocol Classifier: Sendable { func classify( _ input: String, history: [ConversationMessage], agents: [any AgentProtocol] ) async throws -> ClassifierResult}Your implementation receives:
| Parameter | Type | Notes |
|---|---|---|
input | String | The user’s current message. |
history | [ConversationMessage] | Merged, [agentId]-prefixed conversation from chat storage. |
agents | [any AgentProtocol] | The full set of agents registered with the Orchestrator. |
It must return a ClassifierResult:
public struct ClassifierResult: Sendable { public let selectedAgent: (any AgentProtocol)? public let confidence: Double
public init(selectedAgent: (any AgentProtocol)?, confidence: Double)}Example: KeywordClassifier
Section titled “Example: KeywordClassifier”A simple classifier that matches agent names against words in the user’s input:
struct KeywordClassifier: Classifier { func classify( _ input: String, history: [ConversationMessage], agents: [any AgentProtocol] ) async throws -> ClassifierResult { let lower = input.lowercased() let match = agents.first { agent in lower.contains(agent.name.lowercased()) } return ClassifierResult( selectedAgent: match, confidence: match != nil ? 1.0 : 0.0 ) }}Pass it to the Orchestrator exactly like the built-in one:
let orchestrator = Orchestrator(classifier: KeywordClassifier(), storage: storage)- Return
ClassifierResult(selectedAgent: nil, confidence: 0.0)when no agent matches; the Orchestrator falls back to the first registered agent. confidenceis captured for tracing only and does not affect dispatch. Use it to record routing certainty without building threshold logic into the Orchestrator.classifyisasync throws, so you can call remote services, run Core ML inference, or await any other async work.- Because
ClassifierinheritsSendable, all stored state must beSendable-safe (value types or actors).
Related pages
Section titled “Related pages”- Classifiers overview — the
Classifierprotocol,ClassifierResult, and the nil-classifier path. - LLMClassifier — built-in LLM-based routing.
- Agents overview —
AgentProtocoland the agents you route to.