Cloud models behind DLP (--provider)
Not every team self-hosts. With --provider, an OpenAI, Anthropic or any OpenAI-compatible model becomes a bairav Model like any other. It has the same name, endpoint, Agents wiring, model status, upgrade and rollback. Every call goes through the bairav DLP gateway.
bairav model deploy gpt-4.1-mini --provider openai --name support-model
bairav model deploy claude-sonnet-4-5 --provider anthropic --name support-model
bairav model deploy my-llama --provider openai-compatible --base-url http://vllm.gpu:8000/v1
The first argument is the provider’s model id. Use whatever id your provider account offers; the ones above are examples.
What the gateway does
Instead of a model server, the Model runs one small container: bairav dlp serve in gateway mode (about 50 MB, starts in seconds, no download).
- Holds the API key. Agents never see it. The gateway strips any key a caller sends, so it is the only door to the provider.
- DLP on every request and response. It scans prompts, system prompts, content parts, tool-call arguments and tool results. Responses are redacted too, including streams. Every decision goes to the audit log (
docker logs/kubectl logs). - Pins the model. Callers can’t switch to a pricier model, and swapping models is a server-side change.
- Allows inference paths only.
/chat/completions,/completions,/embeddings,/responses,/messages. Anything else (files, fine-tuning, batches, admin) gets a 404.GET /v1/modelslists only the pinned model. - Fails closed. A body it can’t parse is refused, not forwarded.
- Caller tokens (optional). Set
BAIRAV_DLP_CLIENT_TOKENS(orBAIRAV_DLP_CLIENT_TOKENS_FILE) and callers must sendAuthorization: Bearer <token>orX-Api-Key: <token>; anything else gets 401. The operator doesn’t mint per-Agent tokens yet (planned, see the roadmap). Until then, on Kubernetes, anything that can reach the gateway Service can use the provider key, so restrict who can reach it. - Loopback by default. On docker the gateway port is published on
127.0.0.1only.BAIRAV_PUBLISH_ADDR=0.0.0.0opts in to LAN access.
Docker
make image-dlp # gateway image (one-time / after upgrades)
export OPENAI_API_KEY=sk-...
bin/bairav model deploy gpt-4.1-mini --provider openai --name support-model
bin/bairav chat --endpoint http://127.0.0.1:8080/v1
docker logs -f bairav-support-model # live DLP audit
The key is written to ~/.bairav/compose/support-model/provider-openai.env (mode 0600) and loaded with env_file. It is never written into docker-compose.yaml.
Key lookup order:
--api-key-env VAROPENAI_API_KEY/ANTHROPIC_API_KEYBAIRAV_PROVIDER_API_KEY
Kubernetes
export ANTHROPIC_API_KEY=sk-ant-...
bin/bairav model deploy claude-sonnet-4-5 --provider anthropic --name support-model --target k8s --namespace team-a
The CLI stores the key in the Secret support-model-anthropic-key, and only the gateway pod mounts it. To use an existing Secret, pass --api-key-secret name[:key]. Or write the Model yourself:
apiVersion: orch.bairavs.com/v1alpha1
kind: Model
metadata: { name: support-model, namespace: team-a }
spec:
provider: anthropic # local (default) | openai | anthropic | openai-compatible
repo: claude-sonnet-4-5 # provider model id
cloud:
apiKeySecretRef: { name: anthropic-key, key: api-key }
dlpAction: redact # redact | block | audit_only
dlpPacks: [global-safe, india]
# baseURL: https://... # required for openai-compatible
A cloud Model without a key Secret (or openai-compatible without baseURL) goes to Failed with a message that says what to add. kubectl get models shows a PROVIDER column.
Key rotation: after updating the Secret, run kubectl rollout restart deploy/support-model -n team-a.
Swap cloud and local (the point of all this)
Start on GPT. When the self-hosted model is good enough, move with one command. Agent code and endpoints don’t change:
bin/bairav model upgrade support-model --to Qwen/Qwen2.5-1.5B-Instruct-GGUF --provider local --target k8s --namespace team-a
bin/bairav model rollback support-model --target k8s --namespace team-a # back to GPT, provider and key included
The same safety rules as any upgrade apply:
- wait until the new model is served
- smoke prompt
- automatic rollback on failure
On docker, cloud → local keeps DLP on: the local model is deployed behind the DLP proxy, because the gateway was doing DLP before.
Anthropic: two ways in
- Native
/v1/messages(Anthropic SDK pointed at the gateway). This is the recommended path for production Claude agents. The gateway inspectssystem,messagesand tool results, redacts responses, and handles streaming events. - OpenAI format (
/v1/chat/completions). This is forwarded to Anthropic’s OpenAI-compatible endpoint, so OpenAI-SDK agents work unchanged. Anthropic describes that layer as meant mainly for testing and comparing models, not long-term production, and some fields are ignored (e.g.response_format,strict). Use it to try Claude; move to/v1/messagesfor production.
Not yet
- Streaming tool-argument deltas (
input_json_delta) and/responsesreplies are passed through without response-side redaction. Request-side inspection covers both. - Azure OpenAI’s
api-keyheader style. For now use an Azure endpoint that acceptsAuthorization: Bearer, viaopenai-compatible. - Remote MCP Skills (a URL instead of a pod). Next on the list.