Allow OpenAI API Compatible Provider to accept a URL
- Lenguaje dominante
- Rust
- Estrellas
- 54.2k
- Forks
- 6.2k
- Merge medio
- 3 d 2 h
- PR fusionados (30 d)
- 262
Descripción
**What problem would this solve?**
Currently the only way to add an OpenAI API compatible servers is using a declarative JSON file. Users using vLLM or llama.cpp have to deal with this.
This is cumbersome and requires the user to look up how the file should be created and making sure the syntax is correct.
**What would a good outcome look like?**
Allow the OpenAI Provider constructor to accept a URL. Then the user could provide the URL and the model and consume a local model
**Possible approaches**
Findings: refactoring openai_provider to accept a base URL
No technical blocker exists. The underlying OpenAiProvider/OpenAiProviderBuilder in crates/goose-providers/src/openai.rs is
already fully general-purpose — it's built from an ApiClient that takes an arbitrary host string, plus a configurable base_path.
It already handles custom/local OpenAI-compatible gateways correctly (e.g. should_use_responses_api deliberately avoids the
Responses API for non-default base paths, since local runtimes like vLLM/llama.cpp only implement /v1/chat/completions). This
machinery is exactly what crates/goose/src/providers/openai_def.rs::from_env already uses to support OPENAI_BASE_URL/OPENAI_HOST
for the CLI's declarative-config path.
The gap is narrow and cosmetic: openai_provider() in crates/goose-sdk/src/bindings.rs:1039 is a thin uniffi-exported wrapper that
hardcodes "https://api.openai.com" and never exposes a URL parameter — unlike anthropic_provider() right below it
(bindings.rs:1054), which already takes base_url: Option and defaults to https://api.anthropic.com when None. The
Anthropic version is the template to copy.
Mechanically trivial to fix, structurally identical to the Anthropic case:
1. Add base_url: Option to openai_provider's signature, defaulting via .unwrap_or_else(||
"https://api.openai.com".to_string()), same pattern as anthropic_provider.
2. Since uniffi bindings here are generated via #[uniffi::export] proc-macros (no hand-maintained .udl), Kotlin/Python/Swift/TS
bindings regenerate automatically from the new Rust signature — confirmed by checking the checksum-gated, clearly-generated
crates/goose-sdk/python/src/goose/__init__.py.
3. Only hand-written glue needing a matching edit: the thin per-language convenience wrappers, e.g.
crates/goose-sdk/maven/src/support/kotlin/.../providers/openai/OpenAi.kt (currently provider(apiKey) → would become
provider(apiKey, baseUrl), mirroring Anthropic.kt's provider(apiKey, baseUrl, betaHeaders)).
4. One judgment call: whether to also expose base_path (chat/completions vs versionless) as a parameter, or just let users pass a
full base URL and rely on the same /v1 auto-detection already present in openai_def.rs's CLI path (parse_openai_base_url).
Anthropic's SDK factory doesn't need this since Anthropic's API shape is fixed, but OpenAI-compatible servers vary here (some
serve /v1/chat/completions, some just /chat/completions). Reusing parse_openai_base_url (already public in
goose-providers::openai) inside the SDK factory would give vLLM/llama.cpp users a single base_url string that "just works,"
matching the CLI's UX.
No blocking issue, no breaking-change concern beyond the public SDK function signature itself (additive Option param is
backward-compatible at the Rust call site, but will shift positional args in generated bindings for other languages — worth
flagging in the PR).
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.