Providers
A provider sends one request to a model and returns its answer. CommonAgent ships the Anthropic Messages API and a mock.
A provider is the only part of CommonAgent that talks to a model. It takes a request with the system blocks, messages, tool specs and token limit, and returns text, tool calls, a stop reason and token usage.
#[async_trait]
pub trait Provider: Send + Sync {
/// Provider name for the ledger, e.g. `anthropic`.
fn name(&self) -> &str;
async fn complete(&self, request: &ProviderRequest) -> Result<ProviderResponse, ProviderError>;
}ProviderRequest |
ProviderResponse |
|---|---|
model |
text: Option<String> |
system: Vec<SystemBlock> |
tool_calls: Vec<ToolCall> |
messages: Vec<Message> |
stop: end_turn, tool_use, max_tokens or other |
tools: Vec<ToolSpec> |
usage: input, output, cache read and cache write tokens |
max_tokens |
model: the model that actually answered |
Anthropic
AnthropicProvider calls the Messages API at POST /v1/messages, without streaming.
- Key:
ANTHROPIC_API_KEYfrom the profile’s.env, or else from the environmentcosruns in. Without a key,coswarns at start-up and model calls fail. - Caching: the stable and context system blocks are marked with
cache_control, so the prefix is cached across turns. See Prompt Tiers. - Tool results: adjacent messages with the same API role are merged, so several tool results become one user message, as the API expects.
- Base URL:
AnthropicProvider::new(key).with_base_url(url)points it at a proxy or gateway.
Choose it in a profile’s config.toml:
provider = "anthropic"
model = "<model id>"CommonOS ships no model ids. You choose the model per profile.
Mock
MockProvider never leaves the machine. It is how you run CommonOS with no key, and how the tests run.
It has two modes:
Scripted. Returns queued responses in order. Use it in tests.
let provider = MockProvider::scripted(vec![
MockProvider::tool_call("c1", "weather", json!({ "city": "Charleston" })),
MockProvider::text("Bring an umbrella."),
]);By rule. When the queue is empty, it answers the last message:
| Last message | Answer |
|---|---|
| A tool result | done: <results> |
delegate: <goal> |
Calls delegate_task with that goal |
remember: <fact> |
Calls memory with add |
| Anything else | echo: <text> |
Every mock call reports 100 input and 20 output tokens. Its model id is mock-1, and CommonBill has a built-in price for it, so cost reports work end to end without a key.
Use the mock for every profile at once with cos serve --mock or COMMONOS_PROVIDER=mock, or for one profile with provider = "mock".
Errors
pub enum ProviderError {
Http { status: u16, body: String },
Transport(String),
BadResponse(String),
NotConfigured(String),
}retryable() is true for HTTP 429, 5xx and transport errors. The loop reports a failed call through api_request_error and transform_api_error_classification, then ends the turn with status failed. Fallback providers on 429 and 5xx are on the roadmap.