Skip to main content
Version: v5.7.0

12.6 Model providers and budgets

packs:ai-agents

After this you can: broker model credentials for an AI Agent with no key on any host, manage the catalog, mark a model approved, and meter spend with token budgets.

Before you start — tick each one:

  • Lesson 12.2 — Enrol, own, assign, grant, ceiling (opschain learn 12.2)

In the GUI: Model providers in the Operations area manages the catalog — the key field is write-only — and Felix's agent sheet links the provider it is bound to; its Budgets tab is the one pane for every allocated token budget (per provider, expandable per agent and grant), mirrored by the dashboard's Model budgets panel. Operations → Providers (the overview, and a model provider's usage dashboard) offers Export CSV — the same model-usage rows opschain agents usage -o csv prints, over the dashboard's current range and grain.

Felix takes on its second job description here: an AI Agent, type ai, reasoning against a language model. The model's API key is exactly the credential that should never be copied onto every agent host. A model provider is the platform's answer — rather than share API keys with each agent, the agent references a provider record that does the heavy lifting — and a token budget on its grant bounds what it may spend. Creating or enabling a provider needs packs:ai-agents, the same pack an ai-type Felix enrols under; the lane's reference is opschain docs ai-agents.

1. The custody model​

A provider is a first-class admin record beside identity providers and secrets providers: a code, a kind (anthropic | openai | azure-foundry-anthropic | azure-openai | openai-compatible), an endpoint (optional for the hosted kinds, where empty means the kind's default; required for the Azure kinds and openai-compatible), an encrypted, write-only API key and an enabled flag — audited writes and admin-plane authorisation on every verb.

The Azure kinds serve Microsoft estates: azure-foundry-anthropic for Claude models deployed in Azure AI Foundry (the Anthropic wire — the Claude adapter is unchanged) and azure-openai for GPT-family models on Azure OpenAI (the chat-completions wire, via the OpenAI adapter). A Microsoft 365 or GitHub Copilot seat licence is not model capacity: brokered calls consume an Azure OpenAI or Foundry deployment you provision and pay for in Azure. Authentication is by API key in this release.

Models you host yourself. The openai-compatible kind registers a model on your own infrastructure — vLLM, Ollama, TGI, llama.cpp server, LiteLLM or any stack that speaks the OpenAI wire format — under the same governance as the vendor kinds. The endpoint is required and the credential is optional: with one stored the gateway sends Authorization: Bearer, without one no auth header — the usual shape for an unauthenticated or mTLS-fronted internal endpoint. Endpoints behind a private certificate authority carry TLS trust options (--ssl-verify, --ssl-ca-cert). The gateway forwards requests and responses faithfully and never translates the protocol.

An agent in brokered custody names its provider by catalog code in its manifest (OPSCHAIN_MODEL_PROVIDER on the agent host) and calls the platform's model gateway (/api/model/{provider}/…) with its own session credential; the gateway injects the stored key server-side and streams the model's answer through. The consequences:

  • No model key ever exists on an agent host. A compromised host yields a revocable agent session, not your vendor key.
  • Rotation happens here, in one place — update the provider and every agent bound to it is rotated.
  • Registration refuses an agent whose manifest names a provider the catalog does not hold (warn:agent:model_provider_refused), so a typo fails loudly at enrolment, not silently at first model call.
  • Exactly one entry, by code. Several entries of one kind coexist on purpose; an agent uses only the entry it names. opschain admin agent show felix renders it as the MODEL PROVIDER row with the entry's kind and live standing; agents list as the PROVIDER column. The MODEL row beside it is the vendor Felix discloses, not the catalog code.

The two other custody modes keep the platform out of the path: the host's own secret handling delivers ANTHROPIC_API_KEY to the process (agent-host custody), or your vault serves the key at deploy time (vault-to-host). Felix discloses its mode either way.

2. Managing the catalog​

opschain admin model-providers create demo-anthropic --kind anthropic --credential-env ANTHROPIC_API_KEY
opschain admin model-providers list
CODE KIND ENDPOINT CREDENTIAL DATA-HANDLING ENABLED ID
demo-anthropic anthropic - set (write-only) - yes 019a0d7e-10c2-7f7a-8b53-3b1c9a4f2e01

The key is never passed on the command line — --credential-env names a variable, --credential-prompt reads it without echo, and --credential-ref pins a secret-vault:// reference — and reads report only whether a credential is stored. show <code> prints one record, update <code> with a supplied credential rotates the key, and delete <code> removes it (agents referencing it refuse at the gateway until it is re-created).

The data-handling-approved marker. Each entry carries a review marker (--data-handling-approved on create or update; the DATA-HANDLING column). Setting it records that your estate has reviewed the provider's data-processing terms — training use, retention, residency, DPA — and approves it for lanes that send customer-submitted content to a model, such as the Support SME's AI lane (lesson 12.8). Those lanes refuse to be configured against an unreviewed entry; a provider you add later inherits the same one-time check. Ordinary brokered calls over your estate's own content are not gated by the marker:

opschain admin model-providers update demo-anthropic --data-handling-approved

The column now reads approved.

3. Felix as an AI Agent​

Enrol Felix with the ai job description: the manifest declares type: ai and discloses the model, the adapter, the tool surface and custody_mode: brokered, naming demo-anthropic as its provider (opschain agent dev --type ai --model anthropic/claude-sonnet-4-5 --adapter opschain-claude-adapter --tool-surface request_lane,docs --custody brokered is the local shape; lesson 12.7). An ai-type enrolment hard-depends on packs:agent-governance + packs:ai-agents and refuses naming every missing pack, so ungoverned AI cannot even enrol — and the ai type's SUPERVISED ceiling from lesson 12.2 pins it.

Every brokered call is checked (a registered, non-revoked, non-halted agent whose manifest names the addressed provider) and audited: info:agent:model_call with the observed input_tokens and output_tokens, or warn:agent:model_call_refused. Every model interaction lands in Felix's adapter-transit transcript, redacted before persistence (lesson 12.3).

4. Token budgets — metering brokered spend​

Brokered calls are metered in the provider's own units: the gateway reads token usage — and the model the response actually served — off each response as it streams through, and lands every call in a per-minute usage bucket. A trust grant carries token caps on up to six windows beside its rate and budget caps — a sliding minute (the burst cap) and the local day, week, month, fiscal quarter and fiscal year on the estate's reporting calendar:

opschain admin trust grant --agent felix --project limebank \
--scope /projects/limebank --action 'patch_*' --tier supervised \
--tokens-per-day 500000 --tokens-per-month 8000000 \
--note "AI lane: half a million tokens a day, eight million a month"

The stored grant comes back with tokens_per_day: 500000 and tokens_per_month: 8000000 (--tokens still works as the day alias); on an estate with the approval fabric it is a supervised raise and waits in the inbox like any other (lesson 12.2). Once Felix's spend reaches a window's cap, further model calls refuse pre-flight — loudly, with warn:trust:cap_refused naming the grant, the window that failed first, the provider, the spend and the local boundary it resets at — until that window resets; at 80% of a cap warn:trust:cap_approaching warns once for the period. The windows reset on the estate's calendar, not UTC: set usage.timezone (an IANA zone) and usage.fiscal_year_start (07-01 for an Australian July year) in the global settings, or in a project's own settings for a subsidiary on another calendar.

See what was spent, and set the caps from it:

opschain agents usage --project limebank --by agent # daily tokens by agent, last 30 days
opschain agents usage --project limebank --grain minute --since 1h --by model
opschain agents usage --recommend-caps --grant <grant-id> # p95 × 1.5 per window the grant carries
opschain agents usage --recommend-caps --grant <grant-id> --propose # raise the replacement grant through the funnel

The trust review shows the spend per provider (tokens_by_provider) and, per token-capped grant, token_caps — observed against cap for every window with its local reset — with its cost attribution (cost_centre, from the project's effective metadata); the dashboard's Model tokens panel and the agent page's Usage tab show the same buckets, and every agent's row on Governance → Agents → Posture (and opschain agents posture) carries the same caps and spend beside its tier, owner, release and last action — the inventory of every agent enrolled in this estate (opschain docs agent-posture). The caps belong to the governed agent identity — owned, killable, transcribed — not to an API key. Tokens and calls are the platform's measure; -o csv hands the buckets to whoever prices them (opschain docs provider-usage).

A ceiling on the provider itself​

Grant caps bound each agent; nothing in them bounds the provider as a whole, so ten agents with a generous daily cap each can together spend more with one vendor than the estate meant to. The provider record carries its own ceiling on the same six windows — a budget across every agent and every call brokered through it, with no estate default (a ceiling is a fact of one provider's contract):

opschain admin model-providers update demo-anthropic \
--tokens-per-day 2000000 --tokens-per-month 40000000
opschain admin model-providers show demo-anthropic # Token budget: 2000000 per day, 40000000 per month

Both apply and the tighter wins: the gateway checks every window of Felix's grants first, then every window of the provider, and the first one over its ceiling refuses by name — an agent over its own cap is told so, while a provider at its ceiling answers model provider demo-anthropic: tokens per local day ceiling of 2000000 reached — resets at … to every agent through it. The same two events carry the news, with scope: provider instead of scope: grant. Read the budget on the provider's dashboard (Administration → Providers → the provider's page: a gauge per window beside its token rows), with opschain admin providers usage --kind model --code demo-anthropic (the ceiling, the spend and what remains per window) or from the opschain.provider.token_budget_remaining gauge your OTel receiver gets. In the GUI the provider dialog's Token budget group sets each window to Unlimited or a custom ceiling, and the provider's Agent token caps panel reads the grant caps beside it. The whole picture — every provider's allocated tokens per day across its agents, the spend today, the headroom, the provider's own day ceiling and an over-allocation marker, expandable per agent and grant — is the Budgets tab of Administration → Model providers, with the dashboard's Model budgets panel as its summary.

5. Entitlement and lapse​

On licence lapse, stored providers keep serving existing agents and only new registrations and the enabling of a disabled record refuse — a lapse never bricks a running fleet. The halt scalpels of lesson 12.5 apply to an AI Agent unchanged, and a model call during a halt is refused with the same typed reason in its error JSON.

Check yourself​

  • Where does the model key live, and what happens when Felix's token budget runs out?
  • Which event carries the tokens of one brokered call, and which row of opschain admin agent show felix names the catalog entry those calls go through?

What you learned​

  • A model provider is a catalog record with a write-only key; a brokered agent names it by code and never holds the key.
  • Five kinds cover the hosted vendors, the Azure deployments and any OpenAI-compatible stack you host yourself.
  • The data-handling-approved marker gates lanes that send customer-submitted content to a model.
  • A grant's token caps meter spend at the gateway on six windows — a sliding minute and the local day, week, month, fiscal quarter and fiscal year on the estate's reporting calendar; the first window over its cap refuses with warn:trust:cap_refused naming the window and its local reset, warn:trust:cap_approaching warns at 80%, opschain agents usage shows the buckets and --recommend-caps sets the caps from them.
  • A provider record can carry its own ceiling on the same six windows — a budget across every agent and call through it, checked after the grant windows (both apply, the tighter wins), refused by name, read on the provider's dashboard and with opschain admin providers usage --kind model --code <code>.

Next: lesson 12.7 — Build one: the SDK and agent dev (opschain learn 12.7), or back to your track (opschain learn).