Overview
Providers are selected via the model field on each agent definition using a provider:model URI:
agents:
assistant:
model: "openai:gpt-4o-mini"
SirenSpec resolves the provider at runtime, instantiates the appropriate client, and calls the model’s chat completions API asynchronously.
OpenAI
Uses the official OpenAI Python SDK.
URI format: openai:<model-name>
agents:
assistant:
model: "openai:gpt-4o-mini"
system: "You are a helpful assistant."
Authentication:
export OPENAI_API_KEY=sk-...
Examples:
| URI | Model |
|---|
openai:gpt-4o-mini | GPT-4o mini |
openai:gpt-4o | GPT-4o |
openai:gpt-4-turbo | GPT-4 Turbo |
Any model name supported by the OpenAI chat completions API can be used.
Anthropic
Uses the official Anthropic Python SDK.
URI format: anthropic:<model-name>
agents:
assistant:
model: "anthropic:claude-haiku-4-5-20251001"
system: "You are a helpful assistant."
Authentication:
export ANTHROPIC_API_KEY=sk-ant-...
Examples:
| URI | Model |
|---|
anthropic:claude-haiku-4-5-20251001 | Claude Haiku |
anthropic:claude-sonnet-4-6 | Claude Sonnet |
anthropic:claude-opus-4-7 | Claude Opus |
The Anthropic provider extracts any system-role message and passes it as the top-level system parameter, as required by the Anthropic Messages API. max_tokens defaults to 4096 but is overridden per node by max_tokens_per_call.
Ollama
Uses Ollama’s OpenAI-compatible API via the OpenAI Python SDK.
URI format: ollama:<model-name>
agents:
assistant:
model: "ollama:llama3.2"
system: "You are a helpful assistant."
Configuration:
| Environment variable | Default | Description |
|---|
OLLAMA_BASE_URL | http://localhost:11434/v1 | Ollama server URL. |
OLLAMA_API_KEY | ollama | API key (for auth-protected deployments; most local setups don’t need this). |
Start Ollama locally:
ollama serve
ollama pull llama3.2
Then run your workflow:
sirenspec run workflow.yaml
Ollama must be running and the model must be pulled locally before running a workflow that references it.
Mixing Providers
You can use different providers in a single workflow. Each agent independently resolves its own provider:
agents:
classifier:
model: "openai:gpt-4o-mini"
system: "Classify the user's intent as 'question' or 'complaint'."
responder:
model: "anthropic:claude-haiku-4-5-20251001"
system: "You are a customer support agent. Compose a helpful reply."
nodes:
classify:
agent: classifier
writes: working.intent
reply:
agent: responder
writes: output.reply
edges:
- from: classify
to: reply
This workflow calls OpenAI for classification and Anthropic for the final response.
Error Handling
Provider URIs are validated when the workflow is executed. An invalid URI raises sirenspec.exceptions.ProviderError (a subclass of SirenSpecError):
import asyncio
from sirenspec import execute
from sirenspec.exceptions import ProviderError
try:
asyncio.run(execute(workflow, user_input="hello"))
except ProviderError as exc:
print(exc) # e.g. "Unknown provider 'vertex'; supported: ['anthropic', 'ollama', 'openai']"
Common reasons a ProviderError is raised:
| Cause | Example URI | Error message |
|---|
| Missing colon separator | openai-gpt4o | Malformed provider URI '...'; expected 'provider:model' format |
| Empty model name | openai: | Malformed provider URI '...'; expected 'provider:model' format |
| Unknown provider | vertex:gemini-pro | Unknown provider 'vertex'; supported: [...] |
Token Tracking
Each provider records prompt and completion token counts from every call. This usage data is surfaced in the execution trace under the usage field:
{
"nodes": [
{
"id": "answer",
"type": "agent",
"tokens": 42,
"usage": {
"prompt_tokens": 30,
"completion_tokens": 12,
"estimated_usd": null
},
...
}
],
"summary": {
"total_tokens": 42,
"total_usage": {
"prompt_tokens": 30,
"completion_tokens": 12,
"total_tokens": 42,
"estimated_usd": null
},
...
}
}
The tokens field is the sum of prompt and completion tokens; the usage field provides the detailed breakdown. estimated_usd is computed from a bundled LiteLLM pricing snapshot — it is null for models without a pricing entry (Ollama and other local backends), so the examples above show null. See Budget & Cost Control for details.