rig_core/providers/opencode.rs
1//! OpenCode Zen and Go: gateways that serve each model on one of three APIs,
2//! Chat Completions, Responses or Anthropic's Messages.
3//!
4//! Which API serves a model is in the model catalog, so
5//! [`Catalog::connect`](crate::catalog::Catalog::connect) reaches each one on
6//! its own. The constructors here build one client per format: [`from_env`]
7//! and [`new`] for Zen's Chat Completions and Responses, which
8//! [`OpenAI::completion`](crate::providers::openai::OpenAI::completion)
9//! chooses between by the catalog (a model it does not list goes to Chat
10//! Completions; name another route with
11//! [`with_route`](crate::providers::openai::OpenAIConfig::with_route)), and
12//! [`anthropic_from_env`] and [`anthropic_new`] for its Messages models. A
13//! Messages model asked of the first client goes to Chat Completions, which
14//! does not serve it. The `go_` constructors are Go's. Both read
15//! `OPENCODE_API_KEY`. Zen's free models answer only OpenCode's own client.
16//! The Messages endpoints list no models, so list them through the first
17//! client. Neither client checks a key without spending tokens.
18//!
19//! Go refuses a request without an `x-opencode-session` header, which
20//! carries the request's
21//! [`cache_key`](crate::completion::GenerationOptions::cache_key), or a fresh
22//! id without one. Set one key per conversation, so Go routes its turns
23//! together and reuses their prompt cache.
24//!
25//! ```no_run
26//! use rig_core::catalog::Catalog;
27//! use rig_core::providers::opencode;
28//!
29//! # fn run() -> Result<(), Box<dyn std::error::Error>> {
30//! let haiku = Catalog::builtin().connect("opencode/claude-haiku-5-5")?;
31//! let glm = opencode::go_from_env()?.completion("glm-5.3");
32//! # let _ = (haiku, glm);
33//! # Ok(())
34//! # }
35//! ```
36
37/// Zen's provider key: the dialect name, a reply's `Origin::provider` and
38/// the catalog vendor.
39pub(crate) const ZEN: &str = "opencode";
40
41/// Go's provider key.
42pub(crate) const GO: &str = "opencode-go";
43
44/// The header Go routes a conversation's requests together by.
45pub(crate) const SESSION_HEADER: &str = "x-opencode-session";
46
47crate::client::macros::openai_vendor!(crate::providers::openai::wire::OPENCODE, "OpenCode Zen");
48crate::client::macros::openai_vendor!(
49 crate::providers::openai::wire::OPENCODE_GO,
50 "OpenCode Go",
51 go_from_env,
52 go_new
53);
54crate::client::macros::anthropic_vendor!(
55 crate::providers::anthropic::wire::OPENCODE,
56 "OpenCode Zen",
57 anthropic_from_env,
58 anthropic_new
59);
60crate::client::macros::anthropic_vendor!(
61 crate::providers::anthropic::wire::OPENCODE_GO,
62 "OpenCode Go",
63 go_anthropic_from_env,
64 go_anthropic_new
65);
66
67#[cfg(test)]
68mod tests;