mirror of
https://github.com/openai/codex.git
synced 2026-04-28 10:21:06 +03:00
4.3 KiB
4.3 KiB
DOs
- Built‑in Provider ID: Reference the OSS provider via the constant and
built_in_model_providers.
let prov = codex_core::built_in_model_providers()
.get(codex_core::BUILT_IN_OSS_MODEL_PROVIDER_ID)
.expect("oss provider");
let base = prov.base_url.as_deref().expect("base_url");
- Base URL Defaults: Honor
CODEX_OSS_BASE_URL, fall back toCODEX_OSS_PORTor11434, and suffix/v1.
let port = std::env::var("CODEX_OSS_PORT")
.ok()
.and_then(|v| v.parse::<u32>().ok())
.unwrap_or(11434);
let base_url = std::env::var("CODEX_OSS_BASE_URL")
.ok()
.filter(|s| !s.trim().is_empty())
.unwrap_or_else(|| format!("http://localhost:{port}/v1"));
- Health Probe: Detect OpenAI‑compatible roots (
.../v1) and probe the right endpoint.
let root = codex_ollama::url::base_url_to_host_root(base_url);
let url = if codex_ollama::url::is_openai_compatible_base_url(base_url) {
format!("{root}/v1/models")
} else {
format!("{root}/api/tags")
};
let ok = reqwest::Client::new().get(url).send().await?.status().is_success();
- Profile Macro: Prefer
--profile oss(backed by a profile) to pick provider and default model together.
# config.toml
[profile.oss]
model_provider = "oss"
default_model = "llama3.2:3b"
// Normalize to profile-based flow
let overrides = ConfigOverrides {
config_profile: Some("oss".into()), // when user selects OSS shortcut
model_provider: None, // let profile supply this
..Default::default()
};
- Exec Parity: Mirror the TUI OSS shortcut/profile behavior in
codex exec.
// In exec CLI bootstrap
if cli.config_profile.as_deref() == Some("oss") {
let client = codex_ollama::OllamaClient::from_oss_provider();
if !client.probe_server().await? {
eprintln!("Ollama not reachable at {}.", client.get_host());
std::process::exit(1);
}
}
- Streamed Pull: Parse newline‑delimited JSON, emit events, and aggregate progress for a clean UX.
let mut stream = resp.bytes_stream();
let mut buf = bytes::BytesMut::new();
while let Some(chunk) = stream.next().await {
buf.extend_from_slice(&chunk?);
while let Some(nl) = buf.iter().position(|b| *b == b'\n') {
let line = buf.split_to(nl + 1);
if let Ok(v) = serde_json::from_slice::<serde_json::Value>(&line) {
for ev in pull_events_from_value(&v) { /* handle PullEvent */ }
}
}
}
DON'Ts
- Don’t Mutate User Config: Do not write providers into
config.tomlat runtime; use built‑ins and overrides.
// Good: ephemeral override, no file writes
let overrides = ConfigOverrides {
model_provider: Some("oss".into()),
..Default::default()
};
- Don’t Require Auth For OSS: Keep
requires_auth = falseand omit OpenAI‑specific headers for the OSS provider.
ModelProviderInfo {
name: "Open Source".into(),
base_url: Some(base_url),
requires_auth: false,
http_headers: None,
env_http_headers: None,
wire_api: WireApi::Chat,
..Default::default()
}
- Don’t Hardcode Native Endpoints: Avoid always calling
/api/tags; switch to/v1/modelswhen base URL ends with/v1.
let url = if is_openai_compatible_base_url(base_url) {
format!("{root}/v1/models")
} else {
format!("{root}/api/tags")
};
- Don’t Spam Status Output: Filter noisy statuses and render single‑line, in‑place progress updates.
if status.eq_ignore_ascii_case("pulling manifest") {
// skip noisy manifest lines
} else {
eprint!("\r{status}");
std::io::stderr().flush()?;
}
- Don’t Make TUI‑Only UX: Any OSS‑selection shortcut must also exist in
codex exec.
// Share the same normalization path
let profile = cli.config_profile.or_else(|| cli.oss.then(|| "oss".into()));
let overrides = ConfigOverrides { config_profile: profile, ..Default::default() };
- Don’t Run Networked Tests In Sandbox: Skip wiremock/network tests when sandboxed without network.
#[tokio::test]
async fn test_fetch_models() {
if std::env::var(codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
tracing::info!("sandboxed; skipping");
return;
}
// wiremock-based test body...
}