LLM
Provider API directly
The built-in ops (reason/decide/…) cover most needs and keep you vendor-neutral. But when you need a parameter the ops don't expose (streaming, vision, a specific endpoint, your own retry logic), call the provider's HTTP API yourself. It's a normal HTTP request — so it's gated by net(host) and uses a secret for auth (see Secrets).
-- Doc example: calling a provider's HTTP API directly (instead of the built-in ops).
-- It's a normal HTTP request, so it is gated by net(host) and uses secret/bearer for auth.
intent: "doc example: provider API directly"
require net("api.anthropic.com")
require secret("ANTHROPIC_API_KEY")
task call_undeclared_provider()
-- api.openai.com is NOT declared → the request is denied at the capability check
give http_post("https://api.openai.com/v1/chat/completions", {}, {"x-api-key": secret("ANTHROPIC_API_KEY")})
test "a direct provider call is gated by net(host) like any HTTP request"
assert_error(call_undeclared_provider)Anthropic (Messages API) — header is x-api-key, not Bearer§
require net("api.anthropic.com")
require secret("ANTHROPIC_API_KEY")
let r be http_post("https://api.anthropic.com/v1/messages",
json_encode({"model": "claude-sonnet-4-6", "max_tokens": 256,
"messages": [{"role": "user", "content": "Say hi"}]}),
{"x-api-key": secret("ANTHROPIC_API_KEY"), -- raw secret in a CUSTOM header
"anthropic-version": "2023-06-01",
"Content-Type": "application/json"})
let reply be json of r -- parsed for you when the API answers JSON (engine v0.6.20+; json_decode(body of r) before)
let answer be reply["content"][0]["text"]
OpenAI / DeepSeek — Authorization: Bearer§
require net("api.openai.com")
require secret("OPENAI_API_KEY")
let r be http_post("https://api.openai.com/v1/chat/completions",
json_encode({"model": "gpt-4o", "messages": [{"role": "user", "content": "Say hi"}]}),
{"Authorization": bearer(secret("OPENAI_API_KEY")), "Content-Type": "application/json"})
The key is a secret: it materializes only at the socket and is redacted in logs/errors. When to use this vs. the built-in ops: the ops for portability and validated decisions; the direct API for provider-specific features. You give up vendor-neutrality and the automatic context/validation.
What the engine records (v0.6.29+). The provider's answer is an input of the program, like any HTTP response: lineage() lists it with source http_post, what = the host only (api.anthropic.com — never the path, the query or a credential) and the sha256 of the body, and receipt() publishes it — see Observability § Lineage. Two HTTP rules of the same release apply here too: an explicit port is part of the grant (require net("http://localhost:11434") covers only that port; net("localhost") covers any), and a URL with user:pass@ sends Authorization: Basic unless you pass your own Authorization — see HTTP client.